Skip to content

Commit

Permalink
Merge pull request #400 from brendenpalmer/bpalmer/fix-ts-bug
Browse files Browse the repository at this point in the history
Update `_shouldHandleTypeScript` to read from `pkg.dependencies` instead of relying on `addons`
  • Loading branch information
rwjblue authored Apr 28, 2021
2 parents 88a8c81 + 12aa427 commit 670773f
Show file tree
Hide file tree
Showing 4 changed files with 168 additions and 57 deletions.
6 changes: 3 additions & 3 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ module.exports = {
},

getSupportedExtensions(config = {}) {
return _getExtensions(config, this.parent);
return _getExtensions(config, this.parent, this.project);
},

_buildBroccoliBabelTranspilerOptions(config = {}) {
Expand Down Expand Up @@ -160,7 +160,7 @@ module.exports = {
let BabelTranspiler = require('broccoli-babel-transpiler');
let transpilationInput = postDebugTree;

if (_shouldHandleTypeScript(config, this.parent)) {
if (_shouldHandleTypeScript(config, this.parent, this.project)) {
let Funnel = require('broccoli-funnel');
let inputWithoutDeclarations = new Funnel(transpilationInput, { exclude: ['**/*.d.ts'] });
transpilationInput = this._debugTree(inputWithoutDeclarations, `${description}:filtered-input`);
Expand All @@ -175,7 +175,7 @@ module.exports = {
setupPreprocessorRegistry(type, registry) {
registry.add('js', {
name: 'ember-cli-babel',
ext: _getExtensions(this._getAddonOptions(), this.parent),
ext: _getExtensions(this._getAddonOptions(), this.parent, this.project),
toTree: (tree) => this.transpileTree(tree)
});
},
Expand Down
76 changes: 62 additions & 14 deletions lib/babel-options-util.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const VersionChecker = require("ember-cli-version-checker");
const resolvePackagePath = require("resolve-package-path");
const clone = require("clone");
const semver = require("semver");

Expand Down Expand Up @@ -264,10 +265,10 @@ function _getHelperVersion(project) {
return APP_BABEL_RUNTIME_VERSION.get(project);
}

function _buildClassFeaturePluginConstraints(constraints, config, parent) {
function _buildClassFeaturePluginConstraints(constraints, config, parent, project) {
// With versions of ember-cli-typescript < 4.0, class feature plugins like
// @babel/plugin-proposal-class-properties were run before the TS transform.
if (!_shouldHandleTypeScript(config, parent)) {
if (!_shouldHandleTypeScript(config, parent, project)) {
constraints.before = constraints.before || [];
constraints.before.push("@babel/plugin-transform-typescript");
}
Expand Down Expand Up @@ -295,7 +296,8 @@ function _addDecoratorPlugins(plugins, options, config, parent, project) {
before: ["@babel/plugin-proposal-class-properties"],
},
config,
parent
parent,
project
)
);
}
Expand All @@ -320,7 +322,8 @@ function _addDecoratorPlugins(plugins, options, config, parent, project) {
after: ["@babel/plugin-proposal-decorators"],
},
config,
parent
parent,
project
)
);
}
Expand Down Expand Up @@ -389,8 +392,8 @@ function _parentName(parent) {
return parentName;
}

function _getExtensions(config, parent) {
let shouldHandleTypeScript = _shouldHandleTypeScript(config, parent);
function _getExtensions(config, parent, project) {
let shouldHandleTypeScript = _shouldHandleTypeScript(config, parent, project);
let emberCLIBabelConfig = config["ember-cli-babel"] || {};
return (
emberCLIBabelConfig.extensions ||
Expand All @@ -404,18 +407,63 @@ function _shouldIncludeDecoratorPlugins(config) {
return customOptions.disableDecoratorTransforms !== true;
}

function _shouldHandleTypeScript(config, parent) {
/**
* Returns whether we should handle TypeScript (based on the existence of
* `ember-cli-typescript` as a depenency). It's worth noting that we parse
* the `package.json` deps/devDeps directly (rather than using `addons` on
* the parent) because it's possible for `ember-cli-typescript` not to exist
* on the addons array, even if it is a dependency.
*
* Some more context:
*
* `ember-cli-typescript` returns a stable cache key so its possible for it to
* be deduped as part of `ember-engines`. The reason this is important is because
* `ember-engines` dedupe is _stateful_ so it's possible for `ember-cli-typescript`
* to not be part of the addons array when `ember-cli-babel` is running.
*
* For more info on `ember-engines` dedupe logic:
* https://github.com/ember-engines/ember-engines/blob/master/packages/ember-engines/lib/utils/deeply-non-duplicated-addon.js#L35
*
* @name _shouldHandleTypeScript
* @returns {boolean}
*/
function _shouldHandleTypeScript(config, parent, project) {
let emberCLIBabelConfig = config["ember-cli-babel"] || {};

if (typeof emberCLIBabelConfig.enableTypeScriptTransform === "boolean") {
return emberCLIBabelConfig.enableTypeScriptTransform;
}
let typeScriptAddon =
parent.addons &&
parent.addons.find((a) => a.name === "ember-cli-typescript");
return (
typeof typeScriptAddon !== "undefined" &&
semver.gte(typeScriptAddon.pkg.version, "4.0.0-alpha.1")
);

let pkg = parent.pkg;

if (!pkg) {
return false;
}

let dependencies;

// consider `dependencies` and `devDependencies` if the parent is the project
// (`ember-cli` uses both in this case), otherwise only care about `dependencies`
if (parent === project) {
dependencies = Object.assign({}, pkg.dependencies, pkg.devDependencies);
} else {
dependencies = pkg.dependencies || {};
}

let tsDependency = dependencies["ember-cli-typescript"];

if (tsDependency !== undefined) {
let tsPkgPath = resolvePackagePath("ember-cli-typescript", parent.root);

if (tsPkgPath === null) {
return false;
}

let tsPkg = require(tsPkgPath);
return semver.gte(tsPkg.version, "4.0.0-alpha.1");
}

return false;
}

function _getAddonProvidedConfig(addonOptions) {
Expand Down
2 changes: 1 addition & 1 deletion lib/get-babel-options.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ module.exports = function getBabelOptions(config, appInstance) {
let { parent, project } = appInstance;
let addonProvidedConfig = _getAddonProvidedConfig(config);
let shouldIncludeHelpers = _shouldIncludeHelpers(config, appInstance);
let shouldHandleTypeScript = _shouldHandleTypeScript(config, parent);
let shouldHandleTypeScript = _shouldHandleTypeScript(config, parent, project);
let shouldIncludeDecoratorPlugins = _shouldIncludeDecoratorPlugins(config);

let emberCLIBabelConfig = config["ember-cli-babel"];
Expand Down
141 changes: 102 additions & 39 deletions node-tests/addon-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -800,14 +800,51 @@ describe('ember-cli-babel', function() {
});

describe('TypeScript transpilation', function() {
beforeEach(function() {
this.addon.parent.addons.push({
name: 'ember-cli-typescript',
pkg: {
version: '4.0.0-alpha.1'
}
let input;
let output;
let subject;
let project;
let unlink;

beforeEach(co.wrap(function*() {
let fixturifyProject = new FixturifyProject('whatever', '0.0.1');
fixturifyProject.addDependency('ember-cli-typescript', '4.0.0-alpha.1', addon => {
return prepareAddon(addon);
});
});
fixturifyProject.addDependency('ember-cli-babel', 'babel/ember-cli-babel#master');
let pkg = JSON.parse(fixturifyProject.toJSON('package.json'));
fixturifyProject.writeSync();

let linkPath = path.join(fixturifyProject.root, 'whatever/node_modules/ember-cli-babel');
let addonPath = path.resolve(__dirname, '../');
rimraf.sync(linkPath);
fs.symlinkSync(addonPath, linkPath, 'junction');
unlink = () => {
fs.unlinkSync(linkPath);
};

let cli = new MockCLI();
let root = path.join(fixturifyProject.root, 'whatever');
project = new EmberProject(root, pkg, cli.ui, cli);
project.initializeAddons();
this.addon = project.addons.find(a => { return a.name === 'ember-cli-babel'; });
input = yield createTempDir();
}));

afterEach(co.wrap(function*() {
unlink();

if (input) {
yield input.dispose();
}

if (output) {
yield output.dispose();
}

// shut down workers after the tests are run so that mocha doesn't hang
yield terminateWorkerPool();
}));

it('should transpile .ts files', co.wrap(function*() {
input.write({ 'foo.ts': `let foo: string = "hi";` });
Expand Down Expand Up @@ -967,41 +1004,67 @@ describe('ember-cli-babel', function() {
});

describe('_shouldHandleTypeScript', function() {
let project;
let unlink;

let setupTsAddon = function*(context, version = '4.0.0-alpha.1') {
let fixturifyProject = new FixturifyProject('whatever', '0.0.1');
fixturifyProject.addDependency('ember-cli-typescript', version, addon => {
return prepareAddon(addon);
});
fixturifyProject.addDependency('ember-cli-babel', 'babel/ember-cli-babel#master');
let pkg = JSON.parse(fixturifyProject.toJSON('package.json'));
fixturifyProject.writeSync();

let linkPath = path.join(fixturifyProject.root, 'whatever/node_modules/ember-cli-babel');
let addonPath = path.resolve(__dirname, '../');
rimraf.sync(linkPath);
fs.symlinkSync(addonPath, linkPath, 'junction');
unlink = () => {
fs.unlinkSync(linkPath);
};

let cli = new MockCLI();
let root = path.join(fixturifyProject.root, 'whatever');
project = new EmberProject(root, pkg, cli.ui, cli);
project.initializeAddons();
context.addon = project.addons.find(a => { return a.name === 'ember-cli-babel'; });
input = yield createTempDir();
}

afterEach(co.wrap(function*() {
if (unlink) {
unlink();
unlink = undefined;
}

// shut down workers after the tests are run so that mocha doesn't hang
yield terminateWorkerPool();
}));

it('should return false by default', function() {
expect(_shouldHandleTypeScript({}, this.addon.parent)).to.be.false;
expect(_shouldHandleTypeScript({}, this.addon.parent, this.addon.project)).to.be.false;
});
it('should return true when ember-cli-typescript >= 4.0.0-alpha.1 is installed', function() {
this.addon.parent.addons.push({
name: 'ember-cli-typescript',
pkg: {
version: '4.0.0-alpha.1',
},
});
expect(_shouldHandleTypeScript({}, this.addon.parent)).to.be.true;
it('should return true when ember-cli-typescript >= 4.0.0-alpha.1 is installed', function*() {
yield setupTsAddon(this);
expect(_shouldHandleTypeScript({}, this.addon.parent, this.addon.project)).to.be.true;
});
it('should return false when ember-cli-typescript < 4.0.0-alpha.1 is installed', function() {
this.addon.parent.addons.push({
name: 'ember-cli-typescript',
pkg: {
version: '3.0.0',
},
});
expect(_shouldHandleTypeScript({}, this.addon.parent)).to.be.false;
it('should return false when ember-cli-typescript < 4.0.0-alpha.1 is installed', function*() {
yield setupTsAddon(this, '3.0.0');
expect(_shouldHandleTypeScript({}, this.addon.parent, this.addon.project)).to.be.false;
});
it('should return true when the TypeScript transform is manually enabled', function() {
expect(_shouldHandleTypeScript({ 'ember-cli-babel': { enableTypeScriptTransform: true } }, this.addon.parent)).to.be.true;
it('should return true when the TypeScript transform is manually enabled', function*() {
yield setupTsAddon(this, '3.0.0');
expect(_shouldHandleTypeScript({ 'ember-cli-babel': { enableTypeScriptTransform: true } }, this.addon.parent, this.addon.project)).to.be.true;
});

it('should return false when the TypeScript transforms is manually disabled', function() {
expect(_shouldHandleTypeScript({ 'ember-cli-babel': { enableTypeScriptTransform: false } }, this.addon.parent)).to.be.false;
expect(_shouldHandleTypeScript({ 'ember-cli-babel': { enableTypeScriptTransform: false } }, this.addon.parent, this.addon.project)).to.be.false;
});
it('should return false when the TypeScript transform is manually disabled, even when ember-cli-typescript >= 4.0.0-alpha.1 is installed', function() {
this.addon.parent.addons.push({
name: 'ember-cli-typescript',
pkg: {
version: '4.0.0-alpha.1',
},
});
expect(_shouldHandleTypeScript({ 'ember-cli-babel': { enableTypeScriptTransform: false } }, this.addon.parent)).to.be.false;

it('should return false when the TypeScript transform is manually disabled, even when ember-cli-typescript >= 4.0.0-alpha.1 is installed', function*() {
yield setupTsAddon(this, '4.1.0');
expect(_shouldHandleTypeScript({ 'ember-cli-babel': { enableTypeScriptTransform: false } }, this.addon.parent, this.addon.project)).to.be.false;
});
});

Expand Down Expand Up @@ -1177,17 +1240,17 @@ describe('ember-cli-babel', function() {

describe('_getExtensions', function() {
it('defaults to js only', function() {
expect(_getExtensions({}, this.addon.parent)).to.have.members(['js']);
expect(_getExtensions({}, this.addon.parent, this.addon.project)).to.have.members(['js']);
});
it('adds ts automatically', function() {
this.addon._shouldHandleTypeScript = function() { return true; }
expect(_getExtensions({ 'ember-cli-babel': { enableTypeScriptTransform: true }}, this.addon.parent)).to.have.members(['js', 'ts']);
expect(_getExtensions({ 'ember-cli-babel': { enableTypeScriptTransform: true } }, this.addon.parent, this.addon.project)).to.have.members(['js', 'ts']);
});
it('respects user-configured extensions', function() {
expect(_getExtensions({ 'ember-cli-babel': { extensions: ['coffee'] } }, this.addon.parent)).to.have.members(['coffee']);
expect(_getExtensions({ 'ember-cli-babel': { extensions: ['coffee'] } }, this.addon.parent, this.addon.project)).to.have.members(['coffee']);
});
it('respects user-configured extensions even when adding TS plugin', function() {
expect(_getExtensions({ 'ember-cli-babel': { enableTypeScriptTransform: true, extensions: ['coffee'] } }, this.addon.parent)).to.have.members(['coffee']);
expect(_getExtensions({ 'ember-cli-babel': { enableTypeScriptTransform: true, extensions: ['coffee'] } }, this.addon.parent, this.addon.project)).to.have.members(['coffee']);
});
});

Expand Down

0 comments on commit 670773f

Please sign in to comment.