From c35ba4d580f504aa11fa913c4f12a9e1d25e61a9 Mon Sep 17 00:00:00 2001 From: Chris Garrett Date: Fri, 19 Feb 2021 13:12:06 -0800 Subject: [PATCH] Adds `useEmberModule` option Adds an option to import `Ember` rather than relying on the global. This will allow this babel plugin to continue working after the global has been deprecated. --- __tests__/tests.js | 59 ++++++++++++++++++++++++++++++++++++++++++++++ index.js | 52 ++++++++++++++++++++++++++++++++++++---- 2 files changed, 107 insertions(+), 4 deletions(-) diff --git a/__tests__/tests.js b/__tests__/tests.js index 604e9154..ad48cbac 100644 --- a/__tests__/tests.js +++ b/__tests__/tests.js @@ -468,4 +468,63 @@ describe('htmlbars-inline-precompile', function () { expect(transformed).toContain(`hello {{firstName}}`); }); }); + + describe('with Ember imports', function () { + it('adds an Ember import if useEmberModule is set to true', function () { + plugins = [ + [ + HTMLBarsInlinePrecompile, + { + precompile() { + return precompile.apply(this, arguments); + }, + + useEmberModule: true, + }, + ], + ]; + + let transpiled = transform( + "import hbs from 'htmlbars-inline-precompile';\nvar compiled = hbs`hello`;" + ); + + expect(transpiled).toMatchInlineSnapshot(` + "import _Ember from \\"ember\\"; + + var compiled = _Ember.HTMLBars.template( + /* + hello + */ + \\"precompiled(hello)\\");" + `); + }); + + it('Uses existing Ember import if one exists', function () { + plugins = [ + [ + HTMLBarsInlinePrecompile, + { + precompile() { + return precompile.apply(this, arguments); + }, + + useEmberModule: true, + }, + ], + ]; + + let transpiled = transform( + "import Foo from 'ember';\nimport hbs from 'htmlbars-inline-precompile';\nvar compiled = hbs`hello`;" + ); + + expect(transpiled).toMatchInlineSnapshot(` + "import Foo from 'ember'; + var compiled = Foo.HTMLBars.template( + /* + hello + */ + \\"precompiled(hello)\\");" + `); + }); + }); }); diff --git a/index.js b/index.js index a4be002c..e694ded1 100644 --- a/index.js +++ b/index.js @@ -50,7 +50,7 @@ module.exports = function (babel) { return result; } - function compileTemplate(precompile, template, _options) { + function compileTemplate(precompile, template, emberIdentifier, _options) { let options = Object.assign({ contents: template }, _options); let precompileResultString; @@ -78,7 +78,7 @@ module.exports = function (babel) { return t.callExpression( t.memberExpression( - t.memberExpression(t.identifier('Ember'), t.identifier('HTMLBars')), + t.memberExpression(emberIdentifier, t.identifier('HTMLBars')), t.identifier('template') ), [templateExpression] @@ -87,6 +87,44 @@ module.exports = function (babel) { return { visitor: { + Program(path, state) { + let options = state.opts || {}; + let useEmberModule = Boolean(options.useEmberModule); + + let preexistingEmberImportDeclaration = path + .get('body') + .filter((n) => n.type === 'ImportDeclaration') + .find((n) => n.get('source').get('value').node === 'ember'); + + if ( + // an import was found + preexistingEmberImportDeclaration && + // this accounts for `import from 'ember'` without a local identifier + preexistingEmberImportDeclaration.node.specifiers.length > 0 + ) { + state.emberIdentifier = preexistingEmberImportDeclaration.node.specifiers[0].local; + } + + state.ensureEmberImport = () => { + if (!useEmberModule) { + // ensures that we can always assume `state.emberIdentifier` is set + state.emberIdentifier = t.identifier('Ember'); + return; + } + + if (state.emberIdentifier) return; + + state.emberIdentifier = path.scope.generateUidIdentifier('Ember'); + + let emberImport = t.importDeclaration( + [t.importDefaultSpecifier(state.emberIdentifier)], + t.stringLiteral('ember') + ); + + path.unshiftContainer('body', emberImport); + }; + }, + ImportDeclaration(path, state) { let node = path.node; @@ -154,7 +192,11 @@ module.exports = function (babel) { let { precompile, isProduction } = state.opts; - path.replaceWith(compileTemplate(precompile, template, { isProduction })); + state.ensureEmberImport(); + + path.replaceWith( + compileTemplate(precompile, template, state.emberIdentifier, { isProduction }) + ); }, CallExpression(path, state) { @@ -222,7 +264,9 @@ module.exports = function (babel) { options.isProduction = isProduction; } - path.replaceWith(compileTemplate(precompile, template, options)); + state.ensureEmberImport(); + + path.replaceWith(compileTemplate(precompile, template, state.emberIdentifier, options)); }, }, };