Skip to content

Commit

Permalink
Add getImportableModules util
Browse files Browse the repository at this point in the history
  • Loading branch information
simonihmig committed Sep 10, 2024
1 parent a0a8021 commit aa4dbb8
Show file tree
Hide file tree
Showing 5 changed files with 262 additions and 38 deletions.
9 changes: 9 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"watch": "cd packages/ember-auto-import && npm run compile -- --watch"
},
"dependencies": {
"pkg-entry-points": "^1.0.2",
"resolve-package-path": "^3.1.0",
"semver": "^7.3.5"
},
Expand Down
231 changes: 231 additions & 0 deletions packages/ember-auto-import/ts/tests/util-test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,231 @@
import QUnit from 'qunit';
import 'qunit-assertions-extra';
import { commonAncestorDirectories, getImportableModules } from '../util';
import { Project } from 'scenario-tester';

const { module: Qmodule, test } = QUnit;

async function generateProject(packageJson = {}) {
const project = new Project('my-package', {
files: {
'package.json': JSON.stringify(packageJson),
src: {
'index.js': 'export default 123',
'module.js': 'export default 123',
nested: {
'module.js': 'export default 123',
},
},
dist: {
'index.js': 'export default 123',
'module.js': 'export default 123',
nested: {
'module.js': 'export default 123',
},
},
declarations: {
'index.d.ts': 'export default 123',
'module.d.ts': 'export default 123',
nested: {
'module.d.ts': 'export default 123',
},
},
lib: {
'module.js': 'export default 123',
},
},
});

await project.write();

return project;
}

Qmodule('commonAncestorDirectories', function () {
test('returns same dirs if no nested', function (assert) {
const result = commonAncestorDirectories([
'/a/b/c/index.js',
'/d/index.js',
]);

assert.deepEqual(result, ['/a/b/c', '/d']);
});

test('returns common dirs', function (assert) {
const result = commonAncestorDirectories([
'/a/b/c/index.js',
'/a/b/index.js',
'/d/index.js',
'/d/e/f/index.js',
]);

assert.deepEqual(result, ['/a/b', '/d']);
});

test('ignores duplicates', function (assert) {
const result = commonAncestorDirectories([
'/a/b/c/index.js',
'/a/b/index.js',
'/a/b/c/index.js',
'/a/b/index.js',
]);

assert.deepEqual(result, ['/a/b']);
});
});

Qmodule('importableModules', function (hooks) {
let project: Project;

hooks.afterEach(function (this: any) {
project?.dispose();
});

test('returns only modules declared in exports', async function (assert) {
project = await generateProject({
exports: './dist/index.js',
});

const result = await getImportableModules(project.baseDir);

assert.deepEqual(result, ['./dist/index.js']);
});

test('ignores types condition', async function (assert) {
project = await generateProject({
exports: {
'.': {
types: './declarations/index.d.ts',
default: './dist/index.js',
},
},
});

const result = await getImportableModules(project.baseDir);

assert.deepEqual(result, ['./dist/index.js']);
});

test('ignores node condition', async function (assert) {
project = await generateProject({
exports: {
'.': {
types: './declarations/index.d.ts',
default: './dist/index.js',
},
'lib/module': {
node: './lib/module.js',
},
},
});

const result = await getImportableModules(project.baseDir);

assert.deepEqual(result, ['./dist/index.js']);
});

test('supports import condition', async function (assert) {
project = await generateProject({
exports: {
'.': {
types: './declarations/index.d.ts',
import: './dist/index.js',
},
},
});

const result = await getImportableModules(project.baseDir);

assert.deepEqual(result, ['./dist/index.js']);
});

test('supports nested conditions', async function (assert) {
project = await generateProject({
exports: {
'.': {
import: {
types: './declarations/index.d.ts',
default: './dist/index.js',
},
},
},
});

const result = await getImportableModules(project.baseDir);

assert.deepEqual(result, ['./dist/index.js']);
});

test('supports subpaths', async function (assert) {
project = await generateProject({
exports: {
'.': {
types: './declarations/index.d.ts',
default: './dist/index.js',
},
module: {
types: './declarations/module.d.ts',
default: './dist/module.js',
},
'nested/module': {
types: './declarations/nested/module.d.ts',
default: './dist/nested/module.js',
},
},
});

const result = await getImportableModules(project.baseDir);

assert.deepEqual(result, [
'./dist/index.js',
'./dist/module.js',
'./dist/nested/module.js',
]);
});

test('supports globstar patterns', async function (assert) {
project = await generateProject({
exports: {
'.': {
types: './declarations/index.d.ts',
default: './dist/index.js',
},
'./*': {
types: './declarations/*.d.ts',
default: './dist/*.js',
},
},
});

const result = await getImportableModules(project.baseDir);

assert.deepEqual(result, [
'./dist/index.js',
'./dist/module.js',
'./dist/nested/module.js',
]);
});

test('returns all possible imports when having only main export', async function (assert) {
project = await generateProject({
main: './dist/index.js',
});

const result = await getImportableModules(project.baseDir);

assert.deepEqual(result, [
'./declarations/index.d.ts',
'./declarations/module.d.ts',
'./declarations/nested/module.d.ts',
'./dist/index.js',
'./dist/module.js',
'./dist/nested/module.js',
'./index.js',
'./lib/module.js',
'./package.json',
'./src/index.js',
'./src/module.js',
'./src/nested/module.js',
]);
});
});
38 changes: 0 additions & 38 deletions packages/ember-auto-import/ts/tests/util.ts

This file was deleted.

21 changes: 21 additions & 0 deletions packages/ember-auto-import/ts/util.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import isSubdir from 'is-subdir';
import { dirname } from 'path';
// @ts-expect-error types don't resolve
import { getPackageEntryPoints } from 'pkg-entry-points';

export function shallowEqual(a: any[], b: any[]) {
return (
Expand Down Expand Up @@ -33,3 +35,22 @@ export function commonAncestorDirectories(dirs: string[]): string[] {
return newResults;
}, [] as string[]);
}

export async function getImportableModules(
packagePath: string
): Promise<string[]> {
const entryPoints = await getPackageEntryPoints(packagePath);

return Object.values(entryPoints)
.map(
(alternatives) =>
alternatives.find(
([conditions]) =>
(conditions.includes('import') || conditions.includes('default')) &&
!conditions.includes('types') &&
!conditions.includes('node')
)?.[1]
)
.filter((item): item is string => !!item)
.filter((item, index, array) => array.indexOf(item) === index);
}

0 comments on commit aa4dbb8

Please sign in to comment.