UNPKG

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