ember-cli 4.0.0-beta.2 → 4.1.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 (114) hide show
  1. package/.github/workflows/ci.yml +5 -5
  2. package/CHANGELOG.md +48 -3
  3. package/blueprints/addon/additional-dev-dependencies.json +2 -2
  4. package/blueprints/addon/files/.github/workflows/ci.yml +5 -1
  5. package/blueprints/addon/files/.travis.yml +1 -1
  6. package/blueprints/addon/files/README.md +2 -2
  7. package/blueprints/addon/files/addon-config/ember-try.js +4 -4
  8. package/blueprints/app/files/.github/workflows/ci.yml +4 -0
  9. package/blueprints/app/files/package.json +17 -17
  10. package/docs/build/data.json +3 -3
  11. package/lib/commands/init.js +9 -1
  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/utilities/get-lang-arg.js +45 -45
  15. package/package.json +25 -25
  16. package/.github/ISSUE_TEMPLATE.md +0 -12
  17. package/.github/dependabot.yml +0 -15
  18. package/.github/workflows/coverage.yml +0 -31
  19. package/docs/analytics.md +0 -44
  20. package/docs/architecture.md +0 -316
  21. package/docs/assets/architecture/Ember-CLI architecture.png +0 -0
  22. package/docs/assets/architecture/Ember-CLI architecture.xml +0 -1
  23. package/docs/assets/architecture/README.md +0 -5
  24. package/docs/brocfile-transition.md +0 -46
  25. package/docs/build/api.js +0 -44
  26. package/docs/build/assets/css/external-small.png +0 -0
  27. package/docs/build/assets/css/logo.png +0 -0
  28. package/docs/build/assets/css/main.css +0 -555
  29. package/docs/build/assets/favicon.ico +0 -0
  30. package/docs/build/assets/img/spinner.gif +0 -0
  31. package/docs/build/assets/index.html +0 -10
  32. package/docs/build/assets/js/api-filter.js +0 -56
  33. package/docs/build/assets/js/api-list.js +0 -255
  34. package/docs/build/assets/js/api-search.js +0 -98
  35. package/docs/build/assets/js/apidocs.js +0 -376
  36. package/docs/build/assets/js/yui-prettify.js +0 -17
  37. package/docs/build/assets/vendor/prettify/CHANGES.html +0 -130
  38. package/docs/build/assets/vendor/prettify/COPYING +0 -202
  39. package/docs/build/assets/vendor/prettify/README.html +0 -203
  40. package/docs/build/assets/vendor/prettify/prettify-min.css +0 -1
  41. package/docs/build/assets/vendor/prettify/prettify-min.js +0 -1
  42. package/docs/build/classes/Addon.html +0 -4318
  43. package/docs/build/classes/AmdTransformAddon.html +0 -202
  44. package/docs/build/classes/Blueprint.html +0 -4796
  45. package/docs/build/classes/Builder.html +0 -611
  46. package/docs/build/classes/CLI.html +0 -810
  47. package/docs/build/classes/Command.html +0 -1655
  48. package/docs/build/classes/DefaultPackager.html +0 -202
  49. package/docs/build/classes/EmberAddon.html +0 -2207
  50. package/docs/build/classes/EmberApp.html +0 -2225
  51. package/docs/build/classes/HardwareInfo.html +0 -620
  52. package/docs/build/classes/HistorySupportAddon.html +0 -203
  53. package/docs/build/classes/Instrumentation.html +0 -695
  54. package/docs/build/classes/NodeModulesList.html +0 -460
  55. package/docs/build/classes/NpmTask.html +0 -333
  56. package/docs/build/classes/PackageInfo.html +0 -1390
  57. package/docs/build/classes/PackageInfoCache.html +0 -963
  58. package/docs/build/classes/PerBundleAddonCache {.html +0 -1010
  59. package/docs/build/classes/Project.html +0 -2083
  60. package/docs/build/classes/ServeFilesAddon.html +0 -260
  61. package/docs/build/classes/TestsServerAddon.html +0 -203
  62. package/docs/build/classes/WatcherAddon.html +0 -204
  63. package/docs/build/classes/WindowsSymlinkChecker.html +0 -1505
  64. package/docs/build/files/lib_broccoli_default-packager.js.html +0 -1426
  65. package/docs/build/files/lib_broccoli_ember-addon.js.html +0 -159
  66. package/docs/build/files/lib_broccoli_ember-app.js.html +0 -1913
  67. package/docs/build/files/lib_cli_cli.js.html +0 -417
  68. package/docs/build/files/lib_models_addon-info.js.html +0 -112
  69. package/docs/build/files/lib_models_addon.js.html +0 -1866
  70. package/docs/build/files/lib_models_blueprint.js.html +0 -1678
  71. package/docs/build/files/lib_models_builder.js.html +0 -417
  72. package/docs/build/files/lib_models_command.js.html +0 -804
  73. package/docs/build/files/lib_models_hardware-info.js.html +0 -479
  74. package/docs/build/files/lib_models_host-info-cache.js.html +0 -428
  75. package/docs/build/files/lib_models_installation-checker.js.html +0 -181
  76. package/docs/build/files/lib_models_instantiate-addons.js.html +0 -191
  77. package/docs/build/files/lib_models_instrumentation.js.html +0 -433
  78. package/docs/build/files/lib_models_package-info-cache_index.js.html +0 -793
  79. package/docs/build/files/lib_models_package-info-cache_node-modules-list.js.html +0 -208
  80. package/docs/build/files/lib_models_package-info-cache_package-info.js.html +0 -661
  81. package/docs/build/files/lib_models_per-bundle-addon-cache_addon-proxy.js.html +0 -252
  82. package/docs/build/files/lib_models_per-bundle-addon-cache_index.js.html +0 -485
  83. package/docs/build/files/lib_models_per-bundle-addon-cache_target-instance.js.html +0 -108
  84. package/docs/build/files/lib_models_project.js.html +0 -913
  85. package/docs/build/files/lib_models_task.js.html +0 -117
  86. package/docs/build/files/lib_tasks_build-watch.js.html +0 -157
  87. package/docs/build/files/lib_tasks_npm-task.js.html +0 -463
  88. package/docs/build/files/lib_tasks_serve.js.html +0 -207
  89. package/docs/build/files/lib_tasks_server_middleware_broccoli-serve-files_index.js.html +0 -127
  90. package/docs/build/files/lib_tasks_server_middleware_broccoli-watcher_index.js.html +0 -158
  91. package/docs/build/files/lib_tasks_server_middleware_history-support_index.js.html +0 -181
  92. package/docs/build/files/lib_tasks_server_middleware_tests-server_index.js.html +0 -171
  93. package/docs/build/files/lib_tasks_test-server.js.html +0 -167
  94. package/docs/build/files/lib_tasks_transforms_amd_index.js.html +0 -143
  95. package/docs/build/files/lib_utilities_ember-app-utils.js.html +0 -292
  96. package/docs/build/files/lib_utilities_insert-into-file.js.html +0 -219
  97. package/docs/build/files/lib_utilities_is-lazy-engine.js.html +0 -125
  98. package/docs/build/files/lib_utilities_is-yarn-project.js.html +0 -120
  99. package/docs/build/files/lib_utilities_valid-project-name.js.html +0 -142
  100. package/docs/build/files/lib_utilities_will-interrupt-process.js.html +0 -290
  101. package/docs/build/files/lib_utilities_windows-admin.js.html +0 -230
  102. package/docs/build/index.html +0 -125
  103. package/docs/build/modules/ember-cli.html +0 -152
  104. package/docs/build/modules/is-lazy-engine.html +0 -106
  105. package/docs/build-concurrency.md +0 -15
  106. package/docs/build-pipeline-debugging.md +0 -33
  107. package/docs/code-coverage.md +0 -14
  108. package/docs/error-propagation.md +0 -136
  109. package/docs/experiments.md +0 -53
  110. package/docs/node-support.md +0 -43
  111. package/docs/perf-guide.md +0 -250
  112. package/docs/project_version_preprocessor.js +0 -8
  113. package/docs/sourcemaps.md +0 -60
  114. 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-beta.2-beta-6d064ff49f
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>