ember-source 4.4.0-alpha.7 → 4.5.0-alpha.2

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.
@@ -1,7 +1,7 @@
1
1
  export { getEngineParent, setEngineParent } from './lib/engine-parent';
2
2
  import { canInvoke } from '@ember/-internals/utils';
3
3
  import Controller from '@ember/controller';
4
- import { Namespace, RegistryProxyMixin } from '@ember/-internals/runtime';
4
+ import { Namespace } from '@ember/-internals/runtime';
5
5
  import { Registry } from '@ember/-internals/container';
6
6
  import DAG from 'dag-map';
7
7
  import { assert } from '@ember/debug';
@@ -11,6 +11,7 @@ import { RoutingService } from '@ember/-internals/routing';
11
11
  import { ContainerDebugAdapter } from '@ember/-internals/extension-support';
12
12
  import { ComponentLookup } from '@ember/-internals/views';
13
13
  import { setupEngineRegistry } from '@ember/-internals/glimmer';
14
+ import RegistryProxyMixin from '@ember/-internals/runtime/lib/mixins/registry_proxy';
14
15
 
15
16
  function props(obj) {
16
17
  let properties = [];
@@ -21,115 +22,141 @@ function props(obj) {
21
22
 
22
23
  return properties;
23
24
  }
24
- /**
25
- @module @ember/engine
26
- */
27
-
28
- /**
29
- The `Engine` class contains core functionality for both applications and
30
- engines.
31
-
32
- Each engine manages a registry that's used for dependency injection and
33
- exposed through `RegistryProxy`.
34
-
35
- Engines also manage initializers and instance initializers.
36
25
 
37
- Engines can spawn `EngineInstance` instances via `buildInstance()`.
26
+ class Engine extends Namespace.extend(RegistryProxyMixin) {
27
+ constructor() {
28
+ super(...arguments);
29
+ /**
30
+ A private flag indicating whether an engine's initializers have run yet.
31
+ @private
32
+ @property _initializersRan
33
+ */
38
34
 
39
- @class Engine
40
- @extends Ember.Namespace
41
- @uses RegistryProxy
42
- @public
43
- */
35
+ this._initializersRan = false;
36
+ }
37
+ /**
38
+ This creates a registry with the default Ember naming conventions.
39
+ It also configures the registry:
40
+ * registered views are created every time they are looked up (they are
41
+ not singletons)
42
+ * registered templates are not factories; the registered value is
43
+ returned directly.
44
+ * the router receives the application as its `namespace` property
45
+ * all controllers receive the router as their `target` and `controllers`
46
+ properties
47
+ * all controllers receive the application as their `namespace` property
48
+ * the application view receives the application controller as its
49
+ `controller` property
50
+ * the application view receives the application template as its
51
+ `defaultTemplate` property
52
+ @method buildRegistry
53
+ @static
54
+ @param {Application} namespace the application for which to
55
+ build the registry
56
+ @return {Ember.Registry} the built registry
57
+ @private
58
+ */
44
59
 
45
60
 
46
- const Engine = Namespace.extend(RegistryProxyMixin, {
47
- init() {
48
- this._super(...arguments);
61
+ static buildRegistry(namespace) {
62
+ let registry = new Registry({
63
+ resolver: resolverFor(namespace)
64
+ });
65
+ registry.set = set;
66
+ registry.register('application:main', namespace, {
67
+ instantiate: false
68
+ });
69
+ commonSetupRegistry(registry);
70
+ setupEngineRegistry(registry);
71
+ return registry;
72
+ }
49
73
 
74
+ init(properties) {
75
+ super.init(properties);
50
76
  this.buildRegistry();
51
- },
52
-
53
- /**
54
- A private flag indicating whether an engine's initializers have run yet.
55
- @private
56
- @property _initializersRan
57
- */
58
- _initializersRan: false,
59
-
77
+ }
60
78
  /**
61
79
  Ensure that initializers are run once, and only once, per engine.
62
- @private
80
+ @private
63
81
  @method ensureInitializers
64
82
  */
83
+
84
+
65
85
  ensureInitializers() {
66
86
  if (!this._initializersRan) {
67
87
  this.runInitializers();
68
88
  this._initializersRan = true;
69
89
  }
70
- },
71
-
90
+ }
72
91
  /**
73
92
  Create an EngineInstance for this engine.
74
- @public
93
+ @public
75
94
  @method buildInstance
76
95
  @return {EngineInstance} the engine instance
77
96
  */
97
+
98
+
78
99
  buildInstance(options = {}) {
79
100
  this.ensureInitializers();
80
- options.base = this;
81
- return EngineInstance.create(options);
82
- },
83
-
101
+ return EngineInstance.create(Object.assign(Object.assign({}, options), {
102
+ base: this
103
+ }));
104
+ }
84
105
  /**
85
106
  Build and configure the registry for the current engine.
86
- @private
107
+ @private
87
108
  @method buildRegistry
88
109
  @return {Ember.Registry} the configured registry
89
110
  */
