ember-cli 3.4.4 → 3.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/.travis.yml +8 -7
  2. package/CHANGELOG.md +98 -6
  3. package/CONTRIBUTING.md +1 -1
  4. package/PERF_GUIDE.md +1 -1
  5. package/README.md +1 -1
  6. package/RELEASE.md +12 -10
  7. package/blueprints/addon/files/addon-config/ember-try.js +2 -2
  8. package/blueprints/addon/files/npmignore +2 -1
  9. package/blueprints/addon-import/index.js +3 -0
  10. package/blueprints/app/files/.eslintignore +2 -0
  11. package/blueprints/app/files/.eslintrc.js +1 -0
  12. package/blueprints/app/files/package.json +4 -4
  13. package/blueprints/module-unification-app/files/.eslintignore +2 -0
  14. package/blueprints/module-unification-app/files/.eslintrc.js +1 -0
  15. package/blueprints/module-unification-app/files/config/environment.js +1 -1
  16. package/blueprints/module-unification-app/files/config/targets.js +1 -1
  17. package/blueprints/module-unification-app/files/package.json +18 -17
  18. package/lib/broccoli/default-packager.js +7 -9
  19. package/lib/broccoli/ember-app.js +43 -34
  20. package/lib/commands/destroy.js +8 -0
  21. package/lib/commands/generate.js +8 -0
  22. package/lib/commands/new.js +2 -2
  23. package/lib/commands/serve.js +2 -0
  24. package/lib/errors/cli.js +4 -0
  25. package/lib/experiments/index.js +33 -12
  26. package/lib/models/addon-info.js +2 -2
  27. package/lib/models/addon.js +9 -10
  28. package/lib/models/blueprint.js +39 -7
  29. package/lib/models/builder.js +137 -17
  30. package/lib/models/command.js +2 -2
  31. package/lib/models/package-info-cache/index.js +11 -10
  32. package/lib/models/package-info-cache/package-info.js +9 -12
  33. package/lib/models/project.js +3 -3
  34. package/lib/models/watcher.js +2 -1
  35. package/lib/tasks/npm-task.js +1 -1
  36. package/lib/tasks/server/express-server.js +1 -1
  37. package/lib/tasks/server/livereload-server.js +2 -1
  38. package/lib/tasks/server/middleware/proxy-server/index.js +8 -3
  39. package/lib/utilities/default-targets.js +1 -1
  40. package/lib/utilities/find-build-file.js +2 -3
  41. package/lib/utilities/is-addon.js +6 -0
  42. package/lib/utilities/is-live-reload-request.js +17 -0
  43. package/lib/utilities/valid-project-name.js +1 -0
  44. package/package.json +8 -4
  45. package/tests/helpers/default-packager.js +1 -1
  46. package/tests/helpers/generate-utils.js +26 -0
  47. package/tests/helpers/init-app.js +14 -0
  48. package/tests/helpers/mock-project.js +5 -5
  49. package/yarn.lock +0 -5695
@@ -26,6 +26,7 @@ const ConfigReplace = require('broccoli-config-replace');
26
26
  const mergeTrees = require('./merge-trees');
27
27
  const WatchedDir = require('broccoli-source').WatchedDir;
28
28
  const UnwatchedDir = require('broccoli-source').UnwatchedDir;
29
+ const BroccoliMergeTrees = require('broccoli-merge-trees');
29
30
 
30
31
  const merge = require('ember-cli-lodash-subset').merge;
31
32
  const defaultsDeep = require('ember-cli-lodash-subset').defaultsDeep;
@@ -37,7 +38,7 @@ const emberAppUtils = require('../utilities/ember-app-utils');
37
38
  const addonProcessTree = require('../utilities/addon-process-tree');
38
39
  const lintAddonsByType = require('../utilities/lint-addons-by-type');
39
40
  const emberCLIBabelConfigKey = require('../utilities/ember-cli-babel-config-key');
40
- const experiments = require('../experiments');
41
+ const { isExperimentEnabled } = require('../experiments');
41
42
  const semver = require('semver');
42
43
  const DefaultPackager = require('./default-packager');
43
44
 
