UNPKG

88.3 kBJavaScriptView Raw
1/**
2 * @license Angular v13.0.2
3 * (c) 2010-2021 Google LLC. https://angular.io/
4 * License: MIT
5 */
6
7import * as i0 from '@angular/core';
8import { Version, Injector, ChangeDetectorRef, Testability, TestabilityRegistry, ApplicationRef, SimpleChange, NgZone, ComponentFactoryResolver, Directive, Inject, ElementRef, EventEmitter, Compiler, resolveForwardRef, NgModule, isDevMode } from '@angular/core';
9import { __decorate, __param, __metadata } from 'tslib';
10import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
11
12/**
13 * @license
14 * Copyright Google LLC All Rights Reserved.
15 *
16 * Use of this source code is governed by an MIT-style license that can be
17 * found in the LICENSE file at https://angular.io/license
18 */
19/**
20 * @publicApi
21 */
22const VERSION = new Version('13.0.2');
23
24/**
25 * @license
26 * Copyright Google LLC All Rights Reserved.
27 *
28 * Use of this source code is governed by an MIT-style license that can be
29 * found in the LICENSE file at https://angular.io/license
30 */
31function noNg() {
32 throw new Error('AngularJS v1.x is not loaded!');
33}
34const noNgElement = (() => noNg());
35noNgElement.cleanData = noNg;
36let angular = {
37 bootstrap: noNg,
38 module: noNg,
39 element: noNgElement,
40 injector: noNg,
41 version: undefined,
42 resumeBootstrap: noNg,
43 getTestability: noNg
44};
45try {
46 if (window.hasOwnProperty('angular')) {
47 angular = window.angular;
48 }
49}
50catch (_a) {
51 // ignore in CJS mode.
52}
53/**
54 * @deprecated Use `setAngularJSGlobal` instead.
55 *
56 * @publicApi
57 */
58function setAngularLib(ng) {
59 setAngularJSGlobal(ng);
60}
61/**
62 * @deprecated Use `getAngularJSGlobal` instead.
63 *
64 * @publicApi
65 */
66function getAngularLib() {
67 return getAngularJSGlobal();
68}
69/**
70 * Resets the AngularJS global.
71 *
72 * Used when AngularJS is loaded lazily, and not available on `window`.
73 *
74 * @publicApi
75 */
76function setAngularJSGlobal(ng) {
77 angular = ng;
78}
79/**
80 * Returns the current AngularJS global.
81 *
82 * @publicApi
83 */
84function getAngularJSGlobal() {
85 return angular;
86}
87const bootstrap = (e, modules, config) => angular.bootstrap(e, modules, config);
88// Do not declare as `module` to avoid webpack bug
89// (see https://github.com/angular/angular/issues/30050).
90const module_ = (prefix, dependencies) => angular.module(prefix, dependencies);
91const element = (e => angular.element(e));
92element.cleanData = nodes => angular.element.cleanData(nodes);
93const injector = (modules, strictDi) => angular.injector(modules, strictDi);
94const resumeBootstrap = () => angular.resumeBootstrap();
95const getTestability = e => angular.getTestability(e);
96
97/**
98 * @license
99 * Copyright Google LLC All Rights Reserved.
100 *
101 * Use of this source code is governed by an MIT-style license that can be
102 * found in the LICENSE file at https://angular.io/license
103 */
104const $COMPILE = '$compile';
105const $CONTROLLER = '$controller';
106const $DELEGATE = '$delegate';
107const $EXCEPTION_HANDLER = '$exceptionHandler';
108const $HTTP_BACKEND = '$httpBackend';
109const $INJECTOR = '$injector';
110const $INTERVAL = '$interval';
111const $PARSE = '$parse';
112const $PROVIDE = '$provide';
113const $ROOT_ELEMENT = '$rootElement';
114const $ROOT_SCOPE = '$rootScope';
115const $SCOPE = '$scope';
116const $TEMPLATE_CACHE = '$templateCache';
117const $TEMPLATE_REQUEST = '$templateRequest';
118const $$TESTABILITY = '$$testability';
119const COMPILER_KEY = '$$angularCompiler';
120const DOWNGRADED_MODULE_COUNT_KEY = '$$angularDowngradedModuleCount';
121const GROUP_PROJECTABLE_NODES_KEY = '$$angularGroupProjectableNodes';
122const INJECTOR_KEY = '$$angularInjector';
123const LAZY_MODULE_REF = '$$angularLazyModuleRef';
124const NG_ZONE_KEY = '$$angularNgZone';
125const UPGRADE_APP_TYPE_KEY = '$$angularUpgradeAppType';
126const REQUIRE_INJECTOR = '?^^' + INJECTOR_KEY;
127const REQUIRE_NG_MODEL = '?ngModel';
128const UPGRADE_MODULE_NAME = '$$UpgradeModule';
129
130/**
131 * @license
132 * Copyright Google LLC All Rights Reserved.
133 *
134 * Use of this source code is governed by an MIT-style license that can be
135 * found in the LICENSE file at https://angular.io/license
136 */
137/**
138 * A `PropertyBinding` represents a mapping between a property name
139 * and an attribute name. It is parsed from a string of the form
140 * `"prop: attr"`; or simply `"propAndAttr" where the property
141 * and attribute have the same identifier.
142 */
143class PropertyBinding {
144 constructor(prop, attr) {
145 this.prop = prop;
146 this.attr = attr;
147 this.parseBinding();
148 }
149 parseBinding() {
150 this.bracketAttr = `[${this.attr}]`;
151 this.parenAttr = `(${this.attr})`;
152 this.bracketParenAttr = `[(${this.attr})]`;
153 const capitalAttr = this.attr.charAt(0).toUpperCase() + this.attr.substr(1);
154 this.onAttr = `on${capitalAttr}`;
155 this.bindAttr = `bind${capitalAttr}`;
156 this.bindonAttr = `bindon${capitalAttr}`;
157 }
158}
159
160/**
161 * @license
162 * Copyright Google LLC All Rights Reserved.
163 *
164 * Use of this source code is governed by an MIT-style license that can be
165 * found in the LICENSE file at https://angular.io/license
166 */
167const DIRECTIVE_PREFIX_REGEXP = /^(?:x|data)[:\-_]/i;
168const DIRECTIVE_SPECIAL_CHARS_REGEXP = /[:\-_]+(.)/g;
169function onError(e) {
170 // TODO: (misko): We seem to not have a stack trace here!
171 if (console.error) {
172 console.error(e, e.stack);
173 }
174 else {
175 // tslint:disable-next-line:no-console
176 console.log(e, e.stack);
177 }
178 throw e;
179}
180/**
181 * Clean the jqLite/jQuery data on the element and all its descendants.
182 * Equivalent to how jqLite/jQuery invoke `cleanData()` on an Element when removed:
183 * https://github.com/angular/angular.js/blob/2e72ea13fa98bebf6ed4b5e3c45eaf5f990ed16f/src/jqLite.js#L349-L355
184 * https://github.com/jquery/jquery/blob/6984d1747623dbc5e87fd6c261a5b6b1628c107c/src/manipulation.js#L182
185 *
186 * NOTE:
187 * `cleanData()` will also invoke the AngularJS `$destroy` DOM event on the element:
188 * https://github.com/angular/angular.js/blob/2e72ea13fa98bebf6ed4b5e3c45eaf5f990ed16f/src/Angular.js#L1932-L1945
189 *
190 * @param node The DOM node whose data needs to be cleaned.
191 */
192function cleanData(node) {
193 element.cleanData([node]);
194 if (isParentNode(node)) {
195 element.cleanData(node.querySelectorAll('*'));
196 }
197}
198function controllerKey(name) {
199 return '$' + name + 'Controller';
200}
201/**
202 * Destroy an AngularJS app given the app `$injector`.
203 *
204 * NOTE: Destroying an app is not officially supported by AngularJS, but try to do our best by
205 * destroying `$rootScope` and clean the jqLite/jQuery data on `$rootElement` and all
206 * descendants.
207 *
208 * @param $injector The `$injector` of the AngularJS app to destroy.
209 */
210function destroyApp($injector) {
211 const $rootElement = $injector.get($ROOT_ELEMENT);
212 const $rootScope = $injector.get($ROOT_SCOPE);
213 $rootScope.$destroy();
214 cleanData($rootElement[0]);
215}
216function directiveNormalize(name) {
217 return name.replace(DIRECTIVE_PREFIX_REGEXP, '')
218 .replace(DIRECTIVE_SPECIAL_CHARS_REGEXP, (_, letter) => letter.toUpperCase());
219}
220function getTypeName(type) {
221 // Return the name of the type or the first line of its stringified version.
222 return type.overriddenName || type.name || type.toString().split('\n')[0];
223}
224function getDowngradedModuleCount($injector) {
225 return $injector.has(DOWNGRADED_MODULE_COUNT_KEY) ? $injector.get(DOWNGRADED_MODULE_COUNT_KEY) :
226 0;
227}
228function getUpgradeAppType($injector) {
229 return $injector.has(UPGRADE_APP_TYPE_KEY) ? $injector.get(UPGRADE_APP_TYPE_KEY) :
230 0 /* None */;
231}
232function isFunction(value) {
233 return typeof value === 'function';
234}
235function isParentNode(node) {
236 return isFunction(node.querySelectorAll);
237}
238function validateInjectionKey($injector, downgradedModule, injectionKey, attemptedAction) {
239 const upgradeAppType = getUpgradeAppType($injector);
240 const downgradedModuleCount = getDowngradedModuleCount($injector);
241 // Check for common errors.
242 switch (upgradeAppType) {
243 case 1 /* Dynamic */:
244 case 2 /* Static */:
245 if (downgradedModule) {
246 throw new Error(`Error while ${attemptedAction}: 'downgradedModule' unexpectedly specified.\n` +
247 'You should not specify a value for \'downgradedModule\', unless you are downgrading ' +
248 'more than one Angular module (via \'downgradeModule()\').');
249 }
250 break;
251 case 3 /* Lite */:
252 if (!downgradedModule && (downgradedModuleCount >= 2)) {
253 throw new Error(`Error while ${attemptedAction}: 'downgradedModule' not specified.\n` +
254 'This application contains more than one downgraded Angular module, thus you need to ' +
255 'always specify \'downgradedModule\' when downgrading components and injectables.');
256 }
257 if (!$injector.has(injectionKey)) {
258 throw new Error(`Error while ${attemptedAction}: Unable to find the specified downgraded module.\n` +
259 'Did you forget to downgrade an Angular module or include it in the AngularJS ' +
260 'application?');
261 }
262 break;
263 default:
264 throw new Error(`Error while ${attemptedAction}: Not a valid '@angular/upgrade' application.\n` +
265 'Did you forget to downgrade an Angular module or include it in the AngularJS ' +
266 'application?');
267 }
268}
269class Deferred {
270 constructor() {
271 this.promise = new Promise((res, rej) => {
272 this.resolve = res;
273 this.reject = rej;
274 });
275 }
276}
277/**
278 * @return Whether the passed-in component implements the subset of the
279 * `ControlValueAccessor` interface needed for AngularJS `ng-model`
280 * compatibility.
281 */
282function supportsNgModel(component) {
283 return typeof component.writeValue === 'function' &&
284 typeof component.registerOnChange === 'function';
285}
286/**
287 * Glue the AngularJS `NgModelController` (if it exists) to the component
288 * (if it implements the needed subset of the `ControlValueAccessor` interface).
289 */
290function hookupNgModel(ngModel, component) {
291 if (ngModel && supportsNgModel(component)) {
292 ngModel.$render = () => {
293 component.writeValue(ngModel.$viewValue);
294 };
295 component.registerOnChange(ngModel.$setViewValue.bind(ngModel));
296 if (typeof component.registerOnTouched === 'function') {
297 component.registerOnTouched(ngModel.$setTouched.bind(ngModel));
298 }
299 }
300}
301/**
302 * Test two values for strict equality, accounting for the fact that `NaN !== NaN`.
303 */
304function strictEquals(val1, val2) {
305 return val1 === val2 || (val1 !== val1 && val2 !== val2);
306}
307
308/**
309 * @license
310 * Copyright Google LLC All Rights Reserved.
311 *
312 * Use of this source code is governed by an MIT-style license that can be
313 * found in the LICENSE file at https://angular.io/license
314 */
315const INITIAL_VALUE$1 = {
316 __UNINITIALIZED__: true
317};
318class DowngradeComponentAdapter {
319 constructor(element, attrs, scope, ngModel, parentInjector, $compile, $parse, componentFactory, wrapCallback) {
320 this.element = element;
321 this.attrs = attrs;
322 this.scope = scope;
323 this.ngModel = ngModel;
324 this.parentInjector = parentInjector;
325 this.$compile = $compile;
326 this.$parse = $parse;
327 this.componentFactory = componentFactory;
328 this.wrapCallback = wrapCallback;
329 this.implementsOnChanges = false;
330 this.inputChangeCount = 0;
331 this.inputChanges = {};
332 this.componentScope = scope.$new();
333 }
334 compileContents() {
335 const compiledProjectableNodes = [];
336 const projectableNodes = this.groupProjectableNodes();
337 const linkFns = projectableNodes.map(nodes => this.$compile(nodes));
338 this.element.empty();
339 linkFns.forEach(linkFn => {
340 linkFn(this.scope, (clone) => {
341 compiledProjectableNodes.push(clone);
342 this.element.append(clone);
343 });
344 });
345 return compiledProjectableNodes;
346 }
347 createComponent(projectableNodes) {
348 const providers = [{ provide: $SCOPE, useValue: this.componentScope }];
349 const childInjector = Injector.create({ providers: providers, parent: this.parentInjector, name: 'DowngradeComponentAdapter' });
350 this.componentRef =
351 this.componentFactory.create(childInjector, projectableNodes, this.element[0]);
352 this.viewChangeDetector = this.componentRef.injector.get(ChangeDetectorRef);
353 this.changeDetector = this.componentRef.changeDetectorRef;
354 this.component = this.componentRef.instance;
355 // testability hook is commonly added during component bootstrap in
356 // packages/core/src/application_ref.bootstrap()
357 // in downgraded application, component creation will take place here as well as adding the
358 // testability hook.
359 const testability = this.componentRef.injector.get(Testability, null);
360 if (testability) {
361 this.componentRef.injector.get(TestabilityRegistry)
362 .registerApplication(this.componentRef.location.nativeElement, testability);
363 }
364 hookupNgModel(this.ngModel, this.component);
365 }
366 setupInputs(manuallyAttachView, propagateDigest = true) {
367 const attrs = this.attrs;
368 const inputs = this.componentFactory.inputs || [];
369 for (let i = 0; i < inputs.length; i++) {
370 const input = new PropertyBinding(inputs[i].propName, inputs[i].templateName);
371 let expr = null;
372 if (attrs.hasOwnProperty(input.attr)) {
373 const observeFn = (prop => {
374 let prevValue = INITIAL_VALUE$1;
375 return (currValue) => {
376 // Initially, both `$observe()` and `$watch()` will call this function.
377 if (!strictEquals(prevValue, currValue)) {
378 if (prevValue === INITIAL_VALUE$1) {
379 prevValue = currValue;
380 }
381 this.updateInput(prop, prevValue, currValue);
382 prevValue = currValue;
383 }
384 };
385 })(input.prop);
386 attrs.$observe(input.attr, observeFn);
387 // Use `$watch()` (in addition to `$observe()`) in order to initialize the input in time
388 // for `ngOnChanges()`. This is necessary if we are already in a `$digest`, which means that
389 // `ngOnChanges()` (which is called by a watcher) will run before the `$observe()` callback.
390 let unwatch = this.componentScope.$watch(() => {
391 unwatch();
392 unwatch = null;
393 observeFn(attrs[input.attr]);
394 });
395 }
396 else if (attrs.hasOwnProperty(input.bindAttr)) {
397 expr = attrs[input.bindAttr];
398 }
399 else if (attrs.hasOwnProperty(input.bracketAttr)) {
400 expr = attrs[input.bracketAttr];
401 }
402 else if (attrs.hasOwnProperty(input.bindonAttr)) {
403 expr = attrs[input.bindonAttr];
404 }
405 else if (attrs.hasOwnProperty(input.bracketParenAttr)) {
406 expr = attrs[input.bracketParenAttr];
407 }
408 if (expr != null) {
409 const watchFn = (prop => (currValue, prevValue) => this.updateInput(prop, prevValue, currValue))(input.prop);
410 this.componentScope.$watch(expr, watchFn);
411 }
412 }
413 // Invoke `ngOnChanges()` and Change Detection (when necessary)
414 const detectChanges = () => this.changeDetector.detectChanges();
415 const prototype = this.componentFactory.componentType.prototype;
416 this.implementsOnChanges = !!(prototype && prototype.ngOnChanges);
417 this.componentScope.$watch(() => this.inputChangeCount, this.wrapCallback(() => {
418 // Invoke `ngOnChanges()`
419 if (this.implementsOnChanges) {
420 const inputChanges = this.inputChanges;
421 this.inputChanges = {};
422 this.component.ngOnChanges(inputChanges);
423 }
424 this.viewChangeDetector.markForCheck();
425 // If opted out of propagating digests, invoke change detection when inputs change.
426 if (!propagateDigest) {
427 detectChanges();
428 }
429 }));
430 // If not opted out of propagating digests, invoke change detection on every digest
431 if (propagateDigest) {
432 this.componentScope.$watch(this.wrapCallback(detectChanges));
433 }
434 // If necessary, attach the view so that it will be dirty-checked.
435 // (Allow time for the initial input values to be set and `ngOnChanges()` to be called.)
436 if (manuallyAttachView || !propagateDigest) {
437 let unwatch = this.componentScope.$watch(() => {
438 unwatch();
439 unwatch = null;
440 const appRef = this.parentInjector.get(ApplicationRef);
441 appRef.attachView(this.componentRef.hostView);
442 });
443 }
444 }
445 setupOutputs() {
446 const attrs = this.attrs;
447 const outputs = this.componentFactory.outputs || [];
448 for (let j = 0; j < outputs.length; j++) {
449 const output = new PropertyBinding(outputs[j].propName, outputs[j].templateName);
450 const bindonAttr = output.bindonAttr.substring(0, output.bindonAttr.length - 6);
451 const bracketParenAttr = `[(${output.bracketParenAttr.substring(2, output.bracketParenAttr.length - 8)})]`;
452 // order below is important - first update bindings then evaluate expressions
453 if (attrs.hasOwnProperty(bindonAttr)) {
454 this.subscribeToOutput(output, attrs[bindonAttr], true);
455 }
456 if (attrs.hasOwnProperty(bracketParenAttr)) {
457 this.subscribeToOutput(output, attrs[bracketParenAttr], true);
458 }
459 if (attrs.hasOwnProperty(output.onAttr)) {
460 this.subscribeToOutput(output, attrs[output.onAttr]);
461 }
462 if (attrs.hasOwnProperty(output.parenAttr)) {
463 this.subscribeToOutput(output, attrs[output.parenAttr]);
464 }
465 }
466 }
467 subscribeToOutput(output, expr, isAssignment = false) {
468 const getter = this.$parse(expr);
469 const setter = getter.assign;
470 if (isAssignment && !setter) {
471 throw new Error(`Expression '${expr}' is not assignable!`);
472 }
473 const emitter = this.component[output.prop];
474 if (emitter) {
475 emitter.subscribe({
476 next: isAssignment ? (v) => setter(this.scope, v) :
477 (v) => getter(this.scope, { '$event': v })
478 });
479 }
480 else {
481 throw new Error(`Missing emitter '${output.prop}' on component '${getTypeName(this.componentFactory.componentType)}'!`);
482 }
483 }
484 registerCleanup() {
485 const testabilityRegistry = this.componentRef.injector.get(TestabilityRegistry);
486 const destroyComponentRef = this.wrapCallback(() => this.componentRef.destroy());
487 let destroyed = false;
488 this.element.on('$destroy', () => {
489 // The `$destroy` event may have been triggered by the `cleanData()` call in the
490 // `componentScope` `$destroy` handler below. In that case, we don't want to call
491 // `componentScope.$destroy()` again.
492 if (!destroyed)
493 this.componentScope.$destroy();
494 });
495 this.componentScope.$on('$destroy', () => {
496 if (!destroyed) {
497 destroyed = true;
498 testabilityRegistry.unregisterApplication(this.componentRef.location.nativeElement);
499 // The `componentScope` might be getting destroyed, because an ancestor element is being
500 // removed/destroyed. If that is the case, jqLite/jQuery would normally invoke `cleanData()`
501 // on the removed element and all descendants.
502 // https://github.com/angular/angular.js/blob/2e72ea13fa98bebf6ed4b5e3c45eaf5f990ed16f/src/jqLite.js#L349-L355
503 // https://github.com/jquery/jquery/blob/6984d1747623dbc5e87fd6c261a5b6b1628c107c/src/manipulation.js#L182
504 //
505 // Here, however, `destroyComponentRef()` may under some circumstances remove the element
506 // from the DOM and therefore it will no longer be a descendant of the removed element when
507 // `cleanData()` is called. This would result in a memory leak, because the element's data
508 // and event handlers (and all objects directly or indirectly referenced by them) would be
509 // retained.
510 //
511 // To ensure the element is always properly cleaned up, we manually call `cleanData()` on
512 // this element and its descendants before destroying the `ComponentRef`.
513 cleanData(this.element[0]);
514 destroyComponentRef();
515 }
516 });
517 }
518 getInjector() {
519 return this.componentRef.injector;
520 }
521 updateInput(prop, prevValue, currValue) {
522 if (this.implementsOnChanges) {
523 this.inputChanges[prop] = new SimpleChange(prevValue, currValue, prevValue === currValue);
524 }
525 this.inputChangeCount++;
526 this.component[prop] = currValue;
527 }
528 groupProjectableNodes() {
529 let ngContentSelectors = this.componentFactory.ngContentSelectors;
530 return groupNodesBySelector(ngContentSelectors, this.element.contents());
531 }
532}
533/**
534 * Group a set of DOM nodes into `ngContent` groups, based on the given content selectors.
535 */
536function groupNodesBySelector(ngContentSelectors, nodes) {
537 const projectableNodes = [];
538 for (let i = 0, ii = ngContentSelectors.length; i < ii; ++i) {
539 projectableNodes[i] = [];
540 }
541 for (let j = 0, jj = nodes.length; j < jj; ++j) {
542 const node = nodes[j];
543 const ngContentIndex = findMatchingNgContentIndex(node, ngContentSelectors);
544 if (ngContentIndex != null) {
545 projectableNodes[ngContentIndex].push(node);
546 }
547 }
548 return projectableNodes;
549}
550function findMatchingNgContentIndex(element, ngContentSelectors) {
551 const ngContentIndices = [];
552 let wildcardNgContentIndex = -1;
553 for (let i = 0; i < ngContentSelectors.length; i++) {
554 const selector = ngContentSelectors[i];
555 if (selector === '*') {
556 wildcardNgContentIndex = i;
557 }
558 else {
559 if (matchesSelector(element, selector)) {
560 ngContentIndices.push(i);
561 }
562 }
563 }
564 ngContentIndices.sort();
565 if (wildcardNgContentIndex !== -1) {
566 ngContentIndices.push(wildcardNgContentIndex);
567 }
568 return ngContentIndices.length ? ngContentIndices[0] : null;
569}
570let _matches;
571function matchesSelector(el, selector) {
572 if (!_matches) {
573 const elProto = Element.prototype;
574 _matches = elProto.matches || elProto.matchesSelector || elProto.mozMatchesSelector ||
575 elProto.msMatchesSelector || elProto.oMatchesSelector || elProto.webkitMatchesSelector;
576 }
577 return el.nodeType === Node.ELEMENT_NODE ? _matches.call(el, selector) : false;
578}
579
580/**
581 * @license
582 * Copyright Google LLC All Rights Reserved.
583 *
584 * Use of this source code is governed by an MIT-style license that can be
585 * found in the LICENSE file at https://angular.io/license
586 */
587function isThenable(obj) {
588 return !!obj && isFunction(obj.then);
589}
590/**
591 * Synchronous, promise-like object.
592 */
593class SyncPromise {
594 constructor() {
595 this.resolved = false;
596 this.callbacks = [];
597 }
598 static all(valuesOrPromises) {
599 const aggrPromise = new SyncPromise();
600 let resolvedCount = 0;
601 const results = [];
602 const resolve = (idx, value) => {
603 results[idx] = value;
604 if (++resolvedCount === valuesOrPromises.length)
605 aggrPromise.resolve(results);
606 };
607 valuesOrPromises.forEach((p, idx) => {
608 if (isThenable(p)) {
609 p.then(v => resolve(idx, v));
610 }
611 else {
612 resolve(idx, p);
613 }
614 });
615 return aggrPromise;
616 }
617 resolve(value) {
618 // Do nothing, if already resolved.
619 if (this.resolved)
620 return;
621 this.value = value;
622 this.resolved = true;
623 // Run the queued callbacks.
624 this.callbacks.forEach(callback => callback(value));
625 this.callbacks.length = 0;
626 }
627 then(callback) {
628 if (this.resolved) {
629 callback(this.value);
630 }
631 else {
632 this.callbacks.push(callback);
633 }
634 }
635}
636
637/**
638 * @license
639 * Copyright Google LLC All Rights Reserved.
640 *
641 * Use of this source code is governed by an MIT-style license that can be
642 * found in the LICENSE file at https://angular.io/license
643 */
644/**
645 * @description
646 *
647 * A helper function that allows an Angular component to be used from AngularJS.
648 *
649 * *Part of the [upgrade/static](api?query=upgrade%2Fstatic)
650 * library for hybrid upgrade apps that support AOT compilation*
651 *
652 * This helper function returns a factory function to be used for registering
653 * an AngularJS wrapper directive for "downgrading" an Angular component.
654 *
655 * @usageNotes
656 * ### Examples
657 *
658 * Let's assume that you have an Angular component called `ng2Heroes` that needs
659 * to be made available in AngularJS templates.
660 *
661 * {@example upgrade/static/ts/full/module.ts region="ng2-heroes"}
662 *
663 * We must create an AngularJS [directive](https://docs.angularjs.org/guide/directive)
664 * that will make this Angular component available inside AngularJS templates.
665 * The `downgradeComponent()` function returns a factory function that we
666 * can use to define the AngularJS directive that wraps the "downgraded" component.
667 *
668 * {@example upgrade/static/ts/full/module.ts region="ng2-heroes-wrapper"}
669 *
670 * For more details and examples on downgrading Angular components to AngularJS components please
671 * visit the [Upgrade guide](guide/upgrade#using-angular-components-from-angularjs-code).
672 *
673 * @param info contains information about the Component that is being downgraded:
674 *
675 * - `component: Type<any>`: The type of the Component that will be downgraded
676 * - `downgradedModule?: string`: The name of the downgraded module (if any) that the component
677 * "belongs to", as returned by a call to `downgradeModule()`. It is the module, whose
678 * corresponding Angular module will be bootstrapped, when the component needs to be instantiated.
679 * <br />
680 * (This option is only necessary when using `downgradeModule()` to downgrade more than one
681 * Angular module.)
682 * - `propagateDigest?: boolean`: Whether to perform {@link ChangeDetectorRef#detectChanges
683 * change detection} on the component on every
684 * [$digest](https://docs.angularjs.org/api/ng/type/$rootScope.Scope#$digest). If set to `false`,
685 * change detection will still be performed when any of the component's inputs changes.
686 * (Default: true)
687 *
688 * @returns a factory function that can be used to register the component in an
689 * AngularJS module.
690 *
691 * @publicApi
692 */
693function downgradeComponent(info) {
694 const directiveFactory = function ($compile, $injector, $parse) {
695 // When using `downgradeModule()`, we need to handle certain things specially. For example:
696 // - We always need to attach the component view to the `ApplicationRef` for it to be
697 // dirty-checked.
698 // - We need to ensure callbacks to Angular APIs (e.g. change detection) are run inside the
699 // Angular zone.
700 // NOTE: This is not needed, when using `UpgradeModule`, because `$digest()` will be run
701 // inside the Angular zone (except if explicitly escaped, in which case we shouldn't
702 // force it back in).
703 const isNgUpgradeLite = getUpgradeAppType($injector) === 3 /* Lite */;
704 const wrapCallback = !isNgUpgradeLite ? cb => cb : cb => () => NgZone.isInAngularZone() ? cb() : ngZone.run(cb);
705 let ngZone;
706 // When downgrading multiple modules, special handling is needed wrt injectors.
707 const hasMultipleDowngradedModules = isNgUpgradeLite && (getDowngradedModuleCount($injector) > 1);
708 return {
709 restrict: 'E',
710 terminal: true,
711 require: [REQUIRE_INJECTOR, REQUIRE_NG_MODEL],
712 link: (scope, element, attrs, required) => {
713 // We might have to compile the contents asynchronously, because this might have been
714 // triggered by `UpgradeNg1ComponentAdapterBuilder`, before the Angular templates have
715 // been compiled.
716 const ngModel = required[1];
717 const parentInjector = required[0];
718 let moduleInjector = undefined;
719 let ranAsync = false;
720 if (!parentInjector || hasMultipleDowngradedModules) {
721 const downgradedModule = info.downgradedModule || '';
722 const lazyModuleRefKey = `${LAZY_MODULE_REF}${downgradedModule}`;
723 const attemptedAction = `instantiating component '${getTypeName(info.component)}'`;
724 validateInjectionKey($injector, downgradedModule, lazyModuleRefKey, attemptedAction);
725 const lazyModuleRef = $injector.get(lazyModuleRefKey);
726 moduleInjector = lazyModuleRef.injector || lazyModuleRef.promise;
727 }
728 // Notes:
729 //
730 // There are two injectors: `finalModuleInjector` and `finalParentInjector` (they might be
731 // the same instance, but that is irrelevant):
732 // - `finalModuleInjector` is used to retrieve `ComponentFactoryResolver`, thus it must be
733 // on the same tree as the `NgModule` that declares this downgraded component.
734 // - `finalParentInjector` is used for all other injection purposes.
735 // (Note that Angular knows to only traverse the component-tree part of that injector,
736 // when looking for an injectable and then switch to the module injector.)
737 //
738 // There are basically three cases:
739 // - If there is no parent component (thus no `parentInjector`), we bootstrap the downgraded
740 // `NgModule` and use its injector as both `finalModuleInjector` and
741 // `finalParentInjector`.
742 // - If there is a parent component (and thus a `parentInjector`) and we are sure that it
743 // belongs to the same `NgModule` as this downgraded component (e.g. because there is only
744 // one downgraded module, we use that `parentInjector` as both `finalModuleInjector` and
745 // `finalParentInjector`.
746 // - If there is a parent component, but it may belong to a different `NgModule`, then we
747 // use the `parentInjector` as `finalParentInjector` and this downgraded component's
748 // declaring `NgModule`'s injector as `finalModuleInjector`.
749 // Note 1: If the `NgModule` is already bootstrapped, we just get its injector (we don't
750 // bootstrap again).
751 // Note 2: It is possible that (while there are multiple downgraded modules) this
752 // downgraded component and its parent component both belong to the same NgModule.
753 // In that case, we could have used the `parentInjector` as both
754 // `finalModuleInjector` and `finalParentInjector`, but (for simplicity) we are
755 // treating this case as if they belong to different `NgModule`s. That doesn't
756 // really affect anything, since `parentInjector` has `moduleInjector` as ancestor
757 // and trying to resolve `ComponentFactoryResolver` from either one will return
758 // the same instance.
759 // If there is a parent component, use its injector as parent injector.
760 // If this is a "top-level" Angular component, use the module injector.
761 const finalParentInjector = parentInjector || moduleInjector;
762 // If this is a "top-level" Angular component or the parent component may belong to a
763 // different `NgModule`, use the module injector for module-specific dependencies.
764 // If there is a parent component that belongs to the same `NgModule`, use its injector.
765 const finalModuleInjector = moduleInjector || parentInjector;
766 const doDowngrade = (injector, moduleInjector) => {
767 // Retrieve `ComponentFactoryResolver` from the injector tied to the `NgModule` this
768 // component belongs to.
769 const componentFactoryResolver = moduleInjector.get(ComponentFactoryResolver);
770 const componentFactory = componentFactoryResolver.resolveComponentFactory(info.component);
771 if (!componentFactory) {
772 throw new Error(`Expecting ComponentFactory for: ${getTypeName(info.component)}`);
773 }
774 const injectorPromise = new ParentInjectorPromise$1(element);
775 const facade = new DowngradeComponentAdapter(element, attrs, scope, ngModel, injector, $compile, $parse, componentFactory, wrapCallback);
776 const projectableNodes = facade.compileContents();
777 facade.createComponent(projectableNodes);
778 facade.setupInputs(isNgUpgradeLite, info.propagateDigest);
779 facade.setupOutputs();
780 facade.registerCleanup();
781 injectorPromise.resolve(facade.getInjector());
782 if (ranAsync) {
783 // If this is run async, it is possible that it is not run inside a
784 // digest and initial input values will not be detected.
785 scope.$evalAsync(() => { });
786 }
787 };
788 const downgradeFn = !isNgUpgradeLite ? doDowngrade : (pInjector, mInjector) => {
789 if (!ngZone) {
790 ngZone = pInjector.get(NgZone);
791 }
792 wrapCallback(() => doDowngrade(pInjector, mInjector))();
793 };
794 // NOTE:
795 // Not using `ParentInjectorPromise.all()` (which is inherited from `SyncPromise`), because
796 // Closure Compiler (or some related tool) complains:
797 // `TypeError: ...$src$downgrade_component_ParentInjectorPromise.all is not a function`
798 SyncPromise.all([finalParentInjector, finalModuleInjector])
799 .then(([pInjector, mInjector]) => downgradeFn(pInjector, mInjector));
800 ranAsync = true;
801 }
802 };
803 };
804 // bracket-notation because of closure - see #14441
805 directiveFactory['$inject'] = [$COMPILE, $INJECTOR, $PARSE];
806 return directiveFactory;
807}
808/**
809 * Synchronous promise-like object to wrap parent injectors,
810 * to preserve the synchronous nature of AngularJS's `$compile`.
811 */
812class ParentInjectorPromise$1 extends SyncPromise {
813 constructor(element) {
814 super();
815 this.element = element;
816 this.injectorKey = controllerKey(INJECTOR_KEY);
817 // Store the promise on the element.
818 element.data(this.injectorKey, this);
819 }
820 resolve(injector) {
821 // Store the real injector on the element.
822 this.element.data(this.injectorKey, injector);
823 // Release the element to prevent memory leaks.
824 this.element = null;
825 // Resolve the promise.
826 super.resolve(injector);
827 }
828}
829
830/**
831 * @license
832 * Copyright Google LLC All Rights Reserved.
833 *
834 * Use of this source code is governed by an MIT-style license that can be
835 * found in the LICENSE file at https://angular.io/license
836 */
837/**
838 * @description
839 *
840 * A helper function to allow an Angular service to be accessible from AngularJS.
841 *
842 * *Part of the [upgrade/static](api?query=upgrade%2Fstatic)
843 * library for hybrid upgrade apps that support AOT compilation*
844 *
845 * This helper function returns a factory function that provides access to the Angular
846 * service identified by the `token` parameter.
847 *
848 * @usageNotes
849 * ### Examples
850 *
851 * First ensure that the service to be downgraded is provided in an `NgModule`
852 * that will be part of the upgrade application. For example, let's assume we have
853 * defined `HeroesService`
854 *
855 * {@example upgrade/static/ts/full/module.ts region="ng2-heroes-service"}
856 *
857 * and that we have included this in our upgrade app `NgModule`
858 *
859 * {@example upgrade/static/ts/full/module.ts region="ng2-module"}
860 *
861 * Now we can register the `downgradeInjectable` factory function for the service
862 * on an AngularJS module.
863 *
864 * {@example upgrade/static/ts/full/module.ts region="downgrade-ng2-heroes-service"}
865 *
866 * Inside an AngularJS component's controller we can get hold of the
867 * downgraded service via the name we gave when downgrading.
868 *
869 * {@example upgrade/static/ts/full/module.ts region="example-app"}
870 *
871 * <div class="alert is-important">
872 *
873 * When using `downgradeModule()`, downgraded injectables will not be available until the Angular
874 * module that provides them is instantiated. In order to be safe, you need to ensure that the
875 * downgraded injectables are not used anywhere _outside_ the part of the app where it is
876 * guaranteed that their module has been instantiated.
877 *
878 * For example, it is _OK_ to use a downgraded service in an upgraded component that is only used
879 * from a downgraded Angular component provided by the same Angular module as the injectable, but
880 * it is _not OK_ to use it in an AngularJS component that may be used independently of Angular or
881 * use it in a downgraded Angular component from a different module.
882 *
883 * </div>
884 *
885 * @param token an `InjectionToken` that identifies a service provided from Angular.
886 * @param downgradedModule the name of the downgraded module (if any) that the injectable
887 * "belongs to", as returned by a call to `downgradeModule()`. It is the module, whose injector will
888 * be used for instantiating the injectable.<br />
889 * (This option is only necessary when using `downgradeModule()` to downgrade more than one Angular
890 * module.)
891 *
892 * @returns a [factory function](https://docs.angularjs.org/guide/di) that can be
893 * used to register the service on an AngularJS module.
894 *
895 * @publicApi
896 */
897function downgradeInjectable(token, downgradedModule = '') {
898 const factory = function ($injector) {
899 const injectorKey = `${INJECTOR_KEY}${downgradedModule}`;
900 const injectableName = isFunction(token) ? getTypeName(token) : String(token);
901 const attemptedAction = `instantiating injectable '${injectableName}'`;
902 validateInjectionKey($injector, downgradedModule, injectorKey, attemptedAction);
903 try {
904 const injector = $injector.get(injectorKey);
905 return injector.get(token);
906 }
907 catch (err) {
908 throw new Error(`Error while ${attemptedAction}: ${err.message || err}`);
909 }
910 };
911 factory['$inject'] = [$INJECTOR];
912 return factory;
913}
914
915/**
916 * @license
917 * Copyright Google LLC All Rights Reserved.
918 *
919 * Use of this source code is governed by an MIT-style license that can be
920 * found in the LICENSE file at https://angular.io/license
921 */
922// Constants
923const REQUIRE_PREFIX_RE = /^(\^\^?)?(\?)?(\^\^?)?/;
924// Classes
925class UpgradeHelper {
926 constructor(injector, name, elementRef, directive) {
927 this.name = name;
928 this.$injector = injector.get($INJECTOR);
929 this.$compile = this.$injector.get($COMPILE);
930 this.$controller = this.$injector.get($CONTROLLER);
931 this.element = elementRef.nativeElement;
932 this.$element = element(this.element);
933 this.directive = directive || UpgradeHelper.getDirective(this.$injector, name);
934 }
935 static getDirective($injector, name) {
936 const directives = $injector.get(name + 'Directive');
937 if (directives.length > 1) {
938 throw new Error(`Only support single directive definition for: ${name}`);
939 }
940 const directive = directives[0];
941 // AngularJS will transform `link: xyz` to `compile: () => xyz`. So we can only tell there was a
942 // user-defined `compile` if there is no `link`. In other cases, we will just ignore `compile`.
943 if (directive.compile && !directive.link)
944 notSupported(name, 'compile');
945 if (directive.replace)
946 notSupported(name, 'replace');
947 if (directive.terminal)
948 notSupported(name, 'terminal');
949 return directive;
950 }
951 static getTemplate($injector, directive, fetchRemoteTemplate = false, $element) {
952 if (directive.template !== undefined) {
953 return getOrCall(directive.template, $element);
954 }
955 else if (directive.templateUrl) {
956 const $templateCache = $injector.get($TEMPLATE_CACHE);
957 const url = getOrCall(directive.templateUrl, $element);
958 const template = $templateCache.get(url);
959 if (template !== undefined) {
960 return template;
961 }
962 else if (!fetchRemoteTemplate) {
963 throw new Error('loading directive templates asynchronously is not supported');
964 }
965 return new Promise((resolve, reject) => {
966 const $httpBackend = $injector.get($HTTP_BACKEND);
967 $httpBackend('GET', url, null, (status, response) => {
968 if (status === 200) {
969 resolve($templateCache.put(url, response));
970 }
971 else {
972 reject(`GET component template from '${url}' returned '${status}: ${response}'`);
973 }
974 });
975 });
976 }
977 else {
978 throw new Error(`Directive '${directive.name}' is not a component, it is missing template.`);
979 }
980 }
981 buildController(controllerType, $scope) {
982 // TODO: Document that we do not pre-assign bindings on the controller instance.
983 // Quoted properties below so that this code can be optimized with Closure Compiler.
984 const locals = { '$scope': $scope, '$element': this.$element };
985 const controller = this.$controller(controllerType, locals, null, this.directive.controllerAs);
986 this.$element.data(controllerKey(this.directive.name), controller);
987 return controller;
988 }
989 compileTemplate(template) {
990 if (template === undefined) {
991 template =
992 UpgradeHelper.getTemplate(this.$injector, this.directive, false, this.$element);
993 }
994 return this.compileHtml(template);
995 }
996 onDestroy($scope, controllerInstance) {
997 if (controllerInstance && isFunction(controllerInstance.$onDestroy)) {
998 controllerInstance.$onDestroy();
999 }
1000 $scope.$destroy();
1001 cleanData(this.element);
1002 }
1003 prepareTransclusion() {
1004 const transclude = this.directive.transclude;
1005 const contentChildNodes = this.extractChildNodes();
1006 const attachChildrenFn = (scope, cloneAttachFn) => {
1007 // Since AngularJS v1.5.8, `cloneAttachFn` will try to destroy the transclusion scope if
1008 // `$template` is empty. Since the transcluded content comes from Angular, not AngularJS,
1009 // there will be no transclusion scope here.
1010 // Provide a dummy `scope.$destroy()` method to prevent `cloneAttachFn` from throwing.
1011 scope = scope || { $destroy: () => undefined };
1012 return cloneAttachFn($template, scope);
1013 };
1014 let $template = contentChildNodes;
1015 if (transclude) {
1016 const slots = Object.create(null);
1017 if (typeof transclude === 'object') {
1018 $template = [];
1019 const slotMap = Object.create(null);
1020 const filledSlots = Object.create(null);
1021 // Parse the element selectors.
1022 Object.keys(transclude).forEach(slotName => {
1023 let selector = transclude[slotName];
1024 const optional = selector.charAt(0) === '?';
1025 selector = optional ? selector.substring(1) : selector;
1026 slotMap[selector] = slotName;
1027 slots[slotName] = null; // `null`: Defined but not yet filled.
1028 filledSlots[slotName] = optional; // Consider optional slots as filled.
1029 });
1030 // Add the matching elements into their slot.
1031 contentChildNodes.forEach(node => {
1032 const slotName = slotMap[directiveNormalize(node.nodeName.toLowerCase())];
1033 if (slotName) {
1034 filledSlots[slotName] = true;
1035 slots[slotName] = slots[slotName] || [];
1036 slots[slotName].push(node);
1037 }
1038 else {
1039 $template.push(node);
1040 }
1041 });
1042 // Check for required slots that were not filled.
1043 Object.keys(filledSlots).forEach(slotName => {
1044 if (!filledSlots[slotName]) {
1045 throw new Error(`Required transclusion slot '${slotName}' on directive: ${this.name}`);
1046 }
1047 });
1048 Object.keys(slots).filter(slotName => slots[slotName]).forEach(slotName => {
1049 const nodes = slots[slotName];
1050 slots[slotName] = (scope, cloneAttach) => {
1051 return cloneAttach(nodes, scope);
1052 };
1053 });
1054 }
1055 // Attach `$$slots` to default slot transclude fn.
1056 attachChildrenFn.$$slots = slots;
1057 // AngularJS v1.6+ ignores empty or whitespace-only transcluded text nodes. But Angular
1058 // removes all text content after the first interpolation and updates it later, after
1059 // evaluating the expressions. This would result in AngularJS failing to recognize text
1060 // nodes that start with an interpolation as transcluded content and use the fallback
1061 // content instead.
1062 // To avoid this issue, we add a
1063 // [zero-width non-joiner character](https://en.wikipedia.org/wiki/Zero-width_non-joiner)
1064 // to empty text nodes (which can only be a result of Angular removing their initial content).
1065 // NOTE: Transcluded text content that starts with whitespace followed by an interpolation
1066 // will still fail to be detected by AngularJS v1.6+
1067 $template.forEach(node => {
1068 if (node.nodeType === Node.TEXT_NODE && !node.nodeValue) {
1069 node.nodeValue = '\u200C';
1070 }
1071 });
1072 }
1073 return attachChildrenFn;
1074 }
1075 resolveAndBindRequiredControllers(controllerInstance) {
1076 const directiveRequire = this.getDirectiveRequire();
1077 const requiredControllers = this.resolveRequire(directiveRequire);
1078 if (controllerInstance && this.directive.bindToController && isMap(directiveRequire)) {
1079 const requiredControllersMap = requiredControllers;
1080 Object.keys(requiredControllersMap).forEach(key => {
1081 controllerInstance[key] = requiredControllersMap[key];
1082 });
1083 }
1084 return requiredControllers;
1085 }
1086 compileHtml(html) {
1087 this.element.innerHTML = html;
1088 return this.$compile(this.element.childNodes);
1089 }
1090 extractChildNodes() {
1091 const childNodes = [];
1092 let childNode;
1093 while (childNode = this.element.firstChild) {
1094 this.element.removeChild(childNode);
1095 childNodes.push(childNode);
1096 }
1097 return childNodes;
1098 }
1099 getDirectiveRequire() {
1100 const require = this.directive.require || (this.directive.controller && this.directive.name);
1101 if (isMap(require)) {
1102 Object.keys(require).forEach(key => {
1103 const value = require[key];
1104 const match = value.match(REQUIRE_PREFIX_RE);
1105 const name = value.substring(match[0].length);
1106 if (!name) {
1107 require[key] = match[0] + key;
1108 }
1109 });
1110 }
1111 return require;
1112 }
1113 resolveRequire(require, controllerInstance) {
1114 if (!require) {
1115 return null;
1116 }
1117 else if (Array.isArray(require)) {
1118 return require.map(req => this.resolveRequire(req));
1119 }
1120 else if (typeof require === 'object') {
1121 const value = {};
1122 Object.keys(require).forEach(key => value[key] = this.resolveRequire(require[key]));
1123 return value;
1124 }
1125 else if (typeof require === 'string') {
1126 const match = require.match(REQUIRE_PREFIX_RE);
1127 const inheritType = match[1] || match[3];
1128 const name = require.substring(match[0].length);
1129 const isOptional = !!match[2];
1130 const searchParents = !!inheritType;
1131 const startOnParent = inheritType === '^^';
1132 const ctrlKey = controllerKey(name);
1133 const elem = startOnParent ? this.$element.parent() : this.$element;
1134 const value = searchParents ? elem.inheritedData(ctrlKey) : elem.data(ctrlKey);
1135 if (!value && !isOptional) {
1136 throw new Error(`Unable to find required '${require}' in upgraded directive '${this.name}'.`);
1137 }
1138 return value;
1139 }
1140 else {
1141 throw new Error(`Unrecognized 'require' syntax on upgraded directive '${this.name}': ${require}`);
1142 }
1143 }
1144}
1145function getOrCall(property, ...args) {
1146 return isFunction(property) ? property(...args) : property;
1147}
1148// NOTE: Only works for `typeof T !== 'object'`.
1149function isMap(value) {
1150 return value && !Array.isArray(value) && typeof value === 'object';
1151}
1152function notSupported(name, feature) {
1153 throw new Error(`Upgraded directive '${name}' contains unsupported feature: '${feature}'.`);
1154}
1155
1156const CAMEL_CASE = /([A-Z])/g;
1157const INITIAL_VALUE = {
1158 __UNINITIALIZED__: true
1159};
1160const NOT_SUPPORTED = 'NOT_SUPPORTED';
1161class UpgradeNg1ComponentAdapterBuilder {
1162 constructor(name) {
1163 this.name = name;
1164 this.inputs = [];
1165 this.inputsRename = [];
1166 this.outputs = [];
1167 this.outputsRename = [];
1168 this.propertyOutputs = [];
1169 this.checkProperties = [];
1170 this.propertyMap = {};
1171 this.directive = null;
1172 const selector = name.replace(CAMEL_CASE, (all, next) => '-' + next.toLowerCase());
1173 const self = this;
1174 // Note: There is a bug in TS 2.4 that prevents us from
1175 // inlining this into @Directive
1176 // TODO(tbosch): find or file a bug against TypeScript for this.
1177 const directive = { selector: selector, inputs: this.inputsRename, outputs: this.outputsRename };
1178 let MyClass = class MyClass extends UpgradeNg1ComponentAdapter {
1179 constructor(scope, injector, elementRef) {
1180 super(new UpgradeHelper(injector, name, elementRef, self.directive || undefined), scope, self.template, self.inputs, self.outputs, self.propertyOutputs, self.checkProperties, self.propertyMap);
1181 }
1182 };
1183 MyClass = __decorate([
1184 Directive(Object.assign({ jit: true }, directive)),
1185 __param(0, Inject($SCOPE)),
1186 __metadata("design:paramtypes", [Object, Injector, ElementRef])
1187 ], MyClass);
1188 this.type = MyClass;
1189 }
1190 extractBindings() {
1191 const btcIsObject = typeof this.directive.bindToController === 'object';
1192 if (btcIsObject && Object.keys(this.directive.scope).length) {
1193 throw new Error(`Binding definitions on scope and controller at the same time are not supported.`);
1194 }
1195 const context = (btcIsObject) ? this.directive.bindToController : this.directive.scope;
1196 if (typeof context == 'object') {
1197 Object.keys(context).forEach(propName => {
1198 const definition = context[propName];
1199 const bindingType = definition.charAt(0);
1200 const bindingOptions = definition.charAt(1);
1201 const attrName = definition.substring(bindingOptions === '?' ? 2 : 1) || propName;
1202 // QUESTION: What about `=*`? Ignore? Throw? Support?
1203 const inputName = `input_${attrName}`;
1204 const inputNameRename = `${inputName}: ${attrName}`;
1205 const outputName = `output_${attrName}`;
1206 const outputNameRename = `${outputName}: ${attrName}`;
1207 const outputNameRenameChange = `${outputNameRename}Change`;
1208 switch (bindingType) {
1209 case '@':
1210 case '<':
1211 this.inputs.push(inputName);
1212 this.inputsRename.push(inputNameRename);
1213 this.propertyMap[inputName] = propName;
1214 break;
1215 case '=':
1216 this.inputs.push(inputName);
1217 this.inputsRename.push(inputNameRename);
1218 this.propertyMap[inputName] = propName;
1219 this.outputs.push(outputName);
1220 this.outputsRename.push(outputNameRenameChange);
1221 this.propertyMap[outputName] = propName;
1222 this.checkProperties.push(propName);
1223 this.propertyOutputs.push(outputName);
1224 break;
1225 case '&':
1226 this.outputs.push(outputName);
1227 this.outputsRename.push(outputNameRename);
1228 this.propertyMap[outputName] = propName;
1229 break;
1230 default:
1231 let json = JSON.stringify(context);
1232 throw new Error(`Unexpected mapping '${bindingType}' in '${json}' in '${this.name}' directive.`);
1233 }
1234 });
1235 }
1236 }
1237 /**
1238 * Upgrade ng1 components into Angular.
1239 */
1240 static resolve(exportedComponents, $injector) {
1241 const promises = Object.keys(exportedComponents).map(name => {
1242 const exportedComponent = exportedComponents[name];
1243 exportedComponent.directive = UpgradeHelper.getDirective($injector, name);
1244 exportedComponent.extractBindings();
1245 return Promise
1246 .resolve(UpgradeHelper.getTemplate($injector, exportedComponent.directive, true))
1247 .then(template => exportedComponent.template = template);
1248 });
1249 return Promise.all(promises);
1250 }
1251}
1252class UpgradeNg1ComponentAdapter {
1253 constructor(helper, scope, template, inputs, outputs, propOuts, checkProperties, propertyMap) {
1254 this.helper = helper;
1255 this.template = template;
1256 this.inputs = inputs;
1257 this.outputs = outputs;
1258 this.propOuts = propOuts;
1259 this.checkProperties = checkProperties;
1260 this.propertyMap = propertyMap;
1261 this.controllerInstance = null;
1262 this.destinationObj = null;
1263 this.checkLastValues = [];
1264 this.$element = null;
1265 this.directive = helper.directive;
1266 this.element = helper.element;
1267 this.$element = helper.$element;
1268 this.componentScope = scope.$new(!!this.directive.scope);
1269 const controllerType = this.directive.controller;
1270 if (this.directive.bindToController && controllerType) {
1271 this.controllerInstance = this.helper.buildController(controllerType, this.componentScope);
1272 this.destinationObj = this.controllerInstance;
1273 }
1274 else {
1275 this.destinationObj = this.componentScope;
1276 }
1277 for (let i = 0; i < inputs.length; i++) {
1278 this[inputs[i]] = null;
1279 }
1280 for (let j = 0; j < outputs.length; j++) {
1281 const emitter = this[outputs[j]] = new EventEmitter();
1282 if (this.propOuts.indexOf(outputs[j]) === -1) {
1283 this.setComponentProperty(outputs[j], (emitter => (value) => emitter.emit(value))(emitter));
1284 }
1285 }
1286 for (let k = 0; k < propOuts.length; k++) {
1287 this.checkLastValues.push(INITIAL_VALUE);
1288 }
1289 }
1290 ngOnInit() {
1291 // Collect contents, insert and compile template
1292 const attachChildNodes = this.helper.prepareTransclusion();
1293 const linkFn = this.helper.compileTemplate(this.template);
1294 // Instantiate controller (if not already done so)
1295 const controllerType = this.directive.controller;
1296 const bindToController = this.directive.bindToController;
1297 if (controllerType && !bindToController) {
1298 this.controllerInstance = this.helper.buildController(controllerType, this.componentScope);
1299 }
1300 // Require other controllers
1301 const requiredControllers = this.helper.resolveAndBindRequiredControllers(this.controllerInstance);
1302 // Hook: $onInit
1303 if (this.controllerInstance && isFunction(this.controllerInstance.$onInit)) {
1304 this.controllerInstance.$onInit();
1305 }
1306 // Linking
1307 const link = this.directive.link;
1308 const preLink = typeof link == 'object' && link.pre;
1309 const postLink = typeof link == 'object' ? link.post : link;
1310 const attrs = NOT_SUPPORTED;
1311 const transcludeFn = NOT_SUPPORTED;
1312 if (preLink) {
1313 preLink(this.componentScope, this.$element, attrs, requiredControllers, transcludeFn);
1314 }
1315 linkFn(this.componentScope, null, { parentBoundTranscludeFn: attachChildNodes });
1316 if (postLink) {
1317 postLink(this.componentScope, this.$element, attrs, requiredControllers, transcludeFn);
1318 }
1319 // Hook: $postLink
1320 if (this.controllerInstance && isFunction(this.controllerInstance.$postLink)) {
1321 this.controllerInstance.$postLink();
1322 }
1323 }
1324 ngOnChanges(changes) {
1325 const ng1Changes = {};
1326 Object.keys(changes).forEach(name => {
1327 const change = changes[name];
1328 this.setComponentProperty(name, change.currentValue);
1329 ng1Changes[this.propertyMap[name]] = change;
1330 });
1331 if (isFunction(this.destinationObj.$onChanges)) {
1332 this.destinationObj.$onChanges(ng1Changes);
1333 }
1334 }
1335 ngDoCheck() {
1336 const destinationObj = this.destinationObj;
1337 const lastValues = this.checkLastValues;
1338 const checkProperties = this.checkProperties;
1339 const propOuts = this.propOuts;
1340 checkProperties.forEach((propName, i) => {
1341 const value = destinationObj[propName];
1342 const last = lastValues[i];
1343 if (!strictEquals(last, value)) {
1344 const eventEmitter = this[propOuts[i]];
1345 eventEmitter.emit(lastValues[i] = value);
1346 }
1347 });
1348 if (this.controllerInstance && isFunction(this.controllerInstance.$doCheck)) {
1349 this.controllerInstance.$doCheck();
1350 }
1351 }
1352 ngOnDestroy() {
1353 this.helper.onDestroy(this.componentScope, this.controllerInstance);
1354 }
1355 setComponentProperty(name, value) {
1356 this.destinationObj[this.propertyMap[name]] = value;
1357 }
1358}
1359UpgradeNg1ComponentAdapter.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.0.2", ngImport: i0, type: UpgradeNg1ComponentAdapter, deps: "invalid", target: i0.ɵɵFactoryTarget.Directive });
1360UpgradeNg1ComponentAdapter.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "13.0.2", type: UpgradeNg1ComponentAdapter, usesOnChanges: true, ngImport: i0 });
1361i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.0.2", ngImport: i0, type: UpgradeNg1ComponentAdapter, decorators: [{
1362 type: Directive
1363 }], ctorParameters: function () { return [{ type: UpgradeHelper }, { type: undefined }, { type: undefined }, { type: undefined }, { type: undefined }, { type: undefined }, { type: undefined }, { type: undefined }]; } });
1364
1365/**
1366 * @license
1367 * Copyright Google LLC All Rights Reserved.
1368 *
1369 * Use of this source code is governed by an MIT-style license that can be
1370 * found in the LICENSE file at https://angular.io/license
1371 */
1372let upgradeCount = 0;
1373/**
1374 * Use `UpgradeAdapter` to allow AngularJS and Angular to coexist in a single application.
1375 *
1376 * The `UpgradeAdapter` allows:
1377 * 1. creation of Angular component from AngularJS component directive
1378 * (See [UpgradeAdapter#upgradeNg1Component()])
1379 * 2. creation of AngularJS directive from Angular component.
1380 * (See [UpgradeAdapter#downgradeNg2Component()])
1381 * 3. Bootstrapping of a hybrid Angular application which contains both of the frameworks
1382 * coexisting in a single application.
1383 *
1384 * @usageNotes
1385 * ### Mental Model
1386 *
1387 * When reasoning about how a hybrid application works it is useful to have a mental model which
1388 * describes what is happening and explains what is happening at the lowest level.
1389 *
1390 * 1. There are two independent frameworks running in a single application, each framework treats
1391 * the other as a black box.
1392 * 2. Each DOM element on the page is owned exactly by one framework. Whichever framework
1393 * instantiated the element is the owner. Each framework only updates/interacts with its own
1394 * DOM elements and ignores others.
1395 * 3. AngularJS directives always execute inside AngularJS framework codebase regardless of
1396 * where they are instantiated.
1397 * 4. Angular components always execute inside Angular framework codebase regardless of
1398 * where they are instantiated.
1399 * 5. An AngularJS component can be upgraded to an Angular component. This creates an
1400 * Angular directive, which bootstraps the AngularJS component directive in that location.
1401 * 6. An Angular component can be downgraded to an AngularJS component directive. This creates
1402 * an AngularJS directive, which bootstraps the Angular component in that location.
1403 * 7. Whenever an adapter component is instantiated the host element is owned by the framework
1404 * doing the instantiation. The other framework then instantiates and owns the view for that
1405 * component. This implies that component bindings will always follow the semantics of the
1406 * instantiation framework. The syntax is always that of Angular syntax.
1407 * 8. AngularJS is always bootstrapped first and owns the bottom most view.
1408 * 9. The new application is running in Angular zone, and therefore it no longer needs calls to
1409 * `$apply()`.
1410 *
1411 * ### Example
1412 *
1413 * ```
1414 * const adapter = new UpgradeAdapter(forwardRef(() => MyNg2Module), myCompilerOptions);
1415 * const module = angular.module('myExample', []);
1416 * module.directive('ng2Comp', adapter.downgradeNg2Component(Ng2Component));
1417 *
1418 * module.directive('ng1Hello', function() {
1419 * return {
1420 * scope: { title: '=' },
1421 * template: 'ng1[Hello {{title}}!](<span ng-transclude></span>)'
1422 * };
1423 * });
1424 *
1425 *
1426 * @Component({
1427 * selector: 'ng2-comp',
1428 * inputs: ['name'],
1429 * template: 'ng2[<ng1-hello [title]="name">transclude</ng1-hello>](<ng-content></ng-content>)',
1430 * directives:
1431 * })
1432 * class Ng2Component {
1433 * }
1434 *
1435 * @NgModule({
1436 * declarations: [Ng2Component, adapter.upgradeNg1Component('ng1Hello')],
1437 * imports: [BrowserModule]
1438 * })
1439 * class MyNg2Module {}
1440 *
1441 *
1442 * document.body.innerHTML = '<ng2-comp name="World">project</ng2-comp>';
1443 *
1444 * adapter.bootstrap(document.body, ['myExample']).ready(function() {
1445 * expect(document.body.textContent).toEqual(
1446 * "ng2[ng1[Hello World!](transclude)](project)");
1447 * });
1448 *
1449 * ```
1450 *
1451 * @deprecated Deprecated since v5. Use `upgrade/static` instead, which also supports
1452 * [Ahead-of-Time compilation](guide/aot-compiler).
1453 * @publicApi
1454 */
1455class UpgradeAdapter {
1456 constructor(ng2AppModule, compilerOptions) {
1457 this.ng2AppModule = ng2AppModule;
1458 this.compilerOptions = compilerOptions;
1459 this.idPrefix = `NG2_UPGRADE_${upgradeCount++}_`;
1460 this.downgradedComponents = [];
1461 /**
1462 * An internal map of ng1 components which need to up upgraded to ng2.
1463 *
1464 * We can't upgrade until injector is instantiated and we can retrieve the component metadata.
1465 * For this reason we keep a list of components to upgrade until ng1 injector is bootstrapped.
1466 *
1467 * @internal
1468 */
1469 this.ng1ComponentsToBeUpgraded = {};
1470 this.upgradedProviders = [];
1471 this.moduleRef = null;
1472 if (!ng2AppModule) {
1473 throw new Error('UpgradeAdapter cannot be instantiated without an NgModule of the Angular app.');
1474 }
1475 }
1476 /**
1477 * Allows Angular Component to be used from AngularJS.
1478 *
1479 * Use `downgradeNg2Component` to create an AngularJS Directive Definition Factory from
1480 * Angular Component. The adapter will bootstrap Angular component from within the
1481 * AngularJS template.
1482 *
1483 * @usageNotes
1484 * ### Mental Model
1485 *
1486 * 1. The component is instantiated by being listed in AngularJS template. This means that the
1487 * host element is controlled by AngularJS, but the component's view will be controlled by
1488 * Angular.
1489 * 2. Even thought the component is instantiated in AngularJS, it will be using Angular
1490 * syntax. This has to be done, this way because we must follow Angular components do not
1491 * declare how the attributes should be interpreted.
1492 * 3. `ng-model` is controlled by AngularJS and communicates with the downgraded Angular component
1493 * by way of the `ControlValueAccessor` interface from @angular/forms. Only components that
1494 * implement this interface are eligible.
1495 *
1496 * ### Supported Features
1497 *
1498 * - Bindings:
1499 * - Attribute: `<comp name="World">`
1500 * - Interpolation: `<comp greeting="Hello {{name}}!">`
1501 * - Expression: `<comp [name]="username">`
1502 * - Event: `<comp (close)="doSomething()">`
1503 * - ng-model: `<comp ng-model="name">`
1504 * - Content projection: yes
1505 *
1506 * ### Example
1507 *
1508 * ```
1509 * const adapter = new UpgradeAdapter(forwardRef(() => MyNg2Module));
1510 * const module = angular.module('myExample', []);
1511 * module.directive('greet', adapter.downgradeNg2Component(Greeter));
1512 *
1513 * @Component({
1514 * selector: 'greet',
1515 * template: '{{salutation}} {{name}}! - <ng-content></ng-content>'
1516 * })
1517 * class Greeter {
1518 * @Input() salutation: string;
1519 * @Input() name: string;
1520 * }
1521 *
1522 * @NgModule({
1523 * declarations: [Greeter],
1524 * imports: [BrowserModule]
1525 * })
1526 * class MyNg2Module {}
1527 *
1528 * document.body.innerHTML =
1529 * 'ng1 template: <greet salutation="Hello" [name]="world">text</greet>';
1530 *
1531 * adapter.bootstrap(document.body, ['myExample']).ready(function() {
1532 * expect(document.body.textContent).toEqual("ng1 template: Hello world! - text");
1533 * });
1534 * ```
1535 */
1536 downgradeNg2Component(component) {
1537 this.downgradedComponents.push(component);
1538 return downgradeComponent({ component });
1539 }
1540 /**
1541 * Allows AngularJS Component to be used from Angular.
1542 *
1543 * Use `upgradeNg1Component` to create an Angular component from AngularJS Component
1544 * directive. The adapter will bootstrap AngularJS component from within the Angular
1545 * template.
1546 *
1547 * @usageNotes
1548 * ### Mental Model
1549 *
1550 * 1. The component is instantiated by being listed in Angular template. This means that the
1551 * host element is controlled by Angular, but the component's view will be controlled by
1552 * AngularJS.
1553 *
1554 * ### Supported Features
1555 *
1556 * - Bindings:
1557 * - Attribute: `<comp name="World">`
1558 * - Interpolation: `<comp greeting="Hello {{name}}!">`
1559 * - Expression: `<comp [name]="username">`
1560 * - Event: `<comp (close)="doSomething()">`
1561 * - Transclusion: yes
1562 * - Only some of the features of
1563 * [Directive Definition Object](https://docs.angularjs.org/api/ng/service/$compile) are
1564 * supported:
1565 * - `compile`: not supported because the host element is owned by Angular, which does
1566 * not allow modifying DOM structure during compilation.
1567 * - `controller`: supported. (NOTE: injection of `$attrs` and `$transclude` is not supported.)
1568 * - `controllerAs`: supported.
1569 * - `bindToController`: supported.
1570 * - `link`: supported. (NOTE: only pre-link function is supported.)
1571 * - `name`: supported.
1572 * - `priority`: ignored.
1573 * - `replace`: not supported.
1574 * - `require`: supported.
1575 * - `restrict`: must be set to 'E'.
1576 * - `scope`: supported.
1577 * - `template`: supported.
1578 * - `templateUrl`: supported.
1579 * - `terminal`: ignored.
1580 * - `transclude`: supported.
1581 *
1582 *
1583 * ### Example
1584 *
1585 * ```
1586 * const adapter = new UpgradeAdapter(forwardRef(() => MyNg2Module));
1587 * const module = angular.module('myExample', []);
1588 *
1589 * module.directive('greet', function() {
1590 * return {
1591 * scope: {salutation: '=', name: '=' },
1592 * template: '{{salutation}} {{name}}! - <span ng-transclude></span>'
1593 * };
1594 * });
1595 *
1596 * module.directive('ng2', adapter.downgradeNg2Component(Ng2Component));
1597 *
1598 * @Component({
1599 * selector: 'ng2',
1600 * template: 'ng2 template: <greet salutation="Hello" [name]="world">text</greet>'
1601 * })
1602 * class Ng2Component {
1603 * }
1604 *
1605 * @NgModule({
1606 * declarations: [Ng2Component, adapter.upgradeNg1Component('greet')],
1607 * imports: [BrowserModule]
1608 * })
1609 * class MyNg2Module {}
1610 *
1611 * document.body.innerHTML = '<ng2></ng2>';
1612 *
1613 * adapter.bootstrap(document.body, ['myExample']).ready(function() {
1614 * expect(document.body.textContent).toEqual("ng2 template: Hello world! - text");
1615 * });
1616 * ```
1617 */
1618 upgradeNg1Component(name) {
1619 if (this.ng1ComponentsToBeUpgraded.hasOwnProperty(name)) {
1620 return this.ng1ComponentsToBeUpgraded[name].type;
1621 }
1622 else {
1623 return (this.ng1ComponentsToBeUpgraded[name] = new UpgradeNg1ComponentAdapterBuilder(name))
1624 .type;
1625 }
1626 }
1627 /**
1628 * Registers the adapter's AngularJS upgrade module for unit testing in AngularJS.
1629 * Use this instead of `angular.mock.module()` to load the upgrade module into
1630 * the AngularJS testing injector.
1631 *
1632 * @usageNotes
1633 * ### Example
1634 *
1635 * ```
1636 * const upgradeAdapter = new UpgradeAdapter(MyNg2Module);
1637 *
1638 * // configure the adapter with upgrade/downgrade components and services
1639 * upgradeAdapter.downgradeNg2Component(MyComponent);
1640 *
1641 * let upgradeAdapterRef: UpgradeAdapterRef;
1642 * let $compile, $rootScope;
1643 *
1644 * // We must register the adapter before any calls to `inject()`
1645 * beforeEach(() => {
1646 * upgradeAdapterRef = upgradeAdapter.registerForNg1Tests(['heroApp']);
1647 * });
1648 *
1649 * beforeEach(inject((_$compile_, _$rootScope_) => {
1650 * $compile = _$compile_;
1651 * $rootScope = _$rootScope_;
1652 * }));
1653 *
1654 * it("says hello", (done) => {
1655 * upgradeAdapterRef.ready(() => {
1656 * const element = $compile("<my-component></my-component>")($rootScope);
1657 * $rootScope.$apply();
1658 * expect(element.html()).toContain("Hello World");
1659 * done();
1660 * })
1661 * });
1662 *
1663 * ```
1664 *
1665 * @param modules any AngularJS modules that the upgrade module should depend upon
1666 * @returns an `UpgradeAdapterRef`, which lets you register a `ready()` callback to
1667 * run assertions once the Angular components are ready to test through AngularJS.
1668 */
1669 registerForNg1Tests(modules) {
1670 const windowNgMock = window['angular'].mock;
1671 if (!windowNgMock || !windowNgMock.module) {
1672 throw new Error('Failed to find \'angular.mock.module\'.');
1673 }
1674 this.declareNg1Module(modules);
1675 windowNgMock.module(this.ng1Module.name);
1676 const upgrade = new UpgradeAdapterRef();
1677 this.ng2BootstrapDeferred.promise.then((ng1Injector) => {
1678 upgrade._bootstrapDone(this.moduleRef, ng1Injector);
1679 }, onError);
1680 return upgrade;
1681 }
1682 /**
1683 * Bootstrap a hybrid AngularJS / Angular application.
1684 *
1685 * This `bootstrap` method is a direct replacement (takes same arguments) for AngularJS
1686 * [`bootstrap`](https://docs.angularjs.org/api/ng/function/angular.bootstrap) method. Unlike
1687 * AngularJS, this bootstrap is asynchronous.
1688 *
1689 * @usageNotes
1690 * ### Example
1691 *
1692 * ```
1693 * const adapter = new UpgradeAdapter(MyNg2Module);
1694 * const module = angular.module('myExample', []);
1695 * module.directive('ng2', adapter.downgradeNg2Component(Ng2));
1696 *
1697 * module.directive('ng1', function() {
1698 * return {
1699 * scope: { title: '=' },
1700 * template: 'ng1[Hello {{title}}!](<span ng-transclude></span>)'
1701 * };
1702 * });
1703 *
1704 *
1705 * @Component({
1706 * selector: 'ng2',
1707 * inputs: ['name'],
1708 * template: 'ng2[<ng1 [title]="name">transclude</ng1>](<ng-content></ng-content>)'
1709 * })
1710 * class Ng2 {
1711 * }
1712 *
1713 * @NgModule({
1714 * declarations: [Ng2, adapter.upgradeNg1Component('ng1')],
1715 * imports: [BrowserModule]
1716 * })
1717 * class MyNg2Module {}
1718 *
1719 * document.body.innerHTML = '<ng2 name="World">project</ng2>';
1720 *
1721 * adapter.bootstrap(document.body, ['myExample']).ready(function() {
1722 * expect(document.body.textContent).toEqual(
1723 * "ng2[ng1[Hello World!](transclude)](project)");
1724 * });
1725 * ```
1726 */
1727 bootstrap(element$1, modules, config) {
1728 this.declareNg1Module(modules);
1729 const upgrade = new UpgradeAdapterRef();
1730 // Make sure resumeBootstrap() only exists if the current bootstrap is deferred
1731 const windowAngular = window /** TODO #???? */['angular'];
1732 windowAngular.resumeBootstrap = undefined;
1733 this.ngZone.run(() => {
1734 bootstrap(element$1, [this.ng1Module.name], config);
1735 });
1736 const ng1BootstrapPromise = new Promise((resolve) => {
1737 if (windowAngular.resumeBootstrap) {
1738 const originalResumeBootstrap = windowAngular.resumeBootstrap;
1739 windowAngular.resumeBootstrap = function () {
1740 windowAngular.resumeBootstrap = originalResumeBootstrap;
1741 const r = windowAngular.resumeBootstrap.apply(this, arguments);
1742 resolve();
1743 return r;
1744 };
1745 }
1746 else {
1747 resolve();
1748 }
1749 });
1750 Promise.all([this.ng2BootstrapDeferred.promise, ng1BootstrapPromise]).then(([ng1Injector]) => {
1751 element(element$1).data(controllerKey(INJECTOR_KEY), this.moduleRef.injector);
1752 this.moduleRef.injector.get(NgZone).run(() => {
1753 upgrade._bootstrapDone(this.moduleRef, ng1Injector);
1754 });
1755 }, onError);
1756 return upgrade;
1757 }
1758 /**
1759 * Allows AngularJS service to be accessible from Angular.
1760 *
1761 * @usageNotes
1762 * ### Example
1763 *
1764 * ```
1765 * class Login { ... }
1766 * class Server { ... }
1767 *
1768 * @Injectable()
1769 * class Example {
1770 * constructor(@Inject('server') server, login: Login) {
1771 * ...
1772 * }
1773 * }
1774 *
1775 * const module = angular.module('myExample', []);
1776 * module.service('server', Server);
1777 * module.service('login', Login);
1778 *
1779 * const adapter = new UpgradeAdapter(MyNg2Module);
1780 * adapter.upgradeNg1Provider('server');
1781 * adapter.upgradeNg1Provider('login', {asToken: Login});
1782 *
1783 * adapter.bootstrap(document.body, ['myExample']).ready((ref) => {
1784 * const example: Example = ref.ng2Injector.get(Example);
1785 * });
1786 *
1787 * ```
1788 */
1789 upgradeNg1Provider(name, options) {
1790 const token = options && options.asToken || name;
1791 this.upgradedProviders.push({
1792 provide: token,
1793 useFactory: ($injector) => $injector.get(name),
1794 deps: [$INJECTOR]
1795 });
1796 }
1797 /**
1798 * Allows Angular service to be accessible from AngularJS.
1799 *
1800 * @usageNotes
1801 * ### Example
1802 *
1803 * ```
1804 * class Example {
1805 * }
1806 *
1807 * const adapter = new UpgradeAdapter(MyNg2Module);
1808 *
1809 * const module = angular.module('myExample', []);
1810 * module.factory('example', adapter.downgradeNg2Provider(Example));
1811 *
1812 * adapter.bootstrap(document.body, ['myExample']).ready((ref) => {
1813 * const example: Example = ref.ng1Injector.get('example');
1814 * });
1815 *
1816 * ```
1817 */
1818 downgradeNg2Provider(token) {
1819 return downgradeInjectable(token);
1820 }
1821 /**
1822 * Declare the AngularJS upgrade module for this adapter without bootstrapping the whole
1823 * hybrid application.
1824 *
1825 * This method is automatically called by `bootstrap()` and `registerForNg1Tests()`.
1826 *
1827 * @param modules The AngularJS modules that this upgrade module should depend upon.
1828 * @returns The AngularJS upgrade module that is declared by this method
1829 *
1830 * @usageNotes
1831 * ### Example
1832 *
1833 * ```
1834 * const upgradeAdapter = new UpgradeAdapter(MyNg2Module);
1835 * upgradeAdapter.declareNg1Module(['heroApp']);
1836 * ```
1837 */
1838 declareNg1Module(modules = []) {
1839 const delayApplyExps = [];
1840 let original$applyFn;
1841 let rootScopePrototype;
1842 const upgradeAdapter = this;
1843 const ng1Module = this.ng1Module = module_(this.idPrefix, modules);
1844 const platformRef = platformBrowserDynamic();
1845 this.ngZone = new NgZone({ enableLongStackTrace: Zone.hasOwnProperty('longStackTraceZoneSpec') });
1846 this.ng2BootstrapDeferred = new Deferred();
1847 ng1Module.constant(UPGRADE_APP_TYPE_KEY, 1 /* Dynamic */)
1848 .factory(INJECTOR_KEY, () => this.moduleRef.injector.get(Injector))
1849 .factory(LAZY_MODULE_REF, [INJECTOR_KEY, (injector) => ({ injector })])
1850 .constant(NG_ZONE_KEY, this.ngZone)
1851 .factory(COMPILER_KEY, () => this.moduleRef.injector.get(Compiler))
1852 .config([
1853 '$provide', '$injector',
1854 (provide, ng1Injector) => {
1855 provide.decorator($ROOT_SCOPE, [
1856 '$delegate',
1857 function (rootScopeDelegate) {
1858 // Capture the root apply so that we can delay first call to $apply until we
1859 // bootstrap Angular and then we replay and restore the $apply.
1860 rootScopePrototype = rootScopeDelegate.constructor.prototype;
1861 if (rootScopePrototype.hasOwnProperty('$apply')) {
1862 original$applyFn = rootScopePrototype.$apply;
1863 rootScopePrototype.$apply = (exp) => delayApplyExps.push(exp);
1864 }
1865 else {
1866 throw new Error('Failed to find \'$apply\' on \'$rootScope\'!');
1867 }
1868 return rootScopeDelegate;
1869 }
1870 ]);
1871 if (ng1Injector.has($$TESTABILITY)) {
1872 provide.decorator($$TESTABILITY, [
1873 '$delegate',
1874 function (testabilityDelegate) {
1875 const originalWhenStable = testabilityDelegate.whenStable;
1876 // Cannot use arrow function below because we need the context
1877 const newWhenStable = function (callback) {
1878 originalWhenStable.call(this, function () {
1879 const ng2Testability = upgradeAdapter.moduleRef.injector.get(Testability);
1880 if (ng2Testability.isStable()) {
1881 callback.apply(this, arguments);
1882 }
1883 else {
1884 ng2Testability.whenStable(newWhenStable.bind(this, callback));
1885 }
1886 });
1887 };
1888 testabilityDelegate.whenStable = newWhenStable;
1889 return testabilityDelegate;
1890 }
1891 ]);
1892 }
1893 }
1894 ]);
1895 ng1Module.run([
1896 '$injector', '$rootScope',
1897 (ng1Injector, rootScope) => {
1898 UpgradeNg1ComponentAdapterBuilder.resolve(this.ng1ComponentsToBeUpgraded, ng1Injector)
1899 .then(() => {
1900 // Note: There is a bug in TS 2.4 that prevents us from
1901 // inlining this into @NgModule
1902 // TODO(tbosch): find or file a bug against TypeScript for this.
1903 const ngModule = {
1904 providers: [
1905 { provide: $INJECTOR, useFactory: () => ng1Injector },
1906 { provide: $COMPILE, useFactory: () => ng1Injector.get($COMPILE) },
1907 this.upgradedProviders
1908 ],
1909 imports: [resolveForwardRef(this.ng2AppModule)],
1910 entryComponents: this.downgradedComponents
1911 };
1912 // At this point we have ng1 injector and we have prepared
1913 // ng1 components to be upgraded, we now can bootstrap ng2.
1914 let DynamicNgUpgradeModule = class DynamicNgUpgradeModule {
1915 constructor() { }
1916 ngDoBootstrap() { }
1917 };
1918 DynamicNgUpgradeModule = __decorate([
1919 NgModule(Object.assign({ jit: true }, ngModule)),
1920 __metadata("design:paramtypes", [])
1921 ], DynamicNgUpgradeModule);
1922 platformRef
1923 .bootstrapModule(DynamicNgUpgradeModule, [this.compilerOptions, { ngZone: this.ngZone }])
1924 .then((ref) => {
1925 this.moduleRef = ref;
1926 this.ngZone.run(() => {
1927 if (rootScopePrototype) {
1928 rootScopePrototype.$apply = original$applyFn; // restore original $apply
1929 while (delayApplyExps.length) {
1930 rootScope.$apply(delayApplyExps.shift());
1931 }
1932 rootScopePrototype = null;
1933 }
1934 });
1935 })
1936 .then(() => this.ng2BootstrapDeferred.resolve(ng1Injector), onError)
1937 .then(() => {
1938 let subscription = this.ngZone.onMicrotaskEmpty.subscribe({
1939 next: () => {
1940 if (rootScope.$$phase) {
1941 if (isDevMode()) {
1942 console.warn('A digest was triggered while one was already in progress. This may mean that something is triggering digests outside the Angular zone.');
1943 }
1944 return rootScope.$evalAsync(() => { });
1945 }
1946 return rootScope.$digest();
1947 }
1948 });
1949 rootScope.$on('$destroy', () => {
1950 subscription.unsubscribe();
1951 });
1952 // Destroy the AngularJS app once the Angular `PlatformRef` is destroyed.
1953 // This does not happen in a typical SPA scenario, but it might be useful for
1954 // other use-cases where disposing of an Angular/AngularJS app is necessary
1955 // (such as Hot Module Replacement (HMR)).
1956 // See https://github.com/angular/angular/issues/39935.
1957 platformRef.onDestroy(() => destroyApp(ng1Injector));
1958 });
1959 })
1960 .catch((e) => this.ng2BootstrapDeferred.reject(e));
1961 }
1962 ]);
1963 return ng1Module;
1964 }
1965}
1966/**
1967 * Synchronous promise-like object to wrap parent injectors,
1968 * to preserve the synchronous nature of AngularJS's $compile.
1969 */
1970class ParentInjectorPromise {
1971 constructor(element) {
1972 this.element = element;
1973 this.callbacks = [];
1974 // store the promise on the element
1975 element.data(controllerKey(INJECTOR_KEY), this);
1976 }
1977 then(callback) {
1978 if (this.injector) {
1979 callback(this.injector);
1980 }
1981 else {
1982 this.callbacks.push(callback);
1983 }
1984 }
1985 resolve(injector) {
1986 this.injector = injector;
1987 // reset the element data to point to the real injector
1988 this.element.data(controllerKey(INJECTOR_KEY), injector);
1989 // clean out the element to prevent memory leaks
1990 this.element = null;
1991 // run all the queued callbacks
1992 this.callbacks.forEach((callback) => callback(injector));
1993 this.callbacks.length = 0;
1994 }
1995}
1996/**
1997 * Use `UpgradeAdapterRef` to control a hybrid AngularJS / Angular application.
1998 *
1999 * @deprecated Deprecated since v5. Use `upgrade/static` instead, which also supports
2000 * [Ahead-of-Time compilation](guide/aot-compiler).
2001 * @publicApi
2002 */
2003class UpgradeAdapterRef {
2004 constructor() {
2005 /* @internal */
2006 this._readyFn = null;
2007 this.ng1RootScope = null;
2008 this.ng1Injector = null;
2009 this.ng2ModuleRef = null;
2010 this.ng2Injector = null;
2011 }
2012 /* @internal */
2013 _bootstrapDone(ngModuleRef, ng1Injector) {
2014 this.ng2ModuleRef = ngModuleRef;
2015 this.ng2Injector = ngModuleRef.injector;
2016 this.ng1Injector = ng1Injector;
2017 this.ng1RootScope = ng1Injector.get($ROOT_SCOPE);
2018 this._readyFn && this._readyFn(this);
2019 }
2020 /**
2021 * Register a callback function which is notified upon successful hybrid AngularJS / Angular
2022 * application has been bootstrapped.
2023 *
2024 * The `ready` callback function is invoked inside the Angular zone, therefore it does not
2025 * require a call to `$apply()`.
2026 */
2027 ready(fn) {
2028 this._readyFn = fn;
2029 }
2030 /**
2031 * Dispose of running hybrid AngularJS / Angular application.
2032 */
2033 dispose() {
2034 this.ng1Injector.get($ROOT_SCOPE).$destroy();
2035 this.ng2ModuleRef.destroy();
2036 }
2037}
2038
2039/**
2040 * @license
2041 * Copyright Google LLC All Rights Reserved.
2042 *
2043 * Use of this source code is governed by an MIT-style license that can be
2044 * found in the LICENSE file at https://angular.io/license
2045 */
2046// This file only re-exports content of the `src` folder. Keep it that way.
2047
2048/**
2049 * @license
2050 * Copyright Google LLC All Rights Reserved.
2051 *
2052 * Use of this source code is governed by an MIT-style license that can be
2053 * found in the LICENSE file at https://angular.io/license
2054 */
2055
2056/**
2057 * Generated bundle index. Do not edit.
2058 */
2059
2060export { UpgradeAdapter, UpgradeAdapterRef, VERSION };
2061//# sourceMappingURL=upgrade.mjs.map