111
+
112
+
90
113
  buildRegistry() {
91
114
  let registry = this.__registry__ = this.constructor.buildRegistry(this);
92
115
  return registry;
93
- },
94
-
116
+ }
95
117
  /**
96
118
  @private
97
119
  @method initializer
98
120
  */
99
- initializer(options) {
100
- this.constructor.initializer(options);
101
- },
102
121
 
122
+
123
+ initializer(initializer) {
124
+ this.constructor.initializer(initializer);
125
+ }
103
126
  /**
104
127
  @private
105
128
  @method instanceInitializer
106
129
  */
107
- instanceInitializer(options) {
108
- this.constructor.instanceInitializer(options);
109
- },
110
130
 
131
+
132
+ instanceInitializer(initializer) {
133
+ this.constructor.instanceInitializer(initializer);
134
+ }
111
135
  /**
112
136
  @private
113
137
  @method runInitializers
114
138
  */
139
+
140
+
115
141
  runInitializers() {
116
142
  this._runInitializer('initializers', (name, initializer) => {
117
- assert(`No application initializer named '${name}'`, Boolean(initializer));
143
+ assert(`No application initializer named '${name}'`, initializer);
118
144
  initializer.initialize(this);
119
145
  });
120
- },
121
-
146
+ }
122
147
  /**
123
148
  @private
124
149
  @since 1.12.0
125
150
  @method runInstanceInitializers
126
151
  */
152
+
153
+
127
154
  runInstanceInitializers(instance) {
128
155
  this._runInitializer('instanceInitializers', (name, initializer) => {
129
- assert(`No instance initializer named '${name}'`, Boolean(initializer));
156
+ assert(`No instance initializer named '${name}'`, initializer);
130
157
  initializer.initialize(instance);
131
158
  });
132
- },
159
+ }
133
160
 
