diff --git a/packages/compiler-cli/linker/babel/src/ast/babel_ast_factory.ts b/packages/compiler-cli/linker/babel/src/ast/babel_ast_factory.ts index 87b23d748c9..0ab33b40591 100644 --- a/packages/compiler-cli/linker/babel/src/ast/babel_ast_factory.ts +++ b/packages/compiler-cli/linker/babel/src/ast/babel_ast_factory.ts @@ -5,9 +5,10 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ +import {types as t} from '@babel/core'; + import {assert} from '../../../../linker'; import {AstFactory, BinaryOperator, LeadingComment, ObjectLiteralProperty, SourceMapRange, TemplateLiteral, VariableDeclarationType} from '../../../../src/ngtsc/translator'; -import {types as t} from '../babel_core'; /** * A Babel flavored implementation of the AstFactory. diff --git a/packages/compiler-cli/linker/babel/src/ast/babel_ast_host.ts b/packages/compiler-cli/linker/babel/src/ast/babel_ast_host.ts index d96b83a14fa..342e810a267 100644 --- a/packages/compiler-cli/linker/babel/src/ast/babel_ast_host.ts +++ b/packages/compiler-cli/linker/babel/src/ast/babel_ast_host.ts @@ -6,8 +6,9 @@ * found in the LICENSE file at https://angular.io/license */ +import {types as t} from '@babel/core'; + import {assert, AstHost, FatalLinkerError, Range} from '../../../../linker'; -import {types as t} from '../babel_core'; /** * This implementation of `AstHost` is able to get information from Babel AST nodes. diff --git a/packages/compiler-cli/linker/babel/src/babel_core.ts b/packages/compiler-cli/linker/babel/src/babel_core.ts deleted file mode 100644 index 455f1bafea9..00000000000 --- a/packages/compiler-cli/linker/babel/src/babel_core.ts +++ /dev/null @@ -1,58 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -/** - * This is an interop file allowing for `@babel/core` to be imported in both CommonJS or - * ES module files. The `@babel/core` package needs some special treatment because: - * - * Using a default import does not with CommonJS because the `@babel/core` package does not - * expose a `default` export at runtime (because it sets the `_esModule` property that causes - * TS to not create the necessary interop `default` export). On the other side, when loaded - * as part of an ESM, NodeJS will make all of the exports available as default export. - * - * Using named import bindings (i.e. namespace import or actual named bindings) is not - * working well for ESM because as said before, NodeJS will make all of the exports available - * as the `default` export. Hence ESM that imports CJS, always should use the default import. - * - * There is no solution that would work for both CJS and ESM, so we need to use a custom interop - * that switches between the named exports or the default exports depending on what is available. - * This allows the code to run in both ESM (for production) and CJS (for development). - * - * TODO(devversion): remove this once devmode uses ESM as well. - */ - -// tslint:disable-next-line -import * as _babelNamespace from '@babel/core'; -// tslint:disable-next-line -import _babelDefault from '@babel/core'; - -const babel: typeof _babelNamespace = _babelDefault ?? _babelNamespace; - -// We create an alias of the `types` namespace so that we can re-export the -// types namespace. Preserving the namespace is important so that types -// can still be referenced using a qualified name. -import _typesNamespace = _babelNamespace.types; - -// If the default export is available, we use its `types` runtime value -// for the type namespace we re-export. This is a trick we use to preserve -// the namespace types, while changing the runtime value of the namespace. -// TS complains about us assigning to a namespace but this is legal at runtime. -if (_babelDefault !== undefined) { - // @ts-ignore - _typesNamespace = _babelDefault.types; -} - -export import types = _typesNamespace; -export type BabelFile = _babelNamespace.BabelFile; -export type PluginObj = _babelNamespace.PluginObj; -export type ConfigAPI = _babelNamespace.ConfigAPI; -export type NodePath = _babelNamespace.NodePath; - -export const NodePath: typeof _babelNamespace.NodePath = babel.NodePath; -export const transformSync: typeof _babelNamespace.transformSync = babel.transformSync; -export const parse: typeof _babelNamespace.parse = babel.parse; diff --git a/packages/compiler-cli/linker/babel/src/babel_declaration_scope.ts b/packages/compiler-cli/linker/babel/src/babel_declaration_scope.ts index 50df224c085..4e00402354e 100644 --- a/packages/compiler-cli/linker/babel/src/babel_declaration_scope.ts +++ b/packages/compiler-cli/linker/babel/src/babel_declaration_scope.ts @@ -5,12 +5,11 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ +import {types as t} from '@babel/core'; import {NodePath, Scope} from '@babel/traverse'; import {DeclarationScope} from '../../../linker'; -import {types as t} from './babel_core'; - export type ConstantScopePath = NodePath|NodePath|NodePath; diff --git a/packages/compiler-cli/linker/babel/src/babel_plugin.ts b/packages/compiler-cli/linker/babel/src/babel_plugin.ts index ca8f1456ebb..68013ee0d1d 100644 --- a/packages/compiler-cli/linker/babel/src/babel_plugin.ts +++ b/packages/compiler-cli/linker/babel/src/babel_plugin.ts @@ -5,11 +5,12 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ +import {ConfigAPI, PluginObj} from '@babel/core'; + import {NodeJSFileSystem} from '../../../src/ngtsc/file_system'; import {ConsoleLogger, LogLevel} from '../../../src/ngtsc/logging'; import {LinkerOptions} from '../../src/file_linker/linker_options'; -import {ConfigAPI, PluginObj} from './babel_core'; import {createEs2015LinkerPlugin} from './es2015_linker_plugin'; /** diff --git a/packages/compiler-cli/linker/babel/src/es2015_linker_plugin.ts b/packages/compiler-cli/linker/babel/src/es2015_linker_plugin.ts index e37915ea76a..1de3f47b01c 100644 --- a/packages/compiler-cli/linker/babel/src/es2015_linker_plugin.ts +++ b/packages/compiler-cli/linker/babel/src/es2015_linker_plugin.ts @@ -6,13 +6,13 @@ * found in the LICENSE file at https://angular.io/license */ +import {BabelFile, PluginObj, types as t} from '@babel/core'; import {NodePath} from '@babel/traverse'; import {FileLinker, isFatalLinkerError, LinkerEnvironment} from '../../../linker'; import {BabelAstFactory} from './ast/babel_ast_factory'; import {BabelAstHost} from './ast/babel_ast_host'; -import {BabelFile, PluginObj, types as t} from './babel_core'; import {BabelDeclarationScope, ConstantScopePath} from './babel_declaration_scope'; import {LinkerPluginOptions} from './linker_plugin_options'; diff --git a/packages/compiler-cli/linker/babel/test/ast/babel_ast_factory_spec.ts b/packages/compiler-cli/linker/babel/test/ast/babel_ast_factory_spec.ts index 8f9ebb539c2..f6941cd4347 100644 --- a/packages/compiler-cli/linker/babel/test/ast/babel_ast_factory_spec.ts +++ b/packages/compiler-cli/linker/babel/test/ast/babel_ast_factory_spec.ts @@ -6,16 +6,20 @@ * found in the LICENSE file at https://angular.io/license */ import {leadingComment} from '@angular/compiler'; -import generate from '@babel/generator'; -import template from '@babel/template'; -import {types as t} from '../../src/babel_core'; +import {types as t} from '@babel/core'; +import _generate from '@babel/generator'; +import _template from '@babel/template'; import {BabelAstFactory} from '../../src/ast/babel_ast_factory'; +// Babel is a CJS package and misuses the `default` named binding: +// https://github.com/babel/babel/issues/15269. +const generate = (_generate as any)['default'] as typeof _generate; + // Exposes shorthands for the `expression` and `statement` // methods exposed by `@babel/template`. -const expression = template.expression; -const statement = template.statement; +const expression = _template.expression; +const statement = _template.statement; describe('BabelAstFactory', () => { let factory: BabelAstFactory; diff --git a/packages/compiler-cli/linker/babel/test/ast/babel_ast_host_spec.ts b/packages/compiler-cli/linker/babel/test/ast/babel_ast_host_spec.ts index 611133d8410..2e57b489bcb 100644 --- a/packages/compiler-cli/linker/babel/test/ast/babel_ast_host_spec.ts +++ b/packages/compiler-cli/linker/babel/test/ast/babel_ast_host_spec.ts @@ -5,11 +5,16 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -import {types as t} from '../../src/babel_core'; -import template from '@babel/template'; -import {parse} from '@babel/parser'; +import {types as t} from '@babel/core'; +import parser from '@babel/parser'; +import _template from '@babel/template'; + import {BabelAstHost} from '../../src/ast/babel_ast_host'; +// Babel is a CJS package and misuses the `default` named binding: +// https://github.com/babel/babel/issues/15269. +const template = (_template as any)['default'] as typeof _template; + describe('BabelAstHost', () => { let host: BabelAstHost; beforeEach(() => host = new BabelAstHost()); @@ -326,7 +331,7 @@ describe('BabelAstHost', () => { describe('getRange()', () => { it('should extract the range from the expression', () => { - const file = parse('// preamble\nx = \'moo\';'); + const file = parser.parse('// preamble\nx = \'moo\';'); const stmt = file.program.body[0] as t.Statement; assertExpressionStatement(stmt); assertAssignmentExpression(stmt.expression); diff --git a/packages/compiler-cli/linker/babel/test/babel_declaration_scope_spec.ts b/packages/compiler-cli/linker/babel/test/babel_declaration_scope_spec.ts index c2a7d231e2c..6fb4fb902ad 100644 --- a/packages/compiler-cli/linker/babel/test/babel_declaration_scope_spec.ts +++ b/packages/compiler-cli/linker/babel/test/babel_declaration_scope_spec.ts @@ -6,16 +6,20 @@ * found in the LICENSE file at https://angular.io/license */ -import {parse} from '@babel/parser'; -import traverse, {NodePath} from '@babel/traverse'; +import {types as t} from '@babel/core'; +import parser from '@babel/parser'; +import _traverse, {NodePath} from '@babel/traverse'; -import {types as t} from '../src/babel_core'; import {BabelDeclarationScope} from '../src/babel_declaration_scope'; +// Babel is a CJS package and misuses the `default` named binding: +// https://github.com/babel/babel/issues/15269. +const traverse = (_traverse as any)['default'] as typeof _traverse; + describe('BabelDeclarationScope', () => { describe('getConstantScopeRef()', () => { it('should return a path to the ES module where the expression was imported', () => { - const ast = parse( + const ast = parser.parse( [ 'import * as core from \'@angular/core\';', 'function foo() {', @@ -31,7 +35,7 @@ describe('BabelDeclarationScope', () => { }); it('should return a path to the ES Module where the expression is declared', () => { - const ast = parse( + const ast = parser.parse( [ 'var core;', 'export function foo() {', @@ -47,7 +51,7 @@ describe('BabelDeclarationScope', () => { }); it('should return null if the file is not an ES module', () => { - const ast = parse( + const ast = parser.parse( [ 'var core;', 'function foo() {', @@ -62,7 +66,7 @@ describe('BabelDeclarationScope', () => { }); it('should return the IIFE factory function where the expression is a parameter', () => { - const ast = parse( + const ast = parser.parse( [ 'var core;', '(function(core) {', diff --git a/packages/compiler-cli/linker/babel/test/babel_plugin_spec.ts b/packages/compiler-cli/linker/babel/test/babel_plugin_spec.ts index ce9d4c580c3..1c74ad1e518 100644 --- a/packages/compiler-cli/linker/babel/test/babel_plugin_spec.ts +++ b/packages/compiler-cli/linker/babel/test/babel_plugin_spec.ts @@ -5,11 +5,11 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -import {transformSync} from '../src/babel_core'; +import babel from '@babel/core'; describe('default babel plugin entry-point', () => { - it('should work as a Babel plugin using the module specifier', () => { - const result = transformSync( + it('should work as a Babel plugin using the module specifier', async () => { + const result = (await babel.transformAsync( ` import * as i0 from "@angular/core"; @@ -20,10 +20,10 @@ describe('default babel plugin entry-point', () => { `, { plugins: [ - '@angular/compiler-cli/linker/babel', + '@angular/compiler-cli/linker/babel/index.mjs', ], filename: 'test.js', - })!; + }))!; expect(result).not.toBeNull(); expect(result.code).not.toContain('ɵɵngDeclareNgModule'); @@ -31,8 +31,8 @@ describe('default babel plugin entry-point', () => { expect(result.code).not.toMatch(/declarations:\s*\[MyComponent]/); }); - it('should be configurable', () => { - const result = transformSync( + it('should be configurable', async () => { + const result = (await babel.transformAsync( ` import * as i0 from "@angular/core"; @@ -43,10 +43,10 @@ describe('default babel plugin entry-point', () => { `, { plugins: [ - ['@angular/compiler-cli/linker/babel', {linkerJitMode: true}], + ['@angular/compiler-cli/linker/babel/index.mjs', {linkerJitMode: true}], ], filename: 'test.js', - })!; + }))!; expect(result).not.toBeNull(); expect(result.code).not.toContain('ɵɵngDeclareNgModule'); diff --git a/packages/compiler-cli/linker/babel/test/es2015_linker_plugin_spec.ts b/packages/compiler-cli/linker/babel/test/es2015_linker_plugin_spec.ts index dfaa58d09a9..a2d803b852b 100644 --- a/packages/compiler-cli/linker/babel/test/es2015_linker_plugin_spec.ts +++ b/packages/compiler-cli/linker/babel/test/es2015_linker_plugin_spec.ts @@ -6,13 +6,17 @@ * found in the LICENSE file at https://angular.io/license */ import * as o from '@angular/compiler/src/output/output_ast'; -import generate from '@babel/generator'; +import babel, {NodePath, PluginObj, types as t} from '@babel/core'; +import _generate from '@babel/generator'; + +// Babel is a CJS package and misuses the `default` named binding: +// https://github.com/babel/babel/issues/15269. +const generate = (_generate as any)['default'] as typeof _generate; import {FileLinker} from '../../../linker'; import {MockFileSystemNative} from '../../../src/ngtsc/file_system/testing'; import {MockLogger} from '../../../src/ngtsc/logging/testing'; import {PartialDirectiveLinkerVersion1} from '../../src/file_linker/partial_linkers/partial_directive_linker_1'; -import {NodePath, PluginObj, transformSync, types as t} from '../src/babel_core'; import {createEs2015LinkerPlugin} from '../src/es2015_linker_plugin'; describe('createEs2015LinkerPlugin()', () => { @@ -37,7 +41,7 @@ describe('createEs2015LinkerPlugin()', () => { const fileSystem = new MockFileSystemNative(); const logger = new MockLogger(); const plugin = createEs2015LinkerPlugin({fileSystem, logger}); - transformSync( + babel.transformSync( [ 'var core;', `fn1()`, 'fn2({prop: () => fn3({})});', `x.method(() => fn4());`, 'spread(...x);' @@ -65,7 +69,7 @@ describe('createEs2015LinkerPlugin()', () => { const logger = new MockLogger(); const plugin = createEs2015LinkerPlugin({fileSystem, logger}); - transformSync( + babel.transformSync( [ 'var core;', `ɵɵngDeclareDirective({minVersion: '0.0.0-PLACEHOLDER', version: '0.0.0-PLACEHOLDER', ngImport: core, x: 1});`, @@ -109,7 +113,7 @@ describe('createEs2015LinkerPlugin()', () => { const fileSystem = new MockFileSystemNative(); const logger = new MockLogger(); const plugin = createEs2015LinkerPlugin({fileSystem, logger}); - const result = transformSync( + const result = babel.transformSync( [ 'var core;', 'ɵɵngDeclareDirective({version: \'0.0.0-PLACEHOLDER\', ngImport: core});', @@ -131,7 +135,7 @@ describe('createEs2015LinkerPlugin()', () => { const fileSystem = new MockFileSystemNative(); const logger = new MockLogger(); const plugin = createEs2015LinkerPlugin({fileSystem, logger}); - const result = transformSync( + const result = babel.transformSync( [ 'import * as core from \'some-module\';', 'import {id} from \'other-module\';', @@ -156,7 +160,7 @@ describe('createEs2015LinkerPlugin()', () => { const fileSystem = new MockFileSystemNative(); const logger = new MockLogger(); const plugin = createEs2015LinkerPlugin({fileSystem, logger}); - const result = transformSync( + const result = babel.transformSync( [ 'var core;', `ɵɵngDeclareDirective({minVersion: '0.0.0-PLACEHOLDER', version: '0.0.0-PLACEHOLDER', ngImport: core})`, @@ -181,7 +185,7 @@ describe('createEs2015LinkerPlugin()', () => { const fileSystem = new MockFileSystemNative(); const logger = new MockLogger(); const plugin = createEs2015LinkerPlugin({fileSystem, logger}); - const result = transformSync( + const result = babel.transformSync( [ 'function run(core) {', ` ɵɵngDeclareDirective({minVersion: '0.0.0-PLACEHOLDER', version: '0.0.0-PLACEHOLDER', ngImport: core})`, @@ -206,7 +210,7 @@ describe('createEs2015LinkerPlugin()', () => { const fileSystem = new MockFileSystemNative(); const logger = new MockLogger(); const plugin = createEs2015LinkerPlugin({fileSystem, logger}); - const result = transformSync( + const result = babel.transformSync( [ 'function run() {', ` ɵɵngDeclareDirective({minVersion: '0.0.0-PLACEHOLDER', version: '0.0.0-PLACEHOLDER', ngImport: core})`, @@ -235,7 +239,7 @@ describe('createEs2015LinkerPlugin()', () => { const fileSystem = new MockFileSystemNative(); const logger = new MockLogger(); const plugin = createEs2015LinkerPlugin({fileSystem, logger}); - const result = transformSync( + const result = babel.transformSync( [ `ɵɵngDeclareDirective({minVersion: '0.0.0-PLACEHOLDER', version: '0.0.0-PLACEHOLDER', ngImport: core}); FOO;`, ].join('\n'), @@ -278,7 +282,7 @@ describe('createEs2015LinkerPlugin()', () => { const fileSystem = new MockFileSystemNative(); const logger = new MockLogger(); const plugin = createEs2015LinkerPlugin({fileSystem, logger}); - const result = transformSync( + const result = babel.transformSync( [ 'import * as core from \'some-module\';', `ɵɵngDeclareDirective({minVersion: '0.0.0-PLACEHOLDER', version: '0.0.0-PLACEHOLDER', ngImport: core})`, diff --git a/tslint.json b/tslint.json index 0da8a8dd69c..928c26a2f6f 100644 --- a/tslint.json +++ b/tslint.json @@ -36,13 +36,7 @@ // `module.exports` as `export default`. Instead, named exports should be used for compat with CJS/ESM. "noDefaultExport": [], // List of modules which are incompatible and should never be imported at all. - "incompatibleModules": { - // `@babel/core` and `@babel/types` suggest named exports which do not exist at runtime within ESM - // (as these named exports are not statically discoverable by NodeJS). At the same time, these modules - // set `__esModule` and the default import does not exist for CJS at runtime (e.g. breaking tests). - "@babel/core": "This module is incompatible with the ESM/CJS interop. Use the custom interop file.", - "@babel/types": "This module is incompatible with the ESM/CJS interop. Use the custom interop file and import the `types` namespace." - } + "incompatibleModules": {} } ], "eofline": true,