UNPKG

@angular/core

Version:

Angular - the core framework

1,315 lines (1,289 loc) 1.15 MB
/** * @license Angular v15.1.5 * (c) 2010-2022 Google LLC. https://angular.io/ * License: MIT */ import { Subject, Subscription, Observable, merge as merge$1 } from 'rxjs'; import { share } from 'rxjs/operators'; function getClosureSafeProperty(objWithPropertyToExtract) { for (let key in objWithPropertyToExtract) { if (objWithPropertyToExtract[key] === getClosureSafeProperty) { return key; } } throw Error('Could not find renamed property on target object.'); } /** * Sets properties on a target object from a source object, but only if * the property doesn't already exist on the target object. * @param target The target to set properties on * @param source The source of the property keys and values to set */ function fillProperties(target, source) { for (const key in source) { if (source.hasOwnProperty(key) && !target.hasOwnProperty(key)) { target[key] = source[key]; } } } function stringify(token) { if (typeof token === 'string') { return token; } if (Array.isArray(token)) { return '[' + token.map(stringify).join(', ') + ']'; } if (token == null) { return '' + token; } if (token.overriddenName) { return `${token.overriddenName}`; } if (token.name) { return `${token.name}`; } const res = token.toString(); if (res == null) { return '' + res; } const newLineIndex = res.indexOf('\n'); return newLineIndex === -1 ? res : res.substring(0, newLineIndex); } /** * Concatenates two strings with separator, allocating new strings only when necessary. * * @param before before string. * @param separator separator string. * @param after after string. * @returns concatenated string. */ function concatStringsWithSpace(before, after) { return (before == null || before === '') ? (after === null ? '' : after) : ((after == null || after === '') ? before : before + ' ' + after); } const __forward_ref__ = getClosureSafeProperty({ __forward_ref__: getClosureSafeProperty }); /** * Allows to refer to references which are not yet defined. * * For instance, `forwardRef` is used when the `token` which we need to refer to for the purposes of * DI is declared, but not yet defined. It is also used when the `token` which we use when creating * a query is not yet defined. * * @usageNotes * ### Example * {@example core/di/ts/forward_ref/forward_ref_spec.ts region='forward_ref'} * @publicApi */ function forwardRef(forwardRefFn) { forwardRefFn.__forward_ref__ = forwardRef; forwardRefFn.toString = function () { return stringify(this()); }; return forwardRefFn; } /** * Lazily retrieves the reference value from a forwardRef. * * Acts as the identity function when given a non-forward-ref value. * * @usageNotes * ### Example * * {@example core/di/ts/forward_ref/forward_ref_spec.ts region='resolve_forward_ref'} * * @see `forwardRef` * @publicApi */ function resolveForwardRef(type) { return isForwardRef(type) ? type() : type; } /** Checks whether a function is wrapped by a `forwardRef`. */ function isForwardRef(fn) { return typeof fn === 'function' && fn.hasOwnProperty(__forward_ref__) && fn.__forward_ref__ === forwardRef; } function isEnvironmentProviders(value) { return value && !!value.ɵproviders; } /** * Base URL for the error details page. * * Keep this constant in sync across: * - packages/compiler-cli/src/ngtsc/diagnostics/src/error_details_base_url.ts * - packages/core/src/error_details_base_url.ts */ const ERROR_DETAILS_PAGE_BASE_URL = 'https://angular.io/errors'; /** * URL for the XSS security documentation. */ const XSS_SECURITY_URL = 'https://g.co/ng/security#xss'; /** * Class that represents a runtime error. * Formats and outputs the error message in a consistent way. * * Example: * ``` * throw new RuntimeError( * RuntimeErrorCode.INJECTOR_ALREADY_DESTROYED, * ngDevMode && 'Injector has already been destroyed.'); * ``` * * Note: the `message` argument contains a descriptive error message as a string in development * mode (when the `ngDevMode` is defined). In production mode (after tree-shaking pass), the * `message` argument becomes `false`, thus we account for it in the typings and the runtime logic. */ class RuntimeError extends Error { constructor(code, message) { super(formatRuntimeError(code, message)); this.code = code; } } /** * Called to format a runtime error. * See additional info on the `message` argument type in the `RuntimeError` class description. */ function formatRuntimeError(code, message) { // Error code might be a negative number, which is a special marker that instructs the logic to // generate a link to the error details page on angular.io. // We also prepend `0` to non-compile-time errors. const fullCode = `NG0${Math.abs(code)}`; let errorMessage = `${fullCode}${message ? ': ' + message.trim() : ''}`; if (ngDevMode && code < 0) { const addPeriodSeparator = !errorMessage.match(/[.,;!?]$/); const separator = addPeriodSeparator ? '.' : ''; errorMessage = `${errorMessage}${separator} Find more at ${ERROR_DETAILS_PAGE_BASE_URL}/${fullCode}`; } return errorMessage; } /** * Used for stringify render output in Ivy. * Important! This function is very performance-sensitive and we should * be extra careful not to introduce megamorphic reads in it. * Check `core/test/render3/perf/render_stringify` for benchmarks and alternate implementations. */ function renderStringify(value) { if (typeof value === 'string') return value; if (value == null) return ''; // Use `String` so that it invokes the `toString` method of the value. Note that this // appears to be faster than calling `value.toString` (see `render_stringify` benchmark). return String(value); } /** * Used to stringify a value so that it can be displayed in an error message. * Important! This function contains a megamorphic read and should only be * used for error messages. */ function stringifyForError(value) { if (typeof value === 'function') return value.name || value.toString(); if (typeof value === 'object' && value != null && typeof value.type === 'function') { return value.type.name || value.type.toString(); } return renderStringify(value); } /** Called when directives inject each other (creating a circular dependency) */ function throwCyclicDependencyError(token, path) { const depPath = path ? `. Dependency path: ${path.join(' > ')} > ${token}` : ''; throw new RuntimeError(-200 /* RuntimeErrorCode.CYCLIC_DI_DEPENDENCY */, `Circular dependency in DI detected for ${token}${depPath}`); } function throwMixedMultiProviderError() { throw new Error(`Cannot mix multi providers and regular providers`); } function throwInvalidProviderError(ngModuleType, providers, provider) { if (ngModuleType && providers) { const providerDetail = providers.map(v => v == provider ? '?' + provider + '?' : '...'); throw new Error(`Invalid provider for the NgModule '${stringify(ngModuleType)}' - only instances of Provider and Type are allowed, got: [${providerDetail.join(', ')}]`); } else if (isEnvironmentProviders(provider)) { if (provider.ɵfromNgModule) { throw new RuntimeError(207 /* RuntimeErrorCode.PROVIDER_IN_WRONG_CONTEXT */, `Invalid providers from 'importProvidersFrom' present in a non-environment injector. 'importProvidersFrom' can't be used for component providers.`); } else { throw new RuntimeError(207 /* RuntimeErrorCode.PROVIDER_IN_WRONG_CONTEXT */, `Invalid providers present in a non-environment injector. 'EnvironmentProviders' can't be used for component providers.`); } } else { throw new Error('Invalid provider'); } } /** Throws an error when a token is not found in DI. */ function throwProviderNotFoundError(token, injectorName) { const injectorDetails = injectorName ? ` in ${injectorName}` : ''; throw new RuntimeError(-201 /* RuntimeErrorCode.PROVIDER_NOT_FOUND */, ngDevMode && `No provider for ${stringifyForError(token)} found${injectorDetails}`); } // The functions in this file verify that the assumptions we are making function assertNumber(actual, msg) { if (!(typeof actual === 'number')) { throwError(msg, typeof actual, 'number', '==='); } } function assertNumberInRange(actual, minInclusive, maxInclusive) { assertNumber(actual, 'Expected a number'); assertLessThanOrEqual(actual, maxInclusive, 'Expected number to be less than or equal to'); assertGreaterThanOrEqual(actual, minInclusive, 'Expected number to be greater than or equal to'); } function assertString(actual, msg) { if (!(typeof actual === 'string')) { throwError(msg, actual === null ? 'null' : typeof actual, 'string', '==='); } } function assertFunction(actual, msg) { if (!(typeof actual === 'function')) { throwError(msg, actual === null ? 'null' : typeof actual, 'function', '==='); } } function assertEqual(actual, expected, msg) { if (!(actual == expected)) { throwError(msg, actual, expected, '=='); } } function assertNotEqual(actual, expected, msg) { if (!(actual != expected)) { throwError(msg, actual, expected, '!='); } } function assertSame(actual, expected, msg) { if (!(actual === expected)) { throwError(msg, actual, expected, '==='); } } function assertNotSame(actual, expected, msg) { if (!(actual !== expected)) { throwError(msg, actual, expected, '!=='); } } function assertLessThan(actual, expected, msg) { if (!(actual < expected)) { throwError(msg, actual, expected, '<'); } } function assertLessThanOrEqual(actual, expected, msg) { if (!(actual <= expected)) { throwError(msg, actual, expected, '<='); } } function assertGreaterThan(actual, expected, msg) { if (!(actual > expected)) { throwError(msg, actual, expected, '>'); } } function assertGreaterThanOrEqual(actual, expected, msg) { if (!(actual >= expected)) { throwError(msg, actual, expected, '>='); } } function assertNotDefined(actual, msg) { if (actual != null) { throwError(msg, actual, null, '=='); } } function assertDefined(actual, msg) { if (actual == null) { throwError(msg, actual, null, '!='); } } function throwError(msg, actual, expected, comparison) { throw new Error(`ASSERTION ERROR: ${msg}` + (comparison == null ? '' : ` [Expected=> ${expected} ${comparison} ${actual} <=Actual]`)); } function assertDomNode(node) { // If we're in a worker, `Node` will not be defined. if (!(typeof Node !== 'undefined' && node instanceof Node) && !(typeof node === 'object' && node != null && node.constructor.name === 'WebWorkerRenderNode')) { throwError(`The provided value must be an instance of a DOM Node but got ${stringify(node)}`); } } function assertIndexInRange(arr, index) { assertDefined(arr, 'Array must be defined.'); const maxLen = arr.length; if (index < 0 || index >= maxLen) { throwError(`Index expected to be less than ${maxLen} but got ${index}`); } } function assertOneOf(value, ...validValues) { if (validValues.indexOf(value) !== -1) return true; throwError(`Expected value to be one of ${JSON.stringify(validValues)} but was ${JSON.stringify(value)}.`); } /** * Construct an injectable definition which defines how a token will be constructed by the DI * system, and in which injectors (if any) it will be available. * * This should be assigned to a static `ɵprov` field on a type, which will then be an * `InjectableType`. * * Options: * * `providedIn` determines which injectors will include the injectable, by either associating it * with an `@NgModule` or other `InjectorType`, or by specifying that this injectable should be * provided in the `'root'` injector, which will be the application-level injector in most apps. * * `factory` gives the zero argument function which will create an instance of the injectable. * The factory can call `inject` to access the `Injector` and request injection of dependencies. * * @codeGenApi * @publicApi This instruction has been emitted by ViewEngine for some time and is deployed to npm. */ function ɵɵdefineInjectable(opts) { return { token: opts.token, providedIn: opts.providedIn || null, factory: opts.factory, value: undefined, }; } /** * @deprecated in v8, delete after v10. This API should be used only by generated code, and that * code should now use ɵɵdefineInjectable instead. * @publicApi */ const defineInjectable = ɵɵdefineInjectable; /** * Construct an `InjectorDef` which configures an injector. * * This should be assigned to a static injector def (`ɵinj`) field on a type, which will then be an * `InjectorType`. * * Options: * * * `providers`: an optional array of providers to add to the injector. Each provider must * either have a factory or point to a type which has a `ɵprov` static property (the * type must be an `InjectableType`). * * `imports`: an optional array of imports of other `InjectorType`s or `InjectorTypeWithModule`s * whose providers will also be added to the injector. Locally provided types will override * providers from imports. * * @codeGenApi */ function ɵɵdefineInjector(options) { return { providers: options.providers || [], imports: options.imports || [] }; } /** * Read the injectable def (`ɵprov`) for `type` in a way which is immune to accidentally reading * inherited value. * * @param type A type which may have its own (non-inherited) `ɵprov`. */ function getInjectableDef(type) { return getOwnDefinition(type, NG_PROV_DEF) || getOwnDefinition(type, NG_INJECTABLE_DEF); } function isInjectable(type) { return getInjectableDef(type) !== null; } /** * Return definition only if it is defined directly on `type` and is not inherited from a base * class of `type`. */ function getOwnDefinition(type, field) { return type.hasOwnProperty(field) ? type[field] : null; } /** * Read the injectable def (`ɵprov`) for `type` or read the `ɵprov` from one of its ancestors. * * @param type A type which may have `ɵprov`, via inheritance. * * @deprecated Will be removed in a future version of Angular, where an error will occur in the * scenario if we find the `ɵprov` on an ancestor only. */ function getInheritedInjectableDef(type) { const def = type && (type[NG_PROV_DEF] || type[NG_INJECTABLE_DEF]); if (def) { const typeName = getTypeName(type); // TODO(FW-1307): Re-add ngDevMode when closure can handle it // ngDevMode && console.warn(`DEPRECATED: DI is instantiating a token "${typeName}" that inherits its @Injectable decorator but does not provide one itself.\n` + `This will become an error in a future version of Angular. Please add @Injectable() to the "${typeName}" class.`); return def; } else { return null; } } /** Gets the name of a type, accounting for some cross-browser differences. */ function getTypeName(type) { // `Function.prototype.name` behaves differently between IE and other browsers. In most browsers // it'll always return the name of the function itself, no matter how many other functions it // inherits from. On IE the function doesn't have its own `name` property, but it takes it from // the lowest level in the prototype chain. E.g. if we have `class Foo extends Parent` most // browsers will evaluate `Foo.name` to `Foo` while IE will return `Parent`. We work around // the issue by converting the function to a string and parsing its name out that way via a regex. if (type.hasOwnProperty('name')) { return type.name; } const match = ('' + type).match(/^function\s*([^\s(]+)/); return match === null ? '' : match[1]; } /** * Read the injector def type in a way which is immune to accidentally reading inherited value. * * @param type type which may have an injector def (`ɵinj`) */ function getInjectorDef(type) { return type && (type.hasOwnProperty(NG_INJ_DEF) || type.hasOwnProperty(NG_INJECTOR_DEF)) ? type[NG_INJ_DEF] : null; } const NG_PROV_DEF = getClosureSafeProperty({ ɵprov: getClosureSafeProperty }); const NG_INJ_DEF = getClosureSafeProperty({ ɵinj: getClosureSafeProperty }); // We need to keep these around so we can read off old defs if new defs are unavailable const NG_INJECTABLE_DEF = getClosureSafeProperty({ ngInjectableDef: getClosureSafeProperty }); const NG_INJECTOR_DEF = getClosureSafeProperty({ ngInjectorDef: getClosureSafeProperty }); /** * Injection flags for DI. * * @publicApi * @deprecated use an options object for `inject` instead. */ var InjectFlags; (function (InjectFlags) { // TODO(alxhub): make this 'const' (and remove `InternalInjectFlags` enum) when ngc no longer // writes exports of it into ngfactory files. /** Check self and check parent injector if needed */ InjectFlags[InjectFlags["Default"] = 0] = "Default"; /** * Specifies that an injector should retrieve a dependency from any injector until reaching the * host element of the current component. (Only used with Element Injector) */ InjectFlags[InjectFlags["Host"] = 1] = "Host"; /** Don't ascend to ancestors of the node requesting injection. */ InjectFlags[InjectFlags["Self"] = 2] = "Self"; /** Skip the node that is requesting injection. */ InjectFlags[InjectFlags["SkipSelf"] = 4] = "SkipSelf"; /** Inject `defaultValue` instead if token not found. */ InjectFlags[InjectFlags["Optional"] = 8] = "Optional"; })(InjectFlags || (InjectFlags = {})); /** * Current implementation of inject. * * By default, it is `injectInjectorOnly`, which makes it `Injector`-only aware. It can be changed * to `directiveInject`, which brings in the `NodeInjector` system of ivy. It is designed this * way for two reasons: * 1. `Injector` should not depend on ivy logic. * 2. To maintain tree shake-ability we don't want to bring in unnecessary code. */ let _injectImplementation; function getInjectImplementation() { return _injectImplementation; } /** * Sets the current inject implementation. */ function setInjectImplementation(impl) { const previous = _injectImplementation; _injectImplementation = impl; return previous; } /** * Injects `root` tokens in limp mode. * * If no injector exists, we can still inject tree-shakable providers which have `providedIn` set to * `"root"`. This is known as the limp mode injection. In such case the value is stored in the * injectable definition. */ function injectRootLimpMode(token, notFoundValue, flags) { const injectableDef = getInjectableDef(token); if (injectableDef && injectableDef.providedIn == 'root') { return injectableDef.value === undefined ? injectableDef.value = injectableDef.factory() : injectableDef.value; } if (flags & InjectFlags.Optional) return null; if (notFoundValue !== undefined) return notFoundValue; throwProviderNotFoundError(stringify(token), 'Injector'); } /** * Assert that `_injectImplementation` is not `fn`. * * This is useful, to prevent infinite recursion. * * @param fn Function which it should not equal to */ function assertInjectImplementationNotEqual(fn) { ngDevMode && assertNotEqual(_injectImplementation, fn, 'Calling ɵɵinject would cause infinite recursion'); } // Always use __globalThis if available, which is the spec-defined global variable across all // environments, then fallback to __global first, because in Node tests both __global and // __window may be defined and _global should be __global in that case. Note: Typeof/Instanceof // checks are considered side-effects in Terser. We explicitly mark this as side-effect free: // https://github.com/terser/terser/issues/250. const _global = ( /* @__PURE__ */(() => (typeof globalThis !== 'undefined' && globalThis) || (typeof global !== 'undefined' && global) || (typeof window !== 'undefined' && window) || (typeof self !== 'undefined' && typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope && self))()); function ngDevModeResetPerfCounters() { const locationString = typeof location !== 'undefined' ? location.toString() : ''; const newCounters = { namedConstructors: locationString.indexOf('ngDevMode=namedConstructors') != -1, firstCreatePass: 0, tNode: 0, tView: 0, rendererCreateTextNode: 0, rendererSetText: 0, rendererCreateElement: 0, rendererAddEventListener: 0, rendererSetAttribute: 0, rendererRemoveAttribute: 0, rendererSetProperty: 0, rendererSetClassName: 0, rendererAddClass: 0, rendererRemoveClass: 0, rendererSetStyle: 0, rendererRemoveStyle: 0, rendererDestroy: 0, rendererDestroyNode: 0, rendererMoveNode: 0, rendererRemoveNode: 0, rendererAppendChild: 0, rendererInsertBefore: 0, rendererCreateComment: 0, }; // Make sure to refer to ngDevMode as ['ngDevMode'] for closure. const allowNgDevModeTrue = locationString.indexOf('ngDevMode=false') === -1; _global['ngDevMode'] = allowNgDevModeTrue && newCounters; return newCounters; } /** * This function checks to see if the `ngDevMode` has been set. If yes, * then we honor it, otherwise we default to dev mode with additional checks. * * The idea is that unless we are doing production build where we explicitly * set `ngDevMode == false` we should be helping the developer by providing * as much early warning and errors as possible. * * `ɵɵdefineComponent` is guaranteed to have been called before any component template functions * (and thus Ivy instructions), so a single initialization there is sufficient to ensure ngDevMode * is defined for the entire instruction set. * * When checking `ngDevMode` on toplevel, always init it before referencing it * (e.g. `((typeof ngDevMode === 'undefined' || ngDevMode) && initNgDevMode())`), otherwise you can * get a `ReferenceError` like in https://github.com/angular/angular/issues/31595. * * Details on possible values for `ngDevMode` can be found on its docstring. * * NOTE: * - changes to the `ngDevMode` name must be synced with `compiler-cli/src/tooling.ts`. */ function initNgDevMode() { // The below checks are to ensure that calling `initNgDevMode` multiple times does not // reset the counters. // If the `ngDevMode` is not an object, then it means we have not created the perf counters // yet. if (typeof ngDevMode === 'undefined' || ngDevMode) { if (typeof ngDevMode !== 'object') { ngDevModeResetPerfCounters(); } return typeof ngDevMode !== 'undefined' && !!ngDevMode; } return false; } const _THROW_IF_NOT_FOUND = {}; const THROW_IF_NOT_FOUND = _THROW_IF_NOT_FOUND; /* * Name of a property (that we patch onto DI decorator), which is used as an annotation of which * InjectFlag this decorator represents. This allows to avoid direct references to the DI decorators * in the code, thus making them tree-shakable. */ const DI_DECORATOR_FLAG = '__NG_DI_FLAG__'; const NG_TEMP_TOKEN_PATH = 'ngTempTokenPath'; const NG_TOKEN_PATH = 'ngTokenPath'; const NEW_LINE = /\n/gm; const NO_NEW_LINE = 'ɵ'; const SOURCE = '__source'; /** * Current injector value used by `inject`. * - `undefined`: it is an error to call `inject` * - `null`: `inject` can be called but there is no injector (limp-mode). * - Injector instance: Use the injector for resolution. */ let _currentInjector = undefined; function setCurrentInjector(injector) { const former = _currentInjector; _currentInjector = injector; return former; } function injectInjectorOnly(token, flags = InjectFlags.Default) { if (_currentInjector === undefined) { throw new RuntimeError(-203 /* RuntimeErrorCode.MISSING_INJECTION_CONTEXT */, ngDevMode && `inject() must be called from an injection context such as a constructor, a factory function, a field initializer, or a function used with \`EnvironmentInjector#runInContext\`.`); } else if (_currentInjector === null) { return injectRootLimpMode(token, undefined, flags); } else { return _currentInjector.get(token, flags & InjectFlags.Optional ? null : undefined, flags); } } function ɵɵinject(token, flags = InjectFlags.Default) { return (getInjectImplementation() || injectInjectorOnly)(resolveForwardRef(token), flags); } /** * Throws an error indicating that a factory function could not be generated by the compiler for a * particular class. * * The name of the class is not mentioned here, but will be in the generated factory function name * and thus in the stack trace. * * @codeGenApi */ function ɵɵinvalidFactoryDep(index) { throw new RuntimeError(202 /* RuntimeErrorCode.INVALID_FACTORY_DEPENDENCY */, ngDevMode && `This constructor is not compatible with Angular Dependency Injection because its dependency at index ${index} of the parameter list is invalid. This can happen if the dependency type is a primitive like a string or if an ancestor of this class is missing an Angular decorator. Please check that 1) the type for the parameter at index ${index} is correct and 2) the correct Angular decorators are defined for this class and its ancestors.`); } /** * Injects a token from the currently active injector. * `inject` is only supported during instantiation of a dependency by the DI system. It can be used * during: * - Construction (via the `constructor`) of a class being instantiated by the DI system, such * as an `@Injectable` or `@Component`. * - In the initializer for fields of such classes. * - In the factory function specified for `useFactory` of a `Provider` or an `@Injectable`. * - In the `factory` function specified for an `InjectionToken`. * * @param token A token that represents a dependency that should be injected. * @param flags Optional flags that control how injection is executed. * The flags correspond to injection strategies that can be specified with * parameter decorators `@Host`, `@Self`, `@SkipSelf`, and `@Optional`. * @returns the injected value if operation is successful, `null` otherwise. * @throws if called outside of a supported context. * * @usageNotes * In practice the `inject()` calls are allowed in a constructor, a constructor parameter and a * field initializer: * * ```typescript * @Injectable({providedIn: 'root'}) * export class Car { * radio: Radio|undefined; * // OK: field initializer * spareTyre = inject(Tyre); * * constructor() { * // OK: constructor body * this.radio = inject(Radio); * } * } * ``` * * It is also legal to call `inject` from a provider's factory: * * ```typescript * providers: [ * {provide: Car, useFactory: () => { * // OK: a class factory * const engine = inject(Engine); * return new Car(engine); * }} * ] * ``` * * Calls to the `inject()` function outside of the class creation context will result in error. Most * notably, calls to `inject()` are disallowed after a class instance was created, in methods * (including lifecycle hooks): * * ```typescript * @Component({ ... }) * export class CarComponent { * ngOnInit() { * // ERROR: too late, the component instance was already created * const engine = inject(Engine); * engine.start(); * } * } * ``` * * @publicApi */ function inject(token, flags = InjectFlags.Default) { return ɵɵinject(token, convertToBitFlags(flags)); } // Converts object-based DI flags (`InjectOptions`) to bit flags (`InjectFlags`). function convertToBitFlags(flags) { if (typeof flags === 'undefined' || typeof flags === 'number') { return flags; } // While TypeScript doesn't accept it without a cast, bitwise OR with false-y values in // JavaScript is a no-op. We can use that for a very codesize-efficient conversion from // `InjectOptions` to `InjectFlags`. return (0 /* InternalInjectFlags.Default */ | // comment to force a line break in the formatter (flags.optional && 8 /* InternalInjectFlags.Optional */) | (flags.host && 1 /* InternalInjectFlags.Host */) | (flags.self && 2 /* InternalInjectFlags.Self */) | (flags.skipSelf && 4 /* InternalInjectFlags.SkipSelf */)); } function injectArgs(types) { const args = []; for (let i = 0; i < types.length; i++) { const arg = resolveForwardRef(types[i]); if (Array.isArray(arg)) { if (arg.length === 0) { throw new RuntimeError(900 /* RuntimeErrorCode.INVALID_DIFFER_INPUT */, ngDevMode && 'Arguments array must have arguments.'); } let type = undefined; let flags = InjectFlags.Default; for (let j = 0; j < arg.length; j++) { const meta = arg[j]; const flag = getInjectFlag(meta); if (typeof flag === 'number') { // Special case when we handle @Inject decorator. if (flag === -1 /* DecoratorFlags.Inject */) { type = meta.token; } else { flags |= flag; } } else { type = meta; } } args.push(ɵɵinject(type, flags)); } else { args.push(ɵɵinject(arg)); } } return args; } /** * Attaches a given InjectFlag to a given decorator using monkey-patching. * Since DI decorators can be used in providers `deps` array (when provider is configured using * `useFactory`) without initialization (e.g. `Host`) and as an instance (e.g. `new Host()`), we * attach the flag to make it available both as a static property and as a field on decorator * instance. * * @param decorator Provided DI decorator. * @param flag InjectFlag that should be applied. */ function attachInjectFlag(decorator, flag) { decorator[DI_DECORATOR_FLAG] = flag; decorator.prototype[DI_DECORATOR_FLAG] = flag; return decorator; } /** * Reads monkey-patched property that contains InjectFlag attached to a decorator. * * @param token Token that may contain monkey-patched DI flags property. */ function getInjectFlag(token) { return token[DI_DECORATOR_FLAG]; } function catchInjectorError(e, token, injectorErrorName, source) { const tokenPath = e[NG_TEMP_TOKEN_PATH]; if (token[SOURCE]) { tokenPath.unshift(token[SOURCE]); } e.message = formatError('\n' + e.message, tokenPath, injectorErrorName, source); e[NG_TOKEN_PATH] = tokenPath; e[NG_TEMP_TOKEN_PATH] = null; throw e; } function formatError(text, obj, injectorErrorName, source = null) { text = text && text.charAt(0) === '\n' && text.charAt(1) == NO_NEW_LINE ? text.slice(2) : text; let context = stringify(obj); if (Array.isArray(obj)) { context = obj.map(stringify).join(' -> '); } else if (typeof obj === 'object') { let parts = []; for (let key in obj) { if (obj.hasOwnProperty(key)) { let value = obj[key]; parts.push(key + ':' + (typeof value === 'string' ? JSON.stringify(value) : stringify(value))); } } context = `{${parts.join(', ')}}`; } return `${injectorErrorName}${source ? '(' + source + ')' : ''}[${context}]: ${text.replace(NEW_LINE, '\n ')}`; } /** * Convince closure compiler that the wrapped function has no side-effects. * * Closure compiler always assumes that `toString` has no side-effects. We use this quirk to * allow us to execute a function but have closure compiler mark the call as no-side-effects. * It is important that the return value for the `noSideEffects` function be assigned * to something which is retained otherwise the call to `noSideEffects` will be removed by closure * compiler. */ function noSideEffects(fn) { return { toString: fn }.toString(); } /** * The strategy that the default change detector uses to detect changes. * When set, takes effect the next time change detection is triggered. * * @see {@link ChangeDetectorRef#usage-notes Change detection usage} * * @publicApi */ var ChangeDetectionStrategy; (function (ChangeDetectionStrategy) { /** * Use the `CheckOnce` strategy, meaning that automatic change detection is deactivated * until reactivated by setting the strategy to `Default` (`CheckAlways`). * Change detection can still be explicitly invoked. * This strategy applies to all child directives and cannot be overridden. */ ChangeDetectionStrategy[ChangeDetectionStrategy["OnPush"] = 0] = "OnPush"; /** * Use the default `CheckAlways` strategy, in which change detection is automatic until * explicitly deactivated. */ ChangeDetectionStrategy[ChangeDetectionStrategy["Default"] = 1] = "Default"; })(ChangeDetectionStrategy || (ChangeDetectionStrategy = {})); /** * Defines the possible states of the default change detector. * @see `ChangeDetectorRef` */ var ChangeDetectorStatus; (function (ChangeDetectorStatus) { /** * A state in which, after calling `detectChanges()`, the change detector * state becomes `Checked`, and must be explicitly invoked or reactivated. */ ChangeDetectorStatus[ChangeDetectorStatus["CheckOnce"] = 0] = "CheckOnce"; /** * A state in which change detection is skipped until the change detector mode * becomes `CheckOnce`. */ ChangeDetectorStatus[ChangeDetectorStatus["Checked"] = 1] = "Checked"; /** * A state in which change detection continues automatically until explicitly * deactivated. */ ChangeDetectorStatus[ChangeDetectorStatus["CheckAlways"] = 2] = "CheckAlways"; /** * A state in which a change detector sub tree is not a part of the main tree and * should be skipped. */ ChangeDetectorStatus[ChangeDetectorStatus["Detached"] = 3] = "Detached"; /** * Indicates that the change detector encountered an error checking a binding * or calling a directive lifecycle method and is now in an inconsistent state. Change * detectors in this state do not detect changes. */ ChangeDetectorStatus[ChangeDetectorStatus["Errored"] = 4] = "Errored"; /** * Indicates that the change detector has been destroyed. */ ChangeDetectorStatus[ChangeDetectorStatus["Destroyed"] = 5] = "Destroyed"; })(ChangeDetectorStatus || (ChangeDetectorStatus = {})); /** * Reports whether a given strategy is currently the default for change detection. * @param changeDetectionStrategy The strategy to check. * @returns True if the given strategy is the current default, false otherwise. * @see `ChangeDetectorStatus` * @see `ChangeDetectorRef` */ function isDefaultChangeDetectionStrategy(changeDetectionStrategy) { return changeDetectionStrategy == null || changeDetectionStrategy === ChangeDetectionStrategy.Default; } /** * Defines the CSS styles encapsulation policies for the {@link Component} decorator's * `encapsulation` option. * * See {@link Component#encapsulation encapsulation}. * * @usageNotes * ### Example * * {@example core/ts/metadata/encapsulation.ts region='longform'} * * @publicApi */ var ViewEncapsulation$1; (function (ViewEncapsulation) { // TODO: consider making `ViewEncapsulation` a `const enum` instead. See // https://github.com/angular/angular/issues/44119 for additional information. /** * Emulates a native Shadow DOM encapsulation behavior by adding a specific attribute to the * component's host element and applying the same attribute to all the CSS selectors provided * via {@link Component#styles styles} or {@link Component#styleUrls styleUrls}. * * This is the default option. */ ViewEncapsulation[ViewEncapsulation["Emulated"] = 0] = "Emulated"; // Historically the 1 value was for `Native` encapsulation which has been removed as of v11. /** * Doesn't provide any sort of CSS style encapsulation, meaning that all the styles provided * via {@link Component#styles styles} or {@link Component#styleUrls styleUrls} are applicable * to any HTML element of the application regardless of their host Component. */ ViewEncapsulation[ViewEncapsulation["None"] = 2] = "None"; /** * Uses the browser's native Shadow DOM API to encapsulate CSS styles, meaning that it creates * a ShadowRoot for the component's host element which is then used to encapsulate * all the Component's styling. */ ViewEncapsulation[ViewEncapsulation["ShadowDom"] = 3] = "ShadowDom"; })(ViewEncapsulation$1 || (ViewEncapsulation$1 = {})); /** * This file contains reuseable "empty" symbols that can be used as default return values * in different parts of the rendering code. Because the same symbols are returned, this * allows for identity checks against these values to be consistently used by the framework * code. */ const EMPTY_OBJ = {}; const EMPTY_ARRAY = []; // freezing the values prevents any code from accidentally inserting new values in if ((typeof ngDevMode === 'undefined' || ngDevMode) && initNgDevMode()) { // These property accesses can be ignored because ngDevMode will be set to false // when optimizing code and the whole if statement will be dropped. // tslint:disable-next-line:no-toplevel-property-access Object.freeze(EMPTY_OBJ); // tslint:disable-next-line:no-toplevel-property-access Object.freeze(EMPTY_ARRAY); } const NG_COMP_DEF = getClosureSafeProperty({ ɵcmp: getClosureSafeProperty }); const NG_DIR_DEF = getClosureSafeProperty({ ɵdir: getClosureSafeProperty }); const NG_PIPE_DEF = getClosureSafeProperty({ ɵpipe: getClosureSafeProperty }); const NG_MOD_DEF = getClosureSafeProperty({ ɵmod: getClosureSafeProperty }); const NG_FACTORY_DEF = getClosureSafeProperty({ ɵfac: getClosureSafeProperty }); /** * If a directive is diPublic, bloomAdd sets a property on the type with this constant as * the key and the directive's unique ID as the value. This allows us to map directives to their * bloom filter bit for DI. */ // TODO(misko): This is wrong. The NG_ELEMENT_ID should never be minified. const NG_ELEMENT_ID = getClosureSafeProperty({ __NG_ELEMENT_ID__: getClosureSafeProperty }); /** Counter used to generate unique IDs for component definitions. */ let componentDefCount = 0; /** * Create a component definition object. * * * # Example * ``` * class MyDirective { * // Generated by Angular Template Compiler * // [Symbol] syntax will not be supported by TypeScript until v2.7 * static ɵcmp = defineComponent({ * ... * }); * } * ``` * @codeGenApi */ function ɵɵdefineComponent(componentDefinition) { return noSideEffects(() => { // Initialize ngDevMode. This must be the first statement in ɵɵdefineComponent. // See the `initNgDevMode` docstring for more information. (typeof ngDevMode === 'undefined' || ngDevMode) && initNgDevMode(); const type = componentDefinition.type; const standalone = componentDefinition.standalone === true; const declaredInputs = {}; const def = { type: type, providersResolver: null, decls: componentDefinition.decls, vars: componentDefinition.vars, factory: null, template: componentDefinition.template || null, consts: componentDefinition.consts || null, ngContentSelectors: componentDefinition.ngContentSelectors, hostBindings: componentDefinition.hostBindings || null, hostVars: componentDefinition.hostVars || 0, hostAttrs: componentDefinition.hostAttrs || null, contentQueries: componentDefinition.contentQueries || null, declaredInputs: declaredInputs, inputs: null, outputs: null, exportAs: componentDefinition.exportAs || null, onPush: componentDefinition.changeDetection === ChangeDetectionStrategy.OnPush, directiveDefs: null, pipeDefs: null, standalone, dependencies: standalone && componentDefinition.dependencies || null, getStandaloneInjector: null, selectors: componentDefinition.selectors || EMPTY_ARRAY, viewQuery: componentDefinition.viewQuery || null, features: componentDefinition.features || null, data: componentDefinition.data || {}, encapsulation: componentDefinition.encapsulation || ViewEncapsulation$1.Emulated, id: `c${componentDefCount++}`, styles: componentDefinition.styles || EMPTY_ARRAY, _: null, setInput: null, schemas: componentDefinition.schemas || null, tView: null, findHostDirectiveDefs: null, hostDirectives: null, }; const dependencies = componentDefinition.dependencies; const feature = componentDefinition.features; def.inputs = invertObject(componentDefinition.inputs, declaredInputs), def.outputs = invertObject(componentDefinition.outputs), feature && feature.forEach((fn) => fn(def)); def.directiveDefs = dependencies ? (() => (typeof dependencies === 'function' ? dependencies() : dependencies) .map(extractDirectiveDef) .filter(nonNull)) : null; def.pipeDefs = dependencies ? (() => (typeof dependencies === 'function' ? dependencies() : dependencies) .map(getPipeDef$1) .filter(nonNull)) : null; return def; }); } /** * Generated next to NgModules to monkey-patch directive and pipe references onto a component's * definition, when generating a direct reference in the component file would otherwise create an * import cycle. * * See [this explanation](https://hackmd.io/Odw80D0pR6yfsOjg_7XCJg?view) for more details. * * @codeGenApi */ function ɵɵsetComponentScope(type, directives, pipes) { const def = type.ɵcmp; def.directiveDefs = () => (typeof directives === 'function' ? directives() : directives).map(extractDirectiveDef); def.pipeDefs = () => (typeof pipes === 'function' ? pipes() : pipes).map(getPipeDef$1); } function extractDirectiveDef(type) { return getComponentDef(type) || getDirectiveDef(type); } function nonNull(value) { return value !== null; } /** * @codeGenApi */ function ɵɵdefineNgModule(def) { return noSideEffects(() => { const res = { type: def.type, bootstrap: def.bootstrap || EMPTY_ARRAY, declarations: def.declarations || EMPTY_ARRAY, imports: def.imports || EMPTY_ARRAY, exports: def.exports || EMPTY_ARRAY, transitiveCompileScopes: null, schemas: def.schemas || null, id: def.id || null, }; return res; }); } /** * Adds the module metadata that is necessary to compute the module's transitive scope to an * existing module definition. * * Scope metadata of modules is not used in production builds, so calls to this function can be * marked pure to tree-shake it from the bundle, allowing for all referenced declarations * to become eligible for tree-shaking as well. * * @codeGenApi */ function ɵɵsetNgModuleScope(type, scope) { return noSideEffects(() => { const ngModuleDef = getNgModuleDef(type, true); ngModuleDef.declarations = scope.declarations || EMPTY_ARRAY; ngModuleDef.imports = scope.imports || EMPTY_ARRAY; ngModuleDef.exports = scope.exports || EMPTY_ARRAY; }); } /** * Inverts an inputs or outputs lookup such that the keys, which were the * minified keys, are part of the values, and the values are parsed so that * the publicName of the property is the new key * * e.g. for * * ``` * class Comp { * @Input() * propName1: string; * * @Input('publicName2') * declaredPropName2: number; * } * ``` * * will be serialized as * * ``` * { * propName1: 'propName1', * declaredPropName2: ['publicName2', 'declaredPropName2'], * } * ``` * * which is than translated by the minifier as: * * ``` * { * minifiedPropName1: 'propName1', * minifiedPropName2: ['publicName2', 'declaredPropName2'], * } * ``` * * becomes: (public name => minifiedName) * * ``` * { * 'propName1': 'minifiedPropName1', * 'publicName2': 'minifiedPropName2', * } * ``` * * Optionally the function can take `secondary` which will result in: (public name => declared name) * * ``` * { * 'propName1': 'propName1', * 'publicName2': 'declaredPropName2', * } * ``` * */ function invertObject(obj, secondary) { if (obj == null) return EMPTY_OBJ; const newLookup = {}; for (const minifiedKey in obj) { if (obj.hasOwnProperty(minifiedKey)) { let publicName = obj[minifiedKey]; let declaredName = publicName; if (Array.isArray(publicName)) { declaredName = publicName[1]; publicName = publicName[0]; } newLookup[publicName] = minifiedKey; if (secondary) { (secondary[publicName] = declaredName); } } } return newLookup; } /** * Create a directive definition object. * * # Example * ```ts * class MyDirective { * // Generated by Angular Template Compiler * // [Symbol] syntax will not be supported by TypeScript until v2.7 * static ɵdir = ɵɵdefineDirective({ * ... * }); * } * ``` * * @codeGenApi */ const ɵɵdefineDirective = ɵɵdefineComponent; /** * Create a pipe definition object. * * # Example * ``` * class MyPipe implements PipeTransform { * // Generated by Angular Template Compiler * static ɵpipe = definePipe({ * ... * }); * } * ``` * @param pipeDef Pipe definition generated by the compiler * * @codeGenApi */ function ɵɵdefinePipe(pipeDef) { return { type: pipeDef.type, name: pipeDef.name, factory: null, pure: pipeDef.pure !== false, standalone: pipeDef.standalone === true, onDestroy: pipeDef.type.prototype.ngOnDestroy || null }; } /** * The following getter methods retrieve the definition from the type. Currently the retrieval * honors inheritance, but in the future we may change the rule to require that definitions are * explicit. This would require some sort of migration strategy. */ function getComponentDef(type) { return type[NG_COMP_DEF] || null; } function getDirectiveDef(type) { return type[NG_DIR_DEF] || null; } function getPipeDef$1(type) { return type[NG_PIPE_DEF] || null; } /** * Checks whether a given Component, Directive or Pipe is marked as standalone. * This will return false if passed anything other than a Component, Directive, or Pipe class * See this guide for additional information: https://angular.io/guide/standalone-components * * @param type A reference to a Component, Directive or Pipe. * @publicApi */ function isStandalone(type) { const def = getComponentDef(type) || getDirectiveDef(type) || getPipeDef$1(type); return def !== null ? def.standalone : false; } function getNgModuleDef(type, throwNotFound) { const ngModuleDef = type[NG_MOD_DEF] || null; if (!ngModuleDef && throwNotFound === true) { throw new Error(`Type ${stringify(type)} does not have 'ɵmod' property.`); } return ngModuleDef; } // Below are constants for LView indices to help us look up LView members // without having to remember the specific indices. // Uglify will inline these when minifying so there shouldn't be a cost. const HOST = 0; const TVIEW = 1; const FLAGS = 2; const PARENT = 3; const NEXT = 4; const TRANSPLANTED_VIEWS_TO_REFRESH = 5; const T_HOST = 6; const CLEANUP = 7; const CONTEXT = 8; const INJECTOR$1 = 9; const RENDERER_FACTORY = 10; const RENDERER = 11; const SANITIZER = 12; const CHILD_HEAD = 13; const CHILD_TAIL = 14; // FIXME(misko): Investigate if the three declarations aren't all same thing. const DECLARATION_VIEW = 15; const DECLARATION_COMPONENT_VIEW = 16; const DECLARATION_LCONTAINER = 17; const PREORDER_HOOK_FLAGS = 18; const QUERIES = 19; const ID = 20; const EMBEDDED_VIEW_INJECTOR = 21; /** * Size of LView's header. Necessary to adjust for it when setting slots. * * IMPORTANT: `HEADER_OFFSET` should only be referred to the in the `ɵɵ*` instructions to translate * instruction index into `LView` index. All other indexes should be in the `LView` index space and * there should be no need to refer to `HEADER_OFFSET` anywhere else. */ const HEADER_OFFSET = 22; // Note: This hack is necessary so we don't erroneously get a circular dependency // failure based on types. const unusedValueExportToPlacateAjd$4 = 1; /** * Special location which allows easy identification of type. If we have an array which was * retrieved from the `LView` and that array has `true` at `TYPE` location, we know it is * `LContainer`. */ const TYPE = 1; /** * Below are constants for LContainer indices to help us look up LContainer members * without having to remember the specific indices. * Uglify will inline these wh