134
161
  _runInitializer(bucketName, cb) {
135
162
  let initializersByName = get(this.constructor, bucketName);
@@ -137,232 +164,238 @@ const Engine = Namespace.extend(RegistryProxyMixin, {
137
164
  let graph = new DAG();
138
165
  let initializer;
139
166
 
140
- for (let i = 0; i < initializers.length; i++) {
141
- initializer = initializersByName[initializers[i]];
167
+ for (let name of initializers) {
168
+ initializer = initializersByName[name];
169
+ assert(`missing ${bucketName}: ${name}`, initializer);
142
170
  graph.add(initializer.name, initializer, initializer.before, initializer.after);
143
171
  }
144
172
 
145
173
  graph.topsort(cb);
146
174
  }
147
175
 
148
- });
149
- Engine.reopenClass({
150
- initializers: Object.create(null),
151
- instanceInitializers: Object.create(null),
176
+ }
152
177
 
153
- /**
154
- The goal of initializers should be to register dependencies and injections.
155
- This phase runs once. Because these initializers may load code, they are
156
- allowed to defer application readiness and advance it. If you need to access
157
- the container or store you should use an InstanceInitializer that will be run
158
- after all initializers and therefore after all code is loaded and the app is
159
- ready.
160
- Initializer receives an object which has the following attributes:
161
- `name`, `before`, `after`, `initialize`. The only required attribute is
162
- `initialize`, all others are optional.
163
- * `name` allows you to specify under which name the initializer is registered.
164
- This must be a unique name, as trying to register two initializers with the
165
- same name will result in an error.
166
- ```app/initializer/named-initializer.js
167
- import { debug } from '@ember/debug';
168
- export function initialize() {
169
- debug('Running namedInitializer!');
170
- }
171
- export default {
172
- name: 'named-initializer',
173
- initialize
174
- };
175
- ```
176
- * `before` and `after` are used to ensure that this initializer is ran prior
177
- or after the one identified by the value. This value can be a single string
178
- or an array of strings, referencing the `name` of other initializers.
179
- An example of ordering initializers, we create an initializer named `first`:
180
- ```app/initializer/first.js
181
- import { debug } from '@ember/debug';
182
- export function initialize() {
183
- debug('First initializer!');
184
- }
185
- export default {
186
- name: 'first',
187
- initialize
188
- };
189
- ```
190
- ```bash
191
- // DEBUG: First initializer!
192
- ```
193
- We add another initializer named `second`, specifying that it should run
194
- after the initializer named `first`:
195
- ```app/initializer/second.js
196
- import { debug } from '@ember/debug';
197
- export function initialize() {
198
- debug('Second initializer!');
199
- }
200
- export default {
201
- name: 'second',
202
- after: 'first',
203
- initialize
204
- };
205
- ```
206
- ```
207
- // DEBUG: First initializer!
208
- // DEBUG: Second initializer!
209
- ```
210
- Afterwards we add a further initializer named `pre`, this time specifying
211
- that it should run before the initializer named `first`:
212
- ```app/initializer/pre.js
213
- import { debug } from '@ember/debug';
214
- export function initialize() {
215
- debug('Pre initializer!');
216
- }
217
- export default {
218
- name: 'pre',
219
- before: 'first',
220
- initialize
221
- };
222
- ```
223
- ```bash
224
- // DEBUG: Pre initializer!
225
- // DEBUG: First initializer!
226
- // DEBUG: Second initializer!
227
- ```
228
- Finally we add an initializer named `post`, specifying it should run after
229
- both the `first` and the `second` initializers:
230
- ```app/initializer/post.js
231
- import { debug } from '@ember/debug';
232
- export function initialize() {
233
- debug('Post initializer!');
234
- }
235
- export default {
236
- name: 'post',
237
- after: ['first', 'second'],
238
- initialize
239
- };
240
- ```
241
- ```bash
242
- // DEBUG: Pre initializer!
243
- // DEBUG: First initializer!
244
- // DEBUG: Second initializer!
245
- // DEBUG: Post initializer!
246
- ```
247
- * `initialize` is a callback function that receives one argument,
248
- `application`, on which you can operate.
249
- Example of using `application` to register an adapter:
250
- ```app/initializer/api-adapter.js
251
- import ApiAdapter from '../utils/api-adapter';
252
- export function initialize(application) {
253
- application.register('api-adapter:main', ApiAdapter);
254
- }
255
- export default {
256
- name: 'post',
257
- after: ['first', 'second'],
258
- initialize
259
- };
260
- ```
261
- @method initializer
262
- @param initializer {Object}
263
- @public
264
- */
265
- initializer: buildInitializerMethod('initializers', 'initializer'),
178
+ Engine.initializers = Object.create(null);
179
+ Engine.instanceInitializers = Object.create(null);
180
+ /**
181
+ The goal of initializers should be to register dependencies and injections.
182
+ This phase runs once. Because these initializers may load code, they are
183
+ allowed to defer application readiness and advance it. If you need to access
184
+ the container or store you should use an InstanceInitializer that will be run
185
+ after all initializers and therefore after all code is loaded and the app is
186
+ ready.
187
+
188
+ Initializer receives an object which has the following attributes:
189
+ `name`, `before`, `after`, `initialize`. The only required attribute is
190
+ `initialize`, all others are optional.
191
+
192
+ * `name` allows you to specify under which name the initializer is registered.
193
+ This must be a unique name, as trying to register two initializers with the
194
+ same name will result in an error.
195
+
196
+ ```app/initializer/named-initializer.js
197
+ import { debug } from '@ember/debug';
198
+
199
+ export function initialize() {
200
+ debug('Running namedInitializer!');
201
+ }
266
202
 
267
- /**
268
- Instance initializers run after all initializers have run. Because
269
- instance initializers run after the app is fully set up. We have access
270
- to the store, container, and other items. However, these initializers run
271
- after code has loaded and are not allowed to defer readiness.
272
- Instance initializer receives an object which has the following attributes:
273
- `name`, `before`, `after`, `initialize`. The only required attribute is
274
- `initialize`, all others are optional.
275
- * `name` allows you to specify under which name the instanceInitializer is
276
- registered. This must be a unique name, as trying to register two
277
- instanceInitializer with the same name will result in an error.
278
- ```app/initializer/named-instance-initializer.js
279
- import { debug } from '@ember/debug';
280
- export function initialize() {
281
- debug('Running named-instance-initializer!');
282
- }
283
- export default {
284
- name: 'named-instance-initializer',
285
- initialize
286
- };
287
- ```
288
- * `before` and `after` are used to ensure that this initializer is ran prior
289
- or after the one identified by the value. This value can be a single string
290
- or an array of strings, referencing the `name` of other initializers.
291
- * See Application.initializer for discussion on the usage of before
292
- and after.
293
- Example instanceInitializer to preload data into the store.
294
- ```app/initializer/preload-data.js
295
- export function initialize(application) {
296
- var userConfig, userConfigEncoded, store;
297
- // We have a HTML escaped JSON representation of the user's basic
298
- // configuration generated server side and stored in the DOM of the main
299
- // index.html file. This allows the app to have access to a set of data
300
- // without making any additional remote calls. Good for basic data that is
301
- // needed for immediate rendering of the page. Keep in mind, this data,
302
- // like all local models and data can be manipulated by the user, so it
303
- // should not be relied upon for security or authorization.
304
- // Grab the encoded data from the meta tag
305
- userConfigEncoded = document.querySelector('head meta[name=app-user-config]').attr('content');
306
- // Unescape the text, then parse the resulting JSON into a real object
307
- userConfig = JSON.parse(unescape(userConfigEncoded));
308
- // Lookup the store
309
- store = application.lookup('service:store');
310
- // Push the encoded JSON into the store
311
- store.pushPayload(userConfig);
312
- }
313
- export default {
314
- name: 'named-instance-initializer',
315
- initialize
316
- };
317
- ```
318
- @method instanceInitializer
319
- @param instanceInitializer
320
- @public
321
- */
322
- instanceInitializer: buildInitializerMethod('instanceInitializers', 'instance initializer'),
203
+ export default {
204
+ name: 'named-initializer',
205
+ initialize
206
+ };
207
+ ```
323
208
 
324
- /**
325
- This creates a registry with the default Ember naming conventions.
326
- It also configures the registry:
327
- * registered views are created every time they are looked up (they are
328
- not singletons)
329
- * registered templates are not factories; the registered value is
330
- returned directly.
331
- * the router receives the application as its `namespace` property
332
- * all controllers receive the router as their `target` and `controllers`
333
- properties
334
- * all controllers receive the application as their `namespace` property
335
- * the application view receives the application controller as its
336
- `controller` property
337
- * the application view receives the application template as its
338
- `defaultTemplate` property
339
- @method buildRegistry
340
- @static
341
- @param {Application} namespace the application for which to
342
- build the registry
343
- @return {Ember.Registry} the built registry
344
- @private
345
- */
346
- buildRegistry(namespace) {
347
- let registry = new Registry({
348
- resolver: resolverFor(namespace)
349
- });
350
- registry.set = set;
351
- registry.register('application:main', namespace, {
352
- instantiate: false
353
- });
354
- commonSetupRegistry(registry);
355
- setupEngineRegistry(registry);
356
- return registry;
357
- },
209
+ * `before` and `after` are used to ensure that this initializer is ran prior
210
+ or after the one identified by the value. This value can be a single string
211
+ or an array of strings, referencing the `name` of other initializers.
358
212
 
359
- /**
360
- Set this to provide an alternate class to `DefaultResolver`
361
- @property resolver
362
- @public
363
- */
364
- Resolver: null
365
- });
213
+ An example of ordering initializers, we create an initializer named `first`:
214
+
215
+ ```app/initializer/first.js
216
+ import { debug } from '@ember/debug';
217
+
218
+ export function initialize() {
219
+ debug('First initializer!');
220
+ }
221
+
222
+ export default {
223
+ name: 'first',
224
+ initialize
225
+ };
226
+ ```
227
+
228
+ ```bash
229
+ // DEBUG: First initializer!
230
+ ```
231
+
232
+ We add another initializer named `second`, specifying that it should run
233
+ after the initializer named `first`:
234
+
235
+ ```app/initializer/second.js
236
+ import { debug } from '@ember/debug';
237
+
238
+ export function initialize() {
239
+ debug('Second initializer!');
240
+ }
241
+
242
+ export default {
243
+ name: 'second',
244
+ after: 'first',
245
+ initialize
246
+ };
247
+ ```
248
+
249
+ ```
250
+ // DEBUG: First initializer!
251
+ // DEBUG: Second initializer!
252
+ ```
253
+
254
+ Afterwards we add a further initializer named `pre`, this time specifying
255
+ that it should run before the initializer named `first`:
256
+
257
+ ```app/initializer/pre.js
258
+ import { debug } from '@ember/debug';
259
+
260
+ export function initialize() {
261
+ debug('Pre initializer!');
262
+ }
263
+
264
+ export default {
265
+ name: 'pre',
266
+ before: 'first',
267
+ initialize
268
+ };
269
+ ```
270
+
271
+ ```bash
272
+ // DEBUG: Pre initializer!
273
+ // DEBUG: First initializer!
274
+ // DEBUG: Second initializer!
275
+ ```
276
+
277
+ Finally we add an initializer named `post`, specifying it should run after
278
+ both the `first` and the `second` initializers:
279
+
280
+ ```app/initializer/post.js
281
+ import { debug } from '@ember/debug';
282
+
283
+ export function initialize() {
284
+ debug('Post initializer!');
285
+ }
286
+
287
+ export default {
288
+ name: 'post',
289
+ after: ['first', 'second'],
290
+ initialize
291
+ };
292
+ ```
293
+
294
+ ```bash
295
+ // DEBUG: Pre initializer!
296
+ // DEBUG: First initializer!
297
+ // DEBUG: Second initializer!
298
+ // DEBUG: Post initializer!
299
+ ```
300
+
301
+ * `initialize` is a callback function that receives one argument,
302
+ `application`, on which you can operate.
303
+
304
+ Example of using `application` to register an adapter:
305
+
306
+ ```app/initializer/api-adapter.js
307
+ import ApiAdapter from '../utils/api-adapter';
308
+
309
+ export function initialize(application) {
310
+ application.register('api-adapter:main', ApiAdapter);
311
+ }
312
+
313
+ export default {
314
+ name: 'post',
315
+ after: ['first', 'second'],
316
+ initialize
317
+ };
318
+ ```
319
+
320
+ @method initializer
321
+ @param initializer {Object}
322
+ @public
323
+ */
324
+
325
+ Engine.initializer = buildInitializerMethod('initializers', 'initializer');
326
+ /**
327
+ Instance initializers run after all initializers have run. Because
328
+ instance initializers run after the app is fully set up. We have access
329
+ to the store, container, and other items. However, these initializers run
330
+ after code has loaded and are not allowed to defer readiness.
331
+
332
+ Instance initializer receives an object which has the following attributes:
333
+ `name`, `before`, `after`, `initialize`. The only required attribute is
334
+ `initialize`, all others are optional.
335
+
336
+ * `name` allows you to specify under which name the instanceInitializer is
337
+ registered. This must be a unique name, as trying to register two
338
+ instanceInitializer with the same name will result in an error.
339
+
340
+ ```app/initializer/named-instance-initializer.js
341
+ import { debug } from '@ember/debug';
342
+
343
+ export function initialize() {
344
+ debug('Running named-instance-initializer!');
345
+ }
346
+
347
+ export default {
348
+ name: 'named-instance-initializer',
349
+ initialize
350
+ };
351
+ ```
352
+
353
+ * `before` and `after` are used to ensure that this initializer is ran prior
354
+ or after the one identified by the value. This value can be a single string
355
+ or an array of strings, referencing the `name` of other initializers.
356
+
357
+ * See Application.initializer for discussion on the usage of before
358
+ and after.
359
+
360
+ Example instanceInitializer to preload data into the store.
361
+
362
+ ```app/initializer/preload-data.js
363
+
364
+ export function initialize(application) {
365
+ var userConfig, userConfigEncoded, store;
366
+ // We have a HTML escaped JSON representation of the user's basic
367
+ // configuration generated server side and stored in the DOM of the main
368
+ // index.html file. This allows the app to have access to a set of data
369
+ // without making any additional remote calls. Good for basic data that is
370
+ // needed for immediate rendering of the page. Keep in mind, this data,
371
+ // like all local models and data can be manipulated by the user, so it
372
+ // should not be relied upon for security or authorization.
373
+
374
+ // Grab the encoded data from the meta tag
375
+ userConfigEncoded = document.querySelector('head meta[name=app-user-config]').attr('content');
376
+
377
+ // Unescape the text, then parse the resulting JSON into a real object
378
+ userConfig = JSON.parse(unescape(userConfigEncoded));
379
+
380
+ // Lookup the store
381
+ store = application.lookup('service:store');
382
+
383
+ // Push the encoded JSON into the store
384
+ store.pushPayload(userConfig);
385
+ }
386
+
387
+ export default {
388
+ name: 'named-instance-initializer',
389
+ initialize
390
+ };
391
+ ```
392
+
393
+ @method instanceInitializer
394
+ @param instanceInitializer
395
+ @public
396
+ */
397
+
398
+ Engine.instanceInitializer = buildInitializerMethod('instanceInitializers', 'instance initializer');
366
399
  /**
367
400
  This function defines the default lookup rules for container lookups:
368
401
 
@@ -376,12 +409,12 @@ Engine.reopenClass({
376
409
 
377
410
  @private
378
411
  @method resolverFor
379
- @param {Ember.Namespace} namespace the namespace to look for classes
412
+ @param {Ember.Enginer} namespace the namespace to look for classes
380
413
  @return {*} the resolved value for a given lookup
381
414
  */
382
415
 
383
416
  function resolverFor(namespace) {
384
- let ResolverClass = get(namespace, 'Resolver');
417
+ let ResolverClass = namespace.Resolver;
385
418
  let props = {
386
419
  namespace
387
420
  };
@@ -394,16 +427,21 @@ function buildInitializerMethod(bucketName, humanName) {
394
427
  // to make sure we have a new `initializers` object, which extends from the parent class' using
395
428
  // prototypal inheritance. Without this, attempting to add initializers to the subclass would
396
429
  // pollute the parent class as well as other subclasses.
397
- if (this.superclass[bucketName] !== undefined && this.superclass[bucketName] === this[bucketName]) {
398
- let attrs = {};
399
- attrs[bucketName] = Object.create(this[bucketName]);
430
+ // SAFETY: The superclass may be an Engine, we don't call unless we confirmed it was ok.
431
+ let superclass = this.superclass;
432
+
433
+ if (superclass[bucketName] !== undefined && superclass[bucketName] === this[bucketName]) {
434
+ let attrs = {
435
+ [bucketName]: Object.create(this[bucketName])
436
+ };
400
437
  this.reopenClass(attrs);
401
438
  }
402
439
 
403
440
  assert(`The ${humanName} '${initializer.name}' has already been registered`, !this[bucketName][initializer.name]);
404
441
  assert(`An ${humanName} cannot be registered without an initialize function`, canInvoke(initializer, 'initialize'));
405
442
  assert(`An ${humanName} cannot be registered without a name property`, initializer.name !== undefined);
406
- this[bucketName][initializer.name] = initializer;
443
+ let initializers = this[bucketName];
444
+ initializers[initializer.name] = initializer;
407
445
  };
408
446
  }
409
447