ember-cli 4.0.0 → 4.2.0-beta.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 (115) hide show
  1. package/.github/workflows/ci.yml +8 -4
  2. package/CHANGELOG.md +43 -2
  3. package/README.md +1 -1
  4. package/blueprints/addon/additional-dev-dependencies.json +1 -1
  5. package/blueprints/addon/files/CONTRIBUTING.md +1 -1
  6. package/blueprints/app/files/README.md +2 -2
  7. package/blueprints/app/files/package.json +8 -8
  8. package/docs/build/data.json +64 -3
  9. package/lib/debug/assert.js +37 -0
  10. package/lib/debug/deprecate.js +111 -0
  11. package/lib/debug/index.js +6 -0
  12. package/lib/models/host-info-cache.js +3 -5
  13. package/lib/models/per-bundle-addon-cache/index.js +2 -3
  14. package/lib/tasks/npm-task.js +1 -1
  15. package/lib/utilities/get-lang-arg.js +45 -45
  16. package/package.json +31 -31
  17. package/.github/ISSUE_TEMPLATE.md +0 -12
  18. package/.github/dependabot.yml +0 -15
  19. package/.github/workflows/coverage.yml +0 -31
  20. package/docs/analytics.md +0 -44
  21. package/docs/architecture.md +0 -316
  22. package/docs/assets/architecture/Ember-CLI architecture.png +0 -0
  23. package/docs/assets/architecture/Ember-CLI architecture.xml +0 -1
  24. package/docs/assets/architecture/README.md +0 -5
  25. package/docs/brocfile-transition.md +0 -46
  26. package/docs/build/api.js +0 -44
  27. package/docs/build/assets/css/external-small.png +0 -0
  28. package/docs/build/assets/css/logo.png +0 -0
  29. package/docs/build/assets/css/main.css +0 -555
  30. package/docs/build/assets/favicon.ico +0 -0
  31. package/docs/build/assets/img/spinner.gif +0 -0
  32. package/docs/build/assets/index.html +0 -10
  33. package/docs/build/assets/js/api-filter.js +0 -56
  34. package/docs/build/assets/js/api-list.js +0 -255
  35. package/docs/build/assets/js/api-search.js +0 -98
  36. package/docs/build/assets/js/apidocs.js +0 -376
  37. package/docs/build/assets/js/yui-prettify.js +0 -17
  38. package/docs/build/assets/vendor/prettify/CHANGES.html +0 -130
  39. package/docs/build/assets/vendor/prettify/COPYING +0 -202
  40. package/docs/build/assets/vendor/prettify/README.html +0 -203
  41. package/docs/build/assets/vendor/prettify/prettify-min.css +0 -1
  42. package/docs/build/assets/vendor/prettify/prettify-min.js +0 -1
  43. package/docs/build/classes/Addon.html +0 -4318
  44. package/docs/build/classes/AmdTransformAddon.html +0 -202
  45. package/docs/build/classes/Blueprint.html +0 -4796
  46. package/docs/build/classes/Builder.html +0 -611
  47. package/docs/build/classes/CLI.html +0 -810
  48. package/docs/build/classes/Command.html +0 -1655
  49. package/docs/build/classes/DefaultPackager.html +0 -202
  50. package/docs/build/classes/EmberAddon.html +0 -2207
  51. package/docs/build/classes/EmberApp.html +0 -2225
  52. package/docs/build/classes/HardwareInfo.html +0 -620
  53. package/docs/build/classes/HistorySupportAddon.html +0 -203
  54. package/docs/build/classes/Instrumentation.html +0 -695
  55. package/docs/build/classes/NodeModulesList.html +0 -460
  56. package/docs/build/classes/NpmTask.html +0 -333
  57. package/docs/build/classes/PackageInfo.html +0 -1390
  58. package/docs/build/classes/PackageInfoCache.html +0 -963
  59. package/docs/build/classes/PerBundleAddonCache {.html +0 -1010
  60. package/docs/build/classes/Project.html +0 -2083
  61. package/docs/build/classes/ServeFilesAddon.html +0 -260
  62. package/docs/build/classes/TestsServerAddon.html +0 -203
  63. package/docs/build/classes/WatcherAddon.html +0 -204
  64. package/docs/build/classes/WindowsSymlinkChecker.html +0 -1505
  65. package/docs/build/files/lib_broccoli_default-packager.js.html +0 -1426
  66. package/docs/build/files/lib_broccoli_ember-addon.js.html +0 -159
  67. package/docs/build/files/lib_broccoli_ember-app.js.html +0 -1913
  68. package/docs/build/files/lib_cli_cli.js.html +0 -417
  69. package/docs/build/files/lib_models_addon-info.js.html +0 -112
  70. package/docs/build/files/lib_models_addon.js.html +0 -1866
  71. package/docs/build/files/lib_models_blueprint.js.html +0 -1678
  72. package/docs/build/files/lib_models_builder.js.html +0 -417
  73. package/docs/build/files/lib_models_command.js.html +0 -804
  74. package/docs/build/files/lib_models_hardware-info.js.html +0 -479
  75. package/docs/build/files/lib_models_host-info-cache.js.html +0 -428
  76. package/docs/build/files/lib_models_installation-checker.js.html +0 -181
  77. package/docs/build/files/lib_models_instantiate-addons.js.html +0 -191
  78. package/docs/build/files/lib_models_instrumentation.js.html +0 -433
  79. package/docs/build/files/lib_models_package-info-cache_index.js.html +0 -793
  80. package/docs/build/files/lib_models_package-info-cache_node-modules-list.js.html +0 -208
  81. package/docs/build/files/lib_models_package-info-cache_package-info.js.html +0 -661
  82. package/docs/build/files/lib_models_per-bundle-addon-cache_addon-proxy.js.html +0 -252
  83. package/docs/build/files/lib_models_per-bundle-addon-cache_index.js.html +0 -485
  84. package/docs/build/files/lib_models_per-bundle-addon-cache_target-instance.js.html +0 -108
  85. package/docs/build/files/lib_models_project.js.html +0 -913
  86. package/docs/build/files/lib_models_task.js.html +0 -117
  87. package/docs/build/files/lib_tasks_build-watch.js.html +0 -157
  88. package/docs/build/files/lib_tasks_npm-task.js.html +0 -463
  89. package/docs/build/files/lib_tasks_serve.js.html +0 -207
  90. package/docs/build/files/lib_tasks_server_middleware_broccoli-serve-files_index.js.html +0 -127
  91. package/docs/build/files/lib_tasks_server_middleware_broccoli-watcher_index.js.html +0 -158
  92. package/docs/build/files/lib_tasks_server_middleware_history-support_index.js.html +0 -181
  93. package/docs/build/files/lib_tasks_server_middleware_tests-server_index.js.html +0 -171
  94. package/docs/build/files/lib_tasks_test-server.js.html +0 -167
  95. package/docs/build/files/lib_tasks_transforms_amd_index.js.html +0 -143
  96. package/docs/build/files/lib_utilities_ember-app-utils.js.html +0 -292
  97. package/docs/build/files/lib_utilities_insert-into-file.js.html +0 -219
  98. package/docs/build/files/lib_utilities_is-lazy-engine.js.html +0 -125
  99. package/docs/build/files/lib_utilities_is-yarn-project.js.html +0 -120
  100. package/docs/build/files/lib_utilities_valid-project-name.js.html +0 -142
  101. package/docs/build/files/lib_utilities_will-interrupt-process.js.html +0 -290
  102. package/docs/build/files/lib_utilities_windows-admin.js.html +0 -230
  103. package/docs/build/index.html +0 -125
  104. package/docs/build/modules/ember-cli.html +0 -152
  105. package/docs/build/modules/is-lazy-engine.html +0 -106
  106. package/docs/build-concurrency.md +0 -15
  107. package/docs/build-pipeline-debugging.md +0 -33
  108. package/docs/code-coverage.md +0 -14
  109. package/docs/error-propagation.md +0 -136
  110. package/docs/experiments.md +0 -53
  111. package/docs/node-support.md +0 -43
  112. package/docs/perf-guide.md +0 -250
  113. package/docs/project_version_preprocessor.js +0 -8
  114. package/docs/sourcemaps.md +0 -60
  115. package/docs/yuidoc.json +0 -13
@@ -1,804 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="utf-8">
5
- <title>lib/models/command.js - ember-cli</title>
6
- <link rel="stylesheet" href="../assets/vendor/prettify/prettify-min.css">
7
- <link rel="stylesheet" href="../assets/css/main.css" id="site_styles">
8
- <script src="https://cdnjs.cloudflare.com/ajax/libs/yui/3.18.0/yui/yui-min.js"></script>
9
- </head>
10
- <body class="yui3-skin-sam">
11
-
12
- <div id="doc">
13
- <div class="yui3-g">
14
- <div id="sidebar" class="yui3-u">
15
- <div class="logo">
16
- <a href="../index.html">
17
- <img src="https://ember-cli.com/assets/images/ember-cli-logo-small-dark.png">
18
- </a>
19
- </div>
20
-
21
- <div id="modules" class="sidebox">
22
- <div class="hd">
23
- <h2 class="no-toc">Modules</h2>
24
- </div>
25
- <div class="bd">
26
- <ul>
27
- <li><a href="../modules/ember-cli.html">ember-cli</a>
28
- </li>
29
- <li><a href="../modules/is-lazy-engine.html">is-lazy-engine</a>
30
- </li>
31
- </ul>
32
- </div>
33
- </div>
34
-
35
- <div id="classes" class="sidebox">
36
- <div class="hd">
37
- <h2 class="no-toc">Classes</h2>
38
- </div>
39
- <div class="bd">
40
- <ul>
41
- <li><a href="../classes/Addon.html">Addon</a></li>
42
- <li><a href="../classes/AmdTransformAddon.html">AmdTransformAddon</a></li>
43
- <li><a href="../classes/Blueprint.html">Blueprint</a></li>
44
- <li><a href="../classes/Builder.html">Builder</a></li>
45
- <li><a href="../classes/CLI.html">CLI</a></li>
46
- <li><a href="../classes/Command.html">Command</a></li>
47
- <li><a href="../classes/DefaultPackager.html">DefaultPackager</a></li>
48
- <li><a href="../classes/EmberAddon.html">EmberAddon</a></li>
49
- <li><a href="../classes/EmberApp.html">EmberApp</a></li>
50
- <li><a href="../classes/HardwareInfo.html">HardwareInfo</a></li>
51
- <li><a href="../classes/HistorySupportAddon.html">HistorySupportAddon</a></li>
52
- <li><a href="../classes/Instrumentation.html">Instrumentation</a></li>
53
- <li><a href="../classes/NodeModulesList.html">NodeModulesList</a></li>
54
- <li><a href="../classes/NpmTask.html">NpmTask</a></li>
55
- <li><a href="../classes/PackageInfo.html">PackageInfo</a></li>
56
- <li><a href="../classes/PackageInfoCache.html">PackageInfoCache</a></li>
57
- <li><a href="../classes/PerBundleAddonCache {.html">PerBundleAddonCache {</a></li>
58
- <li><a href="../classes/Project.html">Project</a></li>
59
- <li><a href="../classes/ServeFilesAddon.html">ServeFilesAddon</a></li>
60
- <li><a href="../classes/TestsServerAddon.html">TestsServerAddon</a></li>
61
- <li><a href="../classes/WatcherAddon.html">WatcherAddon</a></li>
62
- <li><a href="../classes/WindowsSymlinkChecker.html">WindowsSymlinkChecker</a></li>
63
- </ul>
64
- </div>
65
- </div>
66
-
67
-
68
-
69
-
70
-
71
- <div class="version-info">
72
- Version: 4.0.0-release-b4cbb1029f
73
- </div>
74
-
75
- </div>
76
-
77
- <div id="main" class="yui3-u">
78
- <div class="content"><div class="title">
79
- <h1 class="file-name">lib/models/command.js</h1>
80
- </div>
81
-
82
- <pre class="code prettyprint linenums">
83
- &#x27;use strict&#x27;;
84
-
85
- const nopt = require(&#x27;nopt&#x27;);
86
- const chalk = require(&#x27;chalk&#x27;);
87
- const path = require(&#x27;path&#x27;);
88
- const isGitRepo = require(&#x27;is-git-url&#x27;);
89
- const camelize = require(&#x27;ember-cli-string-utils&#x27;).camelize;
90
- const getCallerFile = require(&#x27;get-caller-file&#x27;);
91
- const printCommand = require(&#x27;../utilities/print-command&#x27;);
92
- const _ = require(&#x27;ember-cli-lodash-subset&#x27;);
93
- const EOL = require(&#x27;os&#x27;).EOL;
94
- const CoreObject = require(&#x27;core-object&#x27;);
95
- const logger = require(&#x27;heimdalljs-logger&#x27;)(&#x27;ember-cli:command&#x27;);
96
- const WatchDetector = require(&#x27;watch-detector&#x27;);
97
- const SilentError = require(&#x27;silent-error&#x27;);
98
- const execSync = require(&#x27;child_process&#x27;).execSync;
99
- const fs = require(&#x27;fs&#x27;);
100
- const isYarnProject = require(&#x27;../utilities/is-yarn-project&#x27;);
101
-
102
- let cache = {};
103
-
104
- let allowedWorkOptions = {
105
- insideProject: true,
106
- outsideProject: true,
107
- everywhere: true,
108
- };
109
-
110
- path.name = &#x27;Path&#x27;;
111
- // extend nopt to recognize &#x27;gitUrl&#x27; as a type
112
- nopt.typeDefs.gitUrl = {
113
- type: &#x27;gitUrl&#x27;,
114
- validate(data, k, val) {
115
- if (isGitRepo(val)) {
116
- data[k] = val;
117
- return true;
118
- } else {
119
- return false;
120
- }
121
- },
122
- };
123
-
124
- /**
125
- * The base class for all CLI commands.
126
- *
127
- * @module ember-cli
128
- * @class Command
129
- * @constructor
130
- * @extends CoreObject
131
- */
132
- let Command = CoreObject.extend({
133
- /**
134
- * The description of what this command does.
135
- *
136
- * @final
137
- * @property description
138
- * @type String
139
- */
140
- description: null,
141
-
142
- /**
143
- * Does this command work everywhere or just inside or outside of projects.
144
- *
145
- * Possible values:
146
- *
147
- * - &#x60;insideProject&#x60;
148
- * - &#x60;outsideProject&#x60;
149
- * - &#x60;everywhere&#x60;
150
- *
151
- * @final
152
- * @property works
153
- * @type String
154
- * @default &#x60;insideProject&#x60;
155
- */
156
- works: &#x27;insideProject&#x27;,
157
-
158
- _printableProperties: [&#x27;name&#x27;, &#x27;description&#x27;, &#x27;aliases&#x27;, &#x27;works&#x27;, &#x27;availableOptions&#x27;, &#x27;anonymousOptions&#x27;],
159
-
160
- init() {
161
- this._super.apply(this, arguments);
162
-
163
- /**
164
- * @final
165
- * @property isWithinProject
166
- * @type Boolean
167
- */
168
- this.isWithinProject = this.project.isEmberCLIProject();
169
-
170
- /**
171
- * The name of the command.
172
- *
173
- * @final
174
- * @property name
175
- * @type String
176
- * @example &#x60;new&#x60; or &#x60;generate&#x60;
177
- */
178
- this.name = this.name || path.basename(getCallerFile(), &#x27;.js&#x27;);
179
-
180
- logger.info(&#x27;initialize: name: %s, name: %s&#x27;, this.name);
181
-
182
- /**
183
- * An array of aliases for the command
184
- *
185
- * @final
186
- * @property aliases
187
- * @type Array
188
- * @example &#x60;[&#x27;g&#x27;]&#x60; for the &#x60;generate&#x60; command
189
- */
190
- this.aliases = this.aliases || [];
191
-
192
- // Works Property
193
- if (!allowedWorkOptions[this.works]) {
194
- throw new Error(
195
- &#x60;The &quot;${this.name}&quot; command&#x27;s works field has to be either &quot;everywhere&quot;, &quot;insideProject&quot; or &quot;outsideProject&quot;.&#x60;
196
- );
197
- }
198
-
199
- /**
200
- * An array of available options for the command
201
- *
202
- * @final
203
- * @property availableOptions
204
- * @type Array
205
- * @example
206
- * &#x60;&#x60;&#x60;js
207
- * availableOptions: [
208
- * { name: &#x27;dry-run&#x27;, type: Boolean, default: false, aliases: [&#x27;d&#x27;] },
209
- * { name: &#x27;verbose&#x27;, type: Boolean, default: false, aliases: [&#x27;v&#x27;] },
210
- * { name: &#x27;blueprint&#x27;, type: String, default: &#x27;app&#x27;, aliases: [&#x27;b&#x27;] },
211
- * { name: &#x27;skip-npm&#x27;, type: Boolean, default: false, aliases: [&#x27;sn&#x27;] },
212
- * { name: &#x27;skip-bower&#x27;, type: Boolean, default: false, aliases: [&#x27;sb&#x27;] },
213
- * { name: &#x27;skip-git&#x27;, type: Boolean, default: false, aliases: [&#x27;sg&#x27;] },
214
- * { name: &#x27;directory&#x27;, type: String , aliases: [&#x27;dir&#x27;] }
215
- * ],
216
- * &#x60;&#x60;&#x60;
217
- */
218
- this.availableOptions = this.availableOptions || [];
219
-
220
- /**
221
- * An array of anonymous options for the command
222
- *
223
- * @final
224
- * @property anonymousOptions
225
- * @type Array
226
- * @example
227
- * &#x60;&#x60;&#x60;js
228
- * anonymousOptions: [
229
- * &#x27;&lt;blueprint&gt;&#x27;
230
- * ],
231
- * &#x60;&#x60;&#x60;
232
- */
233
- this.anonymousOptions = this.anonymousOptions || [];
234
- },
235
-
236
- /**
237
- Registers options with command. This method provides the ability to extend or override command options.
238
- Expects an object containing anonymousOptions or availableOptions, which it will then merge with
239
- existing availableOptions before building the optionsAliases which are used to define shorthands.
240
-
241
- @method registerOptions
242
- @param {Object} options
243
- */
244
- registerOptions(options) {
245
- let extendedAvailableOptions = (options &amp;&amp; options.availableOptions) || [];
246
- let extendedAnonymousOptions = (options &amp;&amp; options.anonymousOptions) || [];
247
-
248
- this.anonymousOptions = _.union(this.anonymousOptions.slice(0), extendedAnonymousOptions);
249
-
250
- // merge any availableOptions
251
- this.availableOptions = _.union(this.availableOptions.slice(0), extendedAvailableOptions);
252
-
253
- let optionKeys = _.uniq(_.map(this.availableOptions, &#x27;name&#x27;));
254
-
255
- optionKeys.map(this.mergeDuplicateOption.bind(this));
256
-
257
- this.optionsAliases = this.optionsAliases || {};
258
-
259
- this.availableOptions.map(this.validateOption.bind(this));
260
- },
261
-
262
- /**
263
- * Called when command is interrupted from outside, e.g. ctrl+C or process kill
264
- * Can be used to cleanup artifacts produced by command and control process exit code
265
- *
266
- * @method onInterrupt
267
- * @return {Promise|undefined} if rejected promise then result of promise will be used as an exit code
268
- */
269
- onInterrupt() {
270
- if (this._currentTask) {
271
- return this._currentTask.onInterrupt();
272
- } else {
273
- // interrupt all external commands which don&#x27;t use &#x60;runTask()&#x60; with an error
274
-
275
- // eslint-disable-next-line no-process-exit
276
- process.exit(1);
277
- }
278
- },
279
-
280
- _env(/* name */) {
281
- return {
282
- ui: this.ui,
283
- analytics: this.analytics,
284
- project: this.project,
285
- testing: this.testing,
286
- settings: this.settings,
287
- };
288
- },
289
-
290
- /**
291
- * Looks up for the task and runs
292
- * It also keeps the reference for the current active task
293
- * Keeping reference for the current task allows to cleanup task on interruption
294
- *
295
- * @private
296
- * @method runTask
297
- * @throws {Error} when no task found
298
- * @throws {Error} on attempt to run concurrent task
299
- * @param {string} name Task name from the tasks registry. Should be capitalized
300
- * @param {object} options
301
- * @return {Promise} Task run
302
- */
303
- runTask(name, options) {
304
- if (this._currentTask) {
305
- throw new Error(&#x60;Concurrent tasks are not supported&#x60;);
306
- }
307
-
308
- logger.info(&#x60;\&#x60;${this.name}\&#x60; command running \&#x60;${name}\&#x60; task&#x60;);
309
-
310
- let Task = this.tasks[name];
311
- if (!Task) {
312
- throw new Error(&#x60;Unknown task &quot;${name}&quot;&#x60;);
313
- }
314
-
315
- let task = new Task(this._env(name));
316
-
317
- this._currentTask = task;
318
-
319
- return Promise.resolve()
320
- .then(() =&gt; task.run(options))
321
- .catch((error) =&gt; {
322
- logger.info(&#x60;An error occurred running \&#x60;${name}\&#x60; from the \&#x60;${this.name}\&#x60; command.&#x60;, error.stack);
323
-
324
- throw error;
325
- })
326
- .finally(() =&gt; {
327
- delete this._currentTask;
328
- });
329
- },
330
-
331
- /**
332
- Hook for extending a command before it is run in the cli.run command.
333
- Most common use case would be to extend availableOptions.
334
- @method beforeRun
335
- @return {Promise|null}
336
- */
337
- beforeRun() {},
338
-
339
- /**
340
- @method validateAndRun
341
- @return {Promise}
342
- */
343
- validateAndRun(args) {
344
- return new Promise((resolve, reject) =&gt; {
345
- let commandOptions = this.parseArgs(args);
346
- // if the help option was passed, resolve with &#x27;callHelp&#x27; to call help command
347
- if (commandOptions &amp;&amp; (commandOptions.options.help || commandOptions.options.h)) {
348
- logger.info(&#x60;${this.name} called with help option&#x60;);
349
- return resolve(&#x27;callHelp&#x27;);
350
- }
351
-
352
- this.analytics.track({
353
- name: &#x27;ember &#x27;,
354
- message: this.name,
355
- });
356
-
357
- if (commandOptions === null) {
358
- return reject();
359
- }
360
-
361
- if (this.works === &#x27;outsideProject&#x27; &amp;&amp; this.isWithinProject) {
362
- throw new SilentError(&#x60;You cannot use the ${chalk.green(this.name)} command inside an ember-cli project.&#x60;);
363
- }
364
-
365
- if (this.works === &#x27;insideProject&#x27;) {
366
- if (!this.project.hasDependencies()) {
367
- if (!this.isWithinProject &amp;&amp; !this.project.isEmberCLIAddon()) {
368
- throw new SilentError(
369
- &#x60;You have to be inside an ember-cli project to use the ${chalk.green(this.name)} command.&#x60;
370
- );
371
- }
372
-
373
- let installInstuction = &#x27;&#x60;npm install&#x60;&#x27;;
374
- if (isYarnProject(this.project.root)) {
375
- installInstuction = &#x27;&#x60;yarn install&#x60;&#x27;;
376
- }
377
- throw new SilentError(
378
- &#x60;Required packages are missing, run ${installInstuction} from this directory to install them.&#x60;
379
- );
380
- }
381
- }
382
-
383
- let detector = new WatchDetector({
384
- ui: this.ui,
385
- childProcess: { execSync },
386
- fs,
387
- watchmanSupportsPlatform: /^win/.test(process.platform),
388
- cache,
389
- root: this.project.root,
390
- });
391
-
392
- let options = commandOptions.options;
393
-
394
- if (this.hasOption(&#x27;watcher&#x27;)) {
395
- // do stuff to try and provide a good experience when it comes to file watching
396
- let watchPreference = detector.findBestWatcherOption(options);
397
- this.project._watchmanInfo = watchPreference.watchmanInfo;
398
- options.watcher = watchPreference.watcher;
399
- }
400
- resolve(this.run(options, commandOptions.args));
401
- });
402
- },
403
-
404
- /**
405
- Reports if the given command has a command line option by a given name
406
-
407
- @method hasOption
408
- @param {String} name
409
- @return {Boolean}
410
- */
411
- hasOption(name) {
412
- for (let i = 0; i &lt; this.availableOptions.length; i++) {
413
- if (this.availableOptions[i].name === name) {
414
- return true;
415
- }
416
- }
417
- return false;
418
- },
419
-
420
- /**
421
- Merges any options with duplicate keys in the availableOptions array.
422
- Used primarily by registerOptions.
423
- @method mergeDuplicateOption
424
- @param {String} key
425
- @return {Object}
426
- */
427
- mergeDuplicateOption(key) {
428
- let duplicateOptions, mergedOption, mergedAliases;
429
- // get duplicates to merge
430
- duplicateOptions = _.filter(this.availableOptions, { name: key });
431
-
432
- if (duplicateOptions.length &gt; 1) {
433
- // TODO: warn on duplicates and overwriting
434
- mergedAliases = [];
435
-
436
- _.map(duplicateOptions, &#x27;aliases&#x27;).map((alias) =&gt; {
437
- alias.map((a) =&gt; {
438
- mergedAliases.push(a);
439
- });
440
- });
441
-
442
- // merge duplicate options
443
- mergedOption = Object.assign.apply(null, duplicateOptions);
444
-
445
- // replace aliases with unique aliases
446
- mergedOption.aliases = _.uniqBy(mergedAliases, (alias) =&gt; {
447
- if (typeof alias === &#x27;object&#x27;) {
448
- return alias[Object.keys(alias)[0]];
449
- }
450
- return alias;
451
- });
452
-
453
- // remove duplicates from options
454
- this.availableOptions = _.reject(this.availableOptions, { name: key });
455
- this.availableOptions.push(mergedOption);
456
- }
457
- return this.availableOptions;
458
- },
459
-
460
- /**
461
- Normalizes option, filling in implicit values
462
- @method normalizeOption
463
- @param {Object} option
464
- @return {Object}
465
- */
466
- normalizeOption(option) {
467
- option.key = camelize(option.name);
468
- option.required = option.required || false;
469
- return option;
470
- },
471
-
472
- /**
473
- Assigns option
474
- @method assignOption
475
- @param {Object} option
476
- @param {Object} parsedOptions
477
- @param {Object} commandOptions
478
- @return {Boolean}
479
- */
480
- assignOption(option, parsedOptions, commandOptions) {
481
- let isValid = isValidParsedOption(option, parsedOptions[option.name]);
482
- if (isValid) {
483
- if (parsedOptions[option.name] === undefined) {
484
- if (option.default !== undefined) {
485
- commandOptions[option.key] = option.default;
486
- }
487
-
488
- if (this.settings[option.name] !== undefined) {
489
- commandOptions[option.key] = this.settings[option.name];
490
- } else if (this.settings[option.key] !== undefined) {
491
- commandOptions[option.key] = this.settings[option.key];
492
- }
493
- } else {
494
- commandOptions[option.key] = parsedOptions[option.name];
495
- delete parsedOptions[option.name];
496
- }
497
- } else {
498
- this.ui.writeLine(
499
- &#x60;The specified command ${chalk.green(this.name)} requires the option ${chalk.green(option.name)}.&#x60;
500
- );
501
- }
502
- return isValid;
503
- },
504
-
505
- /**
506
- Validates option
507
- @method validateOption
508
- @param {Object} option
509
- @return {Boolean}
510
- */
511
- validateOption(option) {
512
- let parsedAliases;
513
-
514
- if (!option.name || !option.type) {
515
- throw new Error(&#x60;The command &quot;${this.name}&quot; has an option without the required type and name fields.&#x60;);
516
- }
517
-
518
- if (option.name !== option.name.toLowerCase()) {
519
- throw new Error(&#x60;The &quot;${option.name}&quot; option&#x27;s name of the &quot;${this.name}&quot; command contains a capital letter.&#x60;);
520
- }
521
-
522
- this.normalizeOption(option);
523
-
524
- if (option.aliases) {
525
- parsedAliases = option.aliases.map(this.parseAlias.bind(this, option));
526
- return parsedAliases.map(this.assignAlias.bind(this, option)).indexOf(false) === -1;
527
- }
528
- return false;
529
- },
530
-
531
- /**
532
- Parses alias for an option and adds it to optionsAliases
533
- @method parseAlias
534
- @param {Object} option
535
- @param {Object|String} alias
536
- @return {Object}
537
- */
538
- parseAlias(option, alias) {
539
- let aliasType = typeof alias;
540
- let key, value, aliasValue;
541
-
542
- if (isValidAlias(alias, option.type)) {
543
- if (aliasType === &#x27;string&#x27;) {
544
- key = alias;
545
- value = [&#x60;--${option.name}&#x60;];
546
- } else if (aliasType === &#x27;object&#x27;) {
547
- key = Object.keys(alias)[0];
548
- value = [&#x60;--${option.name}&#x60;, alias[key]];
549
- }
550
- } else {
551
- if (Array.isArray(alias)) {
552
- aliasType = &#x27;array&#x27;;
553
- aliasValue = alias.join(&#x27;,&#x27;);
554
- } else {
555
- aliasValue = alias;
556
- try {
557
- aliasValue = JSON.parse(alias);
558
- } catch (e) {
559
- const logger = require(&#x27;heimdalljs-logger&#x27;)(&#x27;ember-cli/models/command&#x27;);
560
- logger.error(e);
561
- }
562
- }
563
- throw new Error(
564
- &#x60;The &quot;${aliasValue}&quot; [type:${aliasType}] alias is not an acceptable value. &#x60; +
565
- &#x60;It must be a string or single key object with a string value (for example, &quot;value&quot; or { &quot;key&quot; : &quot;value&quot; }).&#x60;
566
- );
567
- }
568
-
569
- return {
570
- key,
571
- value,
572
- original: alias,
573
- };
574
- },
575
-
576
- /**
577
- * @method assignAlias
578
- * @param option
579
- * @param alias
580
- * @return {Boolean}
581
- */
582
- assignAlias(option, alias) {
583
- let isValid = this.validateAlias(option, alias);
584
-
585
- if (isValid) {
586
- this.optionsAliases[alias.key] = alias.value;
587
- }
588
- return isValid;
589
- },
590
-
591
- /**
592
- Validates alias value
593
- @method validateAlias
594
- @param {Object} alias
595
- @return {Boolean}
596
- */
597
- validateAlias(option, alias) {
598
- let key = alias.key;
599
- let value = alias.value;
600
-
601
- if (!this.optionsAliases[key]) {
602
- return true;
603
- } else {
604
- if (value[0] !== this.optionsAliases[key][0]) {
605
- throw new SilentError(
606
- &#x60;The &quot;${key}&quot; alias is already in use by the &quot;${this.optionsAliases[key][0]}&quot; option &#x60; +
607
- &#x60;and cannot be used by the &quot;${value[0]}&quot; option. Please use a different alias.&#x60;
608
- );
609
- } else if (value[1] !== this.optionsAliases[key][1]) {
610
- this.ui.writeLine(chalk.yellow(&#x60;The &quot;${key}&quot; alias cannot be overridden. Please use a different alias.&#x60;));
611
- // delete offending alias from options
612
- let index = this.availableOptions.indexOf(option);
613
- let aliasIndex = this.availableOptions[index].aliases.indexOf(alias.original);
614
- if (this.availableOptions[index].aliases[aliasIndex]) {
615
- // first one wins
616
- this.availableOptions[index].aliases = [this.availableOptions[index].aliases[0]];
617
- }
618
- }
619
- return false;
620
- }
621
- },
622
-
623
- /**
624
- Parses command arguments and processes
625
- @method parseArgs
626
- @param {Object} commandArgs
627
- @return {Object|null}
628
- */
629
- parseArgs(commandArgs) {
630
- let knownOpts = {}; // Parse options
631
- let commandOptions = {};
632
- let parsedOptions;
633
-
634
- this.registerOptions();
635
-
636
- let assembleAndValidateOption = function (option) {
637
- return this.assignOption(option, parsedOptions, commandOptions);
638
- };
639
-
640
- let validateParsed = function (key) {
641
- // ignore &#x27;argv&#x27;, &#x27;h&#x27;, and &#x27;help&#x27;
642
- if (!(key in commandOptions) &amp;&amp; key !== &#x27;argv&#x27; &amp;&amp; key !== &#x27;h&#x27; &amp;&amp; key !== &#x27;help&#x27;) {
643
- this.ui.writeLine(
644
- chalk.yellow(
645
- &#x60;The option &#x27;--${key}&#x27; is not registered with the &#x27;${this.name}&#x27; command. &#x60; +
646
- &#x60;Run \&#x60;ember ${this.name} --help\&#x60; for a list of supported options.&#x60;
647
- )
648
- );
649
- }
650
- if (typeof parsedOptions[key] !== &#x27;object&#x27;) {
651
- commandOptions[camelize(key)] = parsedOptions[key];
652
- }
653
- };
654
-
655
- this.availableOptions.forEach((option) =&gt; {
656
- if (typeof option.type !== &#x27;string&#x27;) {
657
- knownOpts[option.name] = option.type;
658
- } else if (option.type === &#x27;Path&#x27;) {
659
- knownOpts[option.name] = path;
660
- } else {
661
- knownOpts[option.name] = String;
662
- }
663
- });
664
-
665
- parsedOptions = nopt(knownOpts, this.optionsAliases, commandArgs, 0);
666
-
667
- if (!this.availableOptions.every(assembleAndValidateOption.bind(this))) {
668
- return null;
669
- }
670
-
671
- Object.keys(parsedOptions).map(validateParsed.bind(this));
672
-
673
- return {
674
- options: _.defaults(commandOptions, this.settings),
675
- args: parsedOptions.argv.remain,
676
- };
677
- },
678
-
679
- /**
680
- * @method run
681
- * @param commandArgs
682
- */
683
- run(commandArgs) {
684
- throw new Error(&#x60;command must implement run${commandArgs.toString()}&#x60;);
685
- },
686
-
687
- _printCommand: printCommand,
688
-
689
- /**
690
- Prints basic help for the command.
691
-
692
- Basic help looks like this:
693
-
694
- ember generate &lt;blueprint&gt; &lt;options...&gt;
695
- Generates new code from blueprints
696
- aliases: g
697
- --dry-run (Default: false)
698
- --verbose (Default: false)
699
-
700
- The default implementation is designed to cover all bases
701
- but may be overridden if necessary.
702
-
703
- @method printBasicHelp
704
- */
705
- printBasicHelp() {
706
- // ember command-name
707
- let output;
708
- if (this.isRoot) {
709
- output = &#x60;Usage: ${this.name}&#x60;;
710
- } else {
711
- output = &#x60;ember ${this.name}&#x60;;
712
- }
713
-
714
- output += this._printCommand();
715
- output += EOL;
716
-
717
- return output;
718
- },
719
-
720
- /**
721
- Prints detailed help for the command.
722
-
723
- The default implementation is no-op and should be overridden
724
- for each command where further help text is required.
725
-
726
- @method printDetailedHelp
727
- */
728
- printDetailedHelp() {},
729
-
730
- /**
731
- * @method getJson
732
- * @param {Object} options
733
- * @return {Object}
734
- */
735
- getJson(options) {
736
- let json = {};
737
-
738
- this.registerOptions(options);
739
- this._printableProperties.forEach((key) =&gt; (json[key] = this[key]));
740
-
741
- if (this.addAdditionalJsonForHelp) {
742
- this.addAdditionalJsonForHelp(json, options);
743
- }
744
-
745
- return json;
746
- },
747
- });
748
-
749
- /*
750
- Validates options parsed by nopt
751
- */
752
- function isValidParsedOption(option, parsedOption) {
753
- // option.name didn&#x27;t parse
754
- if (parsedOption === undefined) {
755
- // no default
756
- if (option.default === undefined) {
757
- if (option.required) {
758
- return false;
759
- }
760
- }
761
- }
762
-
763
- return true;
764
- }
765
-
766
- /*
767
- Validates alias. Must be a string or single key object
768
- */
769
- function isValidAlias(alias, expectedType) {
770
- let type = typeof alias;
771
- let value, valueType;
772
- if (type === &#x27;string&#x27;) {
773
- return true;
774
- } else if (type === &#x27;object&#x27;) {
775
- // no arrays, no multi-key objects
776
- if (!Array.isArray(alias) &amp;&amp; Object.keys(alias).length === 1) {
777
- value = alias[Object.keys(alias)[0]];
778
- valueType = typeof value;
779
- if (!Array.isArray(expectedType)) {
780
- if (valueType === expectedType.name.toLowerCase()) {
781
- return true;
782
- }
783
- } else if (expectedType.indexOf(value) &gt; -1) {
784
- return true;
785
- }
786
- }
787
- }
788
-
789
- return false;
790
- }
791
-
792
- module.exports = Command;
793
-
794
- </pre>
795
-
796
- </div>
797
- </div>
798
- </div>
799
- </div>
800
- <script src="../assets/vendor/prettify/prettify-min.js"></script>
801
- <script>prettyPrint();</script>
802
- <script src="../assets/js/yui-prettify.js"></script>
803
- </body>
804
- </html>