From 194264f17bfb9f2e7df4c67158f1cd150f012db3 Mon Sep 17 00:00:00 2001 From: Edward Faulkner Date: Tue, 31 Aug 2021 12:57:53 -0400 Subject: [PATCH 1/2] add failing test for old vs new analyzer The changes in #440 can break when an addon is using a 2.x copy of ember-auto-import that predates the changes. The problem is that older copies will run their own `included` hook which does not install the babel plugin. --- package-lock.json | 348 ++++++++++++++++++++++++++++++++ test-scenarios/indirect-test.ts | 208 ++++++++++--------- test-scenarios/package.json | 1 + 3 files changed, 465 insertions(+), 92 deletions(-) diff --git a/package-lock.json b/package-lock.json index f3f310e5d..9d907022a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -30834,6 +30834,195 @@ "node": ">=0.10.0" } }, + "node_modules/old-analyzer": { + "name": "ember-auto-import", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ember-auto-import/-/ember-auto-import-2.1.0.tgz", + "integrity": "sha512-82iTXahaiswdOpMrosUzIvblpxCVd6jC1tvqKVd/wrUVVMj9tP3s5jqsVF7wKvf4im8ZjGkkuR8rMFU0CiqJNQ==", + "dev": true, + "dependencies": { + "@babel/core": "^7.1.6", + "@babel/plugin-proposal-class-properties": "^7.13.0", + "@babel/plugin-proposal-decorators": "^7.13.5", + "@babel/preset-env": "^7.10.2", + "@babel/traverse": "^7.1.6", + "@babel/types": "^7.1.6", + "@embroider/shared-internals": "^0.40.0", + "babel-loader": "^8.0.6", + "babel-plugin-ember-modules-api-polyfill": "^3.5.0", + "babel-plugin-htmlbars-inline-precompile": "^5.2.1", + "babel-plugin-syntax-dynamic-import": "^6.18.0", + "broccoli-debug": "^0.6.4", + "broccoli-merge-trees": "^4.2.0", + "broccoli-node-api": "^1.7.0", + "broccoli-plugin": "^4.0.0", + "broccoli-source": "^3.0.0", + "css-loader": "^5.2.0", + "debug": "^4.3.1", + "ember-cli-babel": "^7.0.0", + "fs-extra": "^6.0.1", + "fs-tree-diff": "^2.0.0", + "handlebars": "^4.3.1", + "js-string-escape": "^1.0.1", + "lodash": "^4.17.19", + "mkdirp": "^0.5.1", + "parse5": "^6.0.1", + "resolve": "^1.20.0", + "resolve-package-path": "^3.1.0", + "rimraf": "^2.6.2", + "semver": "^7.3.4", + "style-loader": "^2.0.0", + "symlink-or-copy": "^1.2.0", + "typescript-memoize": "^1.0.0-alpha.3", + "walk-sync": "^0.3.3" + }, + "engines": { + "node": "12 || >= 14" + } + }, + "node_modules/old-analyzer/node_modules/@babel/code-frame": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz", + "integrity": "sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/old-analyzer/node_modules/@babel/generator": { + "version": "7.15.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.15.0.tgz", + "integrity": "sha512-eKl4XdMrbpYvuB505KTta4AV9g+wWzmVBW69tX0H2NwKVKd2YJbKgyK6M8j/rgLbmHOYJn6rUklV677nOyJrEQ==", + "dev": true, + "dependencies": { + "@babel/types": "^7.15.0", + "jsesc": "^2.5.1", + "source-map": "^0.5.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/old-analyzer/node_modules/@babel/helper-function-name": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.14.5.tgz", + "integrity": "sha512-Gjna0AsXWfFvrAuX+VKcN/aNNWonizBj39yGwUzVDVTlMYJMK2Wp6xdpy72mfArFq5uK+NOuexfzZlzI1z9+AQ==", + "dev": true, + "dependencies": { + "@babel/helper-get-function-arity": "^7.14.5", + "@babel/template": "^7.14.5", + "@babel/types": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/old-analyzer/node_modules/@babel/helper-get-function-arity": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.14.5.tgz", + "integrity": "sha512-I1Db4Shst5lewOM4V+ZKJzQ0JGGaZ6VY1jYvMghRjqs6DWgxLCIyFt30GlnKkfUeFLpJt2vzbMVEXVSXlIFYUg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/old-analyzer/node_modules/@babel/helper-split-export-declaration": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.14.5.tgz", + "integrity": "sha512-hprxVPu6e5Kdp2puZUmvOGjaLv9TCe58E/Fl6hRq4YiVQxIcNvuq6uTM2r1mT/oPskuS9CgR+I94sqAYv0NGKA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/old-analyzer/node_modules/@babel/highlight": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", + "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.14.5", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/old-analyzer/node_modules/@babel/template": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.14.5.tgz", + "integrity": "sha512-6Z3Po85sfxRGachLULUhOmvAaOo7xCvqGQtxINai2mEGPFm6pQ4z5QInFnUrRpfoSV60BnjyF5F3c+15fxFV1g==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.14.5", + "@babel/parser": "^7.14.5", + "@babel/types": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/old-analyzer/node_modules/@babel/traverse": { + "version": "7.15.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.15.0.tgz", + "integrity": "sha512-392d8BN0C9eVxVWd8H6x9WfipgVH5IaIoLp23334Sc1vbKKWINnvwRpb4us0xtPaCumlwbTtIYNA0Dv/32sVFw==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.14.5", + "@babel/generator": "^7.15.0", + "@babel/helper-function-name": "^7.14.5", + "@babel/helper-hoist-variables": "^7.14.5", + "@babel/helper-split-export-declaration": "^7.14.5", + "@babel/parser": "^7.15.0", + "@babel/types": "^7.15.0", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/old-analyzer/node_modules/@babel/types": { + "version": "7.15.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.15.0.tgz", + "integrity": "sha512-OBvfqnllOIdX4ojTHpwZbpvz4j3EWyjkZEdmjH0/cgsd6QOdSgU8rLSk6ard/pcW7rlmjdVSX/AWOaORR1uNOQ==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.14.9", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/old-analyzer/node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "node_modules/old-analyzer/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, "node_modules/on-finished": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", @@ -41485,6 +41674,7 @@ "lodash-es": "^4.17.10", "moment": "^2.22.1", "newer-resolver": "npm:ember-resolver@^8.0.0", + "old-analyzer": "npm:ember-auto-import@2.1.0", "typescript-4": "npm:typescript@^4.1.2", "webpack": "^5.31.0" } @@ -46578,6 +46768,7 @@ "lodash-es": "^4.17.10", "moment": "^2.22.1", "newer-resolver": "npm:ember-resolver@^8.0.0", + "old-analyzer": "npm:ember-auto-import@2.1.0", "qunit": "^2.6.1", "scenario-tester": "^1.0.0", "ts-node": "^9.1.1", @@ -71449,6 +71640,163 @@ } } }, + "old-analyzer": { + "version": "npm:ember-auto-import@2.1.0", + "resolved": "https://registry.npmjs.org/ember-auto-import/-/ember-auto-import-2.1.0.tgz", + "integrity": "sha512-82iTXahaiswdOpMrosUzIvblpxCVd6jC1tvqKVd/wrUVVMj9tP3s5jqsVF7wKvf4im8ZjGkkuR8rMFU0CiqJNQ==", + "dev": true, + "requires": { + "@babel/core": "^7.1.6", + "@babel/plugin-proposal-class-properties": "^7.13.0", + "@babel/plugin-proposal-decorators": "^7.13.5", + "@babel/preset-env": "^7.10.2", + "@babel/traverse": "^7.1.6", + "@babel/types": "^7.1.6", + "@embroider/shared-internals": "^0.40.0", + "babel-loader": "^8.0.6", + "babel-plugin-ember-modules-api-polyfill": "^3.5.0", + "babel-plugin-htmlbars-inline-precompile": "^5.2.1", + "babel-plugin-syntax-dynamic-import": "^6.18.0", + "broccoli-debug": "^0.6.4", + "broccoli-merge-trees": "^4.2.0", + "broccoli-node-api": "^1.7.0", + "broccoli-plugin": "^4.0.0", + "broccoli-source": "^3.0.0", + "css-loader": "^5.2.0", + "debug": "^4.3.1", + "ember-cli-babel": "^7.0.0", + "fs-extra": "^6.0.1", + "fs-tree-diff": "^2.0.0", + "handlebars": "^4.3.1", + "js-string-escape": "^1.0.1", + "lodash": "^4.17.19", + "mkdirp": "^0.5.1", + "parse5": "^6.0.1", + "resolve": "^1.20.0", + "resolve-package-path": "^3.1.0", + "rimraf": "^2.6.2", + "semver": "^7.3.4", + "style-loader": "^2.0.0", + "symlink-or-copy": "^1.2.0", + "typescript-memoize": "^1.0.0-alpha.3", + "walk-sync": "^0.3.3" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz", + "integrity": "sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==", + "dev": true, + "requires": { + "@babel/highlight": "^7.14.5" + } + }, + "@babel/generator": { + "version": "7.15.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.15.0.tgz", + "integrity": "sha512-eKl4XdMrbpYvuB505KTta4AV9g+wWzmVBW69tX0H2NwKVKd2YJbKgyK6M8j/rgLbmHOYJn6rUklV677nOyJrEQ==", + "dev": true, + "requires": { + "@babel/types": "^7.15.0", + "jsesc": "^2.5.1", + "source-map": "^0.5.0" + } + }, + "@babel/helper-function-name": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.14.5.tgz", + "integrity": "sha512-Gjna0AsXWfFvrAuX+VKcN/aNNWonizBj39yGwUzVDVTlMYJMK2Wp6xdpy72mfArFq5uK+NOuexfzZlzI1z9+AQ==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.14.5", + "@babel/template": "^7.14.5", + "@babel/types": "^7.14.5" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.14.5.tgz", + "integrity": "sha512-I1Db4Shst5lewOM4V+ZKJzQ0JGGaZ6VY1jYvMghRjqs6DWgxLCIyFt30GlnKkfUeFLpJt2vzbMVEXVSXlIFYUg==", + "dev": true, + "requires": { + "@babel/types": "^7.14.5" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.14.5.tgz", + "integrity": "sha512-hprxVPu6e5Kdp2puZUmvOGjaLv9TCe58E/Fl6hRq4YiVQxIcNvuq6uTM2r1mT/oPskuS9CgR+I94sqAYv0NGKA==", + "dev": true, + "requires": { + "@babel/types": "^7.14.5" + } + }, + "@babel/highlight": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", + "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.14.5", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "@babel/template": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.14.5.tgz", + "integrity": "sha512-6Z3Po85sfxRGachLULUhOmvAaOo7xCvqGQtxINai2mEGPFm6pQ4z5QInFnUrRpfoSV60BnjyF5F3c+15fxFV1g==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.14.5", + "@babel/parser": "^7.14.5", + "@babel/types": "^7.14.5" + } + }, + "@babel/traverse": { + "version": "7.15.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.15.0.tgz", + "integrity": "sha512-392d8BN0C9eVxVWd8H6x9WfipgVH5IaIoLp23334Sc1vbKKWINnvwRpb4us0xtPaCumlwbTtIYNA0Dv/32sVFw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.14.5", + "@babel/generator": "^7.15.0", + "@babel/helper-function-name": "^7.14.5", + "@babel/helper-hoist-variables": "^7.14.5", + "@babel/helper-split-export-declaration": "^7.14.5", + "@babel/parser": "^7.15.0", + "@babel/types": "^7.15.0", + "debug": "^4.1.0", + "globals": "^11.1.0" + } + }, + "@babel/types": { + "version": "7.15.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.15.0.tgz", + "integrity": "sha512-OBvfqnllOIdX4ojTHpwZbpvz4j3EWyjkZEdmjH0/cgsd6QOdSgU8rLSk6ard/pcW7rlmjdVSX/AWOaORR1uNOQ==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.14.9", + "to-fast-properties": "^2.0.0" + } + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + } + } + }, "on-finished": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", diff --git a/test-scenarios/indirect-test.ts b/test-scenarios/indirect-test.ts index 0cbe9f063..469c9d9aa 100644 --- a/test-scenarios/indirect-test.ts +++ b/test-scenarios/indirect-test.ts @@ -1,14 +1,13 @@ -import { appScenarios } from './scenarios'; -import { PreparedApp, Project } from 'scenario-tester'; +import { appScenarios, baseAddon, baseApp } from './scenarios'; +import { PreparedApp, Scenarios } from 'scenario-tester'; import QUnit from 'qunit'; import merge from 'lodash/merge'; -import { dirname } from 'path'; import { setupFastboot } from './fastboot-helper'; const { module: Qmodule, test } = QUnit; -function makeAddon() { - let addon = Project.fromDir(dirname(require.resolve('@ef4/addon-template/package.json')), { linkDeps: true }); - addon.linkDependency('ember-auto-import', { baseDir: __dirname }); +function makeAddon(resolveEAI?: string) { + let addon = baseAddon(); + addon.linkDependency('ember-auto-import', { baseDir: __dirname, resolveName: resolveEAI }); addon.pkg.name = 'sample-addon'; merge(addon.files, { 'index.js': ` @@ -94,103 +93,107 @@ function makeAddon() { return addon; } -appScenarios - .map('indirect', project => { - project.addDevDependency(makeAddon()); - project.linkDependency('ember-cli-fastboot', { baseDir: __dirname }); - - // top-level auto-import is mandatory - project.linkDependency('ember-auto-import', { baseDir: __dirname }); - project.linkDependency('webpack', { baseDir: __dirname }); +function projectFiles() { + return { + app: { + 'router.js': ` + import EmberRouter from '@ember/routing/router'; + import config from './config/environment'; - merge(project.files, { - app: { - 'router.js': ` - import EmberRouter from '@ember/routing/router'; - import config from './config/environment'; + const Router = EmberRouter.extend({ + location: config.locationType, + rootURL: config.rootURL, + }); - const Router = EmberRouter.extend({ - location: config.locationType, - rootURL: config.rootURL, - }); + Router.map(function () { + this.route('dep-check'); + }); - Router.map(function () { - this.route('dep-check'); + export default Router; + `, + templates: { + 'application.hbs': `{{outlet}}`, + 'index.hbs': ` + {{from-sample-addon}} + `, + 'dep-check.hbs': ` +
{{#if hasLib2}}yes{{else}}no{{/if}}
+ `, + }, + controllers: { + 'dep-check.js': ` + import Controller from '@ember/controller'; + import { computed } from '@ember/object'; + + export default Controller.extend({ + hasLib2: computed(function () { + try { + // hiding from webpack + let r = "r" + "equire"; + window[r]('some-lib2'); + return true; + } catch (err) { + return false; + } + }), }); - export default Router; `, - templates: { - 'application.hbs': `{{outlet}}`, - 'index.hbs': ` - {{from-sample-addon}} - `, - 'dep-check.hbs': ` -
{{#if hasLib2}}yes{{else}}no{{/if}}
- `, - }, - controllers: { - 'dep-check.js': ` - import Controller from '@ember/controller'; - import { computed } from '@ember/object'; - - export default Controller.extend({ - hasLib2: computed(function () { - try { - // hiding from webpack - let r = "r" + "equire"; - window[r]('some-lib2'); - return true; - } catch (err) { - return false; - } - }), + }, + }, + tests: { + acceptance: { + 'basic-test.js': ` + import { module, test } from 'qunit'; + import { visit } from '@ember/test-helpers'; + import { setupApplicationTest } from 'ember-qunit'; + + module('Acceptance | basic', function (hooks) { + setupApplicationTest(hooks); + + test('an addon can use an auto-imported dependency when called from an app that does not', async function (assert) { + await visit('/'); + assert.equal(document.querySelector('[data-test="from-sample-addon"]').textContent.trim(), 'This is the message'); }); - `, - }, - }, - tests: { - acceptance: { - 'basic-test.js': ` - import { module, test } from 'qunit'; - import { visit } from '@ember/test-helpers'; - import { setupApplicationTest } from 'ember-qunit'; - - module('Acceptance | basic', function (hooks) { - setupApplicationTest(hooks); - - test('an addon can use an auto-imported dependency when called from an app that does not', async function (assert) { - await visit('/'); - assert.equal(document.querySelector('[data-test="from-sample-addon"]').textContent.trim(), 'This is the message'); - }); - - test('addon-test-support deps are present inside the test suite', async function (assert) { - await visit('/dep-check'); - assert.equal( - document.querySelector('[data-test="lib2-status"]').textContent.trim(), - 'yes', - 'expected inner-lib2 to be present' - ); - }); + test('addon-test-support deps are present inside the test suite', async function (assert) { + await visit('/dep-check'); + assert.equal( + document.querySelector('[data-test="lib2-status"]').textContent.trim(), + 'yes', + 'expected inner-lib2 to be present' + ); }); - `, - }, - unit: { - 'addon-dynamic-import-test.js': ` - import { module, test } from 'qunit'; - import { useExtra } from 'sample-addon'; - - module('Unit | addon-dynamic-import', function () { - test('addon can load a dependency dynamically', async function(assert) { - let result = await useExtra(); - assert.equal(result, "This is from the extra module that we lazily load"); - }); + }); + `, + }, + unit: { + 'addon-dynamic-import-test.js': ` + import { module, test } from 'qunit'; + import { useExtra } from 'sample-addon'; + + module('Unit | addon-dynamic-import', function () { + test('addon can load a dependency dynamically', async function(assert) { + let result = await useExtra(); + assert.equal(result, "This is from the extra module that we lazily load"); }); - `, - }, + }); + `, }, - }); + }, + }; +} + +appScenarios + .map('indirect', project => { + project.addDevDependency(makeAddon()); + project.linkDependency('ember-cli-fastboot', { baseDir: __dirname }); + + // top-level auto-import is mandatory + project.linkDependency('ember-auto-import', { baseDir: __dirname }); + project.linkDependency('webpack', { baseDir: __dirname }); + + merge(project.files, projectFiles()); }) .forEachScenario(scenario => { Qmodule(scenario.name, function (hooks) { @@ -229,3 +232,24 @@ appScenarios }); }); }); + +Scenarios.fromProject(baseApp) + .map('indirect-analyzer-skew', project => { + project.addDevDependency(makeAddon('old-analyzer')); + project.linkDependency('ember-auto-import', { baseDir: __dirname }); + project.linkDependency('webpack', { baseDir: __dirname }); + merge(project.files, projectFiles()); + }) + .forEachScenario(scenario => { + Qmodule(scenario.name, function (hooks) { + let app: PreparedApp; + hooks.before(async () => { + app = await scenario.prepare(); + }); + + test('npm run test', async function (assert) { + let result = await app.execute('npm run test'); + assert.equal(result.exitCode, 0, result.output); + }); + }); + }); diff --git a/test-scenarios/package.json b/test-scenarios/package.json index 6759e2119..2e89ff255 100644 --- a/test-scenarios/package.json +++ b/test-scenarios/package.json @@ -24,6 +24,7 @@ "fs-extra": "^6.0.1", "leader-v1": "npm:ember-auto-import@1.7", "leader-v2": "npm:ember-auto-import@1.11", + "old-analyzer": "npm:ember-auto-import@2.1.0", "ember-cli-babel-older": "npm:ember-cli-babel@7.11.1", "ember-cli-lts": "npm:ember-cli@~3.4.0", "ember-cli-latest": "npm:ember-cli@latest", From a649b0a4f0d433d7a04ec1a480b1cc542698f501 Mon Sep 17 00:00:00 2001 From: Edward Faulkner Date: Tue, 31 Aug 2021 15:47:46 -0400 Subject: [PATCH 2/2] re-introduce fallback to slower parse --- .../ember-auto-import/ts/analyzer-plugin.ts | 5 +- packages/ember-auto-import/ts/analyzer.ts | 62 ++++++++++++++++--- packages/ember-auto-import/ts/auto-import.ts | 33 +++++----- packages/ember-auto-import/ts/index.ts | 8 +-- packages/ember-auto-import/ts/package.ts | 16 ++++- .../ts/tests/analyzer-test.ts | 2 +- .../ts/tests/splitter-test.ts | 2 +- 7 files changed, 97 insertions(+), 31 deletions(-) diff --git a/packages/ember-auto-import/ts/analyzer-plugin.ts b/packages/ember-auto-import/ts/analyzer-plugin.ts index af57ebb6e..236e76724 100644 --- a/packages/ember-auto-import/ts/analyzer-plugin.ts +++ b/packages/ember-auto-import/ts/analyzer-plugin.ts @@ -5,6 +5,9 @@ import { ImportSyntax, serialize } from './analyzer-syntax'; interface State { imports: ImportSyntax[]; handled: WeakSet; + opts: { + imports?: ImportSyntax[]; + }; } // Ignores type-only imports & exports, which are erased from the final build @@ -23,7 +26,7 @@ function analyzerPlugin(babel: typeof Babel) { visitor: { Program: { enter(_path: NodePath, state: State) { - state.imports = []; + state.imports = state.opts.imports || []; state.handled = new WeakSet(); }, exit(path: NodePath, state: State) { diff --git a/packages/ember-auto-import/ts/analyzer.ts b/packages/ember-auto-import/ts/analyzer.ts index ef89b1f42..d123deacb 100644 --- a/packages/ember-auto-import/ts/analyzer.ts +++ b/packages/ember-auto-import/ts/analyzer.ts @@ -1,13 +1,14 @@ import type { Node } from 'broccoli-node-api'; import { Funnel } from 'broccoli-funnel'; import walkSync from 'walk-sync'; -import { createReadStream } from 'fs'; +import { createReadStream, readFileSync } from 'fs'; import FSTree from 'fs-tree-diff'; import makeDebug from 'debug'; import { join, extname } from 'path'; import { isEqual, flatten } from 'lodash'; import type Package from './package'; -import { deserialize, LiteralImportSyntax, TemplateImportSyntax } from './analyzer-syntax'; +import { deserialize, ImportSyntax, LiteralImportSyntax, TemplateImportSyntax } from './analyzer-syntax'; +import { Memoize } from 'typescript-memoize'; makeDebug.formatters.m = (modules: Import[]) => { return JSON.stringify( @@ -59,7 +60,12 @@ export default class Analyzer extends Funnel { private modules: Import[] | null = []; private paths: Map = new Map(); - constructor(inputTree: Node, private pack: Package, private treeType?: TreeType) { + constructor( + inputTree: Node, + private pack: Package, + private treeType: TreeType | undefined, + private supportsFastAnalyzer: true | undefined + ) { super(inputTree, { annotation: 'ember-auto-import-analyzer', }); @@ -115,10 +121,17 @@ export default class Analyzer extends Funnel { } async updateImports(relativePath: string): Promise { - debug(`updating imports for ${relativePath}`); - let stream = createReadStream(join(this.inputPaths[0], relativePath), { encoding: 'utf8' }); - let meta = await deserialize(stream); - debug(`it worked`); + let meta: ImportSyntax[]; + if (this.supportsFastAnalyzer) { + debug(`updating imports for ${relativePath}`); + let stream = createReadStream(join(this.inputPaths[0], relativePath), { encoding: 'utf8' }); + meta = await deserialize(stream); + } else { + debug(`updating imports (the slower way) for ${relativePath}`); + let parse = await this.parser(); + meta = parse(readFileSync(join(this.inputPaths[0], relativePath), 'utf8'), relativePath); + } + let newImports = meta.map(m => ({ path: relativePath, package: this.pack, @@ -131,4 +144,39 @@ export default class Analyzer extends Funnel { this.modules = null; // invalidates cache } } + + @Memoize() + async parser(): Promise<(source: string, relativePath: string) => ImportSyntax[]> { + if (this.pack.babelMajorVersion !== 7) { + throw new Error( + `don't know how to setup a parser for Babel version ${this.pack.babelMajorVersion} (used by ${this.pack.name})` + ); + } + const { transformSync } = await import('@babel/core'); + const analyzerPlugin = require.resolve('./analyzer-plugin'); + + return (source: string, relativePath: string) => { + let options = Object.assign({}, this.pack.babelOptions); + options.code = false; + options.filename = relativePath; + if (options.plugins) { + options.plugins = options.plugins.slice(); + } else { + options.plugins = []; + } + let analyzerOptions: { imports: ImportSyntax[] } = { + imports: [], + }; + options.plugins.unshift([analyzerPlugin, analyzerOptions]); + try { + transformSync(source, options); + } catch (err) { + if (err.name !== 'SyntaxError') { + throw err; + } + debug('Ignoring an unparseable file'); + } + return analyzerOptions.imports; + }; + } } diff --git a/packages/ember-auto-import/ts/auto-import.ts b/packages/ember-auto-import/ts/auto-import.ts index 55b5f4308..c37a1131f 100644 --- a/packages/ember-auto-import/ts/auto-import.ts +++ b/packages/ember-auto-import/ts/auto-import.ts @@ -7,13 +7,7 @@ import { buildDebugCallback } from 'broccoli-debug'; import BundleConfig from './bundle-config'; import type { Node } from 'broccoli-node-api'; import { LeaderChooser } from './leader'; -import { - AddonInstance, - AppInstance, - findTopmostAddon, - isDeepAddonInstance, - ShallowAddonInstance, -} from '@embroider/shared-internals'; +import { AddonInstance, AppInstance, findTopmostAddon, isDeepAddonInstance } from '@embroider/shared-internals'; import WebpackBundler from './webpack'; import { Memoize } from 'typescript-memoize'; import { WatchedDir } from 'broccoli-source'; @@ -33,11 +27,10 @@ const debugTree = buildDebugCallback('ember-auto-import'); // what you're doing. export interface AutoImportSharedAPI { isPrimary(addonInstance: AddonInstance): boolean; - analyze(tree: Node, addon: AddonInstance, treeType?: TreeType): Node; + analyze(tree: Node, addon: AddonInstance, treeType?: TreeType, supportsFastAnalyzer?: true): Node; included(addonInstance: AddonInstance): void; addTo(tree: Node): Node; registerV2Addon(packageName: string, packageRoot: string): void; - installBabelPlugin(addonInstance: AddonInstance): void; } export default class AutoImport implements AutoImportSharedAPI { @@ -78,10 +71,15 @@ export default class AutoImport implements AutoImportSharedAPI { return false; } - analyze(tree: Node, addon: AddonInstance, treeType?: TreeType) { + analyze(tree: Node, addon: AddonInstance, treeType?: TreeType, supportsFastAnalyzer?: true) { let pack = Package.lookupParentOf(addon); this.packages.add(pack); - let analyzer = new Analyzer(debugTree(tree, `preprocessor:input-${this.analyzers.size}`), pack, treeType); + let analyzer = new Analyzer( + debugTree(tree, `preprocessor:input-${this.analyzers.size}`), + pack, + treeType, + supportsFastAnalyzer + ); this.analyzers.set(analyzer, pack); return analyzer; } @@ -156,11 +154,18 @@ export default class AutoImport implements AutoImportSharedAPI { return mergeTrees(trees, { overwrite: true }); } - included(addonInstance: ShallowAddonInstance) { - this.configureFingerprints(addonInstance.app); + // CAUTION: versions <= 2.1.0 only invoked this method on the app's copy of + // ember-auto-import, whereas we now invoke it on every copy. That means you + // can't guarantee this will be called for an addon that is using one of those + // older versions. + included(addonInstance: AddonInstance) { + this.installBabelPlugin(addonInstance); + if (!isDeepAddonInstance(addonInstance)) { + this.configureFingerprints(addonInstance.app); + } } - installBabelPlugin(addonInstance: AddonInstance): void { + private installBabelPlugin(addonInstance: AddonInstance): void { let parent: AppInstance | AddonInstance; if (isDeepAddonInstance(addonInstance)) { parent = addonInstance.parent; diff --git a/packages/ember-auto-import/ts/index.ts b/packages/ember-auto-import/ts/index.ts index 9de0c3909..ab965bfaa 100644 --- a/packages/ember-auto-import/ts/index.ts +++ b/packages/ember-auto-import/ts/index.ts @@ -2,7 +2,6 @@ import AutoImport from './auto-import'; import type { Node } from 'broccoli-node-api'; // @ts-ignore import pkg from '../package'; -import { isDeepAddonInstance } from '@embroider/shared-internals'; module.exports = { name: pkg.name, @@ -31,17 +30,14 @@ module.exports = { treeType = options.treeType; } - return AutoImport.lookup(this).analyze(tree, this, treeType); + return AutoImport.lookup(this).analyze(tree, this, treeType, true); }, }); }, included(...args: unknown[]) { this._super.included.apply(this, ...args); - AutoImport.lookup(this).installBabelPlugin(this); - if (!isDeepAddonInstance(this)) { - AutoImport.lookup(this).included(this); - } + AutoImport.lookup(this).included(this); }, // this exists to be called by @embroider/addon-shim diff --git a/packages/ember-auto-import/ts/package.ts b/packages/ember-auto-import/ts/package.ts index 725787ecc..70070e2bf 100644 --- a/packages/ember-auto-import/ts/package.ts +++ b/packages/ember-auto-import/ts/package.ts @@ -68,6 +68,8 @@ export default class Package { private _options: any; private _parent: Project | AddonInstance; private _hasBabelDetails = false; + private _babelMajorVersion?: number; + private _babelOptions: any; private _emberCLIBabelExtensions?: string[]; private autoImportOptions: Options | undefined; private isDeveloping: boolean; @@ -114,11 +116,23 @@ export default class Package { if (this._hasBabelDetails) { return; } - let { extensions } = this.buildBabelOptions(this._parent, this._options); + let { babelOptions, extensions, version } = this.buildBabelOptions(this._parent, this._options); this._emberCLIBabelExtensions = extensions; + this._babelOptions = babelOptions; + this._babelMajorVersion = version; this._hasBabelDetails = true; } + get babelOptions(): TransformOptions { + this._ensureBabelDetails(); + return this._babelOptions; + } + + get babelMajorVersion() { + this._ensureBabelDetails(); + return this._babelMajorVersion; + } + @Memoize() get isFastBootEnabled() { return ( diff --git a/packages/ember-auto-import/ts/tests/analyzer-test.ts b/packages/ember-auto-import/ts/tests/analyzer-test.ts index a2ae25c08..38706bdc9 100644 --- a/packages/ember-auto-import/ts/tests/analyzer-test.ts +++ b/packages/ember-auto-import/ts/tests/analyzer-test.ts @@ -41,7 +41,7 @@ Qmodule('analyzer', function (hooks) { ], }; let transpiled = broccoliBabel(new UnwatchedDir(upstream), babelConfig); - analyzer = new Analyzer(transpiled, pack); + analyzer = new Analyzer(transpiled, pack, undefined, true); builder = new broccoli.Builder(analyzer); }); diff --git a/packages/ember-auto-import/ts/tests/splitter-test.ts b/packages/ember-auto-import/ts/tests/splitter-test.ts index 96158e4f6..89f06f158 100644 --- a/packages/ember-auto-import/ts/tests/splitter-test.ts +++ b/packages/ember-auto-import/ts/tests/splitter-test.ts @@ -66,7 +66,7 @@ Qmodule('splitter', function (hooks) { require('../../babel-plugin'), ], }); - let analyzer = new Analyzer(transpiled, pack); + let analyzer = new Analyzer(transpiled, pack, undefined, true); splitter = new Splitter({ bundles: new BundleConfig({ vendor: {