Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/hot-cars-leave.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@codeshift/fetcher': patch
'@codeshift/cli': patch
---

Correctly checks remote pacakge entrypoints for configs (as opposed to just checking for codeshift.config.js files)
37 changes: 37 additions & 0 deletions packages/cli/src/list.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ describe('list', () => {
})),
}));
});

afterEach(() => {
jest.resetAllMocks();
});
Expand All @@ -37,6 +38,12 @@ describe('list', () => {
├─ transforms
| ├─ 18.0.0
| └─ 19.0.0
└─ presets
└─ sort-imports
${chalk.bold('foobar')}
├─ transforms
| ├─ 18.0.0
| └─ 19.0.0
└─ presets
└─ sort-imports`);
expect(console.warn).not.toHaveBeenCalled();
Expand All @@ -51,6 +58,12 @@ describe('list', () => {
├─ transforms
| ├─ 18.0.0
| └─ 19.0.0
└─ presets
└─ sort-imports
${chalk.bold('@foo/bar')}
├─ transforms
| ├─ 18.0.0
| └─ 19.0.0
└─ presets
└─ sort-imports`);
expect(console.warn).not.toHaveBeenCalled();
Expand All @@ -65,12 +78,24 @@ describe('list', () => {
├─ transforms
| ├─ 18.0.0
| └─ 19.0.0
└─ presets
└─ sort-imports
${chalk.bold('bar')}
├─ transforms
| ├─ 18.0.0
| └─ 19.0.0
└─ presets
└─ sort-imports
${chalk.bold('@codeshift/mod-foo__bar')}
├─ transforms
| ├─ 18.0.0
| └─ 19.0.0
└─ presets
└─ sort-imports
${chalk.bold('@foo/bar')}
├─ transforms
| ├─ 18.0.0
| └─ 19.0.0
└─ presets
└─ sort-imports`);
expect(console.warn).not.toHaveBeenCalled();
Expand Down Expand Up @@ -136,12 +161,24 @@ ${chalk.bold('@codeshift/mod-foo__bar')}
├─ transforms
| ├─ 18.0.0
| └─ 19.0.0
└─ presets
└─ sort-imports
${chalk.bold('found1')}
├─ transforms
| ├─ 18.0.0
| └─ 19.0.0
└─ presets
└─ sort-imports
${chalk.bold('@codeshift/mod-found2')}
├─ transforms
| ├─ 18.0.0
| └─ 19.0.0
└─ presets
└─ sort-imports
${chalk.bold('found2')}
├─ transforms
| ├─ 18.0.0
| └─ 19.0.0
└─ presets
└─ sort-imports`);

Expand Down
58 changes: 58 additions & 0 deletions packages/fetcher/src/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,10 @@ describe('fetcher', () => {
it('correctly fetches package and returns a config', async () => {
const mockPackageManager = {
install: jest.fn(),
require: jest
.fn()
.mockReturnValueOnce({}) // fail the entrypoint config check
.mockReturnValueOnce(mockConfig),
getInfo: jest.fn().mockReturnValue({
location: mockBasePath,
}),
Expand Down Expand Up @@ -166,6 +170,60 @@ describe('fetcher', () => {
).rejects.toEqual('Import error');
});

it('correctly fetches package and returns an entrypoint-based config', async () => {
const mockPackageManager = {
install: jest.fn(),
require: jest.fn().mockReturnValueOnce(mockConfig),
getInfo: jest.fn().mockReturnValue({
location: mockBasePath + '/index.js',
}),
};

const { config, filePath } = await fetchRemotePackage(
'fake-package',
mockPackageManager as unknown as PluginManager,
);

expect(config).toEqual(mockConfig);
expect(filePath).toEqual(mockBasePath + '/index.js');
});

it('throws if entrypoint-based config does not contain a valid config (and there are no config files available elsewhere)', async () => {
const mockPackageManager = {
install: jest.fn(),
require: jest.fn().mockReturnValueOnce({}),
getInfo: jest.fn().mockReturnValue({
location: mockBasePath + '/index.js',
}),
};

(globby as unknown as jest.Mock).mockImplementation(() =>
Promise.resolve([]),
);

const res = await fetchRemotePackage(
'fake-package',
mockPackageManager as unknown as PluginManager,
);

expect(res).toBeUndefined();
});

it('should throw if fetching fails', async () => {
const mockPackageManager = {
install: jest.fn().mockRejectedValue('Import error'),
};

expect.assertions(1);

await expect(
fetchRemotePackage(
'fake-package',
mockPackageManager as unknown as PluginManager,
),
).rejects.toEqual('Import error');
});

it('should throw if package source cannot be retrieved', async () => {
const mockPackageManager = {
install: jest.fn(),
Expand Down
18 changes: 18 additions & 0 deletions packages/fetcher/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ export async function fetchConfig(filePath: string): Promise<ConfigMeta> {

export async function fetchConfigs(filePath: string): Promise<ConfigMeta[]> {
const matchedPaths = await globby([
path.join(filePath, 'hypermod.config.(js|ts|tsx)'),
path.join(filePath, 'src', 'hypermod.config.(js|ts|tsx)'),
path.join(filePath, 'codemods', 'hypermod.config.(js|ts|tsx)'),
path.join(filePath, 'codeshift.config.(js|ts|tsx)'),
path.join(filePath, 'src', 'codeshift.config.(js|ts|tsx)'),
path.join(filePath, 'codemods', 'codeshift.config.(js|ts|tsx)'),
Expand Down Expand Up @@ -101,5 +104,20 @@ export async function fetchRemotePackage(
);
}

// Search main entrypoint for transform/presets from the default import
try {
const pkg = packageManager.require(packageName);
const configExport = resolveConfigExport(pkg);

if (configExport.transforms || configExport.presets) {
return {
filePath: info.location,
config: resolveConfigExport(pkg),
};
}
} catch (e) {
// Swallow this error
}

return await fetchConfig(info.location);
}