UNPKG

22.1 kBTypeScriptView Raw
1declare module '@ember/-internals/owner' {
2 /**
3 @module @ember/owner
4 */
5 /**
6 The name for a factory consists of a namespace and the name of a specific type
7 within that namespace, like `'service:session'`.
8
9 **Note:** `FullName` is *not* a class, just a contract for strings used in the
10 DI system. It is currently documented as a class only due to limits in our
11 documentation infrastructure.
12
13 @for @ember/owner
14 @class FullName
15 @public
16 */
17 export type FullName<
18 Type extends string = string,
19 Name extends string = string
20 > = `${Type}:${Name}`;
21 /**
22 A type registry for the DI system, which other participants in the DI system
23 can register themselves into with declaration merging. The contract for this
24 type is that its keys are the `Type` from a `FullName`, and each value for a
25 `Type` is another registry whose keys are the `Name` from a `FullName`. The
26 mechanic for providing a registry is [declaration merging][handbook].
27
28 [handbook]: https://www.typescriptlang.org/docs/handbook/declaration-merging.html
29
30 For example, Ember's `@ember/service` module includes this set of definitions:
31
32 ```ts
33 export default class Service extends EmberObject {}
34
35 // For concrete singleton classes to be merged into.
36 interface Registry extends Record<string, Service> {}
37
38 declare module '@ember/owner' {
39 service: Registry;
40 }
41 ```
42
43 Declarations of services can then include the registry:
44
45 ```ts
46 import Service from '@ember/service';
47
48 export default class Session extends Service {
49 login(username: string, password: string) {
50 // ...
51 }
52 }
53
54 declare module '@ember/service' {
55 interface Registry {
56 session: Session;
57 }
58 }
59 ```
60
61 Then users of the `Owner` API will be able to do things like this with strong
62 type safety guarantees:
63
64 ```ts
65 getOwner(this)?.lookup('service:session').login("hello", "1234abcd");
66 ```
67
68 @for @ember/owner
69 @private
70 */
71 export interface DIRegistry {}
72 /**
73 @private
74 */
75 type ResolveFactoryManager<Type extends string, Name extends string> = Type extends ValidType
76 ? Name extends ValidName<Type>
77 ? DIRegistry[Type][Name] extends infer RegistryEntry extends object
78 ? FactoryManager<RegistryEntry>
79 : FactoryManagerDefault
80 : FactoryManagerDefault
81 : FactoryManagerDefault;
82 type FactoryManagerDefault = FactoryManager<object> | undefined;
83 type Lookup<Type extends string, Name extends string> = Type extends ValidType
84 ? Name extends ValidName<Type>
85 ? DIRegistry[Type][Name]
86 : unknown
87 : unknown;
88 /**
89 The common interface for the ability to `register()` an item, shared by the
90 `Owner` and `RegistryProxy` interfaces.
91
92 @for @ember/owner
93 @class BasicRegistry
94 @private
95 */
96 interface BasicRegistry {
97 /**
98 Registers a factory that can be used for dependency injection (with
99 `inject`) or for service lookup. Each factory is registered with
100 a full name including two parts: `type:name`.
101
102 A simple example:
103
104 ```javascript
105 import Application from '@ember/application';
106 import EmberObject from '@ember/object';
107
108 let App = Application.create();
109
110 App.Orange = EmberObject.extend();
111 App.register('fruit:favorite', App.Orange);
112 ```
113
114 Ember will resolve factories from the `App` namespace automatically.
115 For example `App.CarsController` will be discovered and returned if
116 an application requests `controller:cars`.
117
118 An example of registering a controller with a non-standard name:
119
120 ```javascript
121 import Application from '@ember/application';
122 import Controller from '@ember/controller';
123
124 let App = Application.create();
125 let Session = Controller.extend();
126
127 App.register('controller:session', Session);
128
129 // The Session controller can now be treated like a normal controller,
130 // despite its non-standard name.
131 App.ApplicationController = Controller.extend({
132 needs: ['session']
133 });
134 ```
135
136 Registered factories are **instantiated** by having `create`
137 called on them. Additionally they are **singletons**, each time
138 they are looked up they return the same instance.
139
140 Some examples modifying that default behavior:
141
142 ```javascript
143 import Application from '@ember/application';
144 import EmberObject from '@ember/object';
145
146 let App = Application.create();
147
148 App.Person = EmberObject.extend();
149 App.Orange = EmberObject.extend();
150 App.Email = EmberObject.extend();
151 App.session = EmberObject.create();
152
153 App.register('model:user', App.Person, { singleton: false });
154 App.register('fruit:favorite', App.Orange);
155 App.register('communication:main', App.Email, { singleton: false });
156 App.register('session', App.session, { instantiate: false });
157 ```
158
159 @method register
160 @param fullName {String} type:name (e.g., 'model:user')
161 @param factory {Factory|object} (e.g., App.Person)
162 @param options {Object} (optional) disable instantiation or singleton usage
163 @public
164 */
165 register(
166 fullName: FullName,
167 factory: Factory<object> | object,
168 options?: RegisterOptions
169 ): void;
170 }
171 type ValidType = keyof DIRegistry & string;
172 type ValidName<Type extends ValidType> = keyof DIRegistry[Type] & string;
173 /**
174 The common interface for the ability to `lookup()` or get the `factoryFor` an
175 item, shared by the `Owner` and `ContainerProxy` interfaces.
176
177 @for @ember/owner
178 @class BasicContainer
179 @private
180 */
181 interface BasicContainer {
182 /**
183 Given a fullName return a corresponding instance.
184
185 The default behavior is for lookup to return a singleton instance.
186 The singleton is scoped to the container, allowing multiple containers
187 to all have their own locally scoped singletons.
188
189 ```javascript
190 let registry = new Registry();
191 let container = registry.container();
192
193 registry.register('api:twitter', Twitter);
194
195 let twitter = container.lookup('api:twitter');
196
197 twitter instanceof Twitter; // => true
198
199 // by default the container will return singletons
200 let twitter2 = container.lookup('api:twitter');
201 twitter2 instanceof Twitter; // => true
202
203 twitter === twitter2; //=> true
204 ```
205
206 If singletons are not wanted an optional flag can be provided at lookup.
207
208 ```javascript
209 let registry = new Registry();
210 let container = registry.container();
211
212 registry.register('api:twitter', Twitter);
213
214 let twitter = container.lookup('api:twitter', { singleton: false });
215 let twitter2 = container.lookup('api:twitter', { singleton: false });
216
217 twitter === twitter2; //=> false
218 ```
219
220 @public
221 @method lookup
222 @param {string} fullName
223 @param {RegisterOptions} options
224 @return {any}
225 */
226 lookup<Type extends string, Name extends string>(
227 fullName: FullName<Type, Name>,
228 options?: RegisterOptions
229 ): Lookup<Type, Name>;
230 /**
231 Given a `FullName`, of the form `"type:name"` return a `FactoryManager`.
232
233 This method returns a manager which can be used for introspection of the
234 factory's class or for the creation of factory instances with initial
235 properties. The manager is an object with the following properties:
236
237 * `class` - The registered or resolved class.
238 * `create` - A function that will create an instance of the class with
239 any dependencies injected.
240
241 For example:
242
243 ```javascript
244 import { getOwner } from '@ember/application';
245
246 let owner = getOwner(otherInstance);
247 // the owner is commonly the `applicationInstance`, and can be accessed via
248 // an instance initializer.
249
250 let factory = owner.factoryFor('service:bespoke');
251
252 factory.class;
253 // The registered or resolved class. For example when used with an Ember-CLI
254 // app, this would be the default export from `app/services/bespoke.js`.
255
256 let instance = factory.create({
257 someProperty: 'an initial property value'
258 });
259 // Create an instance with any injections and the passed options as
260 // initial properties.
261 ```
262
263 Any instances created via the factory's `.create()` method *must* be destroyed
264 manually by the caller of `.create()`. Typically, this is done during the creating
265 objects own `destroy` or `willDestroy` methods.
266
267 @public
268 @method factoryFor
269 @param {string} fullName
270 @return {FactoryManager}
271 */
272 factoryFor<Type extends string, Name extends string>(
273 fullName: FullName<Type, Name>
274 ): ResolveFactoryManager<Type, Name>;
275 }
276 /**
277 Framework objects in an Ember application (components, services, routes,
278 etc.) are created via a factory and dependency injection system. Each of
279 these objects is the responsibility of an "owner", which handles its
280 instantiation and manages its lifetime.
281
282 An `Owner` is not a class you construct; it is one the framework constructs
283 for you. The normal way to get access to the relevant `Owner` is using the
284 `getOwner` function.
285
286 @for @ember/owner
287 @uses BasicRegistry
288 @uses BasicContainer
289 @class Owner
290 @since 4.10.0
291 @public
292 */
293 export default interface Owner extends BasicRegistry, BasicContainer {}
294 /**
295 * Interface representing the options for registering an item as a factory.
296 *
297 * @for @ember/owner
298 * @class RegisterOptions
299 * @public
300 */
301 export interface RegisterOptions {
302 /**
303 Whether to instantiate the item when returning it from a lookup. Defaults
304 to `true`.
305
306 @property instantiate
307 @type Boolean
308 @optional
309 @default true
310 @public
311 */
312 instantiate?: boolean | undefined;
313 /**
314 Whether the item is a singleton (like a service) and so should return the
315 same instance every time, or should generate a new instance on each call.
316 Defaults to `true`.
317
318 @property singleton
319 @type Boolean
320 @optional
321 @default true
322 @public
323 */
324 singleton?: boolean | undefined;
325 }
326 /**
327 Registered factories are instantiated by having create called on them.
328 Additionally they are singletons by default, so each time they are looked up
329 they return the same instance.
330
331 However, that behavior can be modified with the `instantiate` and `singleton`
332 options to the `Owner.register()` method.
333
334 @for @ember/owner
335 @class Factory
336 @since 4.10.0
337 @public
338 */
339 export interface Factory<T extends object> {
340 /**
341 * A function that will create an instance of the class with any
342 * dependencies injected.
343 *
344 * @method create
345 * @param initialValues {Object} Any values to set on an instance of the class
346 * @return {Object} The item produced by the factory.
347 * @public
348 */
349 create(initialValues?: object): T;
350 }
351 /**
352 The interface representing a manager which can be used for introspection of
353 the factory's class or for the creation of factory instances with initial
354 properties. The manager is an object with the following properties:
355
356 - `class` - The registered or resolved class.
357 - `create` - A function that will create an instance of the class with any
358 dependencies injected.
359
360 **Note:** `FactoryManager` is *not* user-constructible; the only legal way
361 to get a `FactoryManager` is via `Owner.factoryFor`.
362
363 @for @ember/owner
364 @class FactoryManager
365 @extends Factory
366 @public
367 */
368 export interface FactoryManager<T extends object> extends Factory<T> {
369 /**
370 The registered or resolved class.
371
372 @property class
373 @type Factory
374 @public
375 */
376 readonly class: Factory<T>;
377 }
378 /**
379 * A record mapping all known items of a given type: if the item is known it
380 * will be `true`; otherwise it will be `false` or `undefined`.
381 */
382 export type KnownForTypeResult<Type extends string> = {
383 [Key in FullName<Type, string>]: boolean | undefined;
384 };
385 /**
386 A `Resolver` is the mechanism responsible for looking up code in your
387 application and converting its naming conventions into the actual classes,
388 functions, and templates that Ember needs to resolve its dependencies, for
389 example, what template to render for a given route. It is a system that helps
390 the app resolve the lookup of JavaScript modules agnostic of what kind of
391 module system is used, which can be AMD, CommonJS or just plain globals. It
392 is used to lookup routes, models, components, templates, or anything that is
393 used in your Ember app.
394
395 This interface is not a concrete class; instead, it represents the contract a
396 custom resolver must implement. Most apps never need to think about this: in
397 the default blueprint, this is supplied by the `ember-resolver` package.
398
399 @for @ember/owner
400 @class Resolver
401 @since 4.10.0
402 @public
403 */
404 export interface Resolver {
405 /**
406 The one required method for a `Resolver`. Given a string, resolve it to a
407 `Factory`, if one exists.
408
409 @method resolve
410 @param name {String}
411 @public
412 */
413 resolve: (name: string) => Factory<object> | object | undefined;
414 /**
415 @method knownForType
416 @param type {String}
417 @return {Object}
418 @public
419 */
420 knownForType?: <Type extends string>(type: Type) => KnownForTypeResult<Type>;
421 /**
422 @method lookupDescription
423 @param fullName {String}
424 @return {String}
425 @public
426 */
427 lookupDescription?: (fullName: FullName) => string;
428 /**
429 @method makeToString
430 @param factory {Factory}
431 @param fullName {String}
432 @return {String}
433 @public
434 */
435 makeToString?: (factory: Factory<object>, fullName: FullName) => string;
436 /**
437 @method normalize
438 @param fullName {String}
439 @return {String}
440 @public
441 */
442 normalize?: (fullName: FullName) => FullName;
443 }
444 export interface FactoryClass {
445 positionalParams?: string | string[] | undefined | null;
446 }
447 /**
448 The internal representation of a `Factory`, for the extra detail available for
449 private use internally than we expose to consumers.
450
451 @for @ember/owner
452 @class InternalFactory
453 @private
454 */
455 export interface InternalFactory<T extends object, C extends FactoryClass | object = FactoryClass>
456 extends Factory<T> {
457 /**
458 @property class
459 @optional
460 @private
461 */
462 class?: C;
463 /**
464 @property name
465 @type String
466 @optional
467 @private
468 */
469 name?: string;
470 /**
471 @property fullName
472 @type String
473 @optional
474 @private
475 */
476 fullName?: FullName;
477 /**
478 @property normalizedName
479 @type String
480 @optional
481 @private
482 */
483 normalizedName?: string;
484 }
485 /**
486 @private
487 @method isFactory
488 @param {Object} obj
489 @return {Boolean}
490 @static
491 */
492 export function isFactory(obj: unknown): obj is InternalFactory<object>;
493 export function getOwner(object: object): InternalOwner | undefined;
494 /**
495 `setOwner` forces a new owner on a given object instance. This is primarily
496 useful in some testing cases.
497
498 @method setOwner
499 @static
500 @for @ember/owner
501 @param {Object} object An object instance.
502 @param {Owner} object The new owner object of the object instance.
503 @since 2.3.0
504 @public
505 */
506 export function setOwner(object: object, owner: Owner): void;
507 /**
508 * The interface for a container proxy, which is itself a private API used
509 * by the private `ContainerProxyMixin` as part of the base definition of
510 * `EngineInstance`.
511 *
512 * @class ContainerProxy
513 * @for @ember/owner
514 * @private
515 * @extends BasicContainer
516 */
517 export interface ContainerProxy extends BasicContainer {
518 /**
519 Returns an object that can be used to provide an owner to a
520 manually created instance.
521
522 Example:
523
524 ```
525 import { getOwner } from '@ember/application';
526
527 let owner = getOwner(this);
528
529 User.create(
530 owner.ownerInjection(),
531 { username: 'rwjblue' }
532 )
533 ```
534
535 @public
536 @method ownerInjection
537 @since 2.3.0
538 @return {Object}
539 */
540 ownerInjection(): object;
541 }
542 /**
543 * @class RegistryProxy
544 * @extends BasicRegistry
545 * @private
546 * @for @ember/owner
547 */
548 export interface RegistryProxy extends BasicRegistry {
549 /**
550 Given a fullName return the corresponding factory.
551
552 @public
553 @method resolveRegistration
554 @param fullName {String}
555 @return {Function} fullName's factory
556 */
557 resolveRegistration(fullName: FullName): Factory<object> | object | undefined;
558 /**
559 Unregister a factory.
560
561 ```javascript
562 import Application from '@ember/application';
563 import EmberObject from '@ember/object';
564
565 let App = Application.create();
566 let User = EmberObject.extend();
567 App.register('model:user', User);
568
569 App.resolveRegistration('model:user').create() instanceof User //=> true
570
571 App.unregister('model:user')
572 App.resolveRegistration('model:user') === undefined //=> true
573 ```
574
575 @public
576 @method unregister
577 @param {String} fullName
578 */
579 unregister(fullName: FullName): void;
580 /**
581 Check if a factory is registered.
582
583 @public
584 @method hasRegistration
585 @param {String} fullName
586 @return {Boolean}
587 */
588 hasRegistration(fullName: FullName): boolean;
589 /**
590 Return a specific registered option for a particular factory.
591
592 @public
593 @method registeredOption
594 @param {String} fullName
595 @param {String} optionName
596 @return {Object} options
597 */
598 registeredOption<K extends keyof RegisterOptions>(
599 fullName: FullName,
600 optionName: K
601 ): RegisterOptions[K] | undefined;
602 /**
603 Register options for a particular factory.
604
605 @public
606 @method registerOptions
607 @param {String} fullName
608 @param {Object} options
609 */
610 registerOptions(fullName: FullName, options: RegisterOptions): void;
611 /**
612 Return registered options for a particular factory.
613
614 @public
615 @method registeredOptions
616 @param {String} fullName
617 @return {Object} options
618 */
619 registeredOptions(fullName: FullName): RegisterOptions | undefined;
620 /**
621 Allow registering options for all factories of a type.
622
623 ```javascript
624 import Application from '@ember/application';
625
626 let App = Application.create();
627 let appInstance = App.buildInstance();
628
629 // if all of type `connection` must not be singletons
630 appInstance.registerOptionsForType('connection', { singleton: false });
631
632 appInstance.register('connection:twitter', TwitterConnection);
633 appInstance.register('connection:facebook', FacebookConnection);
634
635 let twitter = appInstance.lookup('connection:twitter');
636 let twitter2 = appInstance.lookup('connection:twitter');
637
638 twitter === twitter2; // => false
639
640 let facebook = appInstance.lookup('connection:facebook');
641 let facebook2 = appInstance.lookup('connection:facebook');
642
643 facebook === facebook2; // => false
644 ```
645
646 @public
647 @method registerOptionsForType
648 @param {String} type
649 @param {Object} options
650 */
651 registerOptionsForType(type: string, options: RegisterOptions): void;
652 /**
653 Return the registered options for all factories of a type.
654
655 @public
656 @method registeredOptionsForType
657 @param {String} type
658 @return {Object} options
659 */
660 registeredOptionsForType(type: string): RegisterOptions | undefined;
661 }
662 /**
663 * @internal This is the same basic interface which is implemented (via the
664 * mixins) by `EngineInstance` and therefore `ApplicationInstance`, which are
665 * the normal interfaces to an `Owner` for end user applications now. However,
666 * going forward, we expect to progressively deprecate and remove the "extra"
667 * APIs which are not exposed on `Owner` itself.
668 */
669 export interface InternalOwner extends RegistryProxy, ContainerProxy {}
670 export {};
671}