Skip to content

Commit

Permalink
refactor: Use babel AST for polyfill
Browse files Browse the repository at this point in the history
  • Loading branch information
mydea committed May 12, 2021
1 parent 1d459ed commit be8503a
Show file tree
Hide file tree
Showing 4 changed files with 148 additions and 28 deletions.
28 changes: 22 additions & 6 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,31 @@
'use strict';

const ReplaceImportsPreprocessor = require('./lib/replace-imports-preprocessor');
const { resolve } = require('path');

module.exports = {
name: require('./package').name,

setupPreprocessorRegistry(type, registry) {
if (type !== 'parent') {
return;
}
included() {
this._super.included.apply(this, arguments);

registry.add('js', new ReplaceImportsPreprocessor());
this.patchEmberModulesAPIPolyfill();
},

patchEmberModulesAPIPolyfill() {
const babel = this.parent.findOwnAddonByName
? this.parent.findOwnAddonByName('ember-cli-babel') // parent is an addon
: this.parent.findAddonByName('ember-cli-babel'); // parent is an app

if (babel.__CachedDecoratorPolyfillApplied) return;
babel.__CachedDecoratorPolyfillApplied = true;

const { _getEmberModulesAPIPolyfill } = babel;

babel._getEmberModulesAPIPolyfill = function (...args) {
const plugins = _getEmberModulesAPIPolyfill.apply(this, args);
if (!plugins) return;

return [[resolve(__dirname, './lib/transpile-modules.js')], ...plugins];
};
}
};
22 changes: 0 additions & 22 deletions lib/replace-imports-preprocessor.js

This file was deleted.

93 changes: 93 additions & 0 deletions lib/transpile-modules.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
'use strict';

const path = require('path');

/**
* Based on `babel-plugin-ember-modules-api-polyfill`.
* @see https://github.com/ember-cli/babel-plugin-ember-modules-api-polyfill/blob/master/src/index.js
*/
module.exports = function (babel) {
const t = babel.types;

const MODULE = '@glimmer/tracking';
const IMPORT = 'cached';
const REPLACED_MODULE = 'ember-cached-decorator-polyfill';

return {
name: 'ember-cache-decorator-polyfill',
visitor: {
ImportDeclaration(path) {
let node = path.node;
let declarations = [];
let removals = [];
let specifiers = path.get('specifiers');
let importPath = node.source.value;

// Only walk specifiers if this is a module we have a mapping for
if (importPath === MODULE) {
// Iterate all the specifiers and attempt to locate their mapping
specifiers.forEach(specifierPath => {
let specifier = specifierPath.node;
let importName;

// imported is the name of the module being imported, e.g. import foo from bar
const imported = specifier.imported;

// local is the name of the module in the current scope, this is usually the same
// as the imported value, unless the module is aliased
const local = specifier.local;

// We only care about these 2 specifiers
if (
specifier.type !== 'ImportDefaultSpecifier' &&
specifier.type !== 'ImportSpecifier'
) {
if (specifier.type === 'ImportNamespaceSpecifier') {
throw new Error(
`Using \`import * as ${specifier.local.name} from '${importPath}'\` is not supported.`
);
}
return;
}

// Determine the import name, either default or named
if (specifier.type === 'ImportDefaultSpecifier') {
importName = 'default';
} else {
importName = imported.name;
}

if (importName !== IMPORT) return;

removals.push(specifierPath);

declarations.push(
t.importDeclaration(
[
t.importSpecifier(
t.identifier(local.name),
t.identifier(IMPORT)
)
],
t.stringLiteral(REPLACED_MODULE)
)
);
});
}

if (removals.length > 0) {
if (removals.length === node.specifiers.length) {
path.replaceWithMultiple(declarations);
} else {
removals.forEach(specifierPath => specifierPath.remove());
path.insertAfter(declarations);
}
}
}
}
};
};

// Provide the path to the package's base directory for caching with broccoli
// Ref: https://github.com/babel/broccoli-babel-transpiler#caching
module.exports.baseDir = () => path.resolve(__dirname, '..');
33 changes: 33 additions & 0 deletions tests/unit/renamed-import-test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { module, test } from 'qunit';
import { tracked, cached as localCached } from '@glimmer/tracking';

module('Unit | Import | renamed import', function () {
test('it works', function (assert) {
class Person {
@tracked firstName = 'Jen';
lastName = 'Weber';

@localCached
get fullName() {
const fullName = `${this.firstName} ${this.lastName}`;
assert.step(fullName);
return fullName;
}
}

const person = new Person();
assert.verifySteps([], 'getter is not called after class initialization');

assert.strictEqual(person.fullName, 'Jen Weber');
assert.verifySteps(
['Jen Weber'],
'getter was called after property access'
);

assert.strictEqual(person.fullName, 'Jen Weber');
assert.verifySteps(
[],
'getter was not called again after repeated property access'
);
});
});

0 comments on commit be8503a

Please sign in to comment.