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,1678 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="utf-8">
5
- <title>lib/models/blueprint.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/blueprint.js</h1>
80
- </div>
81
-
82
- <pre class="code prettyprint linenums">
83
- &#x27;use strict&#x27;;
84
-
85
- /**
86
- @module ember-cli
87
- */
88
- const FileInfo = require(&#x27;./file-info&#x27;);
89
- const chalk = require(&#x27;chalk&#x27;);
90
- const MarkdownColor = require(&#x27;../utilities/markdown-color&#x27;);
91
- const sequence = require(&#x27;../utilities/sequence&#x27;);
92
- const printCommand = require(&#x27;../utilities/print-command&#x27;);
93
- const insertIntoFile = require(&#x27;../utilities/insert-into-file&#x27;);
94
- const cleanRemove = require(&#x27;../utilities/clean-remove&#x27;);
95
- const fs = require(&#x27;fs-extra&#x27;);
96
- const inflector = require(&#x27;inflection&#x27;);
97
- const minimatch = require(&#x27;minimatch&#x27;);
98
- const path = require(&#x27;path&#x27;);
99
- const stringUtils = require(&#x27;ember-cli-string-utils&#x27;);
100
- const _ = require(&#x27;ember-cli-lodash-subset&#x27;);
101
- const walkSync = require(&#x27;walk-sync&#x27;);
102
- const SilentError = require(&#x27;silent-error&#x27;);
103
- const CoreObject = require(&#x27;core-object&#x27;);
104
- const EOL = require(&#x27;os&#x27;).EOL;
105
- const bowEpParser = require(&#x27;bower-endpoint-parser&#x27;);
106
- const logger = require(&#x27;heimdalljs-logger&#x27;)(&#x27;ember-cli:blueprint&#x27;);
107
- const normalizeEntityName = require(&#x27;ember-cli-normalize-entity-name&#x27;);
108
- const isAddon = require(&#x27;../utilities/is-addon&#x27;);
109
-
110
- const initialIgnoredFiles = [&#x27;.DS_Store&#x27;];
111
-
112
- /**
113
- A blueprint is a bundle of template files with optional install
114
- logic.
115
-
116
- Blueprints follow a simple structure. Let&#x27;s take the built-in
117
- &#x60;controller&#x60; blueprint as an example:
118
-
119
- &#x60;&#x60;&#x60;
120
- blueprints/controller
121
- ├── files
122
- │ ├── app
123
- │ │ └── __path__
124
- │ │ └── __name__.js
125
- └── index.js
126
-
127
- blueprints/controller-test
128
- ├── files
129
- │ └── tests
130
- │ └── unit
131
- │ └── controllers
132
- │ └── __test__.js
133
- └── index.js
134
- &#x60;&#x60;&#x60;
135
-
136
- ## Files
137
-
138
- &#x60;files&#x60; contains templates for the all the files to be
139
- installed into the target directory.
140
-
141
- The &#x60;__name__&#x60; token is subtituted with the dasherized
142
- entity name at install time. For example, when the user
143
- invokes &#x60;ember generate controller foo&#x60; then &#x60;__name__&#x60; becomes
144
- &#x60;foo&#x60;. When the &#x60;--pod&#x60; flag is used, for example &#x60;ember
145
- generate controller foo --pod&#x60; then &#x60;__name__&#x60; becomes
146
- &#x60;controller&#x60;.
147
-
148
- The &#x60;__path__&#x60; token is substituted with the blueprint
149
- name at install time. For example, when the user invokes
150
- &#x60;ember generate controller foo&#x60; then &#x60;__path__&#x60; becomes
151
- &#x60;controller&#x60;. When the &#x60;--pod&#x60; flag is used, for example
152
- &#x60;ember generate controller foo --pod&#x60; then &#x60;__path__&#x60;
153
- becomes &#x60;foo&#x60; (or &#x60;&lt;podModulePrefix&gt;/foo&#x60; if the
154
- podModulePrefix is defined). This token is primarily for
155
- pod support, and is only necessary if the blueprint can be
156
- used in pod structure. If the blueprint does not require pod
157
- support, simply use the blueprint name instead of the
158
- &#x60;__path__&#x60; token.
159
-
160
- The &#x60;__test__&#x60; token is substituted with the dasherized
161
- entity name and appended with &#x60;-test&#x60; at install time.
162
- This token is primarily for pod support and only necessary
163
- if the blueprint requires support for a pod structure. If
164
- the blueprint does not require pod support, simply use the
165
- &#x60;__name__&#x60; token instead.
166
-
167
- ## Template Variables (AKA Locals)
168
-
169
- Variables can be inserted into templates with
170
- &#x60;&lt;%= someVariableName %&gt;&#x60;.
171
-
172
- For example, the built-in &#x60;util&#x60; blueprint
173
- &#x60;files/app/utils/__name__.js&#x60; looks like this:
174
-
175
- &#x60;&#x60;&#x60;js
176
- export default function &lt;%= camelizedModuleName %&gt;() {
177
- return true;
178
- }
179
- &#x60;&#x60;&#x60;
180
-
181
- &#x60;&lt;%= camelizedModuleName %&gt;&#x60; is replaced with the real
182
- value at install time.
183
-
184
- The following template variables are provided by default:
185
-
186
- - &#x60;dasherizedPackageName&#x60;
187
- - &#x60;classifiedPackageName&#x60;
188
- - &#x60;dasherizedModuleName&#x60;
189
- - &#x60;classifiedModuleName&#x60;
190
- - &#x60;camelizedModuleName&#x60;
191
-
192
- &#x60;packageName&#x60; is the project name as found in the project&#x27;s
193
- &#x60;package.json&#x60;.
194
-
195
- &#x60;moduleName&#x60; is the name of the entity being generated.
196
-
197
- The mechanism for providing custom template variables is
198
- described below.
199
-
200
- ## Index.js
201
-
202
- Custom installation and uninstallation behavior can be added
203
- by overriding the hooks documented below. &#x60;index.js&#x60; should
204
- export a plain object, which will extend the prototype of the
205
- &#x60;Blueprint&#x60; class. If needed, the original &#x60;Blueprint&#x60; prototype
206
- can be accessed through the &#x60;_super&#x60; property.
207
-
208
- &#x60;&#x60;&#x60;js
209
- module.exports = {
210
- locals(options) {
211
- // Return custom template variables here.
212
- return {};
213
- },
214
-
215
- normalizeEntityName(entityName) {
216
- // Normalize and validate entity name here.
217
- return entityName;
218
- },
219
-
220
- fileMapTokens(options) {
221
- // Return custom tokens to be replaced in your files
222
- return {
223
- __token__(options){
224
- // logic to determine value goes here
225
- return &#x27;value&#x27;;
226
- }
227
- }
228
- },
229
-
230
- filesPath(options) {
231
- return path.join(this.path, &#x27;files&#x27;);
232
- },
233
-
234
- beforeInstall(options) {},
235
- afterInstall(options) {},
236
- beforeUninstall(options) {},
237
- afterUninstall(options) {}
238
-
239
- };
240
- &#x60;&#x60;&#x60;
241
-
242
- ## Blueprint Hooks
243
-
244
- ### beforeInstall &amp; beforeUninstall
245
-
246
- Called before any of the template files are processed and receives
247
- the &#x60;options&#x60; and &#x60;locals&#x60; hashes as parameters. Typically used for
248
- validating any additional command line options or for any asynchronous
249
- setup that is needed. As an example, the &#x60;controller&#x60; blueprint validates
250
- its &#x60;--type&#x60; option in this hook. If you need to run any asynchronous code,
251
- wrap it in a promise and return that promise from these hooks. This will
252
- ensure that your code is executed correctly.
253
-
254
- ### afterInstall &amp; afterUninstall
255
-
256
- The &#x60;afterInstall&#x60; and &#x60;afterUninstall&#x60; hooks receives the same
257
- arguments as &#x60;locals&#x60;. Use it to perform any custom work after the
258
- files are processed. For example, the built-in &#x60;route&#x60; blueprint
259
- uses these hooks to add and remove relevant route declarations in
260
- &#x60;app/router.js&#x60;.
261
-
262
- ### Overriding Install
263
-
264
- If you don&#x27;t want your blueprint to install the contents of
265
- &#x60;files&#x60; you can override the &#x60;install&#x60; method. It receives the
266
- same &#x60;options&#x60; object described above and must return a promise.
267
- See the built-in &#x60;resource&#x60; blueprint for an example of this.
268
-
269
- @class Blueprint
270
- @constructor
271
- @extends CoreObject
272
- @param {String} [blueprintPath]
273
- */
274
- let Blueprint = CoreObject.extend({
275
- availableOptions: [],
276
- anonymousOptions: [&#x27;name&#x27;],
277
-
278
- _printableProperties: [&#x27;name&#x27;, &#x27;description&#x27;, &#x27;availableOptions&#x27;, &#x27;anonymousOptions&#x27;, &#x27;overridden&#x27;],
279
-
280
- init(blueprintPath) {
281
- this._super();
282
-
283
- this.path = blueprintPath;
284
- this.name = path.basename(blueprintPath);
285
- },
286
-
287
- /**
288
- Hook to specify the path to the blueprint&#x27;s files. By default this is
289
- &#x60;path.join(this.path, &#x27;files)&#x60;.
290
-
291
- This can be used to customize which set of files to install based on options
292
- or environmental variables. It defaults to the &#x60;files&#x60; directory within the
293
- blueprint&#x27;s folder.
294
-
295
- @public
296
- @method filesPath
297
- @param {Object} options
298
- @return {String} Path to the blueprints files directory.
299
- */
300
- filesPath(/* options */) {
301
- return path.join(this.path, &#x27;files&#x27;);
302
- },
303
-
304
- /**
305
- Used to retrieve files for blueprint.
306
-
307
- @public
308
- @method files
309
- @return {Array} Contents of the blueprint&#x27;s files directory
310
- */
311
- files() {
312
- if (this._files) {
313
- return this._files;
314
- }
315
-
316
- let filesPath = this.filesPath(this.options);
317
- if (Blueprint._existsSync(filesPath)) {
318
- this._files = walkSync(filesPath);
319
- } else {
320
- this._files = [];
321
- }
322
-
323
- return this._files;
324
- },
325
-
326
- /**
327
- @method srcPath
328
- @param {String} file
329
- @return {String} Resolved path to the file
330
- */
331
- srcPath(file) {
332
- return path.resolve(this.filesPath(this.options), file);
333
- },
334
-
335
- /**
336
- Hook for normalizing entity name
337
-
338
- Use the &#x60;normalizeEntityName&#x60; hook to add custom normalization and
339
- validation of the provided entity name. The default hook does not
340
- make any changes to the entity name, but makes sure an entity name
341
- is present and that it doesn&#x27;t have a trailing slash.
342
-
343
- This hook receives the entity name as its first argument. The string
344
- returned by this hook will be used as the new entity name.
345
-
346
- @public
347
- @method normalizeEntityName
348
- @param {String} entityName
349
- @return {null}
350
- */
351
- normalizeEntityName(entityName) {
352
- return normalizeEntityName(entityName);
353
- },
354
-
355
- /**
356
- Write a status and message to the UI
357
- @private
358
- @method _writeStatusToUI
359
- @param {Function} chalkColor
360
- @param {String} keyword
361
- @param {String} message
362
- */
363
- _writeStatusToUI(chalkColor, keyword, message) {
364
- if (this.ui) {
365
- this.ui.writeLine(&#x60; ${chalkColor(keyword)} ${message}&#x60;);
366
- }
367
- },
368
-
369
- /**
370
- @private
371
- @method _writeFile
372
- @param {Object} info
373
- @return {Promise}
374
- */
375
- async _writeFile(info) {
376
- if (!this.dryRun) {
377
- return fs.outputFile(info.outputPath, await info.render());
378
- }
379
- },
380
-
381
- /**
382
- Actions lookup
383
- @private
384
- @property _actions
385
- @type Object
386
- */
387
- _actions: {
388
- write(info) {
389
- this._writeStatusToUI(chalk.green, &#x27;create&#x27;, info.displayPath);
390
- return this._writeFile(info);
391
- },
392
- skip(info) {
393
- let label = &#x27;skip&#x27;;
394
-
395
- if (info.resolution === &#x27;identical&#x27;) {
396
- label = &#x27;identical&#x27;;
397
- }
398
-
399
- this._writeStatusToUI(chalk.yellow, label, info.displayPath);
400
- },
401
-
402
- overwrite(info) {
403
- this._writeStatusToUI(chalk.yellow, &#x27;overwrite&#x27;, info.displayPath);
404
- return this._writeFile(info);
405
- },
406
-
407
- edit(info) {
408
- this._writeStatusToUI(chalk.green, &#x27;edited&#x27;, info.displayPath);
409
- },
410
-
411
- remove(info) {
412
- this._writeStatusToUI(chalk.red, &#x27;remove&#x27;, info.displayPath);
413
- if (!this.dryRun) {
414
- return cleanRemove(info);
415
- }
416
- },
417
- },
418
-
419
- /**
420
- Calls an action.
421
- @private
422
- @method _commit
423
- @param {Object} result
424
- @return {Promise}
425
- @throws {Error} Action doesn&#x27;t exist.
426
- */
427
- _commit(result) {
428
- let action = this._actions[result.action];
429
-
430
- if (action) {
431
- return action.call(this, result);
432
- } else {
433
- throw new Error(&#x60;Tried to call action &quot;${result.action}&quot; but it does not exist&#x60;);
434
- }
435
- },
436
-
437
- /**
438
- Prints warning for pod unsupported.
439
- @private
440
- @method _checkForPod
441
- */
442
- _checkForPod(verbose) {
443
- if (!this.hasPathToken &amp;&amp; this.pod &amp;&amp; verbose) {
444
- this.ui.writeLine(
445
- chalk.yellow(
446
- &#x27;You specified the pod flag, but this&#x27; +
447
- &#x27; blueprint does not support pod structure. It will be generated with&#x27; +
448
- &#x27; the default structure.&#x27;
449
- )
450
- );
451
- }
452
- },
453
-
454
- /**
455
- @private
456
- @method _normalizeEntityName
457
- @param {Object} entity
458
- */
459
- _normalizeEntityName(entity) {
460
- if (entity) {
461
- entity.name = this.normalizeEntityName(entity.name);
462
- }
463
- },
464
-
465
- /**
466
- @private
467
- @method _checkInRepoAddonExists
468
- @param {Object} options
469
- */
470
- _checkInRepoAddonExists(options) {
471
- let addon;
472
-
473
- if (options.inRepoAddon) {
474
- addon = findAddonByName(this.project, options.inRepoAddon);
475
-
476
- if (!addon) {
477
- throw new SilentError(
478
- &#x60;You specified the &#x27;in-repo-addon&#x27; flag, but the &#x60; +
479
- &#x60;in-repo-addon &#x27;${options.inRepoAddon}&#x27; does not exist. Please check the name and try again.&#x60;
480
- );
481
- }
482
- }
483
-
484
- if (options.in) {
485
- if (!ensureTargetDirIsAddon(options.in)) {
486
- throw new SilentError(
487
- &#x60;You specified the &#x27;in&#x27; flag, but the &#x60; +
488
- &#x60;in repo addon &#x27;${options.in}&#x27; does not exist. Please check the name and try again.&#x60;
489
- );
490
- }
491
- }
492
- },
493
-
494
- /**
495
- @private
496
- @method _process
497
- @param {Object} options
498
- @param {Function} beforeHook
499
- @param {Function} process
500
- @param {Function} afterHook
501
- */
502
- async _process(options, beforeHook, process, afterHook) {
503
- let intoDir = options.target;
504
-
505
- let locals = await this._locals(options);
506
-
507
- // run beforeInstall/beforeUninstall userland hooks
508
- await beforeHook.call(this, options, locals);
509
-
510
- // gather fileInfos to be processed
511
- let fileInfos = await process.call(this, intoDir, locals);
512
-
513
- // commit changes for each FileInfo (with prompting as needed)
514
- await Promise.all(fileInfos.map((fi) =&gt; this._commit(fi)));
515
-
516
- // run afterInstall/afterUninstall userland hooks
517
- await afterHook.call(this, options);
518
- },
519
-
520
- /**
521
- @method install
522
- @param {Object} options
523
- @return {Promise}
524
- */
525
- install(options) {
526
- let ui = (this.ui = options.ui);
527
- let dryRun = (this.dryRun = options.dryRun);
528
- this.project = options.project;
529
- this.pod = options.pod;
530
- this.options = options;
531
- this.hasPathToken = hasPathToken(this.files(this.options));
532
-
533
- ui.writeLine(&#x60;installing ${this.name}&#x60;);
534
-
535
- if (dryRun) {
536
- ui.writeLine(chalk.yellow(&#x27;You specified the dry-run flag, so no&#x27; + &#x27; changes will be written.&#x27;));
537
- }
538
-
539
- this._normalizeEntityName(options.entity);
540
- this._checkForPod(options.verbose);
541
- this._checkInRepoAddonExists(options);
542
-
543
- logger.info(&#x27;START: processing blueprint: &#x60;%s&#x60;&#x27;, this.name);
544
- let start = new Date();
545
- return this._process(options, this.beforeInstall, this.processFiles, this.afterInstall).finally(() =&gt;
546
- logger.info(&#x27;END: processing blueprint: &#x60;%s&#x60; in (%dms)&#x27;, this.name, new Date() - start)
547
- );
548
- },
549
-
550
- /**
551
- @method uninstall
552
- @param {Object} options
553
- @return {Promise}
554
- */
555
- uninstall(options) {
556
- let ui = (this.ui = options.ui);
557
- let dryRun = (this.dryRun = options.dryRun);
558
- this.project = options.project;
559
- this.pod = options.pod;
560
- this.options = options;
561
- this.hasPathToken = hasPathToken(this.files(this.options));
562
-
563
- ui.writeLine(&#x60;uninstalling ${this.name}&#x60;);
564
-
565
- if (dryRun) {
566
- ui.writeLine(chalk.yellow(&#x27;You specified the dry-run flag, so no&#x27; + &#x27; files will be deleted.&#x27;));
567
- }
568
-
569
- this._normalizeEntityName(options.entity);
570
- this._checkForPod(options.verbose);
571
-
572
- return this._process(options, this.beforeUninstall, this.processFilesForUninstall, this.afterUninstall);
573
- },
574
-
575
- /**
576
- Hook for running operations before install.
577
- @method beforeInstall
578
- @return {Promise|null}
579
- */
580
- beforeInstall() {},
581
-
582
- /**
583
- Hook for running operations after install.
584
- @method afterInstall
585
- @return {Promise|null}
586
- */
587
- afterInstall() {},
588
-
589
- /**
590
- Hook for running operations before uninstall.
591
- @method beforeUninstall
592
- @return {Promise|null}
593
- */
594
- beforeUninstall() {},
595
-
596
- /**
597
- Hook for running operations after uninstall.
598
- @method afterUninstall
599
- @return {Promise|null}
600
- */
601
- afterUninstall() {},
602
-
603
- filesToRemove: [],
604
-
605
- /**
606
- Hook for adding custom template variables.
607
-
608
- When the following is called on the command line:
609
-
610
- &#x60;&#x60;&#x60;sh
611
- ember generate controller foo --type=array --dry-run isAdmin:true
612
- &#x60;&#x60;&#x60;
613
-
614
- The object passed to &#x60;locals&#x60; looks like this:
615
-
616
- &#x60;&#x60;&#x60;js
617
- {
618
- entity: {
619
- name: &#x27;foo&#x27;,
620
- options: {
621
- isAdmin: true
622
- }
623
- },
624
- dryRun: true
625
- type: &quot;array&quot;
626
- // more keys
627
- }
628
- &#x60;&#x60;&#x60;
629
-
630
- This hook must return an object or a Promise which resolves to an object.
631
- The resolved object will be merged with the aforementioned default locals.
632
-
633
- @public
634
- @method locals
635
- @param {Object} options General and entity-specific options
636
- @return {Object|Promise|null}
637
- */
638
- locals(/* options */) {},
639
-
640
- /**
641
- Hook to add additional or override existing fileMap tokens.
642
-
643
- Use &#x60;fileMapTokens&#x60; to add custom fileMap tokens for use
644
- in the &#x60;mapFile&#x60; method. The hook must return an object in the
645
- following pattern:
646
-
647
- &#x60;&#x60;&#x60;js
648
- {
649
- __token__(options){
650
- // logic to determine value goes here
651
- return &#x27;value&#x27;;
652
- }
653
- }
654
- &#x60;&#x60;&#x60;
655
-
656
- It will be merged with the default &#x60;fileMapTokens&#x60;, and can be used
657
- to override any of the default tokens.
658
-
659
- Tokens are used in the files folder (see &#x60;files&#x60;), and get replaced with
660
- values when the &#x60;mapFile&#x60; method is called.
661
-
662
- @public
663
- @method fileMapTokens
664
- @return {Object|null}
665
- */
666
- fileMapTokens() {},
667
-
668
- /**
669
- @private
670
- @method _fileMapTokens
671
- @param {Object} options
672
- @return {Object}
673
- */
674
- _fileMapTokens(options) {
675
- let { project } = this;
676
- let standardTokens = {
677
- __name__(options) {
678
- if (options.pod &amp;&amp; options.hasPathToken) {
679
- return options.blueprintName;
680
- }
681
- return options.dasherizedModuleName;
682
- },
683
- __path__(options) {
684
- let blueprintName = options.blueprintName;
685
-
686
- if (/-test/.test(blueprintName)) {
687
- blueprintName = options.blueprintName.slice(0, options.blueprintName.indexOf(&#x27;-test&#x27;));
688
- }
689
- if (options.pod &amp;&amp; options.hasPathToken) {
690
- return path.join(options.podPath, options.dasherizedModuleName);
691
- }
692
- return inflector.pluralize(blueprintName);
693
- },
694
- __root__(options) {
695
- if (options.inRepoAddon) {
696
- let addon = findAddonByName(project, options.inRepoAddon);
697
- let relativeAddonPath = path.relative(project.root, addon.root);
698
- return path.join(relativeAddonPath, &#x27;addon&#x27;);
699
- }
700
- if (options.in) {
701
- let relativeAddonPath = path.relative(project.root, options.in);
702
- return path.join(relativeAddonPath, &#x27;addon&#x27;);
703
- }
704
- if (options.inDummy) {
705
- return path.join(&#x27;tests&#x27;, &#x27;dummy&#x27;, &#x27;app&#x27;);
706
- }
707
- if (options.inAddon) {
708
- return &#x27;addon&#x27;;
709
- }
710
- return &#x27;app&#x27;;
711
- },
712
- __test__(options) {
713
- if (options.pod &amp;&amp; options.hasPathToken) {
714
- return options.blueprintName;
715
- }
716
- return &#x60;${options.dasherizedModuleName}-test&#x60;;
717
- },
718
- };
719
-
720
- let customTokens = this.fileMapTokens(options) || options.fileMapTokens || {};
721
- return _.merge(standardTokens, customTokens);
722
- },
723
-
724
- /**
725
- Used to generate fileMap tokens for mapFile.
726
-
727
- @method generateFileMap
728
- @param {Object} fileMapVariables
729
- @return {Object}
730
- */
731
- generateFileMap(fileMapVariables) {
732
- let tokens = this._fileMapTokens(fileMapVariables);
733
- let fileMapValues = _.values(tokens);
734
- let tokenValues = fileMapValues.map((token) =&gt; token(fileMapVariables));
735
- let tokenKeys = Object.keys(tokens);
736
- return _.zipObject(tokenKeys, tokenValues);
737
- },
738
-
739
- /**
740
- @method buildFileInfo
741
- @param {Function} destPath
742
- @param {Object} templateVariables
743
- @param {String} file
744
- @return {FileInfo}
745
- */
746
- buildFileInfo(intoDir, templateVariables, file) {
747
- let mappedPath = this.mapFile(file, templateVariables);
748
-
749
- return new FileInfo({
750
- action: &#x27;write&#x27;,
751
- outputBasePath: path.normalize(intoDir),
752
- outputPath: path.join(intoDir, mappedPath),
753
- displayPath: path.normalize(mappedPath),
754
- inputPath: this.srcPath(file),
755
- templateVariables,
756
- ui: this.ui,
757
- });
758
- },
759
-
760
- /**
761
- @method isUpdate
762
- @return {Boolean}
763
- */
764
- isUpdate() {
765
- if (this.project &amp;&amp; this.project.isEmberCLIProject) {
766
- return this.project.isEmberCLIProject();
767
- }
768
- },
769
-
770
- /**
771
- @private
772
- @method _getFileInfos
773
- @param {Array} files
774
- @param {String} intoDir
775
- @param {Object} templateVariables
776
- @return {Array} file infos
777
- */
778
- _getFileInfos(files, intoDir, templateVariables) {
779
- return files.map(this.buildFileInfo.bind(this, intoDir, templateVariables));
780
- },
781
-
782
- /**
783
- Add update files to ignored files or reset them
784
- @private
785
- @method _ignoreUpdateFiles
786
- */
787
- _ignoreUpdateFiles() {
788
- if (this.isUpdate()) {
789
- Blueprint.ignoredFiles = Blueprint.ignoredFiles.concat(Blueprint.ignoredUpdateFiles);
790
- } else {
791
- Blueprint.ignoredFiles = initialIgnoredFiles;
792
- }
793
- },
794
-
795
- /**
796
- @private
797
- @method _getFilesForInstall
798
- @param {Array} targetFiles
799
- @return {Array} files
800
- */
801
- _getFilesForInstall(targetFiles) {
802
- let files = this.files(this.options);
803
-
804
- // if we&#x27;ve defined targetFiles, get file info on ones that match
805
- return (targetFiles &amp;&amp; targetFiles.length &gt; 0 &amp;&amp; _.intersection(files, targetFiles)) || files;
806
- },
807
-
808
- /**
809
- @private
810
- @method _checkForNoMatch
811
- @param {Array} fileInfos
812
- @param {String} rawArgs
813
- */
814
- _checkForNoMatch(fileInfos, rawArgs) {
815
- if (fileInfos.filter(isFilePath).length &lt; 1 &amp;&amp; rawArgs) {
816
- this.ui.writeLine(
817
- chalk.yellow(&#x60;The globPattern &quot;${rawArgs}&quot; &#x60; + &#x60;did not match any files, so no file updates will be made.&#x60;)
818
- );
819
- }
820
- },
821
-
822
- /**
823
- @method processFiles
824
- @param {String} intoDir
825
- @param {Object} templateVariables
826
- @return {Promise&lt;FileInfo[]&gt;}
827
- */
828
- processFiles(intoDir, templateVariables) {
829
- let files = this._getFilesForInstall(templateVariables.targetFiles);
830
- let fileInfos = this._getFileInfos(files, intoDir, templateVariables);
831
- this._checkForNoMatch(fileInfos, templateVariables.rawArgs);
832
-
833
- this._ignoreUpdateFiles();
834
-
835
- let fileInfosToRemove = this._getFileInfos(this.filesToRemove, intoDir, templateVariables);
836
-
837
- fileInfosToRemove = finishProcessingForUninstall(fileInfosToRemove);
838
-
839
- return Promise.all(fileInfos.filter(isValidFile).map(prepareConfirm))
840
- .then(finishProcessingForInstall)
841
- .then((fileInfos) =&gt; fileInfos.concat(fileInfosToRemove));
842
- },
843
-
844
- /**
845
- @method processFilesForUninstall
846
- @param {String} intoDir
847
- @param {Object} templateVariables
848
- */
849
- processFilesForUninstall(intoDir, templateVariables) {
850
- let fileInfos = this._getFileInfos(this.files(this.options), intoDir, templateVariables);
851
-
852
- this._ignoreUpdateFiles();
853
-
854
- return finishProcessingForUninstall(fileInfos.filter(isValidFile));
855
- },
856
-
857
- /**
858
- @method mapFile
859
- @param {String} file
860
- @param locals
861
- @return {String}
862
- */
863
- mapFile(file, locals) {
864
- let pattern, i;
865
- let fileMap = locals.fileMap || { __name__: locals.dasherizedModuleName };
866
- file = Blueprint.renamedFiles[file] || file;
867
- for (i in fileMap) {
868
- pattern = new RegExp(i, &#x27;g&#x27;);
869
- file = file.replace(pattern, fileMap[i]);
870
- }
871
- return file;
872
- },
873
-
874
- /**
875
- Looks for a __root__ token in the files folder. Must be present for
876
- the blueprint to support addon tokens. The &#x60;server&#x60;, &#x60;blueprints&#x60;, and &#x60;test&#x60;
877
-
878
- @private
879
- @method supportsAddon
880
- @return {Boolean}
881
- */
882
- supportsAddon() {
883
- return /__root__/.test(this.files().join());
884
- },
885
-
886
- /**
887
- @private
888
- @method _generateFileMapVariables
889
- @param {String} moduleName
890
- @param locals
891
- @param {Object} options
892
- @return {Object}
893
- */
894
- _generateFileMapVariables(moduleName, locals, options) {
895
- let originBlueprintName = options.originBlueprintName || this.name;
896
- let podModulePrefix = this.project.config().podModulePrefix || &#x27;&#x27;;
897
- let podPath = podModulePrefix.substr(podModulePrefix.lastIndexOf(&#x27;/&#x27;) + 1);
898
- let inAddon = this.project.isEmberCLIAddon() || !!options.inRepoAddon;
899
- let inDummy = this.project.isEmberCLIAddon() ? options.dummy : false;
900
-
901
- return {
902
- pod: this.pod,
903
- podPath,
904
- hasPathToken: this.hasPathToken,
905
- inAddon,
906
- inRepoAddon: options.inRepoAddon,
907
- in: options.in,
908
- inDummy,
909
- blueprintName: this.name,
910
- originBlueprintName,
911
- dasherizedModuleName: stringUtils.dasherize(moduleName),
912
- locals,
913
- };
914
- },
915
-
916
- /**
917
- @private
918
- @method _locals
919
- @param {Object} options
920
- @return {Object}
921
- */
922
- _locals(options) {
923
- let packageName = options.project.name();
924
- let moduleName = (options.entity &amp;&amp; options.entity.name) || packageName;
925
- let sanitizedModuleName = moduleName.replace(/\//g, &#x27;-&#x27;);
926
-
927
- return new Promise((resolve) =&gt; {
928
- resolve(this.locals(options));
929
- }).then((customLocals) =&gt; {
930
- let fileMapVariables = this._generateFileMapVariables(moduleName, customLocals, options);
931
- let fileMap = this.generateFileMap(fileMapVariables);
932
- let standardLocals = {
933
- dasherizedPackageName: stringUtils.dasherize(packageName),
934
- classifiedPackageName: stringUtils.classify(packageName),
935
- dasherizedModuleName: stringUtils.dasherize(moduleName),
936
- classifiedModuleName: stringUtils.classify(sanitizedModuleName),
937
- camelizedModuleName: stringUtils.camelize(sanitizedModuleName),
938
- decamelizedModuleName: stringUtils.decamelize(sanitizedModuleName),
939
- fileMap,
940
- hasPathToken: this.hasPathToken,
941
- targetFiles: options.targetFiles,
942
- rawArgs: options.rawArgs,
943
- };
944
-
945
- return _.merge({}, standardLocals, customLocals);
946
- });
947
- },
948
-
949
- /**
950
- Used to add a package to the project&#x27;s &#x60;package.json&#x60;.
951
-
952
- Generally, this would be done from the &#x60;afterInstall&#x60; hook, to
953
- ensure that a package that is required by a given blueprint is
954
- available.
955
-
956
- @method addPackageToProject
957
- @param {String} packageName
958
- @param {String} target
959
- @return {Promise}
960
- */
961
- addPackageToProject(packageName, target) {
962
- let packageObject = { name: packageName };
963
-
964
- if (target) {
965
- packageObject.target = target;
966
- }
967
-
968
- return this.addPackagesToProject([packageObject]);
969
- },
970
-
971
- /**
972
- Used to add multiple packages to the project&#x27;s &#x60;package.json&#x60;.
973
-
974
- Generally, this would be done from the &#x60;afterInstall&#x60; hook, to
975
- ensure that a package that is required by a given blueprint is
976
- available.
977
-
978
- Expects each array item to be an object with a &#x60;name&#x60;. Each object
979
- may optionally have a &#x60;target&#x60; to specify a specific version.
980
-
981
- @method addPackagesToProject
982
- @param {Array} packages
983
- @return {Promise}
984
-
985
- @example
986
- &#x60;&#x60;&#x60;js
987
- this.addPackagesToProject([
988
- { name: &#x27;lodash&#x27; },
989
- { name: &#x27;moment&#x27;, target: &#x27;^2.17.0&#x27; },
990
- ]);
991
- &#x60;&#x60;&#x60;
992
- */
993
- addPackagesToProject(packages) {
994
- let task = this.taskFor(&#x27;npm-install&#x27;);
995
- let installText = packages.length &gt; 1 ? &#x27;install packages&#x27; : &#x27;install package&#x27;;
996
- let packageNames = [];
997
- let packageArray = [];
998
-
999
- for (let i = 0; i &lt; packages.length; i++) {
1000
- packageNames.push(packages[i].name);
1001
-
1002
- let packageNameAndVersion = packages[i].name;
1003
-
1004
- if (packages[i].target) {
1005
- packageNameAndVersion += &#x60;@${packages[i].target}&#x60;;
1006
- }
1007
-
1008
- packageArray.push(packageNameAndVersion);
1009
- }
1010
-
1011
- this._writeStatusToUI(chalk.green, installText, packageNames.join(&#x27;, &#x27;));
1012
-
1013
- return task.run({
1014
- &#x27;save-dev&#x27;: true,
1015
- verbose: false,
1016
- packages: packageArray,
1017
- });
1018
- },
1019
-
1020
- /**
1021
- Used to remove a package from the project&#x27;s &#x60;package.json&#x60;.
1022
-
1023
- Generally, this would be done from the &#x60;afterInstall&#x60; hook, to
1024
- ensure that any package conflicts can be resolved before the
1025
- addon is used.
1026
-
1027
- @method removePackageFromProject
1028
- @param {String} packageName
1029
- @return {Promise}
1030
- */
1031
- removePackageFromProject(packageName) {
1032
- let packageObject = { name: packageName };
1033
-
1034
- return this.removePackagesFromProject([packageObject]);
1035
- },
1036
-
1037
- /**
1038
- Used to remove multiple packages from the project&#x27;s &#x60;package.json&#x60;.
1039
-
1040
- Generally, this would be done from the &#x60;afterInstall&#x60; hook, to
1041
- ensure that any package conflicts can be resolved before the
1042
- addon is used.
1043
-
1044
- Expects each array item to be an object with a &#x60;name&#x60; property.
1045
-
1046
- @method removePackagesFromProject
1047
- @param {Array} packages
1048
- @return {Promise}
1049
- */
1050
- removePackagesFromProject(packages) {
1051
- let task = this.taskFor(&#x27;npm-uninstall&#x27;);
1052
- let installText = packages.length &gt; 1 ? &#x27;uninstall packages&#x27; : &#x27;uninstall package&#x27;;
1053
- let packageNames = [];
1054
-
1055
- let projectDependencies = this.project.dependencies();
1056
-
1057
- for (let i = 0; i &lt; packages.length; i++) {
1058
- let packageName = packages[i].name;
1059
- if (packageName in projectDependencies) {
1060
- packageNames.push(packageName);
1061
- }
1062
- }
1063
-
1064
- if (packageNames.length === 0) {
1065
- this._writeStatusToUI(chalk.yellow, &#x27;remove&#x27;, &#x27;Skipping uninstall because no matching package is installed.&#x27;);
1066
- return Promise.resolve();
1067
- }
1068
-
1069
- this._writeStatusToUI(chalk.green, installText, packageNames.join(&#x27;, &#x27;));
1070
-
1071
- return task.run({
1072
- &#x27;save-dev&#x27;: true,
1073
- verbose: false,
1074
- packages: packageNames,
1075
- });
1076
- },
1077
-
1078
- /**
1079
- Used to add a package to the projects &#x60;bower.json&#x60;.
1080
-
1081
- Generally, this would be done from the &#x60;afterInstall&#x60; hook, to
1082
- ensure that a package that is required by a given blueprint is
1083
- available.
1084
-
1085
- &#x60;localPackageName&#x60; and &#x60;target&#x60; may be thought of as equivalent
1086
- to the key-value pairs in the &#x60;dependency&#x60; or &#x60;devDepencency&#x60;
1087
- objects contained within a bower.json file.
1088
- @method addBowerPackageToProject
1089
- @param {String} localPackageName
1090
- @param {String} target
1091
- @param {Object} installOptions
1092
- @return {Promise}
1093
-
1094
- @example
1095
- &#x60;&#x60;&#x60;js
1096
- addBowerPackageToProject(&#x27;jquery&#x27;, &#x27;~1.11.1&#x27;);
1097
- addBowerPackageToProject(&#x27;old_jquery&#x27;, &#x27;jquery#~1.9.1&#x27;);
1098
- addBowerPackageToProject(&#x27;bootstrap-3&#x27;, &#x27;https://twitter.github.io/bootstrap/assets/bootstrap&#x27;);
1099
- &#x60;&#x60;&#x60;
1100
- */
1101
- addBowerPackageToProject(localPackageName, target, installOptions) {
1102
- let lpn = localPackageName;
1103
- let tar = target;
1104
- let packageObject = bowEpParser.json2decomposed(lpn, tar);
1105
- return this.addBowerPackagesToProject([packageObject], installOptions);
1106
- },
1107
-
1108
- /**
1109
- Used to add an array of packages to the projects &#x60;bower.json&#x60;.
1110
-
1111
- Generally, this would be done from the &#x60;afterInstall&#x60; hook, to
1112
- ensure that a package that is required by a given blueprint is
1113
- available.
1114
-
1115
- Expects each array item to be an object with a &#x60;name&#x60;. Each object
1116
- may optionally have a &#x60;target&#x60; to specify a specific version, or a
1117
- &#x60;source&#x60; to specify a non-local name to be resolved.
1118
-
1119
- @method addBowerPackagesToProject
1120
- @param {Array} packages
1121
- @param {Object} installOptions
1122
- @return {Promise}
1123
- */
1124
- addBowerPackagesToProject(packages, installOptions) {
1125
- let task = this.taskFor(&#x27;bower-install&#x27;);
1126
- let installText = packages.length &gt; 1 ? &#x27;install bower packages&#x27; : &#x27;install bower package&#x27;;
1127
- let packageNames = [];
1128
- let packageNamesAndVersions = packages
1129
- .map((pkg) =&gt; {
1130
- pkg.source = pkg.source || pkg.name;
1131
- packageNames.push(pkg.name);
1132
- return pkg;
1133
- })
1134
- .map(bowEpParser.compose);
1135
-
1136
- this._writeStatusToUI(chalk.green, installText, packageNames.join(&#x27;, &#x27;));
1137
-
1138
- return task.run({
1139
- verbose: true,
1140
- packages: packageNamesAndVersions,
1141
- installOptions: installOptions || { save: true },
1142
- });
1143
- },
1144
-
1145
- /**
1146
- Used to add an addon to the project&#x27;s &#x60;package.json&#x60; and run it&#x27;s
1147
- &#x60;defaultBlueprint&#x60; if it provides one.
1148
-
1149
- Generally, this would be done from the &#x60;afterInstall&#x60; hook, to
1150
- ensure that a package that is required by a given blueprint is
1151
- available.
1152
-
1153
- @method addAddonToProject
1154
- @param {Object} options
1155
- @return {Promise}
1156
- */
1157
- addAddonToProject(options) {
1158
- return this.addAddonsToProject({
1159
- packages: [options],
1160
- extraArgs: options.extraArgs || {},
1161
- blueprintOptions: options.blueprintOptions || {},
1162
- });
1163
- },
1164
-
1165
- /**
1166
- Used to add multiple addons to the project&#x27;s &#x60;package.json&#x60; and run their
1167
- &#x60;defaultBlueprint&#x60; if they provide one.
1168
-
1169
- Generally, this would be done from the &#x60;afterInstall&#x60; hook, to
1170
- ensure that a package that is required by a given blueprint is
1171
- available.
1172
-
1173
- @method addAddonsToProject
1174
- @param {Object} options
1175
- @return {Promise}
1176
- */
1177
- addAddonsToProject(options) {
1178
- let taskOptions = {
1179
- packages: [],
1180
- extraArgs: options.extraArgs || [],
1181
- blueprintOptions: options.blueprintOptions || {},
1182
- };
1183
-
1184
- let packages = options.packages;
1185
- if (packages &amp;&amp; packages.length) {
1186
- taskOptions.packages = packages.map((pkg) =&gt; {
1187
- if (typeof pkg === &#x27;string&#x27;) {
1188
- return pkg;
1189
- }
1190
-
1191
- if (!pkg.name) {
1192
- throw new SilentError(&#x27;You must provide a package &#x60;name&#x60; to addAddonsToProject&#x27;);
1193
- }
1194
-
1195
- if (pkg.target) {
1196
- pkg.name += &#x60;@${pkg.target}&#x60;;
1197
- }
1198
-
1199
- return pkg.name;
1200
- });
1201
- } else {
1202
- throw new SilentError(&#x27;You must provide package to addAddonsToProject&#x27;);
1203
- }
1204
-
1205
- let installText = packages.length &gt; 1 ? &#x27;install addons&#x27; : &#x27;install addon&#x27;;
1206
- this._writeStatusToUI(chalk.green, installText, taskOptions[&#x27;packages&#x27;].join(&#x27;, &#x27;));
1207
-
1208
- return this.taskFor(&#x27;addon-install&#x27;).run(taskOptions);
1209
- },
1210
-
1211
- /**
1212
- Used to retrieve a task with the given name. Passes the new task
1213
- the standard information available (like &#x60;ui&#x60;, &#x60;analytics&#x60;, &#x60;project&#x60;, etc).
1214
-
1215
- @method taskFor
1216
- @param dasherizedName
1217
- @public
1218
- */
1219
- taskFor(dasherizedName) {
1220
- const Task = require(&#x60;../tasks/${dasherizedName}&#x60;);
1221
-
1222
- return new Task({
1223
- ui: this.ui,
1224
- project: this.project,
1225
- analytics: this.analytics,
1226
- });
1227
- },
1228
-
1229
- /**
1230
- Inserts the given content into a file. If the &#x60;contentsToInsert&#x60; string is already
1231
- present in the current contents, the file will not be changed unless &#x60;force&#x60; option
1232
- is passed.
1233
-
1234
- If &#x60;options.before&#x60; is specified, &#x60;contentsToInsert&#x60; will be inserted before
1235
- the first instance of that string. If &#x60;options.after&#x60; is specified, the
1236
- contents will be inserted after the first instance of that string.
1237
- If the string specified by options.before or options.after is not in the file,
1238
- no change will be made.
1239
-
1240
- If neither &#x60;options.before&#x60; nor &#x60;options.after&#x60; are present, &#x60;contentsToInsert&#x60;
1241
- will be inserted at the end of the file.
1242
-
1243
- Example:
1244
- &#x60;&#x60;&#x60;
1245
- // app/router.js
1246
- Router.map(function () {
1247
- });
1248
- &#x60;&#x60;&#x60;
1249
-
1250
- &#x60;&#x60;&#x60;
1251
- insertIntoFile(&#x27;app/router.js&#x27;, &#x27; this.route(&quot;admin&quot;);&#x27;, {
1252
- after: &#x27;Router.map(function () {&#x27; + EOL
1253
- }).then(function() {
1254
- // file has been inserted into!
1255
- });
1256
-
1257
-
1258
- &#x60;&#x60;&#x60;
1259
-
1260
- &#x60;&#x60;&#x60;
1261
- // app/router.js
1262
- Router.map(function () {
1263
- this.route(&quot;admin&quot;);
1264
- });
1265
- &#x60;&#x60;&#x60;
1266
-
1267
- @method insertIntoFile
1268
- @param {String} pathRelativeToProjectRoot
1269
- @param {String} contentsToInsert
1270
- @param {Object} providedOptions
1271
- @return {Promise}
1272
- */
1273
- insertIntoFile(pathRelativeToProjectRoot, contentsToInsert, providedOptions) {
1274
- let fullPath = path.join(this.project.root, pathRelativeToProjectRoot);
1275
- return insertIntoFile(fullPath, contentsToInsert, providedOptions);
1276
- },
1277
-
1278
- _printCommand: printCommand,
1279
-
1280
- printBasicHelp(verbose) {
1281
- let initialMargin = &#x27; &#x27;;
1282
- let output = initialMargin;
1283
- if (this.overridden) {
1284
- output += chalk.grey(&#x60;(overridden) ${this.name}&#x60;);
1285
- } else {
1286
- output += this.name;
1287
-
1288
- output += this._printCommand(initialMargin, true);
1289
-
1290
- if (verbose) {
1291
- output += EOL + this.printDetailedHelp(this.availableOptions);
1292
- }
1293
- }
1294
-
1295
- return output;
1296
- },
1297
-
1298
- printDetailedHelp() {
1299
- let markdownColor = new MarkdownColor();
1300
- let filePath = getDetailedHelpPath(this.path);
1301
-
1302
- if (Blueprint._existsSync(filePath)) {
1303
- return markdownColor.renderFile(filePath, { indent: &#x27; &#x27; });
1304
- }
1305
- return &#x27;&#x27;;
1306
- },
1307
-
1308
- getJson(verbose) {
1309
- let json = {};
1310
- this._printableProperties.forEach((key) =&gt; {
1311
- let value = this[key];
1312
- if (key === &#x27;availableOptions&#x27;) {
1313
- value = _.cloneDeep(value);
1314
- value.forEach((option) =&gt; {
1315
- if (typeof option.type === &#x27;function&#x27;) {
1316
- option.type = option.type.name;
1317
- }
1318
- });
1319
- }
1320
- json[key] = value;
1321
- });
1322
-
1323
- if (verbose) {
1324
- let detailedHelp = this.printDetailedHelp(this.availableOptions);
1325
- if (detailedHelp) {
1326
- json.detailedHelp = detailedHelp;
1327
- }
1328
- }
1329
-
1330
- return json;
1331
- },
1332
-
1333
- /**
1334
- Used to retrieve a blueprint with the given name.
1335
-
1336
- @method lookupBlueprint
1337
- @param {String} dasherizedName
1338
- @return {Blueprint}
1339
- @public
1340
- */
1341
- lookupBlueprint(dasherizedName) {
1342
- let projectPaths = this.project ? this.project.blueprintLookupPaths() : [];
1343
-
1344
- return Blueprint.lookup(dasherizedName, {
1345
- paths: projectPaths,
1346
- });
1347
- },
1348
- });
1349
-
1350
- /**
1351
- @static
1352
- @method lookup
1353
- @namespace Blueprint
1354
- @param {String} name
1355
- @param {Object} [options]
1356
- @param {Array} [options.paths] Extra paths to search for blueprints
1357
- @param {Boolean} [options.ignoreMissing] Throw a &#x60;SilentError&#x60; if a
1358
- matching Blueprint could not be found
1359
- @return {Blueprint}
1360
- */
1361
- Blueprint.lookup = function (name, options) {
1362
- options = options || {};
1363
-
1364
- let lookupPaths = generateLookupPaths(options.paths);
1365
-
1366
- let lookupPath;
1367
- for (let i = 0; (lookupPath = lookupPaths[i]); i++) {
1368
- let blueprintPath = path.resolve(lookupPath, name);
1369
-
1370
- if (Blueprint._existsSync(blueprintPath)) {
1371
- return Blueprint.load(blueprintPath);
1372
- }
1373
- }
1374
-
1375
- if (!options.ignoreMissing) {
1376
- throw new SilentError(&#x60;Unknown blueprint: ${name}&#x60;);
1377
- }
1378
- };
1379
-
1380
- /**
1381
- Loads a blueprint from given path.
1382
- @static
1383
- @method load
1384
- @namespace Blueprint
1385
- @param {String} blueprintPath
1386
- @return {Blueprint} blueprint instance
1387
- */
1388
- Blueprint.load = function (blueprintPath) {
1389
- if (fs.lstatSync(blueprintPath).isDirectory()) {
1390
- let Constructor = Blueprint;
1391
-
1392
- let constructorPath = path.resolve(blueprintPath, &#x27;index.js&#x27;);
1393
- if (Blueprint._existsSync(constructorPath)) {
1394
- const blueprintModule = require(constructorPath);
1395
-
1396
- if (typeof blueprintModule === &#x27;function&#x27;) {
1397
- Constructor = blueprintModule;
1398
- } else {
1399
- Constructor = Blueprint.extend(blueprintModule);
1400
- }
1401
- }
1402
-
1403
- return new Constructor(blueprintPath);
1404
- }
1405
- };
1406
-
1407
- /**
1408
- @static
1409
- @method list
1410
- @namespace Blueprint
1411
- @param {Object} [options]
1412
- @param {Array} [options.paths] Extra paths to search for blueprints
1413
- @return {Array}
1414
- */
1415
- Blueprint.list = function (options) {
1416
- options = options || {};
1417
-
1418
- let lookupPaths = generateLookupPaths(options.paths);
1419
- let seen = [];
1420
-
1421
- return lookupPaths.map((lookupPath) =&gt; {
1422
- let source;
1423
- let packagePath = path.join(lookupPath, &#x27;../package.json&#x27;);
1424
- if (Blueprint._existsSync(packagePath)) {
1425
- source = require(packagePath).name;
1426
- } else {
1427
- source = path.basename(path.join(lookupPath, &#x27;..&#x27;));
1428
- }
1429
-
1430
- let blueprints = dir(lookupPath).map((blueprintPath) =&gt; {
1431
- let blueprint = Blueprint.load(blueprintPath);
1432
- if (blueprint) {
1433
- let name = blueprint.name;
1434
- blueprint.overridden = _.includes(seen, name);
1435
- seen.push(name);
1436
-
1437
- return blueprint;
1438
- }
1439
- });
1440
-
1441
- return {
1442
- source,
1443
- blueprints: _.compact(blueprints),
1444
- };
1445
- });
1446
- };
1447
-
1448
- Blueprint._existsSync = function (path, parent) {
1449
- return fs.existsSync(path, parent);
1450
- };
1451
-
1452
- Blueprint._readdirSync = function (path) {
1453
- return fs.readdirSync(path);
1454
- };
1455
-
1456
- /**
1457
- Files that are renamed when installed into the target directory.
1458
- This allows including files in the blueprint that would have an effect
1459
- on another process, such as a file named &#x60;.gitignore&#x60;.
1460
-
1461
- The keys are the filenames used in the files folder.
1462
- The values are the filenames used in the target directory.
1463
-
1464
- @static
1465
- @property renamedFiles
1466
- */
1467
- Blueprint.renamedFiles = {
1468
- gitignore: &#x27;.gitignore&#x27;,
1469
- };
1470
-
1471
- /**
1472
- @static
1473
- @property ignoredFiles
1474
- */
1475
- Blueprint.ignoredFiles = initialIgnoredFiles;
1476
-
1477
- /**
1478
- @static
1479
- @property ignoredUpdateFiles
1480
- */
1481
- Blueprint.ignoredUpdateFiles = [&#x27;.gitkeep&#x27;, &#x27;app.css&#x27;, &#x27;LICENSE.md&#x27;];
1482
-
1483
- /**
1484
- @static
1485
- @property defaultLookupPaths
1486
- */
1487
- Blueprint.defaultLookupPaths = function () {
1488
- return [path.resolve(__dirname, &#x27;..&#x27;, &#x27;..&#x27;, &#x27;blueprints&#x27;)];
1489
- };
1490
-
1491
- /**
1492
- @private
1493
- @method prepareConfirm
1494
- @param {FileInfo} info
1495
- @return {Promise}
1496
- */
1497
- function prepareConfirm(info) {
1498
- return info.checkForConflict().then((resolution) =&gt; {
1499
- info.resolution = resolution;
1500
- return info;
1501
- });
1502
- }
1503
-
1504
- /**
1505
- @private
1506
- @method markIdenticalToBeSkipped
1507
- @param {FileInfo} info
1508
- */
1509
- function markIdenticalToBeSkipped(info) {
1510
- if (info.resolution === &#x27;identical&#x27;) {
1511
- info.action = &#x27;skip&#x27;;
1512
- }
1513
- }
1514
-
1515
- /**
1516
- @private
1517
- @method markToBeRemoved
1518
- @param {FileInfo} info
1519
- */
1520
- function markToBeRemoved(info) {
1521
- info.action = &#x27;remove&#x27;;
1522
- }
1523
-
1524
- /**
1525
- @private
1526
- @method gatherConfirmationMessages
1527
- @param {Array} collection
1528
- @param {FileInfo} info
1529
- @return {Array}
1530
- */
1531
- function gatherConfirmationMessages(collection, info) {
1532
- if (info.resolution === &#x27;confirm&#x27;) {
1533
- collection.push(info.confirmOverwriteTask());
1534
- }
1535
- return collection;
1536
- }
1537
-
1538
- /**
1539
- @private
1540
- @method isIgnored
1541
- @param {FileInfo} info
1542
- @return {Boolean}
1543
- */
1544
- function isIgnored(info) {
1545
- let fn = info.inputPath;
1546
-
1547
- return Blueprint.ignoredFiles.some((ignoredFile) =&gt; minimatch(fn, ignoredFile, { matchBase: true }));
1548
- }
1549
-
1550
- /**
1551
- Combines provided lookup paths with defaults and removes
1552
- duplicates.
1553
-
1554
- @private
1555
- @method generateLookupPaths
1556
- @param {Array} lookupPaths
1557
- @return {Array}
1558
- */
1559
- function generateLookupPaths(lookupPaths) {
1560
- lookupPaths = lookupPaths || [];
1561
- lookupPaths = lookupPaths.concat(Blueprint.defaultLookupPaths());
1562
- return _.uniq(lookupPaths);
1563
- }
1564
-
1565
- /**
1566
- Looks for a __path__ token in the files folder. Must be present for
1567
- the blueprint to support pod tokens.
1568
-
1569
- @private
1570
- @method hasPathToken
1571
- @param {files} files
1572
- @return {Boolean}
1573
- */
1574
- function hasPathToken(files) {
1575
- return /__path__/.test(files.join());
1576
- }
1577
-
1578
- function findAddonByName(addonOrProject, name) {
1579
- let addon = addonOrProject.addons.find((addon) =&gt; addon.name === name);
1580
-
1581
- if (addon) {
1582
- return addon;
1583
- }
1584
-
1585
- return addonOrProject.addons.find((addon) =&gt; findAddonByName(addon, name));
1586
- }
1587
-
1588
- function ensureTargetDirIsAddon(addonPath) {
1589
- let projectInfo;
1590
-
1591
- try {
1592
- projectInfo = require(path.join(addonPath, &#x27;package.json&#x27;));
1593
- } catch (err) {
1594
- if (err.code === &#x27;MODULE_NOT_FOUND&#x27;) {
1595
- throw new Error(&#x60;The directory ${addonPath} does not appear to be a valid addon directory.&#x60;);
1596
- } else {
1597
- throw err;
1598
- }
1599
- }
1600
-
1601
- return isAddon(projectInfo.keywords);
1602
- }
1603
-
1604
- /**
1605
- @private
1606
- @method isValidFile
1607
- @param {Object} fileInfo
1608
- @return {Promise}
1609
- */
1610
- function isValidFile(fileInfo) {
1611
- if (isIgnored(fileInfo)) {
1612
- return false;
1613
- } else {
1614
- return isFilePath(fileInfo);
1615
- }
1616
- }
1617
-
1618
- /**
1619
- @private
1620
- @method isFilePath
1621
- @param {Object} fileInfo
1622
- @return {Promise}
1623
- */
1624
- function isFilePath(fileInfo) {
1625
- return fs.statSync(fileInfo.inputPath).isFile();
1626
- }
1627
-
1628
- /**
1629
- @private
1630
- @method dir
1631
- @return {Array} list of files in the given directory or and empty array if no directory exists
1632
- */
1633
- function dir(fullPath) {
1634
- if (Blueprint._existsSync(fullPath)) {
1635
- return Blueprint._readdirSync(fullPath).map((fileName) =&gt; path.join(fullPath, fileName));
1636
- } else {
1637
- return [];
1638
- }
1639
- }
1640
-
1641
- /**
1642
- @private
1643
- @method getDetailedHelpPath
1644
- @param {String} thisPath
1645
- @return {String} help path
1646
- */
1647
- function getDetailedHelpPath(thisPath) {
1648
- return path.join(thisPath, &#x27;./HELP.md&#x27;);
1649
- }
1650
-
1651
- function finishProcessingForInstall(infos) {
1652
- infos.forEach(markIdenticalToBeSkipped);
1653
-
1654
- let infosNeedingConfirmation = infos.reduce(gatherConfirmationMessages, []);
1655
-
1656
- return sequence(infosNeedingConfirmation).then(() =&gt; infos);
1657
- }
1658
-
1659
- function finishProcessingForUninstall(infos) {
1660
- let validInfos = infos.filter((info) =&gt; fs.existsSync(info.outputPath));
1661
- validInfos.forEach(markToBeRemoved);
1662
-
1663
- return validInfos;
1664
- }
1665
-
1666
- module.exports = Blueprint;
1667
-
1668
- </pre>
1669
-
1670
- </div>
1671
- </div>
1672
- </div>
1673
- </div>
1674
- <script src="../assets/vendor/prettify/prettify-min.js"></script>
1675
- <script>prettyPrint();</script>
1676
- <script src="../assets/js/yui-prettify.js"></script>
1677
- </body>
1678
- </html>