@@ -166,7 +167,7 @@ class EmberApp {
166
167
  additionalAssetPaths: this.otherAssetPaths,
167
168
  vendorTestStaticStyles: this.vendorTestStaticStyles,
168
169
  legacyTestFilesToAppend: this.legacyTestFilesToAppend,
169
- isModuleUnificationEnabled: experiments.MODULE_UNIFICATION && !!this.trees.src,
170
+ isModuleUnificationEnabled: isExperimentEnabled('MODULE_UNIFICATION') && !!this.trees.src,
170
171
  distPaths: {
171
172
  appJsFile: this.options.outputPaths.app.js,
172
173
  appCssFile: this.options.outputPaths.app.css,
@@ -179,6 +180,7 @@ class EmberApp {
179
180
  },
180
181
  });
181
182
 
183
+ this._isPackageHookSupplied = typeof this.options.package === 'function';
182
184
  this._cachedAddonBundles = {};
183
185
  }
184
186
 
@@ -263,7 +265,7 @@ class EmberApp {
263
265
  // these are contained within app/ no need to watch again
264
266
  // (we should probably have the builder or the watcher dedup though)
265
267
 
266
- if (experiments.MODULE_UNIFICATION) {
268
+ if (isExperimentEnabled('MODULE_UNIFICATION')) {
267
269
  let srcStylesPath = `${resolvePathFor('src', trees.src)}/ui/styles`;
268
270
  this._stylesPath = fs.existsSync(srcStylesPath) ? srcStylesPath : resolvePathFor('app/styles', trees.styles);
269
271
  } else {
@@ -967,7 +969,7 @@ class EmberApp {
967
969
  addons: this.project.addons,
968
970
  autoRun: this.options.autoRun,
969
971
  storeConfigInMeta: this.options.storeConfigInMeta,
970
- isModuleUnification: experiments.MODULE_UNIFICATION && !!this.trees.src,
972
+ isModuleUnification: isExperimentEnabled('MODULE_UNIFICATION') && !!this.trees.src,
971
973
  });
972
974
 
973
975
  return new ConfigReplace(index, this._defaultPackager.packageConfig(this.tests), {
@@ -1028,7 +1030,7 @@ class EmberApp {
1028
1030
  annotation: 'ProcessedAppTree',
1029
1031
  });
1030
1032
 
1031
- if (experiments.PACKAGER && isPackageHookSupplied) {
1033
+ if (isExperimentEnabled('PACKAGER') && isPackageHookSupplied) {
1032
1034
  appTree = this._precompileAppJsTree(appTree);
1033
1035
  }
1034
1036
 
@@ -1161,7 +1163,7 @@ class EmberApp {
1161
1163
  for (let addonBundle of addonBundles) {
1162
1164
  let { name, root } = addonBundle;
1163
1165
 
1164
- if (experiments.DELAYED_TRANSPILATION) {
1166
+ if (isExperimentEnabled('DELAYED_TRANSPILATION')) {
1165
1167
  if (!options.moduleNormalizerDisabled) {
1166
1168
  // move legacy /modules/addon to /addon
1167
1169
  let hasAlreadyPrintedModuleDeprecation;
@@ -1392,7 +1394,7 @@ class EmberApp {
1392
1394
  lintTrees.push(lintedApp);
1393
1395
  }
1394
1396
 
1395
- if (experiments.MODULE_UNIFICATION && this.trees.src) {
1397
+ if (isExperimentEnabled('MODULE_UNIFICATION') && this.trees.src) {
1396
1398
  let lintedSrc = this.addonLintTree('src', this.trees.src);
1397
1399
  lintedSrc = new Funnel(lintedSrc, {
1398
1400
  destDir: 'lint/src/',
@@ -1611,33 +1613,15 @@ class EmberApp {
1611
1613
  @return {Array} An array of trees
1612
1614
  */
1613
1615
  toArray() {
1614
- // allows us to optimize if they aren't using the hook
1615
- let isPackageHookSupplied = typeof this.package === 'function';
1616
-
1617
- let trees = [
1616
+ return [
1618
1617
  this.getAddonTemplates(),
1619
1618
  this.getStyles(),
1620
1619
  this.getTests(),
1621
1620
  this.getExternalTree(),
1622
1621
  this.getPublic(),
1623
1622
  this.getSrc(),
1624
- this.getAppJavascript(isPackageHookSupplied),
1623
+ this.getAppJavascript(this._isPackageHookSupplied),
1625
1624
  ].filter(Boolean);
1626
-
1627
- let fullTree = mergeTrees(trees, {
1628
- overwrite: true,
1629
- annotation: 'Full Application',
1630
- });
1631
-
1632
- if (experiments.PACKAGER) {
1633
- if (isPackageHookSupplied) {
1634
- return [this.package.call(this, fullTree)];
1635
- } else {
1636
- this.project.ui.writeWarnLine('`package` hook must be a function, falling back to default packaging.');
1637
- }
1638
- }
1639
-
1640
- return this._legacyPackager(fullTree);
1641
1625
  }
1642
1626
 
1643
1627
  _legacyAddonCompile(type, outputDir, _options) {
@@ -1705,8 +1689,8 @@ class EmberApp {
1705
1689
  });
1706
1690
  }
1707
1691
 
1708
- _legacyPackager(fullTree) {
1709
- if (experiments.DELAYED_TRANSPILATION) {
1692
+ _legacyPackage(fullTree) {
1693
+ if (isExperimentEnabled('DELAYED_TRANSPILATION')) {
1710
1694
  fullTree = mergeTrees(
1711
1695
  [
1712
1696
  fullTree,
@@ -1723,6 +1707,8 @@ class EmberApp {
1723
1707
  overwrite: true,
1724
1708
  }
1725
1709
  );
1710
+
1711
+ fullTree = this._debugTree(fullTree, 'postcompiledAddonTrees');
1726
1712
  }
1727
1713
 
1728
1714
  let javascriptTree = this._defaultPackager.packageJavascript(fullTree);
@@ -1743,7 +1729,10 @@ class EmberApp {
1743
1729
  sourceTrees.push(this._defaultPackager.packageTests(fullTree));
1744
1730
  }
1745
1731
 
1746
- return sourceTrees;
1732
+ return mergeTrees(sourceTrees, {
1733
+ overwrite: true,
1734
+ annotation: 'Application Dist',
1735
+ });
1747
1736
  }
1748
1737
 
1749
1738
  /**
@@ -1751,16 +1740,36 @@ class EmberApp {
1751
1740
 
1752
1741
  @public
1753
1742
  @method toTree
1754
- @param {Array} additionalTrees Array of additional trees to merge
1743
+ @param {Array} [additionalTrees] Array of additional trees to merge
1755
1744
  @return {Tree} Merged tree for this application
1756
1745
  */
1757
1746
  toTree(additionalTrees) {
1758
- let tree = mergeTrees(this.toArray().concat(additionalTrees || []), {
1747
+ let packagedTree;
1748
+ let packageFn = this.options.package;
1749
+
1750
+ let fullTree = mergeTrees(this.toArray(), {
1759
1751
  overwrite: true,
1760
- annotation: 'TreeMerger (allTrees)',
1752
+ annotation: 'Full Application',
1761
1753
  });
1762
1754
 
1763
- return this.addonPostprocessTree('all', tree);
1755
+ fullTree = this._debugTree(fullTree, 'prepackage');
1756
+
1757
+ if (isExperimentEnabled('PACKAGER')) {
1758
+ if (this._isPackageHookSupplied) {
1759
+ packagedTree = packageFn.call(this, fullTree);
1760
+ } else {
1761
+ this.project.ui.writeWarnLine('`package` hook must be a function, falling back to default packaging.');
1762
+ }
1763
+ }
1764
+
1765
+ if (!packagedTree) {
1766
+ packagedTree = this._legacyPackage(fullTree);
1767
+ }
1768
+
1769
+ let trees = [].concat(packagedTree, additionalTrees).filter(Boolean);
1770
+ let combinedPackageTree = new BroccoliMergeTrees(trees);
1771
+
1772
+ return this.addonPostprocessTree('all', combinedPackageTree);
1764
1773
  }
1765
1774
  }
1766
1775
 
@@ -1,5 +1,6 @@
1
1
  'use strict';
2
2
 
3
+ const path = require('path');
3
4
  const Command = require('../models/command');
4
5
  const Promise = require('rsvp').Promise;
5
6
  const mergeBlueprintOptions = require('../utilities/merge-blueprint-options');
@@ -19,6 +20,8 @@ module.exports = Command.extend({
19
20
  { name: 'classic', type: Boolean, default: false, aliases: ['c'] },
20
21
  { name: 'dummy', type: Boolean, default: false, aliases: ['dum', 'id'] },
21
22
  { name: 'in-repo-addon', type: String, default: null, aliases: ['in-repo', 'ir'] },
23
+ { name: 'in', type: String, default: null, description: 'Runs a blueprint against an in repo addon. ' +
24
+ 'A path is expected, relative to the root of the project.' },
22
25
  ],
23
26
 
24
27
  anonymousOptions: [
@@ -51,6 +54,11 @@ module.exports = Command.extend({
51
54
  commandOptions.pod = !commandOptions.pod;
52
55
  }
53
56
 
57
+ if (commandOptions.in) {
58
+ let relativePath = path.relative(this.project.root, commandOptions.in);
59
+ commandOptions.in = path.resolve(relativePath);
60
+ }
61
+
54
62
  let taskOptions = merge(taskArgs, commandOptions || {});
55
63
 
56
64
  if (this.project.initializeAddons) {
@@ -1,5 +1,6 @@
1
1
  'use strict';
2
2
 
3
+ const path = require('path');
3
4
  const chalk = require('chalk');
4
5
  const Command = require('../models/command');
5
6
  const Promise = require('rsvp').Promise;
@@ -22,6 +23,8 @@ module.exports = Command.extend({
22
23
  { name: 'classic', type: Boolean, default: false, aliases: ['c'] },
23
24
  { name: 'dummy', type: Boolean, default: false, aliases: ['dum', 'id'] },
24
25
  { name: 'in-repo-addon', type: String, default: null, aliases: ['in-repo', 'ir'] },
26
+ { name: 'in', type: String, default: null, description: 'Runs a blueprint against an in repo addon. ' +
27
+ 'A path is expected, relative to the root of the project.' },
25
28
  ],
26
29
 
27
30
  anonymousOptions: [
@@ -55,6 +58,11 @@ module.exports = Command.extend({
55
58
  }
56
59
  }
57
60
 
61
+ if (commandOptions.in) {
62
+ let relativePath = path.relative(this.project.root, commandOptions.in);
63
+ commandOptions.in = path.resolve(relativePath);
64
+ }
65
+
58
66
  let taskOptions = _.merge(taskArgs, commandOptions || {});
59
67
 
60
68
  if (this.project.initializeAddons) {
@@ -9,7 +9,7 @@ const SilentError = require('silent-error');
9
9
  const validProjectName = require('../utilities/valid-project-name');
10
10
  const normalizeBlueprint = require('../utilities/normalize-blueprint-option');
11
11
  const mergeBlueprintOptions = require('../utilities/merge-blueprint-options');
12
- const experiments = require('../experiments');
12
+ const { isExperimentEnabled } = require('../experiments');
13
13
 
14
14
  const rmdir = RSVP.denodeify(fs.remove);
15
15
  const Promise = RSVP.Promise;
@@ -38,7 +38,7 @@ module.exports = Command.extend({
38
38
  beforeRun: mergeBlueprintOptions,
39
39
 
40
40
  run(commandOptions, rawArgs) {
41
- if (experiments.MODULE_UNIFICATION) {
41
+ if (isExperimentEnabled('MODULE_UNIFICATION')) {
42
42
  if (commandOptions.blueprint === 'app') {
43
43
  commandOptions.blueprint = 'module-unification-app';
44
44
  } else if (commandOptions.blueprint === 'addon') {
@@ -23,6 +23,8 @@ module.exports = Command.extend({
23
23
  { name: 'port', type: Number, default: defaultPort, aliases: ['p'], description: `To use a port different than ${defaultPort}. Pass 0 to automatically pick an available port.` },
24
24
  { name: 'host', type: String, aliases: ['H'], description: 'Listens on all interfaces by default' },
25
25
  { name: 'proxy', type: String, aliases: ['pr', 'pxy'] },
26
+ { name: 'proxy-in-timeout', type: Number, default: 120000, aliases: ['pit'], description: 'When using --proxy: timeout (in ms) for incoming requests' },
27
+ { name: 'proxy-out-timeout', type: Number, default: 0, aliases: ['pot'], description: 'When using --proxy: timeout (in ms) for outgoing requests' },
26
28
  { name: 'secure-proxy', type: Boolean, default: true, aliases: ['spr'], description: 'Set to false to proxy self-signed SSL certificates' },
27
29
  { name: 'transparent-proxy', type: Boolean, default: true, aliases: ['transp'], description: 'Set to false to omit x-forwarded-* headers when proxying' },
28
30
  { name: 'watcher', type: String, default: 'events', aliases: ['w'] },
@@ -0,0 +1,4 @@
1
+
2
+ 'use strict';
3
+
4
+ module.exports = class BuildError extends Error {};
@@ -1,25 +1,46 @@
1
1
  'use strict';
2
2
 
3
- // eslint-disable-next-line no-unused
3
+ const CliError = require('../errors/cli');
4
+
5
+ const availableExperiments = Object.freeze([
6
+ 'PACKAGER',
7
+ 'MODULE_UNIFICATION',
8
+ 'DELAYED_TRANSPILATION',
9
+ 'BROCCOLI_2',
10
+ 'SYSTEM_TEMP',
11
+ ]);
12
+
13
+ const enabledExperiments = Object.freeze([
14
+ 'BROCCOLI_2',
15
+ ]);
16
+
4
17
  function isExperimentEnabled(experimentName) {
18
+ if (!availableExperiments.includes(experimentName)) {
19
+ return false;
20
+ }
21
+
5
22
  if (process.env.EMBER_CLI_ENABLE_ALL_EXPERIMENTS) {
6
23
  return true;
7
24
  }
8
25
 
9
26
  let experimentEnvironmentVariable = `EMBER_CLI_${experimentName}`;
10
- if (process.env[experimentEnvironmentVariable]) {
27
+ let experimentValue = process.env[experimentEnvironmentVariable];
28
+ if (enabledExperiments.includes(experimentName)) {
29
+ return experimentValue !== 'false';
30
+ } else if (
31
+ experimentName === 'SYSTEM_TEMP' &&
32
+ experimentValue === undefined &&
33
+ isExperimentEnabled('BROCCOLI_2')
34
+ ) {
11
35
  return true;
36
+ } else {
37
+ return experimentValue !== undefined && experimentValue !== 'false';
12
38
  }
13
-
14
- return false;
15
39
  }
16
40
 
17
- let experiments = {
18
- PACKAGER: isExperimentEnabled('PACKAGER'),
19
- MODULE_UNIFICATION: isExperimentEnabled('MODULE_UNIFICATION'),
20
- DELAYED_TRANSPILATION: isExperimentEnabled('DELAYED_TRANSPILATION'),
21
- };
22
-
23
- Object.freeze(experiments);
41
+ // SYSTEM_TEMP can only be used with BROCCOLI_2
42
+ if (isExperimentEnabled('SYSTEM_TEMP') && !isExperimentEnabled('BROCCOLI_2')) {
43
+ throw new CliError('EMBER_CLI_SYSTEM_TEMP only works in combination with EMBER_CLI_BROCCOLI_2');
44
+ }
24
45
 
25
- module.exports = experiments;
46
+ module.exports = { isExperimentEnabled };
@@ -1,10 +1,10 @@
1
1
  'use strict';
2
2
 
3
3
  /**
4
- * @module addon-info
5
- *
6
4
  * A simple class to store metadata info about an addon. This replaces a plain JS object
7
5
  * that used to be created with the same fields.
6
+ *
7
+ * @module ember-cli
8
8
  */
9
9
 
10
10
  class AddonInfo {
@@ -11,7 +11,7 @@ const heimdallLogger = require('heimdalljs-logger');
11
11
  const logger = heimdallLogger('ember-cli:addon');
12
12
  const treeCacheLogger = heimdallLogger('ember-cli:addon:tree-cache');
13
13
  const cacheKeyLogger = heimdallLogger('ember-cli:addon:cache-key-for-tree');
14
- const experiments = require('../experiments');
14
+ const { isExperimentEnabled } = require('../experiments');
15
15
  const PackageInfoCache = require('../models/package-info-cache');
16
16
 
17
17
  const p = require('ember-cli-preprocess-registry/preprocessors');
@@ -242,7 +242,7 @@ let addonProto = {
242
242
 
243
243
  this._initDefaultBabelOptions();
244
244
 
245
- if (experiments.DELAYED_TRANSPILATION) {
245
+ if (isExperimentEnabled('DELAYED_TRANSPILATION')) {
246
246
  this.registry.remove('template', 'ember-cli-htmlbars');
247
247
  }
248
248
  },
@@ -253,7 +253,7 @@ let addonProto = {
253
253
  });
254
254
 
255
255
  let defaultEmberCLIBabelOptions;
256
- if (experiments.DELAYED_TRANSPILATION) {
256
+ if (isExperimentEnabled('DELAYED_TRANSPILATION')) {
257
257
  defaultEmberCLIBabelOptions = {
258
258
  compileModules: false,
259
259
  disablePresetEnv: true,
@@ -400,11 +400,10 @@ let addonProto = {
400
400
  let pkgInfo = this.packageInfoCache.getEntry(this.root);
401
401
 
402
402
  if (pkgInfo) {
403
- let self = this;
404
403
  let addonPackageList = pkgInfo.discoverAddonAddons();
405
404
  this.addonPackages =
406
405
  pkgInfo.generateAddonPackages(addonPackageList,
407
- addonInfo => (self.shouldIncludeChildAddon && !self.shouldIncludeChildAddon(addonInfo)));
406
+ addonInfo => (this.shouldIncludeChildAddon && !this.shouldIncludeChildAddon(addonInfo)));
408
407
 
409
408
  // in case any child addons are invalid, dump to the console about them.
410
409
  pkgInfo.dumpInvalidAddonPackages(addonPackageList);
@@ -747,7 +746,7 @@ let addonProto = {
747
746
  @return {Tree} App file tree
748
747
  */
749
748
  treeForApp(tree) {
750
- if (!experiments.MODULE_UNIFICATION) {
749
+ if (!isExperimentEnabled('MODULE_UNIFICATION')) {
751
750
  return tree;
752
751
  } else if (this.project.isModuleUnification() && this.isModuleUnification()) {
753
752
  return null;
@@ -788,7 +787,7 @@ let addonProto = {
788
787
  @return
789
788
  */
790
789
  treeForSrc(rawSrcTree) {
791
- if (!experiments.MODULE_UNIFICATION) {
790
+ if (!isExperimentEnabled('MODULE_UNIFICATION')) {
792
791
  return null;
793
792
  }
794
793
  if (!rawSrcTree) { return null; }
@@ -801,7 +800,7 @@ let addonProto = {
801
800
  let srcAfterPreprocessTreeHook = this._addonPreprocessTree('src', srcNamespacedTree);
802
801
 
803
802
  let srcAfterTemplatePreprocessing = srcAfterPreprocessTreeHook;
804
- if (!experiments.DELAYED_TRANSPILATION || registryHasPreprocessor(this.registry, 'template')) {
803
+ if (!isExperimentEnabled('DELAYED_TRANSPILATION') || registryHasPreprocessor(this.registry, 'template')) {
805
804
  srcAfterTemplatePreprocessing = preprocessTemplates(srcAfterPreprocessTreeHook, {
806
805
  registry: this.registry,
807
806
  annotation: `Addon#treeForSrc(${this.name})`,
@@ -1132,7 +1131,7 @@ let addonProto = {
1132
1131
  this._requireBuildPackages();
1133
1132
 
1134
1133
  if (this.shouldCompileTemplates()) {
1135
- if (!experiments.DELAYED_TRANSPILATION && !registryHasPreprocessor(this.registry, 'template')) {
1134
+ if (!isExperimentEnabled('DELAYED_TRANSPILATION') && !registryHasPreprocessor(this.registry, 'template')) {
1136
1135
  throw new SilentError(`Addon templates were detected, but there are no template compilers registered for \`${this.name}\`. ` +
1137
1136
  `Please make sure your template precompiler (commonly \`ember-cli-htmlbars\`) is listed in \`dependencies\` ` +
1138
1137
  `(NOT \`devDependencies\`) in \`${this.name}\`'s \`package.json\`.`);
@@ -1141,7 +1140,7 @@ let addonProto = {
1141
1140
  let preprocessedTemplateTree = this._addonPreprocessTree('template', this._addonTemplateFiles(addonTree));
1142
1141
 
1143
1142
  let processedTemplateTree;
1144
- if (!experiments.DELAYED_TRANSPILATION || registryHasPreprocessor(this.registry, 'template')) {
1143
+ if (!isExperimentEnabled('DELAYED_TRANSPILATION') || registryHasPreprocessor(this.registry, 'template')) {
1145
1144
  processedTemplateTree = preprocessTemplates(preprocessedTemplateTree, {
1146
1145
  annotation: `compileTemplates(${this.name})`,
1147
1146
  registry: this.registry,
@@ -24,6 +24,7 @@ const EOL = require('os').EOL;
24
24
  const bowEpParser = require('bower-endpoint-parser');
25
25
  const logger = require('heimdalljs-logger')('ember-cli:blueprint');
26
26
  const normalizeEntityName = require('ember-cli-normalize-entity-name');
27
+ const isAddon = require('../utilities/is-addon');
27
28
 
28
29
  const Promise = RSVP.Promise;
29
30
  const stat = RSVP.denodeify(fs.stat);
@@ -385,14 +386,24 @@ let Blueprint = CoreObject.extend({
385
386
  /**
386
387
  @private
387
388
  @method _checkInRepoAddonExists
388
- @param {String} inRepoAddon
389
+ @param {Object} options
389
390
  */
390
- _checkInRepoAddonExists(inRepoAddon) {
391
- if (inRepoAddon) {
392
- let addon = findAddonByName(this.project, inRepoAddon);
391
+ _checkInRepoAddonExists(options) {
392
+ let addon;
393
+
394
+ if (options.inRepoAddon) {
395
+ addon = findAddonByName(this.project, options.inRepoAddon);
396
+
393
397
  if (!addon) {
394
- throw new SilentError(`You specified the in-repo-addon flag, but the ` +
395
- `in-repo-addon '${inRepoAddon}' does not exist. Please check the name and try again.`);
398
+ throw new SilentError(`You specified the 'in-repo-addon' flag, but the ` +
399
+ `in-repo-addon '${options.inRepoAddon}' does not exist. Please check the name and try again.`);
400
+ }
401
+ }
402
+
403
+ if (options.in) {
404
+ if (!ensureTargetDirIsAddon(options.in)) {
405
+ throw new SilentError(`You specified the 'in' flag, but the ` +
406
+ `in repo addon '${options.in}' does not exist. Please check the name and try again.`);
396
407
  }
397
408
  }
398
409
  },
@@ -438,7 +449,7 @@ let Blueprint = CoreObject.extend({
438
449
 
439
450
  this._normalizeEntityName(options.entity);
440
451
  this._checkForPod(options.verbose);
441
- this._checkInRepoAddonExists(options.inRepoAddon);
452
+ this._checkInRepoAddonExists(options);
442
453
 
443
454
  logger.info('START: processing blueprint: `%s`', this.name);
444
455
  let start = new Date();
@@ -599,6 +610,10 @@ let Blueprint = CoreObject.extend({
599
610
  let relativeAddonPath = path.relative(project.root, addon.root);
600
611
  return path.join(relativeAddonPath, 'addon');
601
612
  }
613
+ if (options.in) {
614
+ let relativeAddonPath = path.relative(project.root, options.in);
615
+ return path.join(relativeAddonPath, 'addon');
616
+ }
602
617
  if (options.inDummy) {
603
618
  return path.join('tests', 'dummy', 'app');
604
619
  }
@@ -800,6 +815,7 @@ let Blueprint = CoreObject.extend({
800
815
  hasPathToken: this.hasPathToken,
801
816
  inAddon,
802
817
  inRepoAddon: options.inRepoAddon,
818
+ in: options.in,
803
819
  inDummy,
804
820
  blueprintName: this.name,
805
821
  originBlueprintName,
@@ -1496,6 +1512,22 @@ function findAddonByName(addonOrProject, name) {
1496
1512
  return addonOrProject.addons.find(addon => findAddonByName(addon, name));
1497
1513
  }
1498
1514
 
1515
+ function ensureTargetDirIsAddon(addonPath) {
1516
+ let projectInfo;
1517
+
1518
+ try {
1519
+ projectInfo = require(path.join(addonPath, 'package.json'));
1520
+ } catch (err) {
1521
+ if (err.code === 'MODULE_NOT_FOUND') {
1522
+ throw new Error(`The directory ${addonPath} does not appear to be a valid addon directory.`);
1523
+ } else {
1524
+ throw err;
1525
+ }
1526
+ }
1527
+
1528
+ return isAddon(projectInfo.keywords);
1529
+ }
1530
+
1499
1531
  /**
1500
1532
  @private
1501
1533
  @method isValidFile