Skip to content

Commit

Permalink
fix(analyzer): ignore type-only imports & exports (#433)
Browse files Browse the repository at this point in the history
Backports #380.

* fix(analyzer): ignore type-only imports & exports

* test(analyzer): type-only imports ignored in created file

* test(analyzer): add `@babel/plugin-syntax-typescript`

If the TS syntax plugin is not loaded, the following scenarios fail, as the `import type` syntax is not understood:
- `lts-own`
- `release-own`
- `beta-own`
- `canary-own`

* test(analyzer): conditional `babel@7` tests

The `import type` syntax is only available with `babel@7`, but
`ember-auto-import@1.x` only tests for `babel@6`.

This commit makes the `analyzer` test module run twice: once for
`babel@6` an once for `babel@7`, where the latter has a different babel
plugin configuration and runs the addition `import type` test.
  • Loading branch information
buschtoens committed Aug 13, 2021
1 parent d84da44 commit 3ac52ff
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 15 deletions.
2 changes: 2 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 packages/ember-auto-import/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
"webpack": "^4.43.0"
},
"devDependencies": {
"@babel/plugin-syntax-typescript": "^7.12.13",
"@types/babel-core": "^6.25.5",
"@types/babel__core": "^7.0.4",
"@types/babel__generator": "^7.0.1",
Expand Down
32 changes: 22 additions & 10 deletions packages/ember-auto-import/ts/analyzer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { isEqual, flatten } from 'lodash';
import type Package from './package';
import symlinkOrCopy from 'symlink-or-copy';
import { TransformOptions } from '@babel/core';
import { Expression, File, TSType } from '@babel/types';
import type { ExportNamedDeclaration, Expression, File, ImportDeclaration, TSType } from '@babel/types';
import traverse from '@babel/traverse';

makeDebug.formatters.m = (modules: Import[]) => {
Expand Down Expand Up @@ -78,6 +78,15 @@ export default class Analyzer extends Plugin {

private parse: undefined | ((source: string) => File);

// Ignores type-only imports & exports, which are erased from the final build
// output.
// TypeScript: `import type foo from 'foo'`
// Flow: `import typeof foo from 'foo'`
private erasedImportKinds: Set<ImportDeclaration['importKind']> = new Set(['type', 'typeof']);
// TypeScript: `export type foo from 'foo'`
// Flow: doesn't have type-only exports
private erasedExportKinds: Set<ExportNamedDeclaration['exportKind']> = new Set(['type']);

constructor(inputTree: Node, private pack: Package, private treeType?: TreeType) {
super([inputTree], {
annotation: 'ember-auto-import-analyzer',
Expand Down Expand Up @@ -231,6 +240,8 @@ export default class Analyzer extends Plugin {
}
},
ImportDeclaration: path => {
if (this.erasedImportKinds.has(path.node.importKind)) return;

imports.push({
isDynamic: false,
specifier: path.node.source.value,
Expand All @@ -240,15 +251,16 @@ export default class Analyzer extends Plugin {
});
},
ExportNamedDeclaration: path => {
if (path.node.source) {
imports.push({
isDynamic: false,
specifier: path.node.source.value,
path: relativePath,
package: this.pack,
treeType: this.treeType,
});
}
if (!path.node.source) return;
if (this.erasedExportKinds.has(path.node.exportKind)) return;

imports.push({
isDynamic: false,
specifier: path.node.source.value,
path: relativePath,
package: this.pack,
treeType: this.treeType,
});
},
});
return imports;
Expand Down
47 changes: 42 additions & 5 deletions packages/ember-auto-import/ts/tests/analyzer-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,14 @@ import { join } from 'path';
import type Package from '../package';
import Analyzer from '../analyzer';

const { module: Qmodule, test } = QUnit;
const { module: Qmodule, test, skip } = QUnit;

Qmodule('analyzer', function (hooks) {
Qmodule('analyzer', function () {
Qmodule('babel@6', hooks => generateAnalyzerTests(hooks, 6));
Qmodule('babel@7', hooks => generateAnalyzerTests(hooks, 7));
});

function generateAnalyzerTests(hooks: NestedHooks, babelMajorVersion: 6 | 7) {
let builder: Builder;
let upstream: string;
let analyzer: Analyzer;
Expand All @@ -24,10 +29,13 @@ Qmodule('analyzer', function (hooks) {
get babelOptions() {
babelOptionsWasAccessed = true;
return {
plugins: [require.resolve('../../babel-plugin')],
plugins:
babelMajorVersion < 7
? [require.resolve('../../babel-plugin')]
: [require.resolve('@babel/plugin-syntax-typescript'), require.resolve('../../babel-plugin')],
};
},
babelMajorVersion: 6,
babelMajorVersion,
fileExtensions: ['js'],
} as Package;
analyzer = new Analyzer(new UnwatchedDir(upstream), pack);
Expand Down Expand Up @@ -175,6 +183,35 @@ Qmodule('analyzer', function (hooks) {
assert.deepEqual(analyzer.imports, []);
});

(babelMajorVersion < 7 ? skip : test)('type-only imports ignored in created file', async function (assert) {
await builder.build();
let original = `
import type Foo from 'type-import';
import Bar from 'value-import';
export type { Qux } from 'type-re-export';
export { Baz } from 'value-re-export';
`;
outputFileSync(join(upstream, 'sample.js'), original);
await builder.build();
assert.deepEqual(analyzer.imports, [
{
isDynamic: false,
specifier: 'value-import',
path: 'sample.js',
package: pack,
treeType: undefined,
},
{
isDynamic: false,
specifier: 'value-re-export',
path: 'sample.js',
package: pack,
treeType: undefined,
},
]);
});

type LiteralExample = [string, string];
type TemplateExample = [string, string[], string[]];
function isLiteralExample(exp: LiteralExample | TemplateExample): exp is LiteralExample {
Expand Down Expand Up @@ -259,4 +296,4 @@ Qmodule('analyzer', function (hooks) {
assert.contains(err.message, 'import() is only allowed to contain string literals or template string literals');
}
});
});
}

0 comments on commit 3ac52ff

Please sign in to comment.