/** * @license Angular v12.2.17 * (c) 2010-2021 Google LLC. https://angular.io/ * License: MIT */ /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ var TagContentType; (function (TagContentType) { TagContentType[TagContentType["RAW_TEXT"] = 0] = "RAW_TEXT"; TagContentType[TagContentType["ESCAPABLE_RAW_TEXT"] = 1] = "ESCAPABLE_RAW_TEXT"; TagContentType[TagContentType["PARSABLE_DATA"] = 2] = "PARSABLE_DATA"; })(TagContentType || (TagContentType = {})); function splitNsName(elementName) { if (elementName[0] != ':') { return [null, elementName]; } const colonIndex = elementName.indexOf(':', 1); if (colonIndex === -1) { throw new Error(`Unsupported format "${elementName}" expecting ":namespace:name"`); } return [elementName.slice(1, colonIndex), elementName.slice(colonIndex + 1)]; } // `` tags work the same regardless the namespace function isNgContainer(tagName) { return splitNsName(tagName)[1] === 'ng-container'; } // `` tags work the same regardless the namespace function isNgContent(tagName) { return splitNsName(tagName)[1] === 'ng-content'; } // `` tags work the same regardless the namespace function isNgTemplate(tagName) { return splitNsName(tagName)[1] === 'ng-template'; } function getNsPrefix(fullName) { return fullName === null ? null : splitNsName(fullName)[0]; } function mergeNsAndName(prefix, localName) { return prefix ? `:${prefix}:${localName}` : localName; } /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ class HtmlTagDefinition { constructor({ closedByChildren, implicitNamespacePrefix, contentType = TagContentType.PARSABLE_DATA, closedByParent = false, isVoid = false, ignoreFirstLf = false, preventNamespaceInheritance = false } = {}) { this.closedByChildren = {}; this.closedByParent = false; this.canSelfClose = false; if (closedByChildren && closedByChildren.length > 0) { closedByChildren.forEach(tagName => this.closedByChildren[tagName] = true); } this.isVoid = isVoid; this.closedByParent = closedByParent || isVoid; this.implicitNamespacePrefix = implicitNamespacePrefix || null; this.contentType = contentType; this.ignoreFirstLf = ignoreFirstLf; this.preventNamespaceInheritance = preventNamespaceInheritance; } isClosedByChild(name) { return this.isVoid || name.toLowerCase() in this.closedByChildren; } getContentType(prefix) { if (typeof this.contentType === 'object') { const overrideType = prefix === undefined ? undefined : this.contentType[prefix]; return overrideType !== null && overrideType !== void 0 ? overrideType : this.contentType.default; } return this.contentType; } } let _DEFAULT_TAG_DEFINITION; // see https://www.w3.org/TR/html51/syntax.html#optional-tags // This implementation does not fully conform to the HTML5 spec. let TAG_DEFINITIONS; function getHtmlTagDefinition(tagName) { var _a, _b; if (!TAG_DEFINITIONS) { _DEFAULT_TAG_DEFINITION = new HtmlTagDefinition(); TAG_DEFINITIONS = { 'base': new HtmlTagDefinition({ isVoid: true }), 'meta': new HtmlTagDefinition({ isVoid: true }), 'area': new HtmlTagDefinition({ isVoid: true }), 'embed': new HtmlTagDefinition({ isVoid: true }), 'link': new HtmlTagDefinition({ isVoid: true }), 'img': new HtmlTagDefinition({ isVoid: true }), 'input': new HtmlTagDefinition({ isVoid: true }), 'param': new HtmlTagDefinition({ isVoid: true }), 'hr': new HtmlTagDefinition({ isVoid: true }), 'br': new HtmlTagDefinition({ isVoid: true }), 'source': new HtmlTagDefinition({ isVoid: true }), 'track': new HtmlTagDefinition({ isVoid: true }), 'wbr': new HtmlTagDefinition({ isVoid: true }), 'p': new HtmlTagDefinition({ closedByChildren: [ 'address', 'article', 'aside', 'blockquote', 'div', 'dl', 'fieldset', 'footer', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'header', 'hgroup', 'hr', 'main', 'nav', 'ol', 'p', 'pre', 'section', 'table', 'ul' ], closedByParent: true }), 'thead': new HtmlTagDefinition({ closedByChildren: ['tbody', 'tfoot'] }), 'tbody': new HtmlTagDefinition({ closedByChildren: ['tbody', 'tfoot'], closedByParent: true }), 'tfoot': new HtmlTagDefinition({ closedByChildren: ['tbody'], closedByParent: true }), 'tr': new HtmlTagDefinition({ closedByChildren: ['tr'], closedByParent: true }), 'td': new HtmlTagDefinition({ closedByChildren: ['td', 'th'], closedByParent: true }), 'th': new HtmlTagDefinition({ closedByChildren: ['td', 'th'], closedByParent: true }), 'col': new HtmlTagDefinition({ isVoid: true }), 'svg': new HtmlTagDefinition({ implicitNamespacePrefix: 'svg' }), 'foreignObject': new HtmlTagDefinition({ // Usually the implicit namespace here would be redundant since it will be inherited from // the parent `svg`, but we have to do it for `foreignObject`, because the way the parser // works is that the parent node of an end tag is its own start tag which means that // the `preventNamespaceInheritance` on `foreignObject` would have it default to the // implicit namespace which is `html`, unless specified otherwise. implicitNamespacePrefix: 'svg', // We want to prevent children of foreignObject from inheriting its namespace, because // the point of the element is to allow nodes from other namespaces to be inserted. preventNamespaceInheritance: true, }), 'math': new HtmlTagDefinition({ implicitNamespacePrefix: 'math' }), 'li': new HtmlTagDefinition({ closedByChildren: ['li'], closedByParent: true }), 'dt': new HtmlTagDefinition({ closedByChildren: ['dt', 'dd'] }), 'dd': new HtmlTagDefinition({ closedByChildren: ['dt', 'dd'], closedByParent: true }), 'rb': new HtmlTagDefinition({ closedByChildren: ['rb', 'rt', 'rtc', 'rp'], closedByParent: true }), 'rt': new HtmlTagDefinition({ closedByChildren: ['rb', 'rt', 'rtc', 'rp'], closedByParent: true }), 'rtc': new HtmlTagDefinition({ closedByChildren: ['rb', 'rtc', 'rp'], closedByParent: true }), 'rp': new HtmlTagDefinition({ closedByChildren: ['rb', 'rt', 'rtc', 'rp'], closedByParent: true }), 'optgroup': new HtmlTagDefinition({ closedByChildren: ['optgroup'], closedByParent: true }), 'option': new HtmlTagDefinition({ closedByChildren: ['option', 'optgroup'], closedByParent: true }), 'pre': new HtmlTagDefinition({ ignoreFirstLf: true }), 'listing': new HtmlTagDefinition({ ignoreFirstLf: true }), 'style': new HtmlTagDefinition({ contentType: TagContentType.RAW_TEXT }), 'script': new HtmlTagDefinition({ contentType: TagContentType.RAW_TEXT }), 'title': new HtmlTagDefinition({ // The browser supports two separate `title` tags which have to use // a different content type: `HTMLTitleElement` and `SVGTitleElement` contentType: { default: TagContentType.ESCAPABLE_RAW_TEXT, svg: TagContentType.PARSABLE_DATA } }), 'textarea': new HtmlTagDefinition({ contentType: TagContentType.ESCAPABLE_RAW_TEXT, ignoreFirstLf: true }), }; } // We have to make both a case-sensitive and a case-insesitive lookup, because // HTML tag names are case insensitive, whereas some SVG tags are case sensitive. return (_b = (_a = TAG_DEFINITIONS[tagName]) !== null && _a !== void 0 ? _a : TAG_DEFINITIONS[tagName.toLowerCase()]) !== null && _b !== void 0 ? _b : _DEFAULT_TAG_DEFINITION; } /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ const _SELECTOR_REGEXP = new RegExp('(\\:not\\()|' + // 1: ":not(" '(([\\.\\#]?)[-\\w]+)|' + // 2: "tag"; 3: "."/"#"; // "-" should appear first in the regexp below as FF31 parses "[.-\w]" as a range // 4: attribute; 5: attribute_string; 6: attribute_value '(?:\\[([-.\\w*\\\\$]+)(?:=([\"\']?)([^\\]\"\']*)\\5)?\\])|' + // "[name]", "[name=value]", // "[name="value"]", // "[name='value']" '(\\))|' + // 7: ")" '(\\s*,\\s*)', // 8: "," 'g'); /** * A css selector contains an element name, * css classes and attribute/value pairs with the purpose * of selecting subsets out of them. */ class CssSelector { constructor() { this.element = null; this.classNames = []; /** * The selectors are encoded in pairs where: * - even locations are attribute names * - odd locations are attribute values. * * Example: * Selector: `[key1=value1][key2]` would parse to: * ``` * ['key1', 'value1', 'key2', ''] * ``` */ this.attrs = []; this.notSelectors = []; } static parse(selector) { const results = []; const _addResult = (res, cssSel) => { if (cssSel.notSelectors.length > 0 && !cssSel.element && cssSel.classNames.length == 0 && cssSel.attrs.length == 0) { cssSel.element = '*'; } res.push(cssSel); }; let cssSelector = new CssSelector(); let match; let current = cssSelector; let inNot = false; _SELECTOR_REGEXP.lastIndex = 0; while (match = _SELECTOR_REGEXP.exec(selector)) { if (match[1 /* NOT */]) { if (inNot) { throw new Error('Nesting :not in a selector is not allowed'); } inNot = true; current = new CssSelector(); cssSelector.notSelectors.push(current); } const tag = match[2 /* TAG */]; if (tag) { const prefix = match[3 /* PREFIX */]; if (prefix === '#') { // #hash current.addAttribute('id', tag.substr(1)); } else if (prefix === '.') { // Class current.addClassName(tag.substr(1)); } else { // Element current.setElement(tag); } } const attribute = match[4 /* ATTRIBUTE */]; if (attribute) { current.addAttribute(current.unescapeAttribute(attribute), match[6 /* ATTRIBUTE_VALUE */]); } if (match[7 /* NOT_END */]) { inNot = false; current = cssSelector; } if (match[8 /* SEPARATOR */]) { if (inNot) { throw new Error('Multiple selectors in :not are not supported'); } _addResult(results, cssSelector); cssSelector = current = new CssSelector(); } } _addResult(results, cssSelector); return results; } /** * Unescape `\$` sequences from the CSS attribute selector. * * This is needed because `$` can have a special meaning in CSS selectors, * but we might want to match an attribute that contains `$`. * [MDN web link for more * info](https://developer.mozilla.org/en-US/docs/Web/CSS/Attribute_selectors). * @param attr the attribute to unescape. * @returns the unescaped string. */ unescapeAttribute(attr) { let result = ''; let escaping = false; for (let i = 0; i < attr.length; i++) { const char = attr.charAt(i); if (char === '\\') { escaping = true; continue; } if (char === '$' && !escaping) { throw new Error(`Error in attribute selector "${attr}". ` + `Unescaped "$" is not supported. Please escape with "\\$".`); } escaping = false; result += char; } return result; } /** * Escape `$` sequences from the CSS attribute selector. * * This is needed because `$` can have a special meaning in CSS selectors, * with this method we are escaping `$` with `\$'. * [MDN web link for more * info](https://developer.mozilla.org/en-US/docs/Web/CSS/Attribute_selectors). * @param attr the attribute to escape. * @returns the escaped string. */ escapeAttribute(attr) { return attr.replace(/\\/g, '\\\\').replace(/\$/g, '\\$'); } isElementSelector() { return this.hasElementSelector() && this.classNames.length == 0 && this.attrs.length == 0 && this.notSelectors.length === 0; } hasElementSelector() { return !!this.element; } setElement(element = null) { this.element = element; } /** Gets a template string for an element that matches the selector. */ getMatchingElementTemplate() { const tagName = this.element || 'div'; const classAttr = this.classNames.length > 0 ? ` class="${this.classNames.join(' ')}"` : ''; let attrs = ''; for (let i = 0; i < this.attrs.length; i += 2) { const attrName = this.attrs[i]; const attrValue = this.attrs[i + 1] !== '' ? `="${this.attrs[i + 1]}"` : ''; attrs += ` ${attrName}${attrValue}`; } return getHtmlTagDefinition(tagName).isVoid ? `<${tagName}${classAttr}${attrs}/>` : `<${tagName}${classAttr}${attrs}>`; } getAttrs() { const result = []; if (this.classNames.length > 0) { result.push('class', this.classNames.join(' ')); } return result.concat(this.attrs); } addAttribute(name, value = '') { this.attrs.push(name, value && value.toLowerCase() || ''); } addClassName(name) { this.classNames.push(name.toLowerCase()); } toString() { let res = this.element || ''; if (this.classNames) { this.classNames.forEach(klass => res += `.${klass}`); } if (this.attrs) { for (let i = 0; i < this.attrs.length; i += 2) { const name = this.escapeAttribute(this.attrs[i]); const value = this.attrs[i + 1]; res += `[${name}${value ? '=' + value : ''}]`; } } this.notSelectors.forEach(notSelector => res += `:not(${notSelector})`); return res; } } /** * Reads a list of CssSelectors and allows to calculate which ones * are contained in a given CssSelector. */ class SelectorMatcher { constructor() { this._elementMap = new Map(); this._elementPartialMap = new Map(); this._classMap = new Map(); this._classPartialMap = new Map(); this._attrValueMap = new Map(); this._attrValuePartialMap = new Map(); this._listContexts = []; } static createNotMatcher(notSelectors) { const notMatcher = new SelectorMatcher(); notMatcher.addSelectables(notSelectors, null); return notMatcher; } addSelectables(cssSelectors, callbackCtxt) { let listContext = null; if (cssSelectors.length > 1) { listContext = new SelectorListContext(cssSelectors); this._listContexts.push(listContext); } for (let i = 0; i < cssSelectors.length; i++) { this._addSelectable(cssSelectors[i], callbackCtxt, listContext); } } /** * Add an object that can be found later on by calling `match`. * @param cssSelector A css selector * @param callbackCtxt An opaque object that will be given to the callback of the `match` function */ _addSelectable(cssSelector, callbackCtxt, listContext) { let matcher = this; const element = cssSelector.element; const classNames = cssSelector.classNames; const attrs = cssSelector.attrs; const selectable = new SelectorContext(cssSelector, callbackCtxt, listContext); if (element) { const isTerminal = attrs.length === 0 && classNames.length === 0; if (isTerminal) { this._addTerminal(matcher._elementMap, element, selectable); } else { matcher = this._addPartial(matcher._elementPartialMap, element); } } if (classNames) { for (let i = 0; i < classNames.length; i++) { const isTerminal = attrs.length === 0 && i === classNames.length - 1; const className = classNames[i]; if (isTerminal) { this._addTerminal(matcher._classMap, className, selectable); } else { matcher = this._addPartial(matcher._classPartialMap, className); } } } if (attrs) { for (let i = 0; i < attrs.length; i += 2) { const isTerminal = i === attrs.length - 2; const name = attrs[i]; const value = attrs[i + 1]; if (isTerminal) { const terminalMap = matcher._attrValueMap; let terminalValuesMap = terminalMap.get(name); if (!terminalValuesMap) { terminalValuesMap = new Map(); terminalMap.set(name, terminalValuesMap); } this._addTerminal(terminalValuesMap, value, selectable); } else { const partialMap = matcher._attrValuePartialMap; let partialValuesMap = partialMap.get(name); if (!partialValuesMap) { partialValuesMap = new Map(); partialMap.set(name, partialValuesMap); } matcher = this._addPartial(partialValuesMap, value); } } } } _addTerminal(map, name, selectable) { let terminalList = map.get(name); if (!terminalList) { terminalList = []; map.set(name, terminalList); } terminalList.push(selectable); } _addPartial(map, name) { let matcher = map.get(name); if (!matcher) { matcher = new SelectorMatcher(); map.set(name, matcher); } return matcher; } /** * Find the objects that have been added via `addSelectable` * whose css selector is contained in the given css selector. * @param cssSelector A css selector * @param matchedCallback This callback will be called with the object handed into `addSelectable` * @return boolean true if a match was found */ match(cssSelector, matchedCallback) { let result = false; const element = cssSelector.element; const classNames = cssSelector.classNames; const attrs = cssSelector.attrs; for (let i = 0; i < this._listContexts.length; i++) { this._listContexts[i].alreadyMatched = false; } result = this._matchTerminal(this._elementMap, element, cssSelector, matchedCallback) || result; result = this._matchPartial(this._elementPartialMap, element, cssSelector, matchedCallback) || result; if (classNames) { for (let i = 0; i < classNames.length; i++) { const className = classNames[i]; result = this._matchTerminal(this._classMap, className, cssSelector, matchedCallback) || result; result = this._matchPartial(this._classPartialMap, className, cssSelector, matchedCallback) || result; } } if (attrs) { for (let i = 0; i < attrs.length; i += 2) { const name = attrs[i]; const value = attrs[i + 1]; const terminalValuesMap = this._attrValueMap.get(name); if (value) { result = this._matchTerminal(terminalValuesMap, '', cssSelector, matchedCallback) || result; } result = this._matchTerminal(terminalValuesMap, value, cssSelector, matchedCallback) || result; const partialValuesMap = this._attrValuePartialMap.get(name); if (value) { result = this._matchPartial(partialValuesMap, '', cssSelector, matchedCallback) || result; } result = this._matchPartial(partialValuesMap, value, cssSelector, matchedCallback) || result; } } return result; } /** @internal */ _matchTerminal(map, name, cssSelector, matchedCallback) { if (!map || typeof name !== 'string') { return false; } let selectables = map.get(name) || []; const starSelectables = map.get('*'); if (starSelectables) { selectables = selectables.concat(starSelectables); } if (selectables.length === 0) { return false; } let selectable; let result = false; for (let i = 0; i < selectables.length; i++) { selectable = selectables[i]; result = selectable.finalize(cssSelector, matchedCallback) || result; } return result; } /** @internal */ _matchPartial(map, name, cssSelector, matchedCallback) { if (!map || typeof name !== 'string') { return false; } const nestedSelector = map.get(name); if (!nestedSelector) { return false; } // TODO(perf): get rid of recursion and measure again // TODO(perf): don't pass the whole selector into the recursion, // but only the not processed parts return nestedSelector.match(cssSelector, matchedCallback); } } class SelectorListContext { constructor(selectors) { this.selectors = selectors; this.alreadyMatched = false; } } // Store context to pass back selector and context when a selector is matched class SelectorContext { constructor(selector, cbContext, listContext) { this.selector = selector; this.cbContext = cbContext; this.listContext = listContext; this.notSelectors = selector.notSelectors; } finalize(cssSelector, callback) { let result = true; if (this.notSelectors.length > 0 && (!this.listContext || !this.listContext.alreadyMatched)) { const notMatcher = SelectorMatcher.createNotMatcher(this.notSelectors); result = !notMatcher.match(cssSelector, null); } if (result && callback && (!this.listContext || !this.listContext.alreadyMatched)) { if (this.listContext) { this.listContext.alreadyMatched = true; } callback(this.selector, this.cbContext); } return result; } } /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ const createInject = makeMetadataFactory('Inject', (token) => ({ token })); const createInjectionToken = makeMetadataFactory('InjectionToken', (desc) => ({ _desc: desc, ɵprov: undefined })); const createAttribute = makeMetadataFactory('Attribute', (attributeName) => ({ attributeName })); // Stores the default value of `emitDistinctChangesOnly` when the `emitDistinctChangesOnly` is not // explicitly set. const emitDistinctChangesOnlyDefaultValue = true; const createContentChildren = makeMetadataFactory('ContentChildren', (selector, data = {}) => (Object.assign({ selector, first: false, isViewQuery: false, descendants: false, emitDistinctChangesOnly: emitDistinctChangesOnlyDefaultValue }, data))); const createContentChild = makeMetadataFactory('ContentChild', (selector, data = {}) => (Object.assign({ selector, first: true, isViewQuery: false, descendants: true }, data))); const createViewChildren = makeMetadataFactory('ViewChildren', (selector, data = {}) => (Object.assign({ selector, first: false, isViewQuery: true, descendants: true, emitDistinctChangesOnly: emitDistinctChangesOnlyDefaultValue }, data))); const createViewChild = makeMetadataFactory('ViewChild', (selector, data) => (Object.assign({ selector, first: true, isViewQuery: true, descendants: true }, data))); const createDirective = makeMetadataFactory('Directive', (dir = {}) => dir); var ViewEncapsulation; (function (ViewEncapsulation) { ViewEncapsulation[ViewEncapsulation["Emulated"] = 0] = "Emulated"; // Historically the 1 value was for `Native` encapsulation which has been removed as of v11. ViewEncapsulation[ViewEncapsulation["None"] = 2] = "None"; ViewEncapsulation[ViewEncapsulation["ShadowDom"] = 3] = "ShadowDom"; })(ViewEncapsulation || (ViewEncapsulation = {})); var ChangeDetectionStrategy; (function (ChangeDetectionStrategy) { ChangeDetectionStrategy[ChangeDetectionStrategy["OnPush"] = 0] = "OnPush"; ChangeDetectionStrategy[ChangeDetectionStrategy["Default"] = 1] = "Default"; })(ChangeDetectionStrategy || (ChangeDetectionStrategy = {})); const createComponent = makeMetadataFactory('Component', (c = {}) => (Object.assign({ changeDetection: ChangeDetectionStrategy.Default }, c))); const createPipe = makeMetadataFactory('Pipe', (p) => (Object.assign({ pure: true }, p))); const createInput = makeMetadataFactory('Input', (bindingPropertyName) => ({ bindingPropertyName })); const createOutput = makeMetadataFactory('Output', (bindingPropertyName) => ({ bindingPropertyName })); const createHostBinding = makeMetadataFactory('HostBinding', (hostPropertyName) => ({ hostPropertyName })); const createHostListener = makeMetadataFactory('HostListener', (eventName, args) => ({ eventName, args })); const createNgModule = makeMetadataFactory('NgModule', (ngModule) => ngModule); const createInjectable = makeMetadataFactory('Injectable', (injectable = {}) => injectable); const CUSTOM_ELEMENTS_SCHEMA = { name: 'custom-elements' }; const NO_ERRORS_SCHEMA = { name: 'no-errors-schema' }; const createOptional = makeMetadataFactory('Optional'); const createSelf = makeMetadataFactory('Self'); const createSkipSelf = makeMetadataFactory('SkipSelf'); const createHost = makeMetadataFactory('Host'); const Type = Function; var SecurityContext; (function (SecurityContext) { SecurityContext[SecurityContext["NONE"] = 0] = "NONE"; SecurityContext[SecurityContext["HTML"] = 1] = "HTML"; SecurityContext[SecurityContext["STYLE"] = 2] = "STYLE"; SecurityContext[SecurityContext["SCRIPT"] = 3] = "SCRIPT"; SecurityContext[SecurityContext["URL"] = 4] = "URL"; SecurityContext[SecurityContext["RESOURCE_URL"] = 5] = "RESOURCE_URL"; })(SecurityContext || (SecurityContext = {})); var MissingTranslationStrategy; (function (MissingTranslationStrategy) { MissingTranslationStrategy[MissingTranslationStrategy["Error"] = 0] = "Error"; MissingTranslationStrategy[MissingTranslationStrategy["Warning"] = 1] = "Warning"; MissingTranslationStrategy[MissingTranslationStrategy["Ignore"] = 2] = "Ignore"; })(MissingTranslationStrategy || (MissingTranslationStrategy = {})); function makeMetadataFactory(name, props) { // This must be declared as a function, not a fat arrow, so that ES2015 devmode produces code // that works with the static_reflector.ts in the ViewEngine compiler. // In particular, `_registerDecoratorOrConstructor` assumes that the value returned here can be // new'ed. function factory(...args) { const values = props ? props(...args) : {}; return Object.assign({ ngMetadataName: name }, values); } factory.isTypeOf = (obj) => obj && obj.ngMetadataName === name; factory.ngMetadataName = name; return factory; } function parserSelectorToSimpleSelector(selector) { const classes = selector.classNames && selector.classNames.length ? [8 /* CLASS */, ...selector.classNames] : []; const elementName = selector.element && selector.element !== '*' ? selector.element : ''; return [elementName, ...selector.attrs, ...classes]; } function parserSelectorToNegativeSelector(selector) { const classes = selector.classNames && selector.classNames.length ? [8 /* CLASS */, ...selector.classNames] : []; if (selector.element) { return [ 1 /* NOT */ | 4 /* ELEMENT */, selector.element, ...selector.attrs, ...classes ]; } else if (selector.attrs.length) { return [1 /* NOT */ | 2 /* ATTRIBUTE */, ...selector.attrs, ...classes]; } else { return selector.classNames && selector.classNames.length ? [1 /* NOT */ | 8 /* CLASS */, ...selector.classNames] : []; } } function parserSelectorToR3Selector(selector) { const positive = parserSelectorToSimpleSelector(selector); const negative = selector.notSelectors && selector.notSelectors.length ? selector.notSelectors.map(notSelector => parserSelectorToNegativeSelector(notSelector)) : []; return positive.concat(...negative); } function parseSelectorToR3Selector(selector) { return selector ? CssSelector.parse(selector).map(parserSelectorToR3Selector) : []; } var core = /*#__PURE__*/Object.freeze({ __proto__: null, createInject: createInject, createInjectionToken: createInjectionToken, createAttribute: createAttribute, emitDistinctChangesOnlyDefaultValue: emitDistinctChangesOnlyDefaultValue, createContentChildren: createContentChildren, createContentChild: createContentChild, createViewChildren: createViewChildren, createViewChild: createViewChild, createDirective: createDirective, get ViewEncapsulation () { return ViewEncapsulation; }, get ChangeDetectionStrategy () { return ChangeDetectionStrategy; }, createComponent: createComponent, createPipe: createPipe, createInput: createInput, createOutput: createOutput, createHostBinding: createHostBinding, createHostListener: createHostListener, createNgModule: createNgModule, createInjectable: createInjectable, CUSTOM_ELEMENTS_SCHEMA: CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA: NO_ERRORS_SCHEMA, createOptional: createOptional, createSelf: createSelf, createSkipSelf: createSkipSelf, createHost: createHost, Type: Type, get SecurityContext () { return SecurityContext; }, get MissingTranslationStrategy () { return MissingTranslationStrategy; }, parseSelectorToR3Selector: parseSelectorToR3Selector }); /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ //// Types var TypeModifier; (function (TypeModifier) { TypeModifier[TypeModifier["Const"] = 0] = "Const"; })(TypeModifier || (TypeModifier = {})); class Type$1 { constructor(modifiers = []) { this.modifiers = modifiers; } hasModifier(modifier) { return this.modifiers.indexOf(modifier) !== -1; } } var BuiltinTypeName; (function (BuiltinTypeName) { BuiltinTypeName[BuiltinTypeName["Dynamic"] = 0] = "Dynamic"; BuiltinTypeName[BuiltinTypeName["Bool"] = 1] = "Bool"; BuiltinTypeName[BuiltinTypeName["String"] = 2] = "String"; BuiltinTypeName[BuiltinTypeName["Int"] = 3] = "Int"; BuiltinTypeName[BuiltinTypeName["Number"] = 4] = "Number"; BuiltinTypeName[BuiltinTypeName["Function"] = 5] = "Function"; BuiltinTypeName[BuiltinTypeName["Inferred"] = 6] = "Inferred"; BuiltinTypeName[BuiltinTypeName["None"] = 7] = "None"; })(BuiltinTypeName || (BuiltinTypeName = {})); class BuiltinType extends Type$1 { constructor(name, modifiers) { super(modifiers); this.name = name; } visitType(visitor, context) { return visitor.visitBuiltinType(this, context); } } class ExpressionType extends Type$1 { constructor(value, modifiers, typeParams = null) { super(modifiers); this.value = value; this.typeParams = typeParams; } visitType(visitor, context) { return visitor.visitExpressionType(this, context); } } class ArrayType extends Type$1 { constructor(of, modifiers) { super(modifiers); this.of = of; } visitType(visitor, context) { return visitor.visitArrayType(this, context); } } class MapType extends Type$1 { constructor(valueType, modifiers) { super(modifiers); this.valueType = valueType || null; } visitType(visitor, context) { return visitor.visitMapType(this, context); } } const DYNAMIC_TYPE = new BuiltinType(BuiltinTypeName.Dynamic); const INFERRED_TYPE = new BuiltinType(BuiltinTypeName.Inferred); const BOOL_TYPE = new BuiltinType(BuiltinTypeName.Bool); const INT_TYPE = new BuiltinType(BuiltinTypeName.Int); const NUMBER_TYPE = new BuiltinType(BuiltinTypeName.Number); const STRING_TYPE = new BuiltinType(BuiltinTypeName.String); const FUNCTION_TYPE = new BuiltinType(BuiltinTypeName.Function); const NONE_TYPE = new BuiltinType(BuiltinTypeName.None); ///// Expressions var UnaryOperator; (function (UnaryOperator) { UnaryOperator[UnaryOperator["Minus"] = 0] = "Minus"; UnaryOperator[UnaryOperator["Plus"] = 1] = "Plus"; })(UnaryOperator || (UnaryOperator = {})); var BinaryOperator; (function (BinaryOperator) { BinaryOperator[BinaryOperator["Equals"] = 0] = "Equals"; BinaryOperator[BinaryOperator["NotEquals"] = 1] = "NotEquals"; BinaryOperator[BinaryOperator["Identical"] = 2] = "Identical"; BinaryOperator[BinaryOperator["NotIdentical"] = 3] = "NotIdentical"; BinaryOperator[BinaryOperator["Minus"] = 4] = "Minus"; BinaryOperator[BinaryOperator["Plus"] = 5] = "Plus"; BinaryOperator[BinaryOperator["Divide"] = 6] = "Divide"; BinaryOperator[BinaryOperator["Multiply"] = 7] = "Multiply"; BinaryOperator[BinaryOperator["Modulo"] = 8] = "Modulo"; BinaryOperator[BinaryOperator["And"] = 9] = "And"; BinaryOperator[BinaryOperator["Or"] = 10] = "Or"; BinaryOperator[BinaryOperator["BitwiseAnd"] = 11] = "BitwiseAnd"; BinaryOperator[BinaryOperator["Lower"] = 12] = "Lower"; BinaryOperator[BinaryOperator["LowerEquals"] = 13] = "LowerEquals"; BinaryOperator[BinaryOperator["Bigger"] = 14] = "Bigger"; BinaryOperator[BinaryOperator["BiggerEquals"] = 15] = "BiggerEquals"; BinaryOperator[BinaryOperator["NullishCoalesce"] = 16] = "NullishCoalesce"; })(BinaryOperator || (BinaryOperator = {})); function nullSafeIsEquivalent(base, other) { if (base == null || other == null) { return base == other; } return base.isEquivalent(other); } function areAllEquivalentPredicate(base, other, equivalentPredicate) { const len = base.length; if (len !== other.length) { return false; } for (let i = 0; i < len; i++) { if (!equivalentPredicate(base[i], other[i])) { return false; } } return true; } function areAllEquivalent(base, other) { return areAllEquivalentPredicate(base, other, (baseElement, otherElement) => baseElement.isEquivalent(otherElement)); } class Expression { constructor(type, sourceSpan) { this.type = type || null; this.sourceSpan = sourceSpan || null; } prop(name, sourceSpan) { return new ReadPropExpr(this, name, null, sourceSpan); } key(index, type, sourceSpan) { return new ReadKeyExpr(this, index, type, sourceSpan); } callMethod(name, params, sourceSpan) { return new InvokeMethodExpr(this, name, params, null, sourceSpan); } callFn(params, sourceSpan, pure) { return new InvokeFunctionExpr(this, params, null, sourceSpan, pure); } instantiate(params, type, sourceSpan) { return new InstantiateExpr(this, params, type, sourceSpan); } conditional(trueCase, falseCase = null, sourceSpan) { return new ConditionalExpr(this, trueCase, falseCase, null, sourceSpan); } equals(rhs, sourceSpan) { return new BinaryOperatorExpr(BinaryOperator.Equals, this, rhs, null, sourceSpan); } notEquals(rhs, sourceSpan) { return new BinaryOperatorExpr(BinaryOperator.NotEquals, this, rhs, null, sourceSpan); } identical(rhs, sourceSpan) { return new BinaryOperatorExpr(BinaryOperator.Identical, this, rhs, null, sourceSpan); } notIdentical(rhs, sourceSpan) { return new BinaryOperatorExpr(BinaryOperator.NotIdentical, this, rhs, null, sourceSpan); } minus(rhs, sourceSpan) { return new BinaryOperatorExpr(BinaryOperator.Minus, this, rhs, null, sourceSpan); } plus(rhs, sourceSpan) { return new BinaryOperatorExpr(BinaryOperator.Plus, this, rhs, null, sourceSpan); } divide(rhs, sourceSpan) { return new BinaryOperatorExpr(BinaryOperator.Divide, this, rhs, null, sourceSpan); } multiply(rhs, sourceSpan) { return new BinaryOperatorExpr(BinaryOperator.Multiply, this, rhs, null, sourceSpan); } modulo(rhs, sourceSpan) { return new BinaryOperatorExpr(BinaryOperator.Modulo, this, rhs, null, sourceSpan); } and(rhs, sourceSpan) { return new BinaryOperatorExpr(BinaryOperator.And, this, rhs, null, sourceSpan); } bitwiseAnd(rhs, sourceSpan, parens = true) { return new BinaryOperatorExpr(BinaryOperator.BitwiseAnd, this, rhs, null, sourceSpan, parens); } or(rhs, sourceSpan) { return new BinaryOperatorExpr(BinaryOperator.Or, this, rhs, null, sourceSpan); } lower(rhs, sourceSpan) { return new BinaryOperatorExpr(BinaryOperator.Lower, this, rhs, null, sourceSpan); } lowerEquals(rhs, sourceSpan) { return new BinaryOperatorExpr(BinaryOperator.LowerEquals, this, rhs, null, sourceSpan); } bigger(rhs, sourceSpan) { return new BinaryOperatorExpr(BinaryOperator.Bigger, this, rhs, null, sourceSpan); } biggerEquals(rhs, sourceSpan) { return new BinaryOperatorExpr(BinaryOperator.BiggerEquals, this, rhs, null, sourceSpan); } isBlank(sourceSpan) { // Note: We use equals by purpose here to compare to null and undefined in JS. // We use the typed null to allow strictNullChecks to narrow types. return this.equals(TYPED_NULL_EXPR, sourceSpan); } cast(type, sourceSpan) { return new CastExpr(this, type, sourceSpan); } nullishCoalesce(rhs, sourceSpan) { return new BinaryOperatorExpr(BinaryOperator.NullishCoalesce, this, rhs, null, sourceSpan); } toStmt() { return new ExpressionStatement(this, null); } } var BuiltinVar; (function (BuiltinVar) { BuiltinVar[BuiltinVar["This"] = 0] = "This"; BuiltinVar[BuiltinVar["Super"] = 1] = "Super"; BuiltinVar[BuiltinVar["CatchError"] = 2] = "CatchError"; BuiltinVar[BuiltinVar["CatchStack"] = 3] = "CatchStack"; })(BuiltinVar || (BuiltinVar = {})); class ReadVarExpr extends Expression { constructor(name, type, sourceSpan) { super(type, sourceSpan); if (typeof name === 'string') { this.name = name; this.builtin = null; } else { this.name = null; this.builtin = name; } } isEquivalent(e) { return e instanceof ReadVarExpr && this.name === e.name && this.builtin === e.builtin; } isConstant() { return false; } visitExpression(visitor, context) { return visitor.visitReadVarExpr(this, context); } set(value) { if (!this.name) { throw new Error(`Built in variable ${this.builtin} can not be assigned to.`); } return new WriteVarExpr(this.name, value, null, this.sourceSpan); } } class TypeofExpr extends Expression { constructor(expr, type, sourceSpan) { super(type, sourceSpan); this.expr = expr; } visitExpression(visitor, context) { return visitor.visitTypeofExpr(this, context); } isEquivalent(e) { return e instanceof TypeofExpr && e.expr.isEquivalent(this.expr); } isConstant() { return this.expr.isConstant(); } } class WrappedNodeExpr extends Expression { constructor(node, type, sourceSpan) { super(type, sourceSpan); this.node = node; } isEquivalent(e) { return e instanceof WrappedNodeExpr && this.node === e.node; } isConstant() { return false; } visitExpression(visitor, context) { return visitor.visitWrappedNodeExpr(this, context); } } class WriteVarExpr extends Expression { constructor(name, value, type, sourceSpan) { super(type || value.type, sourceSpan); this.name = name; this.value = value; } isEquivalent(e) { return e instanceof WriteVarExpr && this.name === e.name && this.value.isEquivalent(e.value); } isConstant() { return false; } visitExpression(visitor, context) { return visitor.visitWriteVarExpr(this, context); } toDeclStmt(type, modifiers) { return new DeclareVarStmt(this.name, this.value, type, modifiers, this.sourceSpan); } toConstDecl() { return this.toDeclStmt(INFERRED_TYPE, [StmtModifier.Final]); } } class WriteKeyExpr extends Expression { constructor(receiver, index, value, type, sourceSpan) { super(type || value.type, sourceSpan); this.receiver = receiver; this.index = index; this.value = value; } isEquivalent(e) { return e instanceof WriteKeyExpr && this.receiver.isEquivalent(e.receiver) && this.index.isEquivalent(e.index) && this.value.isEquivalent(e.value); } isConstant() { return false; } visitExpression(visitor, context) { return visitor.visitWriteKeyExpr(this, context); } } class WritePropExpr extends Expression { constructor(receiver, name, value, type, sourceSpan) { super(type || value.type, sourceSpan); this.receiver = receiver; this.name = name; this.value = value; } isEquivalent(e) { return e instanceof WritePropExpr && this.receiver.isEquivalent(e.receiver) && this.name === e.name && this.value.isEquivalent(e.value); } isConstant() { return false; } visitExpression(visitor, context) { return visitor.visitWritePropExpr(this, context); } } var BuiltinMethod; (function (BuiltinMethod) { BuiltinMethod[BuiltinMethod["ConcatArray"] = 0] = "ConcatArray"; BuiltinMethod[BuiltinMethod["SubscribeObservable"] = 1] = "SubscribeObservable"; BuiltinMethod[BuiltinMethod["Bind"] = 2] = "Bind"; })(BuiltinMethod || (BuiltinMethod = {})); class InvokeMethodExpr extends Expression { constructor(receiver, method, args, type, sourceSpan) { super(type, sourceSpan); this.receiver = receiver; this.args = args; if (typeof method === 'string') { this.name = method; this.builtin = null; } else { this.name = null; this.builtin = method; } } isEquivalent(e) { return e instanceof InvokeMethodExpr && this.receiver.isEquivalent(e.receiver) && this.name === e.name && this.builtin === e.builtin && areAllEquivalent(this.args, e.args); } isConstant() { return false; } visitExpression(visitor, context) { return visitor.visitInvokeMethodExpr(this, context); } } class InvokeFunctionExpr extends Expression { constructor(fn, args, type, sourceSpan, pure = false) { super(type, sourceSpan); this.fn = fn; this.args = args; this.pure = pure; } isEquivalent(e) { return e instanceof InvokeFunctionExpr && this.fn.isEquivalent(e.fn) && areAllEquivalent(this.args, e.args) && this.pure === e.pure; } isConstant() { return false; } visitExpression(visitor, context) { return visitor.visitInvokeFunctionExpr(this, context); } } class TaggedTemplateExpr extends Expression { constructor(tag, template, type, sourceSpan) { super(type, sourceSpan); this.tag = tag; this.template = template; } isEquivalent(e) { return e instanceof TaggedTemplateExpr && this.tag.isEquivalent(e.tag) && areAllEquivalentPredicate(this.template.elements, e.template.elements, (a, b) => a.text === b.text) && areAllEquivalent(this.template.expressions, e.template.expressions); } isConstant() { return false; } visitExpression(visitor, context) { return visitor.visitTaggedTemplateExpr(this, context); } } class InstantiateExpr extends Expression { constructor(classExpr, args, type, sourceSpan) { super(type, sourceSpan); this.classExpr = classExpr; this.args = args; } isEquivalent(e) { return e instanceof InstantiateExpr && this.classExpr.isEquivalent(e.classExpr) && areAllEquivalent(this.args, e.args); } isConstant() { return false; } visitExpression(visitor, context) { return visitor.visitInstantiateExpr(this, context); } } class LiteralExpr extends Expression { constructor(value, type, sourceSpan) { super(type, sourceSpan); this.value = value; } isEquivalent(e) { return e instanceof LiteralExpr && this.value === e.value; } isConstant() { return true; } visitExpression(visitor, context) { return visitor.visitLiteralExpr(this, context); } } class TemplateLiteral { constructor(elements, expressions) { this.elements = elements; this.expressions = expressions; } } class TemplateLiteralElement { constructor(text, sourceSpan, rawText) { var _a; this.text = text; this.sourceSpan = sourceSpan; // If `rawText` is not provided, try to extract the raw string from its // associated `sourceSpan`. If that is also not available, "fake" the raw // string instead by escaping the following control sequences: // - "\" would otherwise indicate that the next character is a control character. // - "`" and "${" are template string control sequences that would otherwise prematurely // indicate the end of the template literal element. this.rawText = (_a = rawText !== null && rawText !== void 0 ? rawText : sourceSpan === null || sourceSpan === void 0 ? void 0 : sourceSpan.toString()) !== null && _a !== void 0 ? _a : escapeForTemplateLiteral(escapeSlashes(text)); } } class MessagePiece { constructor(text, sourceSpan) { this.text = text; this.sourceSpan = sourceSpan; } } class LiteralPiece extends MessagePiece { } class PlaceholderPiece extends MessagePiece { } class LocalizedString extends Expression { constructor(metaBlock, messageParts, placeHolderNames, expressions, sourceSpan) { super(STRING_TYPE, sourceSpan); this.metaBlock = metaBlock; this.messageParts = messageParts; this.placeHolderNames = placeHolderNames; this.expressions = expressions; } isEquivalent(e) { // return e instanceof LocalizedString && this.message === e.message; return false; } isConstant() { return false; } visitExpression(visitor, context) { return visitor.visitLocalizedString(this, context); } /** * Serialize the given `meta` and `messagePart` into "cooked" and "raw" strings that can be used * in a `$localize` tagged string. The format of the metadata is the same as that parsed by * `parseI18nMeta()`. * * @param meta The metadata to serialize * @param messagePart The first part of the tagged string */ serializeI18nHead() { const MEANING_SEPARATOR = '|'; const ID_SEPARATOR = '@@'; const LEGACY_ID_INDICATOR = '␟'; let metaBlock = this.metaBlock.description || ''; if (this.metaBlock.meaning) { metaBlock = `${this.metaBlock.meaning}${MEANING_SEPARATOR}${metaBlock}`; } if (this.metaBlock.customId) { metaBlock = `${metaBlock}${ID_SEPARATOR}${this.metaBlock.customId}`; } if (this.metaBlock.legacyIds) { this.metaBlock.legacyIds.forEach(legacyId => { metaBlock = `${metaBlock}${LEGACY_ID_INDICATOR}${legacyId}`; }); } return createCookedRawString(metaBlock, this.messageParts[0].text, this.getMessagePartSourceSpan(0)); } getMessagePartSourceSpan(i) { var _a, _b; return (_b = (_a = this.messageParts[i]) === null || _a === void 0 ? void 0 : _a.sourceSpan) !== null && _b !== void 0 ? _b : this.sourceSpan; } getPlaceholderSourceSpan(i) { var _a, _b, _c, _d; return (_d = (_b = (_a = this.placeHolderNames[i]) === null || _a === void 0 ? void 0 : _a.sourceSpan) !== null && _b !== void 0 ? _b : (_c = this.expressions[i]) === null || _c === void 0 ? void 0 : _c.sourceSpan) !== null && _d !== void 0 ? _d : this.sourceSpan; } /** * Serialize the given `placeholderName` and `messagePart` into "cooked" and "raw" strings that * can be used in a `$localize` tagged string. * * @param placeholderName The placeholder name to serialize * @param messagePart The following message string after this placeholder */ serializeI18nTemplatePart(partIndex) { const placeholderName = this.placeHolderNames[partIndex - 1].text; const messagePart = this.messageParts[partIndex]; return createCookedRawString(placeholderName, messagePart.text, this.getMessagePartSourceSpan(partIndex)); } } const escapeSlashes = (str) => str.replace(/\\/g, '\\\\'); const escapeStartingColon = (str) => str.replace(/^:/, '\\:'); const escapeColons = (str) => str.replace(/:/g, '\\:'); const escapeForTemplateLiteral = (str) => str.replace(/`/g, '\\`').replace(/\${/g, '$\\{'); /** * Creates a `{cooked, raw}` object from the `metaBlock` and `messagePart`. * * The `raw` text must have various character sequences escaped: * * "\" would otherwise indicate that the next character is a control character. * * "`" and "${" are template string control sequences that would otherwise prematurely indicate * the end of a message part. * * ":" inside a metablock would prematurely indicate the end of the metablock. * * ":" at the start of a messagePart with no metablock would erroneously indicate the start of a * metablock. * * @param metaBlock Any metadata that should be prepended to the string * @param messagePart The message part of the string */ function createCookedRawString(metaBlock, messagePart, range) { if (metaBlock === '') { return { cooked: messagePart, raw: escapeForTemplateLiteral(escapeStartingColon(escapeSlashes(messagePart))), range, }; } else { return { cooked: `:${metaBlock}:${messagePart}`, raw: escapeForTemplateLiteral(`:${escapeColons(escapeSlashes(metaBlock))}:${escapeSlashes(messagePart)}`), range, }; } } class ExternalExpr extends Expression { constructor(value, type, typeParams = null, sourceSpan) { super(type, sourceSpan); this.value = value; this.typeParams = typeParams; } isEquivalent(e) { return e instanceof ExternalExpr && this.value.name === e.value.name && this.value.moduleName === e.value.moduleName && this.value.runtime === e.value.runtime; } isConstant() { return false; } visitExpression(visitor, context) { return visitor.visitExternalExpr(this, context); } } class ExternalReference { constructor(moduleName, name, runtime) { this.moduleName = moduleName; this.name = name; this.runtime = runtime; } } class ConditionalExpr extends Expression { constructor(condition, trueCase, falseCase = null, type, sourceSpan) { super(type || trueCase.type, sourceSpan); this.condition = condition; this.falseCase = falseCase; this.trueCase = trueCase; } isEquivalent(e) { return e instanceof ConditionalExpr && this.condition.isEquivalent(e.condition) && this.trueCase.isEquivalent(e.trueCase) && nullSafeIsEquivalent(this.falseCase, e.falseCase); } isConstant() { return false; } visitExpression(visitor, context) { return visitor.visitConditionalExpr(this, context); } } class NotExpr extends Expression { constructor(condition, sourceSpan) { super(BOOL_TYPE, sourceSpan); this.condition = condition; } isEquivalent(e) { return e instanceof NotExpr && this.condition.isEquivalent(e.condition); } isConstant() { return false; } visitExpression(visitor, context) { return visitor.visitNotExpr(this, context); } } class AssertNotNull extends Expression { constructor(condition, sourceSpan) { super(condition.type, sourceSpan); this.condition = condition; } isEquivalent(e) { return e instanceof AssertNotNull && this.condition.isEquivalent(e.condition); } isConstant() { return false; } visitExpression(visitor, context) { return visitor.visitAssertNotNullExpr(this, context); } } class CastExpr extends Expression { constructor(value, type, sourceSpan) { super(type, sourceSpan); this.value = value; } isEquivalent(e) { return e instanceof CastExpr && this.value.isEquivalent(e.value); } isConstant() { return false; } visitExpression(visitor, context) { return visitor.visitCastExpr(this, context); } } class FnParam { constructor(name, type = null) { this.name = name; this.type = type; } isEquivalent(param) { return this.name === param.name; } } class FunctionExpr extends Expression { constructor(params, statements, type, sourceSpan, name) { super(type, sourceSpan); this.params = params; this.statements = statements; this.name = name; } isEquivalent(e) { return e instanceof FunctionExpr && areAllEquivalent(this.params, e.params) && areAllEquivalent(this.statements, e.statements); } isConstant() { return false; } visitExpression(visitor, context) { return visitor.visitFunctionExpr(this, context); } toDeclStmt(name, modifiers) { return new DeclareFunctionStmt(name, this.params, this.statements, this.type, modifiers, this.sourceSpan); } } class UnaryOperatorExpr extends Expression { constructor(operator, expr, type, sourceSpan, parens = true) { super(type || NUMBER_TYPE, sourceSpan); this.operator = operator; this.expr = expr; this.parens = parens; } isEquivalent(e) { return e instanceof UnaryOperatorExpr && this.operator === e.operator && this.expr.isEquivalent(e.expr); } isConstant() { return false; } visitExpression(visitor, context) { return visitor.visitUnaryOperatorExpr(this, context); } } class BinaryOperatorExpr extends Expression { constructor(operator, lhs, rhs, type, sourceSpan, parens = true) { super(type || lhs.type, sourceSpan); this.operator = operator; this.rhs = rhs; this.parens = parens; this.lhs = lhs; } isEquivalent(e) { return e instanceof BinaryOperatorExpr && this.operator === e.operator && this.lhs.isEquivalent(e.lhs) && this.rhs.isEquivalent(e.rhs); } isConstant() { return false; } visitExpression(visitor, context) { return visitor.visitBinaryOperatorExpr(this, context); } } class ReadPropExpr extends Expression { constructor(receiver, name, type, sourceSpan) { super(type, sourceSpan); this.receiver = receiver; this.name = name; } isEquivalent(e) { return e instanceof ReadPropExpr && this.receiver.isEquivalent(e.receiver) && this.name === e.name; } isConstant() { return false; } visitExpression(visitor, context) { return visitor.visitReadPropExpr(this, context); } set(value) { return new WritePropExpr(this.receiver, this.name, value, null, this.sourceSpan); } } class ReadKeyExpr extends Expression { constructor(receiver, index, type, sourceSpan) { super(type, sourceSpan); this.receiver = receiver; this.index = index; } isEquivalent(e) { return e instanceof ReadKeyExpr && this.receiver.isEquivalent(e.receiver) && this.index.isEquivalent(e.index); } isConstant() { return false; } visitExpression(visitor, context) { return visitor.visitReadKeyExpr(this, context); } set(value) { return new WriteKeyExpr(this.receiver, this.index, value, null, this.sourceSpan); } } class LiteralArrayExpr extends Expression { constructor(entries, type, sourceSpan) { super(type, sourceSpan); this.entries = entries; } isConstant() { return this.entries.every(e => e.isConstant()); } isEquivalent(e) { return e instanceof LiteralArrayExpr && areAllEquivalent(this.entries, e.entries); } visitExpression(visitor, context) { return visitor.visitLiteralArrayExpr(this, context); } } class LiteralMapEntry { constructor(key, value, quoted) { this.key = key; this.value = value; this.quoted = quoted; } isEquivalent(e) { return this.key === e.key && this.value.isEquivalent(e.value); } } class LiteralMapExpr extends Expression { constructor(entries, type, sourceSpan) { super(type, sourceSpan); this.entries = entries; this.valueType = null; if (type) { this.valueType = type.valueType; } } isEquivalent(e) { return e instanceof LiteralMapExpr && areAllEquivalent(this.entries, e.entries); } isConstant() { return this.entries.every(e => e.value.isConstant()); } visitExpression(visitor, context) { return visitor.visitLiteralMapExpr(this, context); } } class CommaExpr extends Expression { constructor(parts, sourceSpan) { super(parts[parts.length - 1].type, sourceSpan); this.parts = parts; } isEquivalent(e) { return e instanceof CommaExpr && areAllEquivalent(this.parts, e.parts); } isConstant() { return false; } visitExpression(visitor, context) { return visitor.visitCommaExpr(this, context); } } const THIS_EXPR = new ReadVarExpr(BuiltinVar.This, null, null); const SUPER_EXPR = new ReadVarExpr(BuiltinVar.Super, null, null); const CATCH_ERROR_VAR = new ReadVarExpr(BuiltinVar.CatchError, null, null); const CATCH_STACK_VAR = new ReadVarExpr(BuiltinVar.CatchStack, null, null); const NULL_EXPR = new LiteralExpr(null, null, null); const TYPED_NULL_EXPR = new LiteralExpr(null, INFERRED_TYPE, null); //// Statements var StmtModifier; (function (StmtModifier) { StmtModifier[StmtModifier["Final"] = 0] = "Final"; StmtModifier[StmtModifier["Private"] = 1] = "Private"; StmtModifier[StmtModifier["Exported"] = 2] = "Exported"; StmtModifier[StmtModifier["Static"] = 3] = "Static"; })(StmtModifier || (StmtModifier = {})); class LeadingComment { constructor(text, multiline, trailingNewline) { this.text = text; this.multiline = multiline; this.trailingNewline = trailingNewline; } toString() { return this.multiline ? ` ${this.text} ` : this.text; } } class JSDocComment extends LeadingComment { constructor(tags) { super('', /* multiline */ true, /* trailingNewline */ true); this.tags = tags; } toString() { return serializeTags(this.tags); } } class Statement { constructor(modifiers = [], sourceSpan = null, leadingComments) { this.modifiers = modifiers; this.sourceSpan = sourceSpan; this.leadingComments = leadingComments; } hasModifier(modifier) { return this.modifiers.indexOf(modifier) !== -1; } addLeadingComment(leadingComment) { var _a; this.leadingComments = (_a = this.leadingComments) !== null && _a !== void 0 ? _a : []; this.leadingComments.push(leadingComment); } } class DeclareVarStmt extends Statement { constructor(name, value, type, modifiers, sourceSpan, leadingComments) { super(modifiers, sourceSpan, leadingComments); this.name = name; this.value = value; this.type = type || (value && value.type) || null; } isEquivalent(stmt) { return stmt instanceof DeclareVarStmt && this.name === stmt.name && (this.value ? !!stmt.value && this.value.isEquivalent(stmt.value) : !stmt.value); } visitStatement(visitor, context) { return visitor.visitDeclareVarStmt(this, context); } } class DeclareFunctionStmt extends Statement { constructor(name, params, statements, type, modifiers, sourceSpan, leadingComments) { super(modifiers, sourceSpan, leadingComments); this.name = name; this.params = params; this.statements = statements; this.type = type || null; } isEquivalent(stmt) { return stmt instanceof DeclareFunctionStmt && areAllEquivalent(this.params, stmt.params) && areAllEquivalent(this.statements, stmt.statements); } visitStatement(visitor, context) { return visitor.visitDeclareFunctionStmt(this, context); } } class ExpressionStatement extends Statement { constructor(expr, sourceSpan, leadingComments) { super([], sourceSpan, leadingComments); this.expr = expr; } isEquivalent(stmt) { return stmt instanceof ExpressionStatement && this.expr.isEquivalent(stmt.expr); } visitStatement(visitor, context) { return visitor.visitExpressionStmt(this, context); } } class ReturnStatement extends Statement { constructor(value, sourceSpan = null, leadingComments) { super([], sourceSpan, leadingComments); this.value = value; } isEquivalent(stmt) { return stmt instanceof ReturnStatement && this.value.isEquivalent(stmt.value); } visitStatement(visitor, context) { return visitor.visitReturnStmt(this, context); } } class AbstractClassPart { constructor(type = null, modifiers = []) { this.type = type; this.modifiers = modifiers; } hasModifier(modifier) { return this.modifiers.indexOf(modifier) !== -1; } } class ClassField extends AbstractClassPart { constructor(name, type, modifiers, initializer) { super(type, modifiers); this.name = name; this.initializer = initializer; } isEquivalent(f) { return this.name === f.name; } } class ClassMethod extends AbstractClassPart { constructor(name, params, body, type, modifiers) { super(type, modifiers); this.name = name; this.params = params; this.body = body; } isEquivalent(m) { return this.name === m.name && areAllEquivalent(this.body, m.body); } } class ClassGetter extends AbstractClassPart { constructor(name, body, type, modifiers) { super(type, modifiers); this.name = name; this.body = body; } isEquivalent(m) { return this.name === m.name && areAllEquivalent(this.body, m.body); } } class ClassStmt extends Statement { constructor(name, parent, fields, getters, constructorMethod, methods, modifiers, sourceSpan, leadingComments) { super(modifiers, sourceSpan, leadingComments); this.name = name; this.parent = parent; this.fields = fields; this.getters = getters; this.constructorMethod = constructorMethod; this.methods = methods; } isEquivalent(stmt) { return stmt instanceof ClassStmt && this.name === stmt.name && nullSafeIsEquivalent(this.parent, stmt.parent) && areAllEquivalent(this.fields, stmt.fields) && areAllEquivalent(this.getters, stmt.getters) && this.constructorMethod.isEquivalent(stmt.constructorMethod) && areAllEquivalent(this.methods, stmt.methods); } visitStatement(visitor, context) { return visitor.visitDeclareClassStmt(this, context); } } class IfStmt extends Statement { constructor(condition, trueCase, falseCase = [], sourceSpan, leadingComments) { super([], sourceSpan, leadingComments); this.condition = condition; this.trueCase = trueCase; this.falseCase = falseCase; } isEquivalent(stmt) { return stmt instanceof IfStmt && this.condition.isEquivalent(stmt.condition) && areAllEquivalent(this.trueCase, stmt.trueCase) && areAllEquivalent(this.falseCase, stmt.falseCase); } visitStatement(visitor, context) { return visitor.visitIfStmt(this, context); } } class TryCatchStmt extends Statement { constructor(bodyStmts, catchStmts, sourceSpan = null, leadingComments) { super([], sourceSpan, leadingComments); this.bodyStmts = bodyStmts; this.catchStmts = catchStmts; } isEquivalent(stmt) { return stmt instanceof TryCatchStmt && areAllEquivalent(this.bodyStmts, stmt.bodyStmts) && areAllEquivalent(this.catchStmts, stmt.catchStmts); } visitStatement(visitor, context) { return visitor.visitTryCatchStmt(this, context); } } class ThrowStmt extends Statement { constructor(error, sourceSpan = null, leadingComments) { super([], sourceSpan, leadingComments); this.error = error; } isEquivalent(stmt) { return stmt instanceof TryCatchStmt && this.error.isEquivalent(stmt.error); } visitStatement(visitor, context) { return visitor.visitThrowStmt(this, context); } } class AstTransformer { transformExpr(expr, context) { return expr; } transformStmt(stmt, context) { return stmt; } visitReadVarExpr(ast, context) { return this.transformExpr(ast, context); } visitWrappedNodeExpr(ast, context) { return this.transformExpr(ast, context); } visitTypeofExpr(expr, context) { return this.transformExpr(new TypeofExpr(expr.expr.visitExpression(this, context), expr.type, expr.sourceSpan), context); } visitWriteVarExpr(expr, context) { return this.transformExpr(new WriteVarExpr(expr.name, expr.value.visitExpression(this, context), expr.type, expr.sourceSpan), context); } visitWriteKeyExpr(expr, context) { return this.transformExpr(new WriteKeyExpr(expr.receiver.visitExpression(this, context), expr.index.visitExpression(this, context), expr.value.visitExpression(this, context), expr.type, expr.sourceSpan), context); } visitWritePropExpr(expr, context) { return this.transformExpr(new WritePropExpr(expr.receiver.visitExpression(this, context), expr.name, expr.value.visitExpression(this, context), expr.type, expr.sourceSpan), context); } visitInvokeMethodExpr(ast, context) { const method = ast.builtin || ast.name; return this.transformExpr(new InvokeMethodExpr(ast.receiver.visitExpression(this, context), method, this.visitAllExpressions(ast.args, context), ast.type, ast.sourceSpan), context); } visitInvokeFunctionExpr(ast, context) { return this.transformExpr(new InvokeFunctionExpr(ast.fn.visitExpression(this, context), this.visitAllExpressions(ast.args, context), ast.type, ast.sourceSpan), context); } visitTaggedTemplateExpr(ast, context) { return this.transformExpr(new TaggedTemplateExpr(ast.tag.visitExpression(this, context), new TemplateLiteral(ast.template.elements, ast.template.expressions.map((e) => e.visitExpression(this, context))), ast.type, ast.sourceSpan), context); } visitInstantiateExpr(ast, context) { return this.transformExpr(new InstantiateExpr(ast.classExpr.visitExpression(this, context), this.visitAllExpressions(ast.args, context), ast.type, ast.sourceSpan), context); } visitLiteralExpr(ast, context) { return this.transformExpr(ast, context); } visitLocalizedString(ast, context) { return this.transformExpr(new LocalizedString(ast.metaBlock, ast.messageParts, ast.placeHolderNames, this.visitAllExpressions(ast.expressions, context), ast.sourceSpan), context); } visitExternalExpr(ast, context) { return this.transformExpr(ast, context); } visitConditionalExpr(ast, context) { return this.transformExpr(new ConditionalExpr(ast.condition.visitExpression(this, context), ast.trueCase.visitExpression(this, context), ast.falseCase.visitExpression(this, context), ast.type, ast.sourceSpan), context); } visitNotExpr(ast, context) { return this.transformExpr(new NotExpr(ast.condition.visitExpression(this, context), ast.sourceSpan), context); } visitAssertNotNullExpr(ast, context) { return this.transformExpr(new AssertNotNull(ast.condition.visitExpression(this, context), ast.sourceSpan), context); } visitCastExpr(ast, context) { return this.transformExpr(new CastExpr(ast.value.visitExpression(this, context), ast.type, ast.sourceSpan), context); } visitFunctionExpr(ast, context) { return this.transformExpr(new FunctionExpr(ast.params, this.visitAllStatements(ast.statements, context), ast.type, ast.sourceSpan), context); } visitUnaryOperatorExpr(ast, context) { return this.transformExpr(new UnaryOperatorExpr(ast.operator, ast.expr.visitExpression(this, context), ast.type, ast.sourceSpan), context); } visitBinaryOperatorExpr(ast, context) { return this.transformExpr(new BinaryOperatorExpr(ast.operator, ast.lhs.visitExpression(this, context), ast.rhs.visitExpression(this, context), ast.type, ast.sourceSpan), context); } visitReadPropExpr(ast, context) { return this.transformExpr(new ReadPropExpr(ast.receiver.visitExpression(this, context), ast.name, ast.type, ast.sourceSpan), context); } visitReadKeyExpr(ast, context) { return this.transformExpr(new ReadKeyExpr(ast.receiver.visitExpression(this, context), ast.index.visitExpression(this, context), ast.type, ast.sourceSpan), context); } visitLiteralArrayExpr(ast, context) { return this.transformExpr(new LiteralArrayExpr(this.visitAllExpressions(ast.entries, context), ast.type, ast.sourceSpan), context); } visitLiteralMapExpr(ast, context) { const entries = ast.entries.map((entry) => new LiteralMapEntry(entry.key, entry.value.visitExpression(this, context), entry.quoted)); const mapType = new MapType(ast.valueType); return this.transformExpr(new LiteralMapExpr(entries, mapType, ast.sourceSpan), context); } visitCommaExpr(ast, context) { return this.transformExpr(new CommaExpr(this.visitAllExpressions(ast.parts, context), ast.sourceSpan), context); } visitAllExpressions(exprs, context) { return exprs.map(expr => expr.visitExpression(this, context)); } visitDeclareVarStmt(stmt, context) { const value = stmt.value && stmt.value.visitExpression(this, context); return this.transformStmt(new DeclareVarStmt(stmt.name, value, stmt.type, stmt.modifiers, stmt.sourceSpan, stmt.leadingComments), context); } visitDeclareFunctionStmt(stmt, context) { return this.transformStmt(new DeclareFunctionStmt(stmt.name, stmt.params, this.visitAllStatements(stmt.statements, context), stmt.type, stmt.modifiers, stmt.sourceSpan, stmt.leadingComments), context); } visitExpressionStmt(stmt, context) { return this.transformStmt(new ExpressionStatement(stmt.expr.visitExpression(this, context), stmt.sourceSpan, stmt.leadingComments), context); } visitReturnStmt(stmt, context) { return this.transformStmt(new ReturnStatement(stmt.value.visitExpression(this, context), stmt.sourceSpan, stmt.leadingComments), context); } visitDeclareClassStmt(stmt, context) { const parent = stmt.parent.visitExpression(this, context); const getters = stmt.getters.map(getter => new ClassGetter(getter.name, this.visitAllStatements(getter.body, context), getter.type, getter.modifiers)); const ctorMethod = stmt.constructorMethod && new ClassMethod(stmt.constructorMethod.name, stmt.constructorMethod.params, this.visitAllStatements(stmt.constructorMethod.body, context), stmt.constructorMethod.type, stmt.constructorMethod.modifiers); const methods = stmt.methods.map(method => new ClassMethod(method.name, method.params, this.visitAllStatements(method.body, context), method.type, method.modifiers)); return this.transformStmt(new ClassStmt(stmt.name, parent, stmt.fields, getters, ctorMethod, methods, stmt.modifiers, stmt.sourceSpan), context); } visitIfStmt(stmt, context) { return this.transformStmt(new IfStmt(stmt.condition.visitExpression(this, context), this.visitAllStatements(stmt.trueCase, context), this.visitAllStatements(stmt.falseCase, context), stmt.sourceSpan, stmt.leadingComments), context); } visitTryCatchStmt(stmt, context) { return this.transformStmt(new TryCatchStmt(this.visitAllStatements(stmt.bodyStmts, context), this.visitAllStatements(stmt.catchStmts, context), stmt.sourceSpan, stmt.leadingComments), context); } visitThrowStmt(stmt, context) { return this.transformStmt(new ThrowStmt(stmt.error.visitExpression(this, context), stmt.sourceSpan, stmt.leadingComments), context); } visitAllStatements(stmts, context) { return stmts.map(stmt => stmt.visitStatement(this, context)); } } class RecursiveAstVisitor { visitType(ast, context) { return ast; } visitExpression(ast, context) { if (ast.type) { ast.type.visitType(this, context); } return ast; } visitBuiltinType(type, context) { return this.visitType(type, context); } visitExpressionType(type, context) { type.value.visitExpression(this, context); if (type.typeParams !== null) { type.typeParams.forEach(param => this.visitType(param, context)); } return this.visitType(type, context); } visitArrayType(type, context) { return this.visitType(type, context); } visitMapType(type, context) { return this.visitType(type, context); } visitWrappedNodeExpr(ast, context) { return ast; } visitTypeofExpr(ast, context) { return this.visitExpression(ast, context); } visitReadVarExpr(ast, context) { return this.visitExpression(ast, context); } visitWriteVarExpr(ast, context) { ast.value.visitExpression(this, context); return this.visitExpression(ast, context); } visitWriteKeyExpr(ast, context) { ast.receiver.visitExpression(this, context); ast.index.visitExpression(this, context); ast.value.visitExpression(this, context); return this.visitExpression(ast, context); } visitWritePropExpr(ast, context) { ast.receiver.visitExpression(this, context); ast.value.visitExpression(this, context); return this.visitExpression(ast, context); } visitInvokeMethodExpr(ast, context) { ast.receiver.visitExpression(this, context); this.visitAllExpressions(ast.args, context); return this.visitExpression(ast, context); } visitInvokeFunctionExpr(ast, context) { ast.fn.visitExpression(this, context); this.visitAllExpressions(ast.args, context); return this.visitExpression(ast, context); } visitTaggedTemplateExpr(ast, context) { ast.tag.visitExpression(this, context); this.visitAllExpressions(ast.template.expressions, context); return this.visitExpression(ast, context); } visitInstantiateExpr(ast, context) { ast.classExpr.visitExpression(this, context); this.visitAllExpressions(ast.args, context); return this.visitExpression(ast, context); } visitLiteralExpr(ast, context) { return this.visitExpression(ast, context); } visitLocalizedString(ast, context) { return this.visitExpression(ast, context); } visitExternalExpr(ast, context) { if (ast.typeParams) { ast.typeParams.forEach(type => type.visitType(this, context)); } return this.visitExpression(ast, context); } visitConditionalExpr(ast, context) { ast.condition.visitExpression(this, context); ast.trueCase.visitExpression(this, context); ast.falseCase.visitExpression(this, context); return this.visitExpression(ast, context); } visitNotExpr(ast, context) { ast.condition.visitExpression(this, context); return this.visitExpression(ast, context); } visitAssertNotNullExpr(ast, context) { ast.condition.visitExpression(this, context); return this.visitExpression(ast, context); } visitCastExpr(ast, context) { ast.value.visitExpression(this, context); return this.visitExpression(ast, context); } visitFunctionExpr(ast, context) { this.visitAllStatements(ast.statements, context); return this.visitExpression(ast, context); } visitUnaryOperatorExpr(ast, context) { ast.expr.visitExpression(this, context); return this.visitExpression(ast, context); } visitBinaryOperatorExpr(ast, context) { ast.lhs.visitExpression(this, context); ast.rhs.visitExpression(this, context); return this.visitExpression(ast, context); } visitReadPropExpr(ast, context) { ast.receiver.visitExpression(this, context); return this.visitExpression(ast, context); } visitReadKeyExpr(ast, context) { ast.receiver.visitExpression(this, context); ast.index.visitExpression(this, context); return this.visitExpression(ast, context); } visitLiteralArrayExpr(ast, context) { this.visitAllExpressions(ast.entries, context); return this.visitExpression(ast, context); } visitLiteralMapExpr(ast, context) { ast.entries.forEach((entry) => entry.value.visitExpression(this, context)); return this.visitExpression(ast, context); } visitCommaExpr(ast, context) { this.visitAllExpressions(ast.parts, context); return this.visitExpression(ast, context); } visitAllExpressions(exprs, context) { exprs.forEach(expr => expr.visitExpression(this, context)); } visitDeclareVarStmt(stmt, context) { if (stmt.value) { stmt.value.visitExpression(this, context); } if (stmt.type) { stmt.type.visitType(this, context); } return stmt; } visitDeclareFunctionStmt(stmt, context) { this.visitAllStatements(stmt.statements, context); if (stmt.type) { stmt.type.visitType(this, context); } return stmt; } visitExpressionStmt(stmt, context) { stmt.expr.visitExpression(this, context); return stmt; } visitReturnStmt(stmt, context) { stmt.value.visitExpression(this, context); return stmt; } visitDeclareClassStmt(stmt, context) { stmt.parent.visitExpression(this, context); stmt.getters.forEach(getter => this.visitAllStatements(getter.body, context)); if (stmt.constructorMethod) { this.visitAllStatements(stmt.constructorMethod.body, context); } stmt.methods.forEach(method => this.visitAllStatements(method.body, context)); return stmt; } visitIfStmt(stmt, context) { stmt.condition.visitExpression(this, context); this.visitAllStatements(stmt.trueCase, context); this.visitAllStatements(stmt.falseCase, context); return stmt; } visitTryCatchStmt(stmt, context) { this.visitAllStatements(stmt.bodyStmts, context); this.visitAllStatements(stmt.catchStmts, context); return stmt; } visitThrowStmt(stmt, context) { stmt.error.visitExpression(this, context); return stmt; } visitAllStatements(stmts, context) { stmts.forEach(stmt => stmt.visitStatement(this, context)); } } function findReadVarNames(stmts) { const visitor = new _ReadVarVisitor(); visitor.visitAllStatements(stmts, null); return visitor.varNames; } class _ReadVarVisitor extends RecursiveAstVisitor { constructor() { super(...arguments); this.varNames = new Set(); } visitDeclareFunctionStmt(stmt, context) { // Don't descend into nested functions return stmt; } visitDeclareClassStmt(stmt, context) { // Don't descend into nested classes return stmt; } visitReadVarExpr(ast, context) { if (ast.name) { this.varNames.add(ast.name); } return null; } } function collectExternalReferences(stmts) { const visitor = new _FindExternalReferencesVisitor(); visitor.visitAllStatements(stmts, null); return visitor.externalReferences; } class _FindExternalReferencesVisitor extends RecursiveAstVisitor { constructor() { super(...arguments); this.externalReferences = []; } visitExternalExpr(e, context) { this.externalReferences.push(e.value); return super.visitExternalExpr(e, context); } } function applySourceSpanToStatementIfNeeded(stmt, sourceSpan) { if (!sourceSpan) { return stmt; } const transformer = new _ApplySourceSpanTransformer(sourceSpan); return stmt.visitStatement(transformer, null); } function applySourceSpanToExpressionIfNeeded(expr, sourceSpan) { if (!sourceSpan) { return expr; } const transformer = new _ApplySourceSpanTransformer(sourceSpan); return expr.visitExpression(transformer, null); } class _ApplySourceSpanTransformer extends AstTransformer { constructor(sourceSpan) { super(); this.sourceSpan = sourceSpan; } _clone(obj) { const clone = Object.create(obj.constructor.prototype); for (let prop of Object.keys(obj)) { clone[prop] = obj[prop]; } return clone; } transformExpr(expr, context) { if (!expr.sourceSpan) { expr = this._clone(expr); expr.sourceSpan = this.sourceSpan; } return expr; } transformStmt(stmt, context) { if (!stmt.sourceSpan) { stmt = this._clone(stmt); stmt.sourceSpan = this.sourceSpan; } return stmt; } } function leadingComment(text, multiline = false, trailingNewline = true) { return new LeadingComment(text, multiline, trailingNewline); } function jsDocComment(tags = []) { return new JSDocComment(tags); } function variable(name, type, sourceSpan) { return new ReadVarExpr(name, type, sourceSpan); } function importExpr(id, typeParams = null, sourceSpan) { return new ExternalExpr(id, null, typeParams, sourceSpan); } function importType(id, typeParams, typeModifiers) { return id != null ? expressionType(importExpr(id, typeParams, null), typeModifiers) : null; } function expressionType(expr, typeModifiers, typeParams) { return new ExpressionType(expr, typeModifiers, typeParams); } function typeofExpr(expr) { return new TypeofExpr(expr); } function literalArr(values, type, sourceSpan) { return new LiteralArrayExpr(values, type, sourceSpan); } function literalMap(values, type = null) { return new LiteralMapExpr(values.map(e => new LiteralMapEntry(e.key, e.value, e.quoted)), type, null); } function unary(operator, expr, type, sourceSpan) { return new UnaryOperatorExpr(operator, expr, type, sourceSpan); } function not(expr, sourceSpan) { return new NotExpr(expr, sourceSpan); } function assertNotNull(expr, sourceSpan) { return new AssertNotNull(expr, sourceSpan); } function fn(params, body, type, sourceSpan, name) { return new FunctionExpr(params, body, type, sourceSpan, name); } function ifStmt(condition, thenClause, elseClause, sourceSpan, leadingComments) { return new IfStmt(condition, thenClause, elseClause, sourceSpan, leadingComments); } function taggedTemplate(tag, template, type, sourceSpan) { return new TaggedTemplateExpr(tag, template, type, sourceSpan); } function literal(value, type, sourceSpan) { return new LiteralExpr(value, type, sourceSpan); } function localizedString(metaBlock, messageParts, placeholderNames, expressions, sourceSpan) { return new LocalizedString(metaBlock, messageParts, placeholderNames, expressions, sourceSpan); } function isNull(exp) { return exp instanceof LiteralExpr && exp.value === null; } /* * Serializes a `Tag` into a string. * Returns a string like " @foo {bar} baz" (note the leading whitespace before `@foo`). */ function tagToString(tag) { let out = ''; if (tag.tagName) { out += ` @${tag.tagName}`; } if (tag.text) { if (tag.text.match(/\/\*|\*\//)) { throw new Error('JSDoc text cannot contain "/*" and "*/"'); } out += ' ' + tag.text.replace(/@/g, '\\@'); } return out; } function serializeTags(tags) { if (tags.length === 0) return ''; if (tags.length === 1 && tags[0].tagName && !tags[0].text) { // The JSDOC comment is a single simple tag: e.g `/** @tagname */`. return `*${tagToString(tags[0])} `; } let out = '*\n'; for (const tag of tags) { out += ' *'; // If the tagToString is multi-line, insert " * " prefixes on lines. out += tagToString(tag).replace(/\n/g, '\n * '); out += '\n'; } out += ' '; return out; } /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ const CONSTANT_PREFIX = '_c'; /** * `ConstantPool` tries to reuse literal factories when two or more literals are identical. * We determine whether literals are identical by creating a key out of their AST using the * `KeyVisitor`. This constant is used to replace dynamic expressions which can't be safely * converted into a key. E.g. given an expression `{foo: bar()}`, since we don't know what * the result of `bar` will be, we create a key that looks like `{foo: }`. Note * that we use a variable, rather than something like `null` in order to avoid collisions. */ const UNKNOWN_VALUE_KEY = variable(''); /** * Context to use when producing a key. * * This ensures we see the constant not the reference variable when producing * a key. */ const KEY_CONTEXT = {}; /** * Generally all primitive values are excluded from the `ConstantPool`, but there is an exclusion * for strings that reach a certain length threshold. This constant defines the length threshold for * strings. */ const POOL_INCLUSION_LENGTH_THRESHOLD_FOR_STRINGS = 50; /** * A node that is a place-holder that allows the node to be replaced when the actual * node is known. * * This allows the constant pool to change an expression from a direct reference to * a constant to a shared constant. It returns a fix-up node that is later allowed to * change the referenced expression. */ class FixupExpression extends Expression { constructor(resolved) { super(resolved.type); this.resolved = resolved; this.original = resolved; } visitExpression(visitor, context) { if (context === KEY_CONTEXT) { // When producing a key we want to traverse the constant not the // variable used to refer to it. return this.original.visitExpression(visitor, context); } else { return this.resolved.visitExpression(visitor, context); } } isEquivalent(e) { return e instanceof FixupExpression && this.resolved.isEquivalent(e.resolved); } isConstant() { return true; } fixup(expression) { this.resolved = expression; this.shared = true; } } /** * A constant pool allows a code emitter to share constant in an output context. * * The constant pool also supports sharing access to ivy definitions references. */ class ConstantPool { constructor(isClosureCompilerEnabled = false) { this.isClosureCompilerEnabled = isClosureCompilerEnabled; this.statements = []; this.literals = new Map(); this.literalFactories = new Map(); this.injectorDefinitions = new Map(); this.directiveDefinitions = new Map(); this.componentDefinitions = new Map(); this.pipeDefinitions = new Map(); this.nextNameIndex = 0; } getConstLiteral(literal, forceShared) { if ((literal instanceof LiteralExpr && !isLongStringLiteral(literal)) || literal instanceof FixupExpression) { // Do no put simple literals into the constant pool or try to produce a constant for a // reference to a constant. return literal; } const key = this.keyOf(literal); let fixup = this.literals.get(key); let newValue = false; if (!fixup) { fixup = new FixupExpression(literal); this.literals.set(key, fixup); newValue = true; } if ((!newValue && !fixup.shared) || (newValue && forceShared)) { // Replace the expression with a variable const name = this.freshName(); let definition; let usage; if (this.isClosureCompilerEnabled && isLongStringLiteral(literal)) { // For string literals, Closure will **always** inline the string at // **all** usages, duplicating it each time. For large strings, this // unnecessarily bloats bundle size. To work around this restriction, we // wrap the string in a function, and call that function for each usage. // This tricks Closure into using inline logic for functions instead of // string literals. Function calls are only inlined if the body is small // enough to be worth it. By doing this, very large strings will be // shared across multiple usages, rather than duplicating the string at // each usage site. // // const myStr = function() { return "very very very long string"; }; // const usage1 = myStr(); // const usage2 = myStr(); definition = variable(name).set(new FunctionExpr([], // Params. [ // Statements. new ReturnStatement(literal), ])); usage = variable(name).callFn([]); } else { // Just declare and use the variable directly, without a function call // indirection. This saves a few bytes and avoids an unncessary call. definition = variable(name).set(literal); usage = variable(name); } this.statements.push(definition.toDeclStmt(INFERRED_TYPE, [StmtModifier.Final])); fixup.fixup(usage); } return fixup; } getDefinition(type, kind, ctx, forceShared = false) { const definitions = this.definitionsOf(kind); let fixup = definitions.get(type); let newValue = false; if (!fixup) { const property = this.propertyNameOf(kind); fixup = new FixupExpression(ctx.importExpr(type).prop(property)); definitions.set(type, fixup); newValue = true; } if ((!newValue && !fixup.shared) || (newValue && forceShared)) { const name = this.freshName(); this.statements.push(variable(name).set(fixup.resolved).toDeclStmt(INFERRED_TYPE, [StmtModifier.Final])); fixup.fixup(variable(name)); } return fixup; } getLiteralFactory(literal) { // Create a pure function that builds an array of a mix of constant and variable expressions if (literal instanceof LiteralArrayExpr) { const argumentsForKey = literal.entries.map(e => e.isConstant() ? e : UNKNOWN_VALUE_KEY); const key = this.keyOf(literalArr(argumentsForKey)); return this._getLiteralFactory(key, literal.entries, entries => literalArr(entries)); } else { const expressionForKey = literalMap(literal.entries.map(e => ({ key: e.key, value: e.value.isConstant() ? e.value : UNKNOWN_VALUE_KEY, quoted: e.quoted }))); const key = this.keyOf(expressionForKey); return this._getLiteralFactory(key, literal.entries.map(e => e.value), entries => literalMap(entries.map((value, index) => ({ key: literal.entries[index].key, value, quoted: literal.entries[index].quoted })))); } } _getLiteralFactory(key, values, resultMap) { let literalFactory = this.literalFactories.get(key); const literalFactoryArguments = values.filter((e => !e.isConstant())); if (!literalFactory) { const resultExpressions = values.map((e, index) => e.isConstant() ? this.getConstLiteral(e, true) : variable(`a${index}`)); const parameters = resultExpressions.filter(isVariable).map(e => new FnParam(e.name, DYNAMIC_TYPE)); const pureFunctionDeclaration = fn(parameters, [new ReturnStatement(resultMap(resultExpressions))], INFERRED_TYPE); const name = this.freshName(); this.statements.push(variable(name).set(pureFunctionDeclaration).toDeclStmt(INFERRED_TYPE, [ StmtModifier.Final ])); literalFactory = variable(name); this.literalFactories.set(key, literalFactory); } return { literalFactory, literalFactoryArguments }; } /** * Produce a unique name. * * The name might be unique among different prefixes if any of the prefixes end in * a digit so the prefix should be a constant string (not based on user input) and * must not end in a digit. */ uniqueName(prefix) { return `${prefix}${this.nextNameIndex++}`; } definitionsOf(kind) { switch (kind) { case 2 /* Component */: return this.componentDefinitions; case 1 /* Directive */: return this.directiveDefinitions; case 0 /* Injector */: return this.injectorDefinitions; case 3 /* Pipe */: return this.pipeDefinitions; } } propertyNameOf(kind) { switch (kind) { case 2 /* Component */: return 'ɵcmp'; case 1 /* Directive */: return 'ɵdir'; case 0 /* Injector */: return 'ɵinj'; case 3 /* Pipe */: return 'ɵpipe'; } } freshName() { return this.uniqueName(CONSTANT_PREFIX); } keyOf(expression) { return expression.visitExpression(new KeyVisitor(), KEY_CONTEXT); } } /** * Visitor used to determine if 2 expressions are equivalent and can be shared in the * `ConstantPool`. * * When the id (string) generated by the visitor is equal, expressions are considered equivalent. */ class KeyVisitor { constructor() { this.visitWrappedNodeExpr = invalid; this.visitWriteVarExpr = invalid; this.visitWriteKeyExpr = invalid; this.visitWritePropExpr = invalid; this.visitInvokeMethodExpr = invalid; this.visitInvokeFunctionExpr = invalid; this.visitTaggedTemplateExpr = invalid; this.visitInstantiateExpr = invalid; this.visitConditionalExpr = invalid; this.visitNotExpr = invalid; this.visitAssertNotNullExpr = invalid; this.visitCastExpr = invalid; this.visitFunctionExpr = invalid; this.visitUnaryOperatorExpr = invalid; this.visitBinaryOperatorExpr = invalid; this.visitReadPropExpr = invalid; this.visitReadKeyExpr = invalid; this.visitCommaExpr = invalid; this.visitLocalizedString = invalid; } visitLiteralExpr(ast) { return `${typeof ast.value === 'string' ? '"' + ast.value + '"' : ast.value}`; } visitLiteralArrayExpr(ast, context) { return `[${ast.entries.map(entry => entry.visitExpression(this, context)).join(',')}]`; } visitLiteralMapExpr(ast, context) { const mapKey = (entry) => { const quote = entry.quoted ? '"' : ''; return `${quote}${entry.key}${quote}`; }; const mapEntry = (entry) => `${mapKey(entry)}:${entry.value.visitExpression(this, context)}`; return `{${ast.entries.map(mapEntry).join(',')}`; } visitExternalExpr(ast) { return ast.value.moduleName ? `EX:${ast.value.moduleName}:${ast.value.name}` : `EX:${ast.value.runtime.name}`; } visitReadVarExpr(node) { return `VAR:${node.name}`; } visitTypeofExpr(node, context) { return `TYPEOF:${node.expr.visitExpression(this, context)}`; } } function invalid(arg) { throw new Error(`Invalid state: Visitor ${this.constructor.name} doesn't handle ${arg.constructor.name}`); } function isVariable(e) { return e instanceof ReadVarExpr; } function isLongStringLiteral(expr) { return expr instanceof LiteralExpr && typeof expr.value === 'string' && expr.value.length >= POOL_INCLUSION_LENGTH_THRESHOLD_FOR_STRINGS; } /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ const CORE = '@angular/core'; class Identifiers { } /* Methods */ Identifiers.NEW_METHOD = 'factory'; Identifiers.TRANSFORM_METHOD = 'transform'; Identifiers.PATCH_DEPS = 'patchedDeps'; Identifiers.core = { name: null, moduleName: CORE }; /* Instructions */ Identifiers.namespaceHTML = { name: 'ɵɵnamespaceHTML', moduleName: CORE }; Identifiers.namespaceMathML = { name: 'ɵɵnamespaceMathML', moduleName: CORE }; Identifiers.namespaceSVG = { name: 'ɵɵnamespaceSVG', moduleName: CORE }; Identifiers.element = { name: 'ɵɵelement', moduleName: CORE }; Identifiers.elementStart = { name: 'ɵɵelementStart', moduleName: CORE }; Identifiers.elementEnd = { name: 'ɵɵelementEnd', moduleName: CORE }; Identifiers.advance = { name: 'ɵɵadvance', moduleName: CORE }; Identifiers.syntheticHostProperty = { name: 'ɵɵsyntheticHostProperty', moduleName: CORE }; Identifiers.syntheticHostListener = { name: 'ɵɵsyntheticHostListener', moduleName: CORE }; Identifiers.attribute = { name: 'ɵɵattribute', moduleName: CORE }; Identifiers.attributeInterpolate1 = { name: 'ɵɵattributeInterpolate1', moduleName: CORE }; Identifiers.attributeInterpolate2 = { name: 'ɵɵattributeInterpolate2', moduleName: CORE }; Identifiers.attributeInterpolate3 = { name: 'ɵɵattributeInterpolate3', moduleName: CORE }; Identifiers.attributeInterpolate4 = { name: 'ɵɵattributeInterpolate4', moduleName: CORE }; Identifiers.attributeInterpolate5 = { name: 'ɵɵattributeInterpolate5', moduleName: CORE }; Identifiers.attributeInterpolate6 = { name: 'ɵɵattributeInterpolate6', moduleName: CORE }; Identifiers.attributeInterpolate7 = { name: 'ɵɵattributeInterpolate7', moduleName: CORE }; Identifiers.attributeInterpolate8 = { name: 'ɵɵattributeInterpolate8', moduleName: CORE }; Identifiers.attributeInterpolateV = { name: 'ɵɵattributeInterpolateV', moduleName: CORE }; Identifiers.classProp = { name: 'ɵɵclassProp', moduleName: CORE }; Identifiers.elementContainerStart = { name: 'ɵɵelementContainerStart', moduleName: CORE }; Identifiers.elementContainerEnd = { name: 'ɵɵelementContainerEnd', moduleName: CORE }; Identifiers.elementContainer = { name: 'ɵɵelementContainer', moduleName: CORE }; Identifiers.styleMap = { name: 'ɵɵstyleMap', moduleName: CORE }; Identifiers.styleMapInterpolate1 = { name: 'ɵɵstyleMapInterpolate1', moduleName: CORE }; Identifiers.styleMapInterpolate2 = { name: 'ɵɵstyleMapInterpolate2', moduleName: CORE }; Identifiers.styleMapInterpolate3 = { name: 'ɵɵstyleMapInterpolate3', moduleName: CORE }; Identifiers.styleMapInterpolate4 = { name: 'ɵɵstyleMapInterpolate4', moduleName: CORE }; Identifiers.styleMapInterpolate5 = { name: 'ɵɵstyleMapInterpolate5', moduleName: CORE }; Identifiers.styleMapInterpolate6 = { name: 'ɵɵstyleMapInterpolate6', moduleName: CORE }; Identifiers.styleMapInterpolate7 = { name: 'ɵɵstyleMapInterpolate7', moduleName: CORE }; Identifiers.styleMapInterpolate8 = { name: 'ɵɵstyleMapInterpolate8', moduleName: CORE }; Identifiers.styleMapInterpolateV = { name: 'ɵɵstyleMapInterpolateV', moduleName: CORE }; Identifiers.classMap = { name: 'ɵɵclassMap', moduleName: CORE }; Identifiers.classMapInterpolate1 = { name: 'ɵɵclassMapInterpolate1', moduleName: CORE }; Identifiers.classMapInterpolate2 = { name: 'ɵɵclassMapInterpolate2', moduleName: CORE }; Identifiers.classMapInterpolate3 = { name: 'ɵɵclassMapInterpolate3', moduleName: CORE }; Identifiers.classMapInterpolate4 = { name: 'ɵɵclassMapInterpolate4', moduleName: CORE }; Identifiers.classMapInterpolate5 = { name: 'ɵɵclassMapInterpolate5', moduleName: CORE }; Identifiers.classMapInterpolate6 = { name: 'ɵɵclassMapInterpolate6', moduleName: CORE }; Identifiers.classMapInterpolate7 = { name: 'ɵɵclassMapInterpolate7', moduleName: CORE }; Identifiers.classMapInterpolate8 = { name: 'ɵɵclassMapInterpolate8', moduleName: CORE }; Identifiers.classMapInterpolateV = { name: 'ɵɵclassMapInterpolateV', moduleName: CORE }; Identifiers.styleProp = { name: 'ɵɵstyleProp', moduleName: CORE }; Identifiers.stylePropInterpolate1 = { name: 'ɵɵstylePropInterpolate1', moduleName: CORE }; Identifiers.stylePropInterpolate2 = { name: 'ɵɵstylePropInterpolate2', moduleName: CORE }; Identifiers.stylePropInterpolate3 = { name: 'ɵɵstylePropInterpolate3', moduleName: CORE }; Identifiers.stylePropInterpolate4 = { name: 'ɵɵstylePropInterpolate4', moduleName: CORE }; Identifiers.stylePropInterpolate5 = { name: 'ɵɵstylePropInterpolate5', moduleName: CORE }; Identifiers.stylePropInterpolate6 = { name: 'ɵɵstylePropInterpolate6', moduleName: CORE }; Identifiers.stylePropInterpolate7 = { name: 'ɵɵstylePropInterpolate7', moduleName: CORE }; Identifiers.stylePropInterpolate8 = { name: 'ɵɵstylePropInterpolate8', moduleName: CORE }; Identifiers.stylePropInterpolateV = { name: 'ɵɵstylePropInterpolateV', moduleName: CORE }; Identifiers.nextContext = { name: 'ɵɵnextContext', moduleName: CORE }; Identifiers.templateCreate = { name: 'ɵɵtemplate', moduleName: CORE }; Identifiers.text = { name: 'ɵɵtext', moduleName: CORE }; Identifiers.enableBindings = { name: 'ɵɵenableBindings', moduleName: CORE }; Identifiers.disableBindings = { name: 'ɵɵdisableBindings', moduleName: CORE }; Identifiers.getCurrentView = { name: 'ɵɵgetCurrentView', moduleName: CORE }; Identifiers.textInterpolate = { name: 'ɵɵtextInterpolate', moduleName: CORE }; Identifiers.textInterpolate1 = { name: 'ɵɵtextInterpolate1', moduleName: CORE }; Identifiers.textInterpolate2 = { name: 'ɵɵtextInterpolate2', moduleName: CORE }; Identifiers.textInterpolate3 = { name: 'ɵɵtextInterpolate3', moduleName: CORE }; Identifiers.textInterpolate4 = { name: 'ɵɵtextInterpolate4', moduleName: CORE }; Identifiers.textInterpolate5 = { name: 'ɵɵtextInterpolate5', moduleName: CORE }; Identifiers.textInterpolate6 = { name: 'ɵɵtextInterpolate6', moduleName: CORE }; Identifiers.textInterpolate7 = { name: 'ɵɵtextInterpolate7', moduleName: CORE }; Identifiers.textInterpolate8 = { name: 'ɵɵtextInterpolate8', moduleName: CORE }; Identifiers.textInterpolateV = { name: 'ɵɵtextInterpolateV', moduleName: CORE }; Identifiers.restoreView = { name: 'ɵɵrestoreView', moduleName: CORE }; Identifiers.pureFunction0 = { name: 'ɵɵpureFunction0', moduleName: CORE }; Identifiers.pureFunction1 = { name: 'ɵɵpureFunction1', moduleName: CORE }; Identifiers.pureFunction2 = { name: 'ɵɵpureFunction2', moduleName: CORE }; Identifiers.pureFunction3 = { name: 'ɵɵpureFunction3', moduleName: CORE }; Identifiers.pureFunction4 = { name: 'ɵɵpureFunction4', moduleName: CORE }; Identifiers.pureFunction5 = { name: 'ɵɵpureFunction5', moduleName: CORE }; Identifiers.pureFunction6 = { name: 'ɵɵpureFunction6', moduleName: CORE }; Identifiers.pureFunction7 = { name: 'ɵɵpureFunction7', moduleName: CORE }; Identifiers.pureFunction8 = { name: 'ɵɵpureFunction8', moduleName: CORE }; Identifiers.pureFunctionV = { name: 'ɵɵpureFunctionV', moduleName: CORE }; Identifiers.pipeBind1 = { name: 'ɵɵpipeBind1', moduleName: CORE }; Identifiers.pipeBind2 = { name: 'ɵɵpipeBind2', moduleName: CORE }; Identifiers.pipeBind3 = { name: 'ɵɵpipeBind3', moduleName: CORE }; Identifiers.pipeBind4 = { name: 'ɵɵpipeBind4', moduleName: CORE }; Identifiers.pipeBindV = { name: 'ɵɵpipeBindV', moduleName: CORE }; Identifiers.hostProperty = { name: 'ɵɵhostProperty', moduleName: CORE }; Identifiers.property = { name: 'ɵɵproperty', moduleName: CORE }; Identifiers.propertyInterpolate = { name: 'ɵɵpropertyInterpolate', moduleName: CORE }; Identifiers.propertyInterpolate1 = { name: 'ɵɵpropertyInterpolate1', moduleName: CORE }; Identifiers.propertyInterpolate2 = { name: 'ɵɵpropertyInterpolate2', moduleName: CORE }; Identifiers.propertyInterpolate3 = { name: 'ɵɵpropertyInterpolate3', moduleName: CORE }; Identifiers.propertyInterpolate4 = { name: 'ɵɵpropertyInterpolate4', moduleName: CORE }; Identifiers.propertyInterpolate5 = { name: 'ɵɵpropertyInterpolate5', moduleName: CORE }; Identifiers.propertyInterpolate6 = { name: 'ɵɵpropertyInterpolate6', moduleName: CORE }; Identifiers.propertyInterpolate7 = { name: 'ɵɵpropertyInterpolate7', moduleName: CORE }; Identifiers.propertyInterpolate8 = { name: 'ɵɵpropertyInterpolate8', moduleName: CORE }; Identifiers.propertyInterpolateV = { name: 'ɵɵpropertyInterpolateV', moduleName: CORE }; Identifiers.i18n = { name: 'ɵɵi18n', moduleName: CORE }; Identifiers.i18nAttributes = { name: 'ɵɵi18nAttributes', moduleName: CORE }; Identifiers.i18nExp = { name: 'ɵɵi18nExp', moduleName: CORE }; Identifiers.i18nStart = { name: 'ɵɵi18nStart', moduleName: CORE }; Identifiers.i18nEnd = { name: 'ɵɵi18nEnd', moduleName: CORE }; Identifiers.i18nApply = { name: 'ɵɵi18nApply', moduleName: CORE }; Identifiers.i18nPostprocess = { name: 'ɵɵi18nPostprocess', moduleName: CORE }; Identifiers.pipe = { name: 'ɵɵpipe', moduleName: CORE }; Identifiers.projection = { name: 'ɵɵprojection', moduleName: CORE }; Identifiers.projectionDef = { name: 'ɵɵprojectionDef', moduleName: CORE }; Identifiers.reference = { name: 'ɵɵreference', moduleName: CORE }; Identifiers.inject = { name: 'ɵɵinject', moduleName: CORE }; Identifiers.injectAttribute = { name: 'ɵɵinjectAttribute', moduleName: CORE }; Identifiers.directiveInject = { name: 'ɵɵdirectiveInject', moduleName: CORE }; Identifiers.invalidFactory = { name: 'ɵɵinvalidFactory', moduleName: CORE }; Identifiers.invalidFactoryDep = { name: 'ɵɵinvalidFactoryDep', moduleName: CORE }; Identifiers.templateRefExtractor = { name: 'ɵɵtemplateRefExtractor', moduleName: CORE }; Identifiers.forwardRef = { name: 'forwardRef', moduleName: CORE }; Identifiers.resolveForwardRef = { name: 'resolveForwardRef', moduleName: CORE }; Identifiers.ɵɵdefineInjectable = { name: 'ɵɵdefineInjectable', moduleName: CORE }; Identifiers.declareInjectable = { name: 'ɵɵngDeclareInjectable', moduleName: CORE }; Identifiers.InjectableDeclaration = { name: 'ɵɵInjectableDeclaration', moduleName: CORE }; Identifiers.resolveWindow = { name: 'ɵɵresolveWindow', moduleName: CORE }; Identifiers.resolveDocument = { name: 'ɵɵresolveDocument', moduleName: CORE }; Identifiers.resolveBody = { name: 'ɵɵresolveBody', moduleName: CORE }; Identifiers.defineComponent = { name: 'ɵɵdefineComponent', moduleName: CORE }; Identifiers.declareComponent = { name: 'ɵɵngDeclareComponent', moduleName: CORE }; Identifiers.setComponentScope = { name: 'ɵɵsetComponentScope', moduleName: CORE }; Identifiers.ChangeDetectionStrategy = { name: 'ChangeDetectionStrategy', moduleName: CORE, }; Identifiers.ViewEncapsulation = { name: 'ViewEncapsulation', moduleName: CORE, }; Identifiers.ComponentDeclaration = { name: 'ɵɵComponentDeclaration', moduleName: CORE, }; Identifiers.FactoryDeclaration = { name: 'ɵɵFactoryDeclaration', moduleName: CORE, }; Identifiers.declareFactory = { name: 'ɵɵngDeclareFactory', moduleName: CORE }; Identifiers.FactoryTarget = { name: 'ɵɵFactoryTarget', moduleName: CORE }; Identifiers.defineDirective = { name: 'ɵɵdefineDirective', moduleName: CORE }; Identifiers.declareDirective = { name: 'ɵɵngDeclareDirective', moduleName: CORE }; Identifiers.DirectiveDeclaration = { name: 'ɵɵDirectiveDeclaration', moduleName: CORE, }; Identifiers.InjectorDef = { name: 'ɵɵInjectorDef', moduleName: CORE }; Identifiers.InjectorDeclaration = { name: 'ɵɵInjectorDeclaration', moduleName: CORE }; Identifiers.defineInjector = { name: 'ɵɵdefineInjector', moduleName: CORE }; Identifiers.declareInjector = { name: 'ɵɵngDeclareInjector', moduleName: CORE }; Identifiers.NgModuleDeclaration = { name: 'ɵɵNgModuleDeclaration', moduleName: CORE, }; Identifiers.ModuleWithProviders = { name: 'ModuleWithProviders', moduleName: CORE, }; Identifiers.defineNgModule = { name: 'ɵɵdefineNgModule', moduleName: CORE }; Identifiers.declareNgModule = { name: 'ɵɵngDeclareNgModule', moduleName: CORE }; Identifiers.setNgModuleScope = { name: 'ɵɵsetNgModuleScope', moduleName: CORE }; Identifiers.PipeDeclaration = { name: 'ɵɵPipeDeclaration', moduleName: CORE }; Identifiers.definePipe = { name: 'ɵɵdefinePipe', moduleName: CORE }; Identifiers.declarePipe = { name: 'ɵɵngDeclarePipe', moduleName: CORE }; Identifiers.declareClassMetadata = { name: 'ɵɵngDeclareClassMetadata', moduleName: CORE }; Identifiers.setClassMetadata = { name: 'ɵsetClassMetadata', moduleName: CORE }; Identifiers.queryRefresh = { name: 'ɵɵqueryRefresh', moduleName: CORE }; Identifiers.viewQuery = { name: 'ɵɵviewQuery', moduleName: CORE }; Identifiers.loadQuery = { name: 'ɵɵloadQuery', moduleName: CORE }; Identifiers.contentQuery = { name: 'ɵɵcontentQuery', moduleName: CORE }; Identifiers.NgOnChangesFeature = { name: 'ɵɵNgOnChangesFeature', moduleName: CORE }; Identifiers.InheritDefinitionFeature = { name: 'ɵɵInheritDefinitionFeature', moduleName: CORE }; Identifiers.CopyDefinitionFeature = { name: 'ɵɵCopyDefinitionFeature', moduleName: CORE }; Identifiers.ProvidersFeature = { name: 'ɵɵProvidersFeature', moduleName: CORE }; Identifiers.listener = { name: 'ɵɵlistener', moduleName: CORE }; Identifiers.getInheritedFactory = { name: 'ɵɵgetInheritedFactory', moduleName: CORE, }; // sanitization-related functions Identifiers.sanitizeHtml = { name: 'ɵɵsanitizeHtml', moduleName: CORE }; Identifiers.sanitizeStyle = { name: 'ɵɵsanitizeStyle', moduleName: CORE }; Identifiers.sanitizeResourceUrl = { name: 'ɵɵsanitizeResourceUrl', moduleName: CORE }; Identifiers.sanitizeScript = { name: 'ɵɵsanitizeScript', moduleName: CORE }; Identifiers.sanitizeUrl = { name: 'ɵɵsanitizeUrl', moduleName: CORE }; Identifiers.sanitizeUrlOrResourceUrl = { name: 'ɵɵsanitizeUrlOrResourceUrl', moduleName: CORE }; Identifiers.trustConstantHtml = { name: 'ɵɵtrustConstantHtml', moduleName: CORE }; Identifiers.trustConstantResourceUrl = { name: 'ɵɵtrustConstantResourceUrl', moduleName: CORE }; Identifiers.validateIframeAttribute = { name: 'ɵɵvalidateIframeAttribute', moduleName: CORE }; /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ const DASH_CASE_REGEXP = /-+([a-z0-9])/g; function dashCaseToCamelCase(input) { return input.replace(DASH_CASE_REGEXP, (...m) => m[1].toUpperCase()); } function splitAtColon(input, defaultValues) { return _splitAt(input, ':', defaultValues); } function splitAtPeriod(input, defaultValues) { return _splitAt(input, '.', defaultValues); } function _splitAt(input, character, defaultValues) { const characterIndex = input.indexOf(character); if (characterIndex == -1) return defaultValues; return [input.slice(0, characterIndex).trim(), input.slice(characterIndex + 1).trim()]; } function visitValue(value, visitor, context) { if (Array.isArray(value)) { return visitor.visitArray(value, context); } if (isStrictStringMap(value)) { return visitor.visitStringMap(value, context); } if (value == null || typeof value == 'string' || typeof value == 'number' || typeof value == 'boolean') { return visitor.visitPrimitive(value, context); } return visitor.visitOther(value, context); } function isDefined(val) { return val !== null && val !== undefined; } function noUndefined(val) { return val === undefined ? null : val; } class ValueTransformer { visitArray(arr, context) { return arr.map(value => visitValue(value, this, context)); } visitStringMap(map, context) { const result = {}; Object.keys(map).forEach(key => { result[key] = visitValue(map[key], this, context); }); return result; } visitPrimitive(value, context) { return value; } visitOther(value, context) { return value; } } const SyncAsync = { assertSync: (value) => { if (isPromise(value)) { throw new Error(`Illegal state: value cannot be a promise`); } return value; }, then: (value, cb) => { return isPromise(value) ? value.then(cb) : cb(value); }, all: (syncAsyncValues) => { return syncAsyncValues.some(isPromise) ? Promise.all(syncAsyncValues) : syncAsyncValues; } }; function error(msg) { throw new Error(`Internal Error: ${msg}`); } // Escape characters that have a special meaning in Regular Expressions function escapeRegExp(s) { return s.replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1'); } const STRING_MAP_PROTO = Object.getPrototypeOf({}); function isStrictStringMap(obj) { return typeof obj === 'object' && obj !== null && Object.getPrototypeOf(obj) === STRING_MAP_PROTO; } function utf8Encode(str) { let encoded = []; for (let index = 0; index < str.length; index++) { let codePoint = str.charCodeAt(index); // decode surrogate // see https://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae if (codePoint >= 0xd800 && codePoint <= 0xdbff && str.length > (index + 1)) { const low = str.charCodeAt(index + 1); if (low >= 0xdc00 && low <= 0xdfff) { index++; codePoint = ((codePoint - 0xd800) << 10) + low - 0xdc00 + 0x10000; } } if (codePoint <= 0x7f) { encoded.push(codePoint); } else if (codePoint <= 0x7ff) { encoded.push(((codePoint >> 6) & 0x1F) | 0xc0, (codePoint & 0x3f) | 0x80); } else if (codePoint <= 0xffff) { encoded.push((codePoint >> 12) | 0xe0, ((codePoint >> 6) & 0x3f) | 0x80, (codePoint & 0x3f) | 0x80); } else if (codePoint <= 0x1fffff) { encoded.push(((codePoint >> 18) & 0x07) | 0xf0, ((codePoint >> 12) & 0x3f) | 0x80, ((codePoint >> 6) & 0x3f) | 0x80, (codePoint & 0x3f) | 0x80); } } return encoded; } 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}`; } if (!token.toString) { return 'object'; } // WARNING: do not try to `JSON.stringify(token)` here // see https://github.com/angular/angular/issues/23440 const res = token.toString(); if (res == null) { return '' + res; } const newLineIndex = res.indexOf('\n'); return newLineIndex === -1 ? res : res.substring(0, newLineIndex); } /** * Lazily retrieves the reference value from a forwardRef. */ function resolveForwardRef(type) { if (typeof type === 'function' && type.hasOwnProperty('__forward_ref__')) { return type(); } else { return type; } } /** * Determine if the argument is shaped like a Promise */ function isPromise(obj) { // allow any Promise/A+ compliant thenable. // It's up to the caller to ensure that obj.then conforms to the spec return !!obj && typeof obj.then === 'function'; } class Version { constructor(full) { this.full = full; const splits = full.split('.'); this.major = splits[0]; this.minor = splits[1]; this.patch = splits.slice(2).join('.'); } } const __window = typeof window !== 'undefined' && window; const __self = typeof self !== 'undefined' && typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope && self; const __global = typeof global !== 'undefined' && global; // Check __global first, because in Node tests both __global and __window may be defined and _global // should be __global in that case. const _global = __global || __window || __self; function newArray(size, value) { const list = []; for (let i = 0; i < size; i++) { list.push(value); } return list; } /** * Partitions a given array into 2 arrays, based on a boolean value returned by the condition * function. * * @param arr Input array that should be partitioned * @param conditionFn Condition function that is called for each item in a given array and returns a * boolean value. */ function partitionArray(arr, conditionFn) { const truthy = []; const falsy = []; for (const item of arr) { (conditionFn(item) ? truthy : falsy).push(item); } return [truthy, falsy]; } /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ // https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit const VERSION = 3; const JS_B64_PREFIX = '# sourceMappingURL=data:application/json;base64,'; class SourceMapGenerator { constructor(file = null) { this.file = file; this.sourcesContent = new Map(); this.lines = []; this.lastCol0 = 0; this.hasMappings = false; } // The content is `null` when the content is expected to be loaded using the URL addSource(url, content = null) { if (!this.sourcesContent.has(url)) { this.sourcesContent.set(url, content); } return this; } addLine() { this.lines.push([]); this.lastCol0 = 0; return this; } addMapping(col0, sourceUrl, sourceLine0, sourceCol0) { if (!this.currentLine) { throw new Error(`A line must be added before mappings can be added`); } if (sourceUrl != null && !this.sourcesContent.has(sourceUrl)) { throw new Error(`Unknown source file "${sourceUrl}"`); } if (col0 == null) { throw new Error(`The column in the generated code must be provided`); } if (col0 < this.lastCol0) { throw new Error(`Mapping should be added in output order`); } if (sourceUrl && (sourceLine0 == null || sourceCol0 == null)) { throw new Error(`The source location must be provided when a source url is provided`); } this.hasMappings = true; this.lastCol0 = col0; this.currentLine.push({ col0, sourceUrl, sourceLine0, sourceCol0 }); return this; } /** * @internal strip this from published d.ts files due to * https://github.com/microsoft/TypeScript/issues/36216 */ get currentLine() { return this.lines.slice(-1)[0]; } toJSON() { if (!this.hasMappings) { return null; } const sourcesIndex = new Map(); const sources = []; const sourcesContent = []; Array.from(this.sourcesContent.keys()).forEach((url, i) => { sourcesIndex.set(url, i); sources.push(url); sourcesContent.push(this.sourcesContent.get(url) || null); }); let mappings = ''; let lastCol0 = 0; let lastSourceIndex = 0; let lastSourceLine0 = 0; let lastSourceCol0 = 0; this.lines.forEach(segments => { lastCol0 = 0; mappings += segments .map(segment => { // zero-based starting column of the line in the generated code let segAsStr = toBase64VLQ(segment.col0 - lastCol0); lastCol0 = segment.col0; if (segment.sourceUrl != null) { // zero-based index into the “sources” list segAsStr += toBase64VLQ(sourcesIndex.get(segment.sourceUrl) - lastSourceIndex); lastSourceIndex = sourcesIndex.get(segment.sourceUrl); // the zero-based starting line in the original source segAsStr += toBase64VLQ(segment.sourceLine0 - lastSourceLine0); lastSourceLine0 = segment.sourceLine0; // the zero-based starting column in the original source segAsStr += toBase64VLQ(segment.sourceCol0 - lastSourceCol0); lastSourceCol0 = segment.sourceCol0; } return segAsStr; }) .join(','); mappings += ';'; }); mappings = mappings.slice(0, -1); return { 'file': this.file || '', 'version': VERSION, 'sourceRoot': '', 'sources': sources, 'sourcesContent': sourcesContent, 'mappings': mappings, }; } toJsComment() { return this.hasMappings ? '//' + JS_B64_PREFIX + toBase64String(JSON.stringify(this, null, 0)) : ''; } } function toBase64String(value) { let b64 = ''; const encoded = utf8Encode(value); for (let i = 0; i < encoded.length;) { const i1 = encoded[i++]; const i2 = i < encoded.length ? encoded[i++] : null; const i3 = i < encoded.length ? encoded[i++] : null; b64 += toBase64Digit(i1 >> 2); b64 += toBase64Digit(((i1 & 3) << 4) | (i2 === null ? 0 : i2 >> 4)); b64 += i2 === null ? '=' : toBase64Digit(((i2 & 15) << 2) | (i3 === null ? 0 : i3 >> 6)); b64 += i2 === null || i3 === null ? '=' : toBase64Digit(i3 & 63); } return b64; } function toBase64VLQ(value) { value = value < 0 ? ((-value) << 1) + 1 : value << 1; let out = ''; do { let digit = value & 31; value = value >> 5; if (value > 0) { digit = digit | 32; } out += toBase64Digit(digit); } while (value > 0); return out; } const B64_DIGITS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; function toBase64Digit(value) { if (value < 0 || value >= 64) { throw new Error(`Can only encode value in the range [0, 63]`); } return B64_DIGITS[value]; } /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ const _SINGLE_QUOTE_ESCAPE_STRING_RE = /'|\\|\n|\r|\$/g; const _LEGAL_IDENTIFIER_RE = /^[$A-Z_][0-9A-Z_$]*$/i; const _INDENT_WITH = ' '; const CATCH_ERROR_VAR$1 = variable('error', null, null); const CATCH_STACK_VAR$1 = variable('stack', null, null); class _EmittedLine { constructor(indent) { this.indent = indent; this.partsLength = 0; this.parts = []; this.srcSpans = []; } } class EmitterVisitorContext { constructor(_indent) { this._indent = _indent; this._classes = []; this._preambleLineCount = 0; this._lines = [new _EmittedLine(_indent)]; } static createRoot() { return new EmitterVisitorContext(0); } /** * @internal strip this from published d.ts files due to * https://github.com/microsoft/TypeScript/issues/36216 */ get _currentLine() { return this._lines[this._lines.length - 1]; } println(from, lastPart = '') { this.print(from || null, lastPart, true); } lineIsEmpty() { return this._currentLine.parts.length === 0; } lineLength() { return this._currentLine.indent * _INDENT_WITH.length + this._currentLine.partsLength; } print(from, part, newLine = false) { if (part.length > 0) { this._currentLine.parts.push(part); this._currentLine.partsLength += part.length; this._currentLine.srcSpans.push(from && from.sourceSpan || null); } if (newLine) { this._lines.push(new _EmittedLine(this._indent)); } } removeEmptyLastLine() { if (this.lineIsEmpty()) { this._lines.pop(); } } incIndent() { this._indent++; if (this.lineIsEmpty()) { this._currentLine.indent = this._indent; } } decIndent() { this._indent--; if (this.lineIsEmpty()) { this._currentLine.indent = this._indent; } } pushClass(clazz) { this._classes.push(clazz); } popClass() { return this._classes.pop(); } get currentClass() { return this._classes.length > 0 ? this._classes[this._classes.length - 1] : null; } toSource() { return this.sourceLines .map(l => l.parts.length > 0 ? _createIndent(l.indent) + l.parts.join('') : '') .join('\n'); } toSourceMapGenerator(genFilePath, startsAtLine = 0) { const map = new SourceMapGenerator(genFilePath); let firstOffsetMapped = false; const mapFirstOffsetIfNeeded = () => { if (!firstOffsetMapped) { // Add a single space so that tools won't try to load the file from disk. // Note: We are using virtual urls like `ng:///`, so we have to // provide a content here. map.addSource(genFilePath, ' ').addMapping(0, genFilePath, 0, 0); firstOffsetMapped = true; } }; for (let i = 0; i < startsAtLine; i++) { map.addLine(); mapFirstOffsetIfNeeded(); } this.sourceLines.forEach((line, lineIdx) => { map.addLine(); const spans = line.srcSpans; const parts = line.parts; let col0 = line.indent * _INDENT_WITH.length; let spanIdx = 0; // skip leading parts without source spans while (spanIdx < spans.length && !spans[spanIdx]) { col0 += parts[spanIdx].length; spanIdx++; } if (spanIdx < spans.length && lineIdx === 0 && col0 === 0) { firstOffsetMapped = true; } else { mapFirstOffsetIfNeeded(); } while (spanIdx < spans.length) { const span = spans[spanIdx]; const source = span.start.file; const sourceLine = span.start.line; const sourceCol = span.start.col; map.addSource(source.url, source.content) .addMapping(col0, source.url, sourceLine, sourceCol); col0 += parts[spanIdx].length; spanIdx++; // assign parts without span or the same span to the previous segment while (spanIdx < spans.length && (span === spans[spanIdx] || !spans[spanIdx])) { col0 += parts[spanIdx].length; spanIdx++; } } }); return map; } setPreambleLineCount(count) { return this._preambleLineCount = count; } spanOf(line, column) { const emittedLine = this._lines[line - this._preambleLineCount]; if (emittedLine) { let columnsLeft = column - _createIndent(emittedLine.indent).length; for (let partIndex = 0; partIndex < emittedLine.parts.length; partIndex++) { const part = emittedLine.parts[partIndex]; if (part.length > columnsLeft) { return emittedLine.srcSpans[partIndex]; } columnsLeft -= part.length; } } return null; } /** * @internal strip this from published d.ts files due to * https://github.com/microsoft/TypeScript/issues/36216 */ get sourceLines() { if (this._lines.length && this._lines[this._lines.length - 1].parts.length === 0) { return this._lines.slice(0, -1); } return this._lines; } } class AbstractEmitterVisitor { constructor(_escapeDollarInStrings) { this._escapeDollarInStrings = _escapeDollarInStrings; } printLeadingComments(stmt, ctx) { if (stmt.leadingComments === undefined) { return; } for (const comment of stmt.leadingComments) { if (comment instanceof JSDocComment) { ctx.print(stmt, `/*${comment.toString()}*/`, comment.trailingNewline); } else { if (comment.multiline) { ctx.print(stmt, `/* ${comment.text} */`, comment.trailingNewline); } else { comment.text.split('\n').forEach((line) => { ctx.println(stmt, `// ${line}`); }); } } } } visitExpressionStmt(stmt, ctx) { this.printLeadingComments(stmt, ctx); stmt.expr.visitExpression(this, ctx); ctx.println(stmt, ';'); return null; } visitReturnStmt(stmt, ctx) { this.printLeadingComments(stmt, ctx); ctx.print(stmt, `return `); stmt.value.visitExpression(this, ctx); ctx.println(stmt, ';'); return null; } visitIfStmt(stmt, ctx) { this.printLeadingComments(stmt, ctx); ctx.print(stmt, `if (`); stmt.condition.visitExpression(this, ctx); ctx.print(stmt, `) {`); const hasElseCase = stmt.falseCase != null && stmt.falseCase.length > 0; if (stmt.trueCase.length <= 1 && !hasElseCase) { ctx.print(stmt, ` `); this.visitAllStatements(stmt.trueCase, ctx); ctx.removeEmptyLastLine(); ctx.print(stmt, ` `); } else { ctx.println(); ctx.incIndent(); this.visitAllStatements(stmt.trueCase, ctx); ctx.decIndent(); if (hasElseCase) { ctx.println(stmt, `} else {`); ctx.incIndent(); this.visitAllStatements(stmt.falseCase, ctx); ctx.decIndent(); } } ctx.println(stmt, `}`); return null; } visitThrowStmt(stmt, ctx) { this.printLeadingComments(stmt, ctx); ctx.print(stmt, `throw `); stmt.error.visitExpression(this, ctx); ctx.println(stmt, `;`); return null; } visitWriteVarExpr(expr, ctx) { const lineWasEmpty = ctx.lineIsEmpty(); if (!lineWasEmpty) { ctx.print(expr, '('); } ctx.print(expr, `${expr.name} = `); expr.value.visitExpression(this, ctx); if (!lineWasEmpty) { ctx.print(expr, ')'); } return null; } visitWriteKeyExpr(expr, ctx) { const lineWasEmpty = ctx.lineIsEmpty(); if (!lineWasEmpty) { ctx.print(expr, '('); } expr.receiver.visitExpression(this, ctx); ctx.print(expr, `[`); expr.index.visitExpression(this, ctx); ctx.print(expr, `] = `); expr.value.visitExpression(this, ctx); if (!lineWasEmpty) { ctx.print(expr, ')'); } return null; } visitWritePropExpr(expr, ctx) { const lineWasEmpty = ctx.lineIsEmpty(); if (!lineWasEmpty) { ctx.print(expr, '('); } expr.receiver.visitExpression(this, ctx); ctx.print(expr, `.${expr.name} = `); expr.value.visitExpression(this, ctx); if (!lineWasEmpty) { ctx.print(expr, ')'); } return null; } visitInvokeMethodExpr(expr, ctx) { expr.receiver.visitExpression(this, ctx); let name = expr.name; if (expr.builtin != null) { name = this.getBuiltinMethodName(expr.builtin); if (name == null) { // some builtins just mean to skip the call. return null; } } ctx.print(expr, `.${name}(`); this.visitAllExpressions(expr.args, ctx, `,`); ctx.print(expr, `)`); return null; } visitInvokeFunctionExpr(expr, ctx) { expr.fn.visitExpression(this, ctx); ctx.print(expr, `(`); this.visitAllExpressions(expr.args, ctx, ','); ctx.print(expr, `)`); return null; } visitTaggedTemplateExpr(expr, ctx) { expr.tag.visitExpression(this, ctx); ctx.print(expr, '`' + expr.template.elements[0].rawText); for (let i = 1; i < expr.template.elements.length; i++) { ctx.print(expr, '${'); expr.template.expressions[i - 1].visitExpression(this, ctx); ctx.print(expr, `}${expr.template.elements[i].rawText}`); } ctx.print(expr, '`'); return null; } visitWrappedNodeExpr(ast, ctx) { throw new Error('Abstract emitter cannot visit WrappedNodeExpr.'); } visitTypeofExpr(expr, ctx) { ctx.print(expr, 'typeof '); expr.expr.visitExpression(this, ctx); } visitReadVarExpr(ast, ctx) { let varName = ast.name; if (ast.builtin != null) { switch (ast.builtin) { case BuiltinVar.Super: varName = 'super'; break; case BuiltinVar.This: varName = 'this'; break; case BuiltinVar.CatchError: varName = CATCH_ERROR_VAR$1.name; break; case BuiltinVar.CatchStack: varName = CATCH_STACK_VAR$1.name; break; default: throw new Error(`Unknown builtin variable ${ast.builtin}`); } } ctx.print(ast, varName); return null; } visitInstantiateExpr(ast, ctx) { ctx.print(ast, `new `); ast.classExpr.visitExpression(this, ctx); ctx.print(ast, `(`); this.visitAllExpressions(ast.args, ctx, ','); ctx.print(ast, `)`); return null; } visitLiteralExpr(ast, ctx) { const value = ast.value; if (typeof value === 'string') { ctx.print(ast, escapeIdentifier(value, this._escapeDollarInStrings)); } else { ctx.print(ast, `${value}`); } return null; } visitLocalizedString(ast, ctx) { const head = ast.serializeI18nHead(); ctx.print(ast, '$localize `' + head.raw); for (let i = 1; i < ast.messageParts.length; i++) { ctx.print(ast, '${'); ast.expressions[i - 1].visitExpression(this, ctx); ctx.print(ast, `}${ast.serializeI18nTemplatePart(i).raw}`); } ctx.print(ast, '`'); return null; } visitConditionalExpr(ast, ctx) { ctx.print(ast, `(`); ast.condition.visitExpression(this, ctx); ctx.print(ast, '? '); ast.trueCase.visitExpression(this, ctx); ctx.print(ast, ': '); ast.falseCase.visitExpression(this, ctx); ctx.print(ast, `)`); return null; } visitNotExpr(ast, ctx) { ctx.print(ast, '!'); ast.condition.visitExpression(this, ctx); return null; } visitAssertNotNullExpr(ast, ctx) { ast.condition.visitExpression(this, ctx); return null; } visitUnaryOperatorExpr(ast, ctx) { let opStr; switch (ast.operator) { case UnaryOperator.Plus: opStr = '+'; break; case UnaryOperator.Minus: opStr = '-'; break; default: throw new Error(`Unknown operator ${ast.operator}`); } if (ast.parens) ctx.print(ast, `(`); ctx.print(ast, opStr); ast.expr.visitExpression(this, ctx); if (ast.parens) ctx.print(ast, `)`); return null; } visitBinaryOperatorExpr(ast, ctx) { let opStr; switch (ast.operator) { case BinaryOperator.Equals: opStr = '=='; break; case BinaryOperator.Identical: opStr = '==='; break; case BinaryOperator.NotEquals: opStr = '!='; break; case BinaryOperator.NotIdentical: opStr = '!=='; break; case BinaryOperator.And: opStr = '&&'; break; case BinaryOperator.BitwiseAnd: opStr = '&'; break; case BinaryOperator.Or: opStr = '||'; break; case BinaryOperator.Plus: opStr = '+'; break; case BinaryOperator.Minus: opStr = '-'; break; case BinaryOperator.Divide: opStr = '/'; break; case BinaryOperator.Multiply: opStr = '*'; break; case BinaryOperator.Modulo: opStr = '%'; break; case BinaryOperator.Lower: opStr = '<'; break; case BinaryOperator.LowerEquals: opStr = '<='; break; case BinaryOperator.Bigger: opStr = '>'; break; case BinaryOperator.BiggerEquals: opStr = '>='; break; case BinaryOperator.NullishCoalesce: opStr = '??'; break; default: throw new Error(`Unknown operator ${ast.operator}`); } if (ast.parens) ctx.print(ast, `(`); ast.lhs.visitExpression(this, ctx); ctx.print(ast, ` ${opStr} `); ast.rhs.visitExpression(this, ctx); if (ast.parens) ctx.print(ast, `)`); return null; } visitReadPropExpr(ast, ctx) { ast.receiver.visitExpression(this, ctx); ctx.print(ast, `.`); ctx.print(ast, ast.name); return null; } visitReadKeyExpr(ast, ctx) { ast.receiver.visitExpression(this, ctx); ctx.print(ast, `[`); ast.index.visitExpression(this, ctx); ctx.print(ast, `]`); return null; } visitLiteralArrayExpr(ast, ctx) { ctx.print(ast, `[`); this.visitAllExpressions(ast.entries, ctx, ','); ctx.print(ast, `]`); return null; } visitLiteralMapExpr(ast, ctx) { ctx.print(ast, `{`); this.visitAllObjects(entry => { ctx.print(ast, `${escapeIdentifier(entry.key, this._escapeDollarInStrings, entry.quoted)}:`); entry.value.visitExpression(this, ctx); }, ast.entries, ctx, ','); ctx.print(ast, `}`); return null; } visitCommaExpr(ast, ctx) { ctx.print(ast, '('); this.visitAllExpressions(ast.parts, ctx, ','); ctx.print(ast, ')'); return null; } visitAllExpressions(expressions, ctx, separator) { this.visitAllObjects(expr => expr.visitExpression(this, ctx), expressions, ctx, separator); } visitAllObjects(handler, expressions, ctx, separator) { let incrementedIndent = false; for (let i = 0; i < expressions.length; i++) { if (i > 0) { if (ctx.lineLength() > 80) { ctx.print(null, separator, true); if (!incrementedIndent) { // continuation are marked with double indent. ctx.incIndent(); ctx.incIndent(); incrementedIndent = true; } } else { ctx.print(null, separator, false); } } handler(expressions[i]); } if (incrementedIndent) { // continuation are marked with double indent. ctx.decIndent(); ctx.decIndent(); } } visitAllStatements(statements, ctx) { statements.forEach((stmt) => stmt.visitStatement(this, ctx)); } } function escapeIdentifier(input, escapeDollar, alwaysQuote = true) { if (input == null) { return null; } const body = input.replace(_SINGLE_QUOTE_ESCAPE_STRING_RE, (...match) => { if (match[0] == '$') { return escapeDollar ? '\\$' : '$'; } else if (match[0] == '\n') { return '\\n'; } else if (match[0] == '\r') { return '\\r'; } else { return `\\${match[0]}`; } }); const requiresQuotes = alwaysQuote || !_LEGAL_IDENTIFIER_RE.test(body); return requiresQuotes ? `'${body}'` : body; } function _createIndent(count) { let res = ''; for (let i = 0; i < count; i++) { res += _INDENT_WITH; } return res; } /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ function typeWithParameters(type, numParams) { if (numParams === 0) { return expressionType(type); } const params = []; for (let i = 0; i < numParams; i++) { params.push(DYNAMIC_TYPE); } return expressionType(type, undefined, params); } const ANIMATE_SYMBOL_PREFIX = '@'; function prepareSyntheticPropertyName(name) { return `${ANIMATE_SYMBOL_PREFIX}${name}`; } function prepareSyntheticListenerName(name, phase) { return `${ANIMATE_SYMBOL_PREFIX}${name}.${phase}`; } function getSafePropertyAccessString(accessor, name) { const escapedName = escapeIdentifier(name, false, false); return escapedName !== name ? `${accessor}[${escapedName}]` : `${accessor}.${name}`; } function prepareSyntheticListenerFunctionName(name, phase) { return `animation_${name}_${phase}`; } function jitOnlyGuardedExpression(expr) { return guardedExpression('ngJitMode', expr); } function devOnlyGuardedExpression(expr) { return guardedExpression('ngDevMode', expr); } function guardedExpression(guard, expr) { const guardExpr = new ExternalExpr({ name: guard, moduleName: null }); const guardNotDefined = new BinaryOperatorExpr(BinaryOperator.Identical, new TypeofExpr(guardExpr), literal('undefined')); const guardUndefinedOrTrue = new BinaryOperatorExpr(BinaryOperator.Or, guardNotDefined, guardExpr, /* type */ undefined, /* sourceSpan */ undefined, true); return new BinaryOperatorExpr(BinaryOperator.And, guardUndefinedOrTrue, expr); } function wrapReference(value) { const wrapped = new WrappedNodeExpr(value); return { value: wrapped, type: wrapped }; } function refsToArray(refs, shouldForwardDeclare) { const values = literalArr(refs.map(ref => ref.value)); return shouldForwardDeclare ? fn([], [new ReturnStatement(values)]) : values; } function createMayBeForwardRefExpression(expression, forwardRef) { return { expression, forwardRef }; } /** * Convert a `MaybeForwardRefExpression` to an `Expression`, possibly wrapping its expression in a * `forwardRef()` call. * * If `MaybeForwardRefExpression.forwardRef` is `ForwardRefHandling.Unwrapped` then the expression * was originally wrapped in a `forwardRef()` call to prevent the value from being eagerly evaluated * in the code. * * See `packages/compiler-cli/src/ngtsc/annotations/src/injectable.ts` and * `packages/compiler/src/jit_compiler_facade.ts` for more information. */ function convertFromMaybeForwardRefExpression({ expression, forwardRef }) { switch (forwardRef) { case 0 /* None */: case 1 /* Wrapped */: return expression; case 2 /* Unwrapped */: return generateForwardRef(expression); } } /** * Generate an expression that has the given `expr` wrapped in the following form: * * ``` * forwardRef(() => expr) * ``` */ function generateForwardRef(expr) { return importExpr(Identifiers.forwardRef).callFn([fn([], [new ReturnStatement(expr)])]); } var R3FactoryDelegateType; (function (R3FactoryDelegateType) { R3FactoryDelegateType[R3FactoryDelegateType["Class"] = 0] = "Class"; R3FactoryDelegateType[R3FactoryDelegateType["Function"] = 1] = "Function"; })(R3FactoryDelegateType || (R3FactoryDelegateType = {})); var FactoryTarget; (function (FactoryTarget) { FactoryTarget[FactoryTarget["Directive"] = 0] = "Directive"; FactoryTarget[FactoryTarget["Component"] = 1] = "Component"; FactoryTarget[FactoryTarget["Injectable"] = 2] = "Injectable"; FactoryTarget[FactoryTarget["Pipe"] = 3] = "Pipe"; FactoryTarget[FactoryTarget["NgModule"] = 4] = "NgModule"; })(FactoryTarget || (FactoryTarget = {})); /** * Construct a factory function expression for the given `R3FactoryMetadata`. */ function compileFactoryFunction(meta) { const t = variable('t'); let baseFactoryVar = null; // The type to instantiate via constructor invocation. If there is no delegated factory, meaning // this type is always created by constructor invocation, then this is the type-to-create // parameter provided by the user (t) if specified, or the current type if not. If there is a // delegated factory (which is used to create the current type) then this is only the type-to- // create parameter (t). const typeForCtor = !isDelegatedFactoryMetadata(meta) ? new BinaryOperatorExpr(BinaryOperator.Or, t, meta.internalType) : t; let ctorExpr = null; if (meta.deps !== null) { // There is a constructor (either explicitly or implicitly defined). if (meta.deps !== 'invalid') { ctorExpr = new InstantiateExpr(typeForCtor, injectDependencies(meta.deps, meta.target)); } } else { // There is no constructor, use the base class' factory to construct typeForCtor. baseFactoryVar = variable(`ɵ${meta.name}_BaseFactory`); ctorExpr = baseFactoryVar.callFn([typeForCtor]); } const body = []; let retExpr = null; function makeConditionalFactory(nonCtorExpr) { const r = variable('r'); body.push(r.set(NULL_EXPR).toDeclStmt()); const ctorStmt = ctorExpr !== null ? r.set(ctorExpr).toStmt() : importExpr(Identifiers.invalidFactory).callFn([]).toStmt(); body.push(ifStmt(t, [ctorStmt], [r.set(nonCtorExpr).toStmt()])); return r; } if (isDelegatedFactoryMetadata(meta)) { // This type is created with a delegated factory. If a type parameter is not specified, call // the factory instead. const delegateArgs = injectDependencies(meta.delegateDeps, meta.target); // Either call `new delegate(...)` or `delegate(...)` depending on meta.delegateType. const factoryExpr = new (meta.delegateType === R3FactoryDelegateType.Class ? InstantiateExpr : InvokeFunctionExpr)(meta.delegate, delegateArgs); retExpr = makeConditionalFactory(factoryExpr); } else if (isExpressionFactoryMetadata(meta)) { // TODO(alxhub): decide whether to lower the value here or in the caller retExpr = makeConditionalFactory(meta.expression); } else { retExpr = ctorExpr; } if (retExpr === null) { // The expression cannot be formed so render an `ɵɵinvalidFactory()` call. body.push(importExpr(Identifiers.invalidFactory).callFn([]).toStmt()); } else if (baseFactoryVar !== null) { // This factory uses a base factory, so call `ɵɵgetInheritedFactory()` to compute it. const getInheritedFactoryCall = importExpr(Identifiers.getInheritedFactory).callFn([meta.internalType]); // Memoize the base factoryFn: `baseFactory || (baseFactory = ɵɵgetInheritedFactory(...))` const baseFactory = new BinaryOperatorExpr(BinaryOperator.Or, baseFactoryVar, baseFactoryVar.set(getInheritedFactoryCall)); body.push(new ReturnStatement(baseFactory.callFn([typeForCtor]))); } else { // This is straightforward factory, just return it. body.push(new ReturnStatement(retExpr)); } let factoryFn = fn([new FnParam('t', DYNAMIC_TYPE)], body, INFERRED_TYPE, undefined, `${meta.name}_Factory`); if (baseFactoryVar !== null) { // There is a base factory variable so wrap its declaration along with the factory function into // an IIFE. factoryFn = fn([], [ new DeclareVarStmt(baseFactoryVar.name), new ReturnStatement(factoryFn) ]).callFn([], /* sourceSpan */ undefined, /* pure */ true); } return { expression: factoryFn, statements: [], type: createFactoryType(meta), }; } function createFactoryType(meta) { const ctorDepsType = meta.deps !== null && meta.deps !== 'invalid' ? createCtorDepsType(meta.deps) : NONE_TYPE; return expressionType(importExpr(Identifiers.FactoryDeclaration, [typeWithParameters(meta.type.type, meta.typeArgumentCount), ctorDepsType])); } function injectDependencies(deps, target) { return deps.map((dep, index) => compileInjectDependency(dep, target, index)); } function compileInjectDependency(dep, target, index) { // Interpret the dependency according to its resolved type. if (dep.token === null) { return importExpr(Identifiers.invalidFactoryDep).callFn([literal(index)]); } else if (dep.attributeNameType === null) { // Build up the injection flags according to the metadata. const flags = 0 /* Default */ | (dep.self ? 2 /* Self */ : 0) | (dep.skipSelf ? 4 /* SkipSelf */ : 0) | (dep.host ? 1 /* Host */ : 0) | (dep.optional ? 8 /* Optional */ : 0) | (target === FactoryTarget.Pipe ? 16 /* ForPipe */ : 0); // If this dependency is optional or otherwise has non-default flags, then additional // parameters describing how to inject the dependency must be passed to the inject function // that's being used. let flagsParam = (flags !== 0 /* Default */ || dep.optional) ? literal(flags) : null; // Build up the arguments to the injectFn call. const injectArgs = [dep.token]; if (flagsParam) { injectArgs.push(flagsParam); } const injectFn = getInjectFn(target); return importExpr(injectFn).callFn(injectArgs); } else { // The `dep.attributeTypeName` value is defined, which indicates that this is an `@Attribute()` // type dependency. For the generated JS we still want to use the `dep.token` value in case the // name given for the attribute is not a string literal. For example given `@Attribute(foo())`, // we want to generate `ɵɵinjectAttribute(foo())`. // // The `dep.attributeTypeName` is only actually used (in `createCtorDepType()`) to generate // typings. return importExpr(Identifiers.injectAttribute).callFn([dep.token]); } } function createCtorDepsType(deps) { let hasTypes = false; const attributeTypes = deps.map(dep => { const type = createCtorDepType(dep); if (type !== null) { hasTypes = true; return type; } else { return literal(null); } }); if (hasTypes) { return expressionType(literalArr(attributeTypes)); } else { return NONE_TYPE; } } function createCtorDepType(dep) { const entries = []; if (dep.attributeNameType !== null) { entries.push({ key: 'attribute', value: dep.attributeNameType, quoted: false }); } if (dep.optional) { entries.push({ key: 'optional', value: literal(true), quoted: false }); } if (dep.host) { entries.push({ key: 'host', value: literal(true), quoted: false }); } if (dep.self) { entries.push({ key: 'self', value: literal(true), quoted: false }); } if (dep.skipSelf) { entries.push({ key: 'skipSelf', value: literal(true), quoted: false }); } return entries.length > 0 ? literalMap(entries) : null; } function isDelegatedFactoryMetadata(meta) { return meta.delegateType !== undefined; } function isExpressionFactoryMetadata(meta) { return meta.expression !== undefined; } function getInjectFn(target) { switch (target) { case FactoryTarget.Component: case FactoryTarget.Directive: case FactoryTarget.Pipe: return Identifiers.directiveInject; case FactoryTarget.NgModule: case FactoryTarget.Injectable: default: return Identifiers.inject; } } /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ /** * This is an R3 `Node`-like wrapper for a raw `html.Comment` node. We do not currently * require the implementation of a visitor for Comments as they are only collected at * the top-level of the R3 AST, and only if `Render3ParseOptions['collectCommentNodes']` * is true. */ class Comment { constructor(value, sourceSpan) { this.value = value; this.sourceSpan = sourceSpan; } visit(_visitor) { throw new Error('visit() not implemented for Comment'); } } class Text { constructor(value, sourceSpan) { this.value = value; this.sourceSpan = sourceSpan; } visit(visitor) { return visitor.visitText(this); } } class BoundText { constructor(value, sourceSpan, i18n) { this.value = value; this.sourceSpan = sourceSpan; this.i18n = i18n; } visit(visitor) { return visitor.visitBoundText(this); } } /** * Represents a text attribute in the template. * * `valueSpan` may not be present in cases where there is no value `
`. * `keySpan` may also not be present for synthetic attributes from ICU expansions. */ class TextAttribute { constructor(name, value, sourceSpan, keySpan, valueSpan, i18n) { this.name = name; this.value = value; this.sourceSpan = sourceSpan; this.keySpan = keySpan; this.valueSpan = valueSpan; this.i18n = i18n; } visit(visitor) { return visitor.visitTextAttribute(this); } } class BoundAttribute { constructor(name, type, securityContext, value, unit, sourceSpan, keySpan, valueSpan, i18n) { this.name = name; this.type = type; this.securityContext = securityContext; this.value = value; this.unit = unit; this.sourceSpan = sourceSpan; this.keySpan = keySpan; this.valueSpan = valueSpan; this.i18n = i18n; } static fromBoundElementProperty(prop, i18n) { if (prop.keySpan === undefined) { throw new Error(`Unexpected state: keySpan must be defined for bound attributes but was not for ${prop.name}: ${prop.sourceSpan}`); } return new BoundAttribute(prop.name, prop.type, prop.securityContext, prop.value, prop.unit, prop.sourceSpan, prop.keySpan, prop.valueSpan, i18n); } visit(visitor) { return visitor.visitBoundAttribute(this); } } class BoundEvent { constructor(name, type, handler, target, phase, sourceSpan, handlerSpan, keySpan) { this.name = name; this.type = type; this.handler = handler; this.target = target; this.phase = phase; this.sourceSpan = sourceSpan; this.handlerSpan = handlerSpan; this.keySpan = keySpan; } static fromParsedEvent(event) { const target = event.type === 0 /* Regular */ ? event.targetOrPhase : null; const phase = event.type === 1 /* Animation */ ? event.targetOrPhase : null; if (event.keySpan === undefined) { throw new Error(`Unexpected state: keySpan must be defined for bound event but was not for ${event.name}: ${event.sourceSpan}`); } return new BoundEvent(event.name, event.type, event.handler, target, phase, event.sourceSpan, event.handlerSpan, event.keySpan); } visit(visitor) { return visitor.visitBoundEvent(this); } } class Element { constructor(name, attributes, inputs, outputs, children, references, sourceSpan, startSourceSpan, endSourceSpan, i18n) { this.name = name; this.attributes = attributes; this.inputs = inputs; this.outputs = outputs; this.children = children; this.references = references; this.sourceSpan = sourceSpan; this.startSourceSpan = startSourceSpan; this.endSourceSpan = endSourceSpan; this.i18n = i18n; } visit(visitor) { return visitor.visitElement(this); } } class Template { constructor(tagName, attributes, inputs, outputs, templateAttrs, children, references, variables, sourceSpan, startSourceSpan, endSourceSpan, i18n) { this.tagName = tagName; this.attributes = attributes; this.inputs = inputs; this.outputs = outputs; this.templateAttrs = templateAttrs; this.children = children; this.references = references; this.variables = variables; this.sourceSpan = sourceSpan; this.startSourceSpan = startSourceSpan; this.endSourceSpan = endSourceSpan; this.i18n = i18n; } visit(visitor) { return visitor.visitTemplate(this); } } class Content { constructor(selector, attributes, sourceSpan, i18n) { this.selector = selector; this.attributes = attributes; this.sourceSpan = sourceSpan; this.i18n = i18n; this.name = 'ng-content'; } visit(visitor) { return visitor.visitContent(this); } } class Variable { constructor(name, value, sourceSpan, keySpan, valueSpan) { this.name = name; this.value = value; this.sourceSpan = sourceSpan; this.keySpan = keySpan; this.valueSpan = valueSpan; } visit(visitor) { return visitor.visitVariable(this); } } class Reference { constructor(name, value, sourceSpan, keySpan, valueSpan) { this.name = name; this.value = value; this.sourceSpan = sourceSpan; this.keySpan = keySpan; this.valueSpan = valueSpan; } visit(visitor) { return visitor.visitReference(this); } } class Icu { constructor(vars, placeholders, sourceSpan, i18n) { this.vars = vars; this.placeholders = placeholders; this.sourceSpan = sourceSpan; this.i18n = i18n; } visit(visitor) { return visitor.visitIcu(this); } } class NullVisitor { visitElement(element) { } visitTemplate(template) { } visitContent(content) { } visitVariable(variable) { } visitReference(reference) { } visitTextAttribute(attribute) { } visitBoundAttribute(attribute) { } visitBoundEvent(attribute) { } visitText(text) { } visitBoundText(text) { } visitIcu(icu) { } } class RecursiveVisitor { visitElement(element) { visitAll(this, element.attributes); visitAll(this, element.inputs); visitAll(this, element.outputs); visitAll(this, element.children); visitAll(this, element.references); } visitTemplate(template) { visitAll(this, template.attributes); visitAll(this, template.inputs); visitAll(this, template.outputs); visitAll(this, template.children); visitAll(this, template.references); visitAll(this, template.variables); } visitContent(content) { } visitVariable(variable) { } visitReference(reference) { } visitTextAttribute(attribute) { } visitBoundAttribute(attribute) { } visitBoundEvent(attribute) { } visitText(text) { } visitBoundText(text) { } visitIcu(icu) { } } class TransformVisitor { visitElement(element) { const newAttributes = transformAll(this, element.attributes); const newInputs = transformAll(this, element.inputs); const newOutputs = transformAll(this, element.outputs); const newChildren = transformAll(this, element.children); const newReferences = transformAll(this, element.references); if (newAttributes != element.attributes || newInputs != element.inputs || newOutputs != element.outputs || newChildren != element.children || newReferences != element.references) { return new Element(element.name, newAttributes, newInputs, newOutputs, newChildren, newReferences, element.sourceSpan, element.startSourceSpan, element.endSourceSpan); } return element; } visitTemplate(template) { const newAttributes = transformAll(this, template.attributes); const newInputs = transformAll(this, template.inputs); const newOutputs = transformAll(this, template.outputs); const newTemplateAttrs = transformAll(this, template.templateAttrs); const newChildren = transformAll(this, template.children); const newReferences = transformAll(this, template.references); const newVariables = transformAll(this, template.variables); if (newAttributes != template.attributes || newInputs != template.inputs || newOutputs != template.outputs || newTemplateAttrs != template.templateAttrs || newChildren != template.children || newReferences != template.references || newVariables != template.variables) { return new Template(template.tagName, newAttributes, newInputs, newOutputs, newTemplateAttrs, newChildren, newReferences, newVariables, template.sourceSpan, template.startSourceSpan, template.endSourceSpan); } return template; } visitContent(content) { return content; } visitVariable(variable) { return variable; } visitReference(reference) { return reference; } visitTextAttribute(attribute) { return attribute; } visitBoundAttribute(attribute) { return attribute; } visitBoundEvent(attribute) { return attribute; } visitText(text) { return text; } visitBoundText(text) { return text; } visitIcu(icu) { return icu; } } function visitAll(visitor, nodes) { const result = []; if (visitor.visit) { for (const node of nodes) { const newNode = visitor.visit(node) || node.visit(visitor); } } else { for (const node of nodes) { const newNode = node.visit(visitor); if (newNode) { result.push(newNode); } } } return result; } function transformAll(visitor, nodes) { const result = []; let changed = false; for (const node of nodes) { const newNode = node.visit(visitor); if (newNode) { result.push(newNode); } changed = changed || newNode != node; } return changed ? result : nodes; } /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ class Message { /** * @param nodes message AST * @param placeholders maps placeholder names to static content and their source spans * @param placeholderToMessage maps placeholder names to messages (used for nested ICU messages) * @param meaning * @param description * @param customId */ constructor(nodes, placeholders, placeholderToMessage, meaning, description, customId) { this.nodes = nodes; this.placeholders = placeholders; this.placeholderToMessage = placeholderToMessage; this.meaning = meaning; this.description = description; this.customId = customId; this.id = this.customId; /** The ids to use if there are no custom id and if `i18nLegacyMessageIdFormat` is not empty */ this.legacyIds = []; if (nodes.length) { this.sources = [{ filePath: nodes[0].sourceSpan.start.file.url, startLine: nodes[0].sourceSpan.start.line + 1, startCol: nodes[0].sourceSpan.start.col + 1, endLine: nodes[nodes.length - 1].sourceSpan.end.line + 1, endCol: nodes[0].sourceSpan.start.col + 1 }]; } else { this.sources = []; } } } class Text$1 { constructor(value, sourceSpan) { this.value = value; this.sourceSpan = sourceSpan; } visit(visitor, context) { return visitor.visitText(this, context); } } // TODO(vicb): do we really need this node (vs an array) ? class Container { constructor(children, sourceSpan) { this.children = children; this.sourceSpan = sourceSpan; } visit(visitor, context) { return visitor.visitContainer(this, context); } } class Icu$1 { constructor(expression, type, cases, sourceSpan) { this.expression = expression; this.type = type; this.cases = cases; this.sourceSpan = sourceSpan; } visit(visitor, context) { return visitor.visitIcu(this, context); } } class TagPlaceholder { constructor(tag, attrs, startName, closeName, children, isVoid, // TODO sourceSpan should cover all (we need a startSourceSpan and endSourceSpan) sourceSpan, startSourceSpan, endSourceSpan) { this.tag = tag; this.attrs = attrs; this.startName = startName; this.closeName = closeName; this.children = children; this.isVoid = isVoid; this.sourceSpan = sourceSpan; this.startSourceSpan = startSourceSpan; this.endSourceSpan = endSourceSpan; } visit(visitor, context) { return visitor.visitTagPlaceholder(this, context); } } class Placeholder { constructor(value, name, sourceSpan) { this.value = value; this.name = name; this.sourceSpan = sourceSpan; } visit(visitor, context) { return visitor.visitPlaceholder(this, context); } } class IcuPlaceholder { constructor(value, name, sourceSpan) { this.value = value; this.name = name; this.sourceSpan = sourceSpan; } visit(visitor, context) { return visitor.visitIcuPlaceholder(this, context); } } // Clone the AST class CloneVisitor { visitText(text, context) { return new Text$1(text.value, text.sourceSpan); } visitContainer(container, context) { const children = container.children.map(n => n.visit(this, context)); return new Container(children, container.sourceSpan); } visitIcu(icu, context) { const cases = {}; Object.keys(icu.cases).forEach(key => cases[key] = icu.cases[key].visit(this, context)); const msg = new Icu$1(icu.expression, icu.type, cases, icu.sourceSpan); msg.expressionPlaceholder = icu.expressionPlaceholder; return msg; } visitTagPlaceholder(ph, context) { const children = ph.children.map(n => n.visit(this, context)); return new TagPlaceholder(ph.tag, ph.attrs, ph.startName, ph.closeName, children, ph.isVoid, ph.sourceSpan, ph.startSourceSpan, ph.endSourceSpan); } visitPlaceholder(ph, context) { return new Placeholder(ph.value, ph.name, ph.sourceSpan); } visitIcuPlaceholder(ph, context) { return new IcuPlaceholder(ph.value, ph.name, ph.sourceSpan); } } // Visit all the nodes recursively class RecurseVisitor { visitText(text, context) { } visitContainer(container, context) { container.children.forEach(child => child.visit(this)); } visitIcu(icu, context) { Object.keys(icu.cases).forEach(k => { icu.cases[k].visit(this); }); } visitTagPlaceholder(ph, context) { ph.children.forEach(child => child.visit(this)); } visitPlaceholder(ph, context) { } visitIcuPlaceholder(ph, context) { } } /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ /** * Represents a big integer using a buffer of its individual digits, with the least significant * digit stored at the beginning of the array (little endian). * * For performance reasons, each instance is mutable. The addition operation can be done in-place * to reduce memory pressure of allocation for the digits array. */ class BigInteger { /** * Creates a big integer using its individual digits in little endian storage. */ constructor(digits) { this.digits = digits; } static zero() { return new BigInteger([0]); } static one() { return new BigInteger([1]); } /** * Creates a clone of this instance. */ clone() { return new BigInteger(this.digits.slice()); } /** * Returns a new big integer with the sum of `this` and `other` as its value. This does not mutate * `this` but instead returns a new instance, unlike `addToSelf`. */ add(other) { const result = this.clone(); result.addToSelf(other); return result; } /** * Adds `other` to the instance itself, thereby mutating its value. */ addToSelf(other) { const maxNrOfDigits = Math.max(this.digits.length, other.digits.length); let carry = 0; for (let i = 0; i < maxNrOfDigits; i++) { let digitSum = carry; if (i < this.digits.length) { digitSum += this.digits[i]; } if (i < other.digits.length) { digitSum += other.digits[i]; } if (digitSum >= 10) { this.digits[i] = digitSum - 10; carry = 1; } else { this.digits[i] = digitSum; carry = 0; } } // Apply a remaining carry if needed. if (carry > 0) { this.digits[maxNrOfDigits] = 1; } } /** * Builds the decimal string representation of the big integer. As this is stored in * little endian, the digits are concatenated in reverse order. */ toString() { let res = ''; for (let i = this.digits.length - 1; i >= 0; i--) { res += this.digits[i]; } return res; } } /** * Represents a big integer which is optimized for multiplication operations, as its power-of-twos * are memoized. See `multiplyBy()` for details on the multiplication algorithm. */ class BigIntForMultiplication { constructor(value) { this.powerOfTwos = [value]; } /** * Returns the big integer itself. */ getValue() { return this.powerOfTwos[0]; } /** * Computes the value for `num * b`, where `num` is a JS number and `b` is a big integer. The * value for `b` is represented by a storage model that is optimized for this computation. * * This operation is implemented in N(log2(num)) by continuous halving of the number, where the * least-significant bit (LSB) is tested in each iteration. If the bit is set, the bit's index is * used as exponent into the power-of-two multiplication of `b`. * * As an example, consider the multiplication num=42, b=1337. In binary 42 is 0b00101010 and the * algorithm unrolls into the following iterations: * * Iteration | num | LSB | b * 2^iter | Add? | product * -----------|------------|------|------------|------|-------- * 0 | 0b00101010 | 0 | 1337 | No | 0 * 1 | 0b00010101 | 1 | 2674 | Yes | 2674 * 2 | 0b00001010 | 0 | 5348 | No | 2674 * 3 | 0b00000101 | 1 | 10696 | Yes | 13370 * 4 | 0b00000010 | 0 | 21392 | No | 13370 * 5 | 0b00000001 | 1 | 42784 | Yes | 56154 * 6 | 0b00000000 | 0 | 85568 | No | 56154 * * The computed product of 56154 is indeed the correct result. * * The `BigIntForMultiplication` representation for a big integer provides memoized access to the * power-of-two values to reduce the workload in computing those values. */ multiplyBy(num) { const product = BigInteger.zero(); this.multiplyByAndAddTo(num, product); return product; } /** * See `multiplyBy()` for details. This function allows for the computed product to be added * directly to the provided result big integer. */ multiplyByAndAddTo(num, result) { for (let exponent = 0; num !== 0; num = num >>> 1, exponent++) { if (num & 1) { const value = this.getMultipliedByPowerOfTwo(exponent); result.addToSelf(value); } } } /** * Computes and memoizes the big integer value for `this.number * 2^exponent`. */ getMultipliedByPowerOfTwo(exponent) { // Compute the powers up until the requested exponent, where each value is computed from its // predecessor. This is simple as `this.number * 2^(exponent - 1)` only has to be doubled (i.e. // added to itself) to reach `this.number * 2^exponent`. for (let i = this.powerOfTwos.length; i <= exponent; i++) { const previousPower = this.powerOfTwos[i - 1]; this.powerOfTwos[i] = previousPower.add(previousPower); } return this.powerOfTwos[exponent]; } } /** * Represents an exponentiation operation for the provided base, of which exponents are computed and * memoized. The results are represented by a `BigIntForMultiplication` which is tailored for * multiplication operations by memoizing the power-of-twos. This effectively results in a matrix * representation that is lazily computed upon request. */ class BigIntExponentiation { constructor(base) { this.base = base; this.exponents = [new BigIntForMultiplication(BigInteger.one())]; } /** * Compute the value for `this.base^exponent`, resulting in a big integer that is optimized for * further multiplication operations. */ toThePowerOf(exponent) { // Compute the results up until the requested exponent, where every value is computed from its // predecessor. This is because `this.base^(exponent - 1)` only has to be multiplied by `base` // to reach `this.base^exponent`. for (let i = this.exponents.length; i <= exponent; i++) { const value = this.exponents[i - 1].multiplyBy(this.base); this.exponents[i] = new BigIntForMultiplication(value); } return this.exponents[exponent]; } } /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ /** * Return the message id or compute it using the XLIFF1 digest. */ function digest(message) { return message.id || computeDigest(message); } /** * Compute the message id using the XLIFF1 digest. */ function computeDigest(message) { return sha1(serializeNodes(message.nodes).join('') + `[${message.meaning}]`); } /** * Return the message id or compute it using the XLIFF2/XMB/$localize digest. */ function decimalDigest(message) { return message.id || computeDecimalDigest(message); } /** * Compute the message id using the XLIFF2/XMB/$localize digest. */ function computeDecimalDigest(message) { const visitor = new _SerializerIgnoreIcuExpVisitor(); const parts = message.nodes.map(a => a.visit(visitor, null)); return computeMsgId(parts.join(''), message.meaning); } /** * Serialize the i18n ast to something xml-like in order to generate an UID. * * The visitor is also used in the i18n parser tests * * @internal */ class _SerializerVisitor { visitText(text, context) { return text.value; } visitContainer(container, context) { return `[${container.children.map(child => child.visit(this)).join(', ')}]`; } visitIcu(icu, context) { const strCases = Object.keys(icu.cases).map((k) => `${k} {${icu.cases[k].visit(this)}}`); return `{${icu.expression}, ${icu.type}, ${strCases.join(', ')}}`; } visitTagPlaceholder(ph, context) { return ph.isVoid ? `` : `${ph.children.map(child => child.visit(this)).join(', ')}`; } visitPlaceholder(ph, context) { return ph.value ? `${ph.value}` : ``; } visitIcuPlaceholder(ph, context) { return `${ph.value.visit(this)}`; } } const serializerVisitor = new _SerializerVisitor(); function serializeNodes(nodes) { return nodes.map(a => a.visit(serializerVisitor, null)); } /** * Serialize the i18n ast to something xml-like in order to generate an UID. * * Ignore the ICU expressions so that message IDs stays identical if only the expression changes. * * @internal */ class _SerializerIgnoreIcuExpVisitor extends _SerializerVisitor { visitIcu(icu, context) { let strCases = Object.keys(icu.cases).map((k) => `${k} {${icu.cases[k].visit(this)}}`); // Do not take the expression into account return `{${icu.type}, ${strCases.join(', ')}}`; } } /** * Compute the SHA1 of the given string * * see https://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf * * WARNING: this function has not been designed not tested with security in mind. * DO NOT USE IT IN A SECURITY SENSITIVE CONTEXT. */ function sha1(str) { const utf8 = utf8Encode(str); const words32 = bytesToWords32(utf8, Endian.Big); const len = utf8.length * 8; const w = newArray(80); let a = 0x67452301, b = 0xefcdab89, c = 0x98badcfe, d = 0x10325476, e = 0xc3d2e1f0; words32[len >> 5] |= 0x80 << (24 - len % 32); words32[((len + 64 >> 9) << 4) + 15] = len; for (let i = 0; i < words32.length; i += 16) { const h0 = a, h1 = b, h2 = c, h3 = d, h4 = e; for (let j = 0; j < 80; j++) { if (j < 16) { w[j] = words32[i + j]; } else { w[j] = rol32(w[j - 3] ^ w[j - 8] ^ w[j - 14] ^ w[j - 16], 1); } const fkVal = fk(j, b, c, d); const f = fkVal[0]; const k = fkVal[1]; const temp = [rol32(a, 5), f, e, k, w[j]].reduce(add32); e = d; d = c; c = rol32(b, 30); b = a; a = temp; } a = add32(a, h0); b = add32(b, h1); c = add32(c, h2); d = add32(d, h3); e = add32(e, h4); } return bytesToHexString(words32ToByteString([a, b, c, d, e])); } function fk(index, b, c, d) { if (index < 20) { return [(b & c) | (~b & d), 0x5a827999]; } if (index < 40) { return [b ^ c ^ d, 0x6ed9eba1]; } if (index < 60) { return [(b & c) | (b & d) | (c & d), 0x8f1bbcdc]; } return [b ^ c ^ d, 0xca62c1d6]; } /** * Compute the fingerprint of the given string * * The output is 64 bit number encoded as a decimal string * * based on: * https://github.com/google/closure-compiler/blob/master/src/com/google/javascript/jscomp/GoogleJsMessageIdGenerator.java */ function fingerprint(str) { const utf8 = utf8Encode(str); let hi = hash32(utf8, 0); let lo = hash32(utf8, 102072); if (hi == 0 && (lo == 0 || lo == 1)) { hi = hi ^ 0x130f9bef; lo = lo ^ -0x6b5f56d8; } return [hi, lo]; } function computeMsgId(msg, meaning = '') { let msgFingerprint = fingerprint(msg); if (meaning) { const meaningFingerprint = fingerprint(meaning); msgFingerprint = add64(rol64(msgFingerprint, 1), meaningFingerprint); } const hi = msgFingerprint[0]; const lo = msgFingerprint[1]; return wordsToDecimalString(hi & 0x7fffffff, lo); } function hash32(bytes, c) { let a = 0x9e3779b9, b = 0x9e3779b9; let i; const len = bytes.length; for (i = 0; i + 12 <= len; i += 12) { a = add32(a, wordAt(bytes, i, Endian.Little)); b = add32(b, wordAt(bytes, i + 4, Endian.Little)); c = add32(c, wordAt(bytes, i + 8, Endian.Little)); const res = mix(a, b, c); a = res[0], b = res[1], c = res[2]; } a = add32(a, wordAt(bytes, i, Endian.Little)); b = add32(b, wordAt(bytes, i + 4, Endian.Little)); // the first byte of c is reserved for the length c = add32(c, len); c = add32(c, wordAt(bytes, i + 8, Endian.Little) << 8); return mix(a, b, c)[2]; } // clang-format off function mix(a, b, c) { a = sub32(a, b); a = sub32(a, c); a ^= c >>> 13; b = sub32(b, c); b = sub32(b, a); b ^= a << 8; c = sub32(c, a); c = sub32(c, b); c ^= b >>> 13; a = sub32(a, b); a = sub32(a, c); a ^= c >>> 12; b = sub32(b, c); b = sub32(b, a); b ^= a << 16; c = sub32(c, a); c = sub32(c, b); c ^= b >>> 5; a = sub32(a, b); a = sub32(a, c); a ^= c >>> 3; b = sub32(b, c); b = sub32(b, a); b ^= a << 10; c = sub32(c, a); c = sub32(c, b); c ^= b >>> 15; return [a, b, c]; } // clang-format on // Utils var Endian; (function (Endian) { Endian[Endian["Little"] = 0] = "Little"; Endian[Endian["Big"] = 1] = "Big"; })(Endian || (Endian = {})); function add32(a, b) { return add32to64(a, b)[1]; } function add32to64(a, b) { const low = (a & 0xffff) + (b & 0xffff); const high = (a >>> 16) + (b >>> 16) + (low >>> 16); return [high >>> 16, (high << 16) | (low & 0xffff)]; } function add64(a, b) { const ah = a[0], al = a[1]; const bh = b[0], bl = b[1]; const result = add32to64(al, bl); const carry = result[0]; const l = result[1]; const h = add32(add32(ah, bh), carry); return [h, l]; } function sub32(a, b) { const low = (a & 0xffff) - (b & 0xffff); const high = (a >> 16) - (b >> 16) + (low >> 16); return (high << 16) | (low & 0xffff); } // Rotate a 32b number left `count` position function rol32(a, count) { return (a << count) | (a >>> (32 - count)); } // Rotate a 64b number left `count` position function rol64(num, count) { const hi = num[0], lo = num[1]; const h = (hi << count) | (lo >>> (32 - count)); const l = (lo << count) | (hi >>> (32 - count)); return [h, l]; } function bytesToWords32(bytes, endian) { const size = (bytes.length + 3) >>> 2; const words32 = []; for (let i = 0; i < size; i++) { words32[i] = wordAt(bytes, i * 4, endian); } return words32; } function byteAt(bytes, index) { return index >= bytes.length ? 0 : bytes[index]; } function wordAt(bytes, index, endian) { let word = 0; if (endian === Endian.Big) { for (let i = 0; i < 4; i++) { word += byteAt(bytes, index + i) << (24 - 8 * i); } } else { for (let i = 0; i < 4; i++) { word += byteAt(bytes, index + i) << 8 * i; } } return word; } function words32ToByteString(words32) { return words32.reduce((bytes, word) => bytes.concat(word32ToByteString(word)), []); } function word32ToByteString(word) { let bytes = []; for (let i = 0; i < 4; i++) { bytes.push((word >>> 8 * (3 - i)) & 0xff); } return bytes; } function bytesToHexString(bytes) { let hex = ''; for (let i = 0; i < bytes.length; i++) { const b = byteAt(bytes, i); hex += (b >>> 4).toString(16) + (b & 0x0f).toString(16); } return hex.toLowerCase(); } /** * Create a shared exponentiation pool for base-256 computations. This shared pool provides memoized * power-of-256 results with memoized power-of-two computations for efficient multiplication. * * For our purposes, this can be safely stored as a global without memory concerns. The reason is * that we encode two words, so only need the 0th (for the low word) and 4th (for the high word) * exponent. */ const base256 = new BigIntExponentiation(256); /** * Represents two 32-bit words as a single decimal number. This requires a big integer storage * model as JS numbers are not accurate enough to represent the 64-bit number. * * Based on https://www.danvk.org/hex2dec.html */ function wordsToDecimalString(hi, lo) { // Encode the four bytes in lo in the lower digits of the decimal number. // Note: the multiplication results in lo itself but represented by a big integer using its // decimal digits. const decimal = base256.toThePowerOf(0).multiplyBy(lo); // Encode the four bytes in hi above the four lo bytes. lo is a maximum of (2^8)^4, which is why // this multiplication factor is applied. base256.toThePowerOf(4).multiplyByAndAddTo(hi, decimal); return decimal.toString(); } /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ class Serializer { // Creates a name mapper, see `PlaceholderMapper` // Returning `null` means that no name mapping is used. createNameMapper(message) { return null; } } /** * A simple mapper that take a function to transform an internal name to a public name */ class SimplePlaceholderMapper extends RecurseVisitor { // create a mapping from the message constructor(message, mapName) { super(); this.mapName = mapName; this.internalToPublic = {}; this.publicToNextId = {}; this.publicToInternal = {}; message.nodes.forEach(node => node.visit(this)); } toPublicName(internalName) { return this.internalToPublic.hasOwnProperty(internalName) ? this.internalToPublic[internalName] : null; } toInternalName(publicName) { return this.publicToInternal.hasOwnProperty(publicName) ? this.publicToInternal[publicName] : null; } visitText(text, context) { return null; } visitTagPlaceholder(ph, context) { this.visitPlaceholderName(ph.startName); super.visitTagPlaceholder(ph, context); this.visitPlaceholderName(ph.closeName); } visitPlaceholder(ph, context) { this.visitPlaceholderName(ph.name); } visitIcuPlaceholder(ph, context) { this.visitPlaceholderName(ph.name); } // XMB placeholders could only contains A-Z, 0-9 and _ visitPlaceholderName(internalName) { if (!internalName || this.internalToPublic.hasOwnProperty(internalName)) { return; } let publicName = this.mapName(internalName); if (this.publicToInternal.hasOwnProperty(publicName)) { // Create a new XMB when it has already been used const nextId = this.publicToNextId[publicName]; this.publicToNextId[publicName] = nextId + 1; publicName = `${publicName}_${nextId}`; } else { this.publicToNextId[publicName] = 1; } this.internalToPublic[internalName] = publicName; this.publicToInternal[publicName] = internalName; } } /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ class _Visitor { visitTag(tag) { const strAttrs = this._serializeAttributes(tag.attrs); if (tag.children.length == 0) { return `<${tag.name}${strAttrs}/>`; } const strChildren = tag.children.map(node => node.visit(this)); return `<${tag.name}${strAttrs}>${strChildren.join('')}`; } visitText(text) { return text.value; } visitDeclaration(decl) { return ``; } _serializeAttributes(attrs) { const strAttrs = Object.keys(attrs).map((name) => `${name}="${attrs[name]}"`).join(' '); return strAttrs.length > 0 ? ' ' + strAttrs : ''; } visitDoctype(doctype) { return ``; } } const _visitor = new _Visitor(); function serialize(nodes) { return nodes.map((node) => node.visit(_visitor)).join(''); } class Declaration { constructor(unescapedAttrs) { this.attrs = {}; Object.keys(unescapedAttrs).forEach((k) => { this.attrs[k] = escapeXml(unescapedAttrs[k]); }); } visit(visitor) { return visitor.visitDeclaration(this); } } class Doctype { constructor(rootTag, dtd) { this.rootTag = rootTag; this.dtd = dtd; } visit(visitor) { return visitor.visitDoctype(this); } } class Tag { constructor(name, unescapedAttrs = {}, children = []) { this.name = name; this.children = children; this.attrs = {}; Object.keys(unescapedAttrs).forEach((k) => { this.attrs[k] = escapeXml(unescapedAttrs[k]); }); } visit(visitor) { return visitor.visitTag(this); } } class Text$2 { constructor(unescapedValue) { this.value = escapeXml(unescapedValue); } visit(visitor) { return visitor.visitText(this); } } class CR extends Text$2 { constructor(ws = 0) { super(`\n${new Array(ws + 1).join(' ')}`); } } const _ESCAPED_CHARS = [ [/&/g, '&'], [/"/g, '"'], [/'/g, '''], [//g, '>'], ]; // Escape `_ESCAPED_CHARS` characters in the given text with encoded entities function escapeXml(text) { return _ESCAPED_CHARS.reduce((text, entry) => text.replace(entry[0], entry[1]), text); } /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ const _MESSAGES_TAG = 'messagebundle'; const _MESSAGE_TAG = 'msg'; const _PLACEHOLDER_TAG = 'ph'; const _EXAMPLE_TAG = 'ex'; const _SOURCE_TAG = 'source'; const _DOCTYPE = ` `; class Xmb extends Serializer { write(messages, locale) { const exampleVisitor = new ExampleVisitor(); const visitor = new _Visitor$1(); let rootNode = new Tag(_MESSAGES_TAG); messages.forEach(message => { const attrs = { id: message.id }; if (message.description) { attrs['desc'] = message.description; } if (message.meaning) { attrs['meaning'] = message.meaning; } let sourceTags = []; message.sources.forEach((source) => { sourceTags.push(new Tag(_SOURCE_TAG, {}, [new Text$2(`${source.filePath}:${source.startLine}${source.endLine !== source.startLine ? ',' + source.endLine : ''}`)])); }); rootNode.children.push(new CR(2), new Tag(_MESSAGE_TAG, attrs, [...sourceTags, ...visitor.serialize(message.nodes)])); }); rootNode.children.push(new CR()); return serialize([ new Declaration({ version: '1.0', encoding: 'UTF-8' }), new CR(), new Doctype(_MESSAGES_TAG, _DOCTYPE), new CR(), exampleVisitor.addDefaultExamples(rootNode), new CR(), ]); } load(content, url) { throw new Error('Unsupported'); } digest(message) { return digest$1(message); } createNameMapper(message) { return new SimplePlaceholderMapper(message, toPublicName); } } class _Visitor$1 { visitText(text, context) { return [new Text$2(text.value)]; } visitContainer(container, context) { const nodes = []; container.children.forEach((node) => nodes.push(...node.visit(this))); return nodes; } visitIcu(icu, context) { const nodes = [new Text$2(`{${icu.expressionPlaceholder}, ${icu.type}, `)]; Object.keys(icu.cases).forEach((c) => { nodes.push(new Text$2(`${c} {`), ...icu.cases[c].visit(this), new Text$2(`} `)); }); nodes.push(new Text$2(`}`)); return nodes; } visitTagPlaceholder(ph, context) { const startTagAsText = new Text$2(`<${ph.tag}>`); const startEx = new Tag(_EXAMPLE_TAG, {}, [startTagAsText]); // TC requires PH to have a non empty EX, and uses the text node to show the "original" value. const startTagPh = new Tag(_PLACEHOLDER_TAG, { name: ph.startName }, [startEx, startTagAsText]); if (ph.isVoid) { // void tags have no children nor closing tags return [startTagPh]; } const closeTagAsText = new Text$2(``); const closeEx = new Tag(_EXAMPLE_TAG, {}, [closeTagAsText]); // TC requires PH to have a non empty EX, and uses the text node to show the "original" value. const closeTagPh = new Tag(_PLACEHOLDER_TAG, { name: ph.closeName }, [closeEx, closeTagAsText]); return [startTagPh, ...this.serialize(ph.children), closeTagPh]; } visitPlaceholder(ph, context) { const interpolationAsText = new Text$2(`{{${ph.value}}}`); // Example tag needs to be not-empty for TC. const exTag = new Tag(_EXAMPLE_TAG, {}, [interpolationAsText]); return [ // TC requires PH to have a non empty EX, and uses the text node to show the "original" value. new Tag(_PLACEHOLDER_TAG, { name: ph.name }, [exTag, interpolationAsText]) ]; } visitIcuPlaceholder(ph, context) { const icuExpression = ph.value.expression; const icuType = ph.value.type; const icuCases = Object.keys(ph.value.cases).map((value) => value + ' {...}').join(' '); const icuAsText = new Text$2(`{${icuExpression}, ${icuType}, ${icuCases}}`); const exTag = new Tag(_EXAMPLE_TAG, {}, [icuAsText]); return [ // TC requires PH to have a non empty EX, and uses the text node to show the "original" value. new Tag(_PLACEHOLDER_TAG, { name: ph.name }, [exTag, icuAsText]) ]; } serialize(nodes) { return [].concat(...nodes.map(node => node.visit(this))); } } function digest$1(message) { return decimalDigest(message); } // TC requires at least one non-empty example on placeholders class ExampleVisitor { addDefaultExamples(node) { node.visit(this); return node; } visitTag(tag) { if (tag.name === _PLACEHOLDER_TAG) { if (!tag.children || tag.children.length == 0) { const exText = new Text$2(tag.attrs['name'] || '...'); tag.children = [new Tag(_EXAMPLE_TAG, {}, [exText])]; } } else if (tag.children) { tag.children.forEach(node => node.visit(this)); } } visitText(text) { } visitDeclaration(decl) { } visitDoctype(doctype) { } } // XMB/XTB placeholders can only contain A-Z, 0-9 and _ function toPublicName(internalName) { return internalName.toUpperCase().replace(/[^A-Z0-9_]/g, '_'); } /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ /* Closure variables holding messages must be named `MSG_[A-Z0-9]+` */ const CLOSURE_TRANSLATION_VAR_PREFIX = 'MSG_'; /** * Prefix for non-`goog.getMsg` i18n-related vars. * Note: the prefix uses lowercase characters intentionally due to a Closure behavior that * considers variables like `I18N_0` as constants and throws an error when their value changes. */ const TRANSLATION_VAR_PREFIX = 'i18n_'; /** Name of the i18n attributes **/ const I18N_ATTR = 'i18n'; const I18N_ATTR_PREFIX = 'i18n-'; /** Prefix of var expressions used in ICUs */ const I18N_ICU_VAR_PREFIX = 'VAR_'; /** Prefix of ICU expressions for post processing */ const I18N_ICU_MAPPING_PREFIX = 'I18N_EXP_'; /** Placeholder wrapper for i18n expressions **/ const I18N_PLACEHOLDER_SYMBOL = '�'; function isI18nAttribute(name) { return name === I18N_ATTR || name.startsWith(I18N_ATTR_PREFIX); } function isI18nRootNode(meta) { return meta instanceof Message; } function isSingleI18nIcu(meta) { return isI18nRootNode(meta) && meta.nodes.length === 1 && meta.nodes[0] instanceof Icu$1; } function hasI18nMeta(node) { return !!node.i18n; } function hasI18nAttrs(element) { return element.attrs.some((attr) => isI18nAttribute(attr.name)); } function icuFromI18nMessage(message) { return message.nodes[0]; } function wrapI18nPlaceholder(content, contextId = 0) { const blockId = contextId > 0 ? `:${contextId}` : ''; return `${I18N_PLACEHOLDER_SYMBOL}${content}${blockId}${I18N_PLACEHOLDER_SYMBOL}`; } function assembleI18nBoundString(strings, bindingStartIndex = 0, contextId = 0) { if (!strings.length) return ''; let acc = ''; const lastIdx = strings.length - 1; for (let i = 0; i < lastIdx; i++) { acc += `${strings[i]}${wrapI18nPlaceholder(bindingStartIndex + i, contextId)}`; } acc += strings[lastIdx]; return acc; } function getSeqNumberGenerator(startsAt = 0) { let current = startsAt; return () => current++; } function placeholdersToParams(placeholders) { const params = {}; placeholders.forEach((values, key) => { params[key] = literal(values.length > 1 ? `[${values.join('|')}]` : values[0]); }); return params; } function updatePlaceholderMap(map, name, ...values) { const current = map.get(name) || []; current.push(...values); map.set(name, current); } function assembleBoundTextPlaceholders(meta, bindingStartIndex = 0, contextId = 0) { const startIdx = bindingStartIndex; const placeholders = new Map(); const node = meta instanceof Message ? meta.nodes.find(node => node instanceof Container) : meta; if (node) { node .children .filter((child) => child instanceof Placeholder) .forEach((child, idx) => { const content = wrapI18nPlaceholder(startIdx + idx, contextId); updatePlaceholderMap(placeholders, child.name, content); }); } return placeholders; } /** * Format the placeholder names in a map of placeholders to expressions. * * The placeholder names are converted from "internal" format (e.g. `START_TAG_DIV_1`) to "external" * format (e.g. `startTagDiv_1`). * * @param params A map of placeholder names to expressions. * @param useCamelCase whether to camelCase the placeholder name when formatting. * @returns A new map of formatted placeholder names to expressions. */ function i18nFormatPlaceholderNames(params = {}, useCamelCase) { const _params = {}; if (params && Object.keys(params).length) { Object.keys(params).forEach(key => _params[formatI18nPlaceholderName(key, useCamelCase)] = params[key]); } return _params; } /** * Converts internal placeholder names to public-facing format * (for example to use in goog.getMsg call). * Example: `START_TAG_DIV_1` is converted to `startTagDiv_1`. * * @param name The placeholder name that should be formatted * @returns Formatted placeholder name */ function formatI18nPlaceholderName(name, useCamelCase = true) { const publicName = toPublicName(name); if (!useCamelCase) { return publicName; } const chunks = publicName.split('_'); if (chunks.length === 1) { // if no "_" found - just lowercase the value return name.toLowerCase(); } let postfix; // eject last element if it's a number if (/^\d+$/.test(chunks[chunks.length - 1])) { postfix = chunks.pop(); } let raw = chunks.shift().toLowerCase(); if (chunks.length) { raw += chunks.map(c => c.charAt(0).toUpperCase() + c.slice(1).toLowerCase()).join(''); } return postfix ? `${raw}_${postfix}` : raw; } /** * Generates a prefix for translation const name. * * @param extra Additional local prefix that should be injected into translation var name * @returns Complete translation const prefix */ function getTranslationConstPrefix(extra) { return `${CLOSURE_TRANSLATION_VAR_PREFIX}${extra}`.toUpperCase(); } /** * Generate AST to declare a variable. E.g. `var I18N_1;`. * @param variable the name of the variable to declare. */ function declareI18nVariable(variable) { return new DeclareVarStmt(variable.name, undefined, INFERRED_TYPE, undefined, variable.sourceSpan); } /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ /** * Checks whether an object key contains potentially unsafe chars, thus the key should be wrapped in * quotes. Note: we do not wrap all keys into quotes, as it may have impact on minification and may * bot work in some cases when object keys are mangled by minifier. * * TODO(FW-1136): this is a temporary solution, we need to come up with a better way of working with * inputs that contain potentially unsafe chars. */ const UNSAFE_OBJECT_KEY_NAME_REGEXP = /[-.]/; /** Name of the temporary to use during data binding */ const TEMPORARY_NAME = '_t'; /** Name of the context parameter passed into a template function */ const CONTEXT_NAME = 'ctx'; /** Name of the RenderFlag passed into a template function */ const RENDER_FLAGS = 'rf'; /** The prefix reference variables */ const REFERENCE_PREFIX = '_r'; /** The name of the implicit context reference */ const IMPLICIT_REFERENCE = '$implicit'; /** Non bindable attribute name **/ const NON_BINDABLE_ATTR = 'ngNonBindable'; /** Name for the variable keeping track of the context returned by `ɵɵrestoreView`. */ const RESTORED_VIEW_CONTEXT_NAME = 'restoredCtx'; /** * Creates an allocator for a temporary variable. * * A variable declaration is added to the statements the first time the allocator is invoked. */ function temporaryAllocator(statements, name) { let temp = null; return () => { if (!temp) { statements.push(new DeclareVarStmt(TEMPORARY_NAME, undefined, DYNAMIC_TYPE)); temp = variable(name); } return temp; }; } function unsupported(feature) { if (this) { throw new Error(`Builder ${this.constructor.name} doesn't support ${feature} yet`); } throw new Error(`Feature ${feature} is not supported yet`); } function invalid$1(arg) { throw new Error(`Invalid state: Visitor ${this.constructor.name} doesn't handle ${arg.constructor.name}`); } function asLiteral(value) { if (Array.isArray(value)) { return literalArr(value.map(asLiteral)); } return literal(value, INFERRED_TYPE); } function conditionallyCreateMapObjectLiteral(keys, keepDeclared) { if (Object.getOwnPropertyNames(keys).length > 0) { return mapToExpression(keys, keepDeclared); } return null; } function mapToExpression(map, keepDeclared) { return literalMap(Object.getOwnPropertyNames(map).map(key => { // canonical syntax: `dirProp: publicProp` // if there is no `:`, use dirProp = elProp const value = map[key]; let declaredName; let publicName; let minifiedName; let needsDeclaredName; if (Array.isArray(value)) { [publicName, declaredName] = value; minifiedName = key; needsDeclaredName = publicName !== declaredName; } else { [declaredName, publicName] = splitAtColon(key, [key, value]); minifiedName = declaredName; // Only include the declared name if extracted from the key, i.e. the key contains a colon. // Otherwise the declared name should be omitted even if it is different from the public name, // as it may have already been minified. needsDeclaredName = publicName !== declaredName && key.includes(':'); } return { key: minifiedName, // put quotes around keys that contain potentially unsafe characters quoted: UNSAFE_OBJECT_KEY_NAME_REGEXP.test(minifiedName), value: (keepDeclared && needsDeclaredName) ? literalArr([asLiteral(publicName), asLiteral(declaredName)]) : asLiteral(publicName) }; })); } /** * Remove trailing null nodes as they are implied. */ function trimTrailingNulls(parameters) { while (isNull(parameters[parameters.length - 1])) { parameters.pop(); } return parameters; } function getQueryPredicate(query, constantPool) { if (Array.isArray(query.predicate)) { let predicate = []; query.predicate.forEach((selector) => { // Each item in predicates array may contain strings with comma-separated refs // (for ex. 'ref, ref1, ..., refN'), thus we extract individual refs and store them // as separate array entities const selectors = selector.split(',').map(token => literal(token.trim())); predicate.push(...selectors); }); return constantPool.getConstLiteral(literalArr(predicate), true); } else { // The original predicate may have been wrapped in a `forwardRef()` call. switch (query.predicate.forwardRef) { case 0 /* None */: case 2 /* Unwrapped */: return query.predicate.expression; case 1 /* Wrapped */: return importExpr(Identifiers.resolveForwardRef).callFn([query.predicate.expression]); } } } /** * A representation for an object literal used during codegen of definition objects. The generic * type `T` allows to reference a documented type of the generated structure, such that the * property names that are set can be resolved to their documented declaration. */ class DefinitionMap { constructor() { this.values = []; } set(key, value) { if (value) { this.values.push({ key: key, value, quoted: false }); } } toLiteralMap() { return literalMap(this.values); } } /** * Extract a map of properties to values for a given element or template node, which can be used * by the directive matching machinery. * * @param elOrTpl the element or template in question * @return an object set up for directive matching. For attributes on the element/template, this * object maps a property name to its (static) value. For any bindings, this map simply maps the * property name to an empty string. */ function getAttrsForDirectiveMatching(elOrTpl) { const attributesMap = {}; if (elOrTpl instanceof Template && elOrTpl.tagName !== 'ng-template') { elOrTpl.templateAttrs.forEach(a => attributesMap[a.name] = ''); } else { elOrTpl.attributes.forEach(a => { if (!isI18nAttribute(a.name)) { attributesMap[a.name] = a.value; } }); elOrTpl.inputs.forEach(i => { attributesMap[i.name] = ''; }); elOrTpl.outputs.forEach(o => { attributesMap[o.name] = ''; }); } return attributesMap; } /** Returns a call expression to a chained instruction, e.g. `property(params[0])(params[1])`. */ function chainedInstruction(reference, calls, span) { let expression = importExpr(reference, null, span); if (calls.length > 0) { for (let i = 0; i < calls.length; i++) { expression = expression.callFn(calls[i], span); } } else { // Add a blank invocation, in case the `calls` array is empty. expression = expression.callFn([], span); } return expression; } /** * Gets the number of arguments expected to be passed to a generated instruction in the case of * interpolation instructions. * @param interpolation An interpolation ast */ function getInterpolationArgsLength(interpolation) { const { expressions, strings } = interpolation; if (expressions.length === 1 && strings.length === 2 && strings[0] === '' && strings[1] === '') { // If the interpolation has one interpolated value, but the prefix and suffix are both empty // strings, we only pass one argument, to a special instruction like `propertyInterpolate` or // `textInterpolate`. return 1; } else { return expressions.length + strings.length; } } /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ function compileInjectable(meta, resolveForwardRefs) { let result = null; const factoryMeta = { name: meta.name, type: meta.type, internalType: meta.internalType, typeArgumentCount: meta.typeArgumentCount, deps: [], target: FactoryTarget.Injectable, }; if (meta.useClass !== undefined) { // meta.useClass has two modes of operation. Either deps are specified, in which case `new` is // used to instantiate the class with dependencies injected, or deps are not specified and // the factory of the class is used to instantiate it. // // A special case exists for useClass: Type where Type is the injectable type itself and no // deps are specified, in which case 'useClass' is effectively ignored. const useClassOnSelf = meta.useClass.expression.isEquivalent(meta.internalType); let deps = undefined; if (meta.deps !== undefined) { deps = meta.deps; } if (deps !== undefined) { // factory: () => new meta.useClass(...deps) result = compileFactoryFunction(Object.assign(Object.assign({}, factoryMeta), { delegate: meta.useClass.expression, delegateDeps: deps, delegateType: R3FactoryDelegateType.Class })); } else if (useClassOnSelf) { result = compileFactoryFunction(factoryMeta); } else { result = { statements: [], expression: delegateToFactory(meta.type.value, meta.useClass.expression, resolveForwardRefs) }; } } else if (meta.useFactory !== undefined) { if (meta.deps !== undefined) { result = compileFactoryFunction(Object.assign(Object.assign({}, factoryMeta), { delegate: meta.useFactory, delegateDeps: meta.deps || [], delegateType: R3FactoryDelegateType.Function })); } else { result = { statements: [], expression: fn([], [new ReturnStatement(meta.useFactory.callFn([]))]) }; } } else if (meta.useValue !== undefined) { // Note: it's safe to use `meta.useValue` instead of the `USE_VALUE in meta` check used for // client code because meta.useValue is an Expression which will be defined even if the actual // value is undefined. result = compileFactoryFunction(Object.assign(Object.assign({}, factoryMeta), { expression: meta.useValue.expression })); } else if (meta.useExisting !== undefined) { // useExisting is an `inject` call on the existing token. result = compileFactoryFunction(Object.assign(Object.assign({}, factoryMeta), { expression: importExpr(Identifiers.inject).callFn([meta.useExisting.expression]) })); } else { result = { statements: [], expression: delegateToFactory(meta.type.value, meta.internalType, resolveForwardRefs) }; } const token = meta.internalType; const injectableProps = new DefinitionMap(); injectableProps.set('token', token); injectableProps.set('factory', result.expression); // Only generate providedIn property if it has a non-null value if (meta.providedIn.expression.value !== null) { injectableProps.set('providedIn', convertFromMaybeForwardRefExpression(meta.providedIn)); } const expression = importExpr(Identifiers.ɵɵdefineInjectable) .callFn([injectableProps.toLiteralMap()], undefined, true); return { expression, type: createInjectableType(meta), statements: result.statements, }; } function createInjectableType(meta) { return new ExpressionType(importExpr(Identifiers.InjectableDeclaration, [typeWithParameters(meta.type.type, meta.typeArgumentCount)])); } function delegateToFactory(type, internalType, unwrapForwardRefs) { if (type.node === internalType.node) { // The types are the same, so we can simply delegate directly to the type's factory. // ``` // factory: type.ɵfac // ``` return internalType.prop('ɵfac'); } if (!unwrapForwardRefs) { // The type is not wrapped in a `forwardRef()`, so we create a simple factory function that // accepts a sub-type as an argument. // ``` // factory: function(t) { return internalType.ɵfac(t); } // ``` return createFactoryFunction(internalType); } // The internalType is actually wrapped in a `forwardRef()` so we need to resolve that before // calling its factory. // ``` // factory: function(t) { return core.resolveForwardRef(type).ɵfac(t); } // ``` const unwrappedType = importExpr(Identifiers.resolveForwardRef).callFn([internalType]); return createFactoryFunction(unwrappedType); } function createFactoryFunction(type) { return fn([new FnParam('t', DYNAMIC_TYPE)], [new ReturnStatement(type.callMethod('ɵfac', [variable('t')]))]); } /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ function assertArrayOfStrings(identifier, value) { if (value == null) { return; } if (!Array.isArray(value)) { throw new Error(`Expected '${identifier}' to be an array of strings.`); } for (let i = 0; i < value.length; i += 1) { if (typeof value[i] !== 'string') { throw new Error(`Expected '${identifier}' to be an array of strings.`); } } } const UNUSABLE_INTERPOLATION_REGEXPS = [ /^\s*$/, /[<>]/, /^[{}]$/, /&(#|[a-z])/i, /^\/\//, // comment ]; function assertInterpolationSymbols(identifier, value) { if (value != null && !(Array.isArray(value) && value.length == 2)) { throw new Error(`Expected '${identifier}' to be an array, [start, end].`); } else if (value != null) { const start = value[0]; const end = value[1]; // Check for unusable interpolation symbols UNUSABLE_INTERPOLATION_REGEXPS.forEach(regexp => { if (regexp.test(start) || regexp.test(end)) { throw new Error(`['${start}', '${end}'] contains unusable interpolation symbol.`); } }); } } /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ class InterpolationConfig { constructor(start, end) { this.start = start; this.end = end; } static fromArray(markers) { if (!markers) { return DEFAULT_INTERPOLATION_CONFIG; } assertInterpolationSymbols('interpolation', markers); return new InterpolationConfig(markers[0], markers[1]); } } const DEFAULT_INTERPOLATION_CONFIG = new InterpolationConfig('{{', '}}'); /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ /** * A token representing the a reference to a static type. * * This token is unique for a filePath and name and can be used as a hash table key. */ class StaticSymbol { constructor(filePath, name, members) { this.filePath = filePath; this.name = name; this.members = members; } assertNoMembers() { if (this.members.length) { throw new Error(`Illegal state: symbol without members expected, but got ${JSON.stringify(this)}.`); } } } /** * A cache of static symbol used by the StaticReflector to return the same symbol for the * same symbol values. */ class StaticSymbolCache { constructor() { this.cache = new Map(); } get(declarationFile, name, members) { members = members || []; const memberSuffix = members.length ? `.${members.join('.')}` : ''; const key = `"${declarationFile}".${name}${memberSuffix}`; let result = this.cache.get(key); if (!result) { result = new StaticSymbol(declarationFile, name, members); this.cache.set(key, result); } return result; } } /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ const $EOF = 0; const $BSPACE = 8; const $TAB = 9; const $LF = 10; const $VTAB = 11; const $FF = 12; const $CR = 13; const $SPACE = 32; const $BANG = 33; const $DQ = 34; const $HASH = 35; const $$ = 36; const $PERCENT = 37; const $AMPERSAND = 38; const $SQ = 39; const $LPAREN = 40; const $RPAREN = 41; const $STAR = 42; const $PLUS = 43; const $COMMA = 44; const $MINUS = 45; const $PERIOD = 46; const $SLASH = 47; const $COLON = 58; const $SEMICOLON = 59; const $LT = 60; const $EQ = 61; const $GT = 62; const $QUESTION = 63; const $0 = 48; const $7 = 55; const $9 = 57; const $A = 65; const $E = 69; const $F = 70; const $X = 88; const $Z = 90; const $LBRACKET = 91; const $BACKSLASH = 92; const $RBRACKET = 93; const $CARET = 94; const $_ = 95; const $a = 97; const $b = 98; const $e = 101; const $f = 102; const $n = 110; const $r = 114; const $t = 116; const $u = 117; const $v = 118; const $x = 120; const $z = 122; const $LBRACE = 123; const $BAR = 124; const $RBRACE = 125; const $NBSP = 160; const $PIPE = 124; const $TILDA = 126; const $AT = 64; const $BT = 96; function isWhitespace(code) { return (code >= $TAB && code <= $SPACE) || (code == $NBSP); } function isDigit(code) { return $0 <= code && code <= $9; } function isAsciiLetter(code) { return code >= $a && code <= $z || code >= $A && code <= $Z; } function isAsciiHexDigit(code) { return code >= $a && code <= $f || code >= $A && code <= $F || isDigit(code); } function isNewLine(code) { return code === $LF || code === $CR; } function isOctalDigit(code) { return $0 <= code && code <= $7; } function isQuote(code) { return code === $SQ || code === $DQ || code === $BT; } /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ class ParseLocation { constructor(file, offset, line, col) { this.file = file; this.offset = offset; this.line = line; this.col = col; } toString() { return this.offset != null ? `${this.file.url}@${this.line}:${this.col}` : this.file.url; } moveBy(delta) { const source = this.file.content; const len = source.length; let offset = this.offset; let line = this.line; let col = this.col; while (offset > 0 && delta < 0) { offset--; delta++; const ch = source.charCodeAt(offset); if (ch == $LF) { line--; const priorLine = source.substr(0, offset - 1).lastIndexOf(String.fromCharCode($LF)); col = priorLine > 0 ? offset - priorLine : offset; } else { col--; } } while (offset < len && delta > 0) { const ch = source.charCodeAt(offset); offset++; delta--; if (ch == $LF) { line++; col = 0; } else { col++; } } return new ParseLocation(this.file, offset, line, col); } // Return the source around the location // Up to `maxChars` or `maxLines` on each side of the location getContext(maxChars, maxLines) { const content = this.file.content; let startOffset = this.offset; if (startOffset != null) { if (startOffset > content.length - 1) { startOffset = content.length - 1; } let endOffset = startOffset; let ctxChars = 0; let ctxLines = 0; while (ctxChars < maxChars && startOffset > 0) { startOffset--; ctxChars++; if (content[startOffset] == '\n') { if (++ctxLines == maxLines) { break; } } } ctxChars = 0; ctxLines = 0; while (ctxChars < maxChars && endOffset < content.length - 1) { endOffset++; ctxChars++; if (content[endOffset] == '\n') { if (++ctxLines == maxLines) { break; } } } return { before: content.substring(startOffset, this.offset), after: content.substring(this.offset, endOffset + 1), }; } return null; } } class ParseSourceFile { constructor(content, url) { this.content = content; this.url = url; } } class ParseSourceSpan { /** * Create an object that holds information about spans of tokens/nodes captured during * lexing/parsing of text. * * @param start * The location of the start of the span (having skipped leading trivia). * Skipping leading trivia makes source-spans more "user friendly", since things like HTML * elements will appear to begin at the start of the opening tag, rather than at the start of any * leading trivia, which could include newlines. * * @param end * The location of the end of the span. * * @param fullStart * The start of the token without skipping the leading trivia. * This is used by tooling that splits tokens further, such as extracting Angular interpolations * from text tokens. Such tooling creates new source-spans relative to the original token's * source-span. If leading trivia characters have been skipped then the new source-spans may be * incorrectly offset. * * @param details * Additional information (such as identifier names) that should be associated with the span. */ constructor(start, end, fullStart = start, details = null) { this.start = start; this.end = end; this.fullStart = fullStart; this.details = details; } toString() { return this.start.file.content.substring(this.start.offset, this.end.offset); } } var ParseErrorLevel; (function (ParseErrorLevel) { ParseErrorLevel[ParseErrorLevel["WARNING"] = 0] = "WARNING"; ParseErrorLevel[ParseErrorLevel["ERROR"] = 1] = "ERROR"; })(ParseErrorLevel || (ParseErrorLevel = {})); class ParseError { constructor(span, msg, level = ParseErrorLevel.ERROR) { this.span = span; this.msg = msg; this.level = level; } contextualMessage() { const ctx = this.span.start.getContext(100, 3); return ctx ? `${this.msg} ("${ctx.before}[${ParseErrorLevel[this.level]} ->]${ctx.after}")` : this.msg; } toString() { const details = this.span.details ? `, ${this.span.details}` : ''; return `${this.contextualMessage()}: ${this.span.start}${details}`; } } function typeSourceSpan(kind, type) { const moduleUrl = identifierModuleUrl(type); const sourceFileName = moduleUrl != null ? `in ${kind} ${identifierName(type)} in ${moduleUrl}` : `in ${kind} ${identifierName(type)}`; const sourceFile = new ParseSourceFile('', sourceFileName); return new ParseSourceSpan(new ParseLocation(sourceFile, -1, -1, -1), new ParseLocation(sourceFile, -1, -1, -1)); } /** * Generates Source Span object for a given R3 Type for JIT mode. * * @param kind Component or Directive. * @param typeName name of the Component or Directive. * @param sourceUrl reference to Component or Directive source. * @returns instance of ParseSourceSpan that represent a given Component or Directive. */ function r3JitTypeSourceSpan(kind, typeName, sourceUrl) { const sourceFileName = `in ${kind} ${typeName} in ${sourceUrl}`; const sourceFile = new ParseSourceFile('', sourceFileName); return new ParseSourceSpan(new ParseLocation(sourceFile, -1, -1, -1), new ParseLocation(sourceFile, -1, -1, -1)); } function syntaxError(msg, parseErrors) { const error = Error(msg); error[ERROR_SYNTAX_ERROR] = true; if (parseErrors) error[ERROR_PARSE_ERRORS] = parseErrors; return error; } const ERROR_SYNTAX_ERROR = 'ngSyntaxError'; const ERROR_PARSE_ERRORS = 'ngParseErrors'; function isSyntaxError(error) { return error[ERROR_SYNTAX_ERROR]; } function getParseErrors(error) { return error[ERROR_PARSE_ERRORS] || []; } let _anonymousTypeIndex = 0; function identifierName(compileIdentifier) { if (!compileIdentifier || !compileIdentifier.reference) { return null; } const ref = compileIdentifier.reference; if (ref instanceof StaticSymbol) { return ref.name; } if (ref['__anonymousType']) { return ref['__anonymousType']; } if (ref['__forward_ref__']) { // We do not want to try to stringify a `forwardRef()` function because that would cause the // inner function to be evaluated too early, defeating the whole point of the `forwardRef`. return '__forward_ref__'; } let identifier = stringify(ref); if (identifier.indexOf('(') >= 0) { // case: anonymous functions! identifier = `anonymous_${_anonymousTypeIndex++}`; ref['__anonymousType'] = identifier; } else { identifier = sanitizeIdentifier(identifier); } return identifier; } function identifierModuleUrl(compileIdentifier) { const ref = compileIdentifier.reference; if (ref instanceof StaticSymbol) { return ref.filePath; } // Runtime type return `./${stringify(ref)}`; } function sanitizeIdentifier(name) { return name.replace(/\W/g, '_'); } /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ /** * In TypeScript, tagged template functions expect a "template object", which is an array of * "cooked" strings plus a `raw` property that contains an array of "raw" strings. This is * typically constructed with a function called `__makeTemplateObject(cooked, raw)`, but it may not * be available in all environments. * * This is a JavaScript polyfill that uses __makeTemplateObject when it's available, but otherwise * creates an inline helper with the same functionality. * * In the inline function, if `Object.defineProperty` is available we use that to attach the `raw` * array. */ const makeTemplateObjectPolyfill = '(this&&this.__makeTemplateObject||function(e,t){return Object.defineProperty?Object.defineProperty(e,"raw",{value:t}):e.raw=t,e})'; class AbstractJsEmitterVisitor extends AbstractEmitterVisitor { constructor() { super(false); } visitDeclareClassStmt(stmt, ctx) { ctx.pushClass(stmt); this._visitClassConstructor(stmt, ctx); if (stmt.parent != null) { ctx.print(stmt, `${stmt.name}.prototype = Object.create(`); stmt.parent.visitExpression(this, ctx); ctx.println(stmt, `.prototype);`); } stmt.getters.forEach((getter) => this._visitClassGetter(stmt, getter, ctx)); stmt.methods.forEach((method) => this._visitClassMethod(stmt, method, ctx)); ctx.popClass(); return null; } _visitClassConstructor(stmt, ctx) { ctx.print(stmt, `function ${stmt.name}(`); if (stmt.constructorMethod != null) { this._visitParams(stmt.constructorMethod.params, ctx); } ctx.println(stmt, `) {`); ctx.incIndent(); if (stmt.constructorMethod != null) { if (stmt.constructorMethod.body.length > 0) { ctx.println(stmt, `var self = this;`); this.visitAllStatements(stmt.constructorMethod.body, ctx); } } ctx.decIndent(); ctx.println(stmt, `}`); } _visitClassGetter(stmt, getter, ctx) { ctx.println(stmt, `Object.defineProperty(${stmt.name}.prototype, '${getter.name}', { get: function() {`); ctx.incIndent(); if (getter.body.length > 0) { ctx.println(stmt, `var self = this;`); this.visitAllStatements(getter.body, ctx); } ctx.decIndent(); ctx.println(stmt, `}});`); } _visitClassMethod(stmt, method, ctx) { ctx.print(stmt, `${stmt.name}.prototype.${method.name} = function(`); this._visitParams(method.params, ctx); ctx.println(stmt, `) {`); ctx.incIndent(); if (method.body.length > 0) { ctx.println(stmt, `var self = this;`); this.visitAllStatements(method.body, ctx); } ctx.decIndent(); ctx.println(stmt, `};`); } visitWrappedNodeExpr(ast, ctx) { throw new Error('Cannot emit a WrappedNodeExpr in Javascript.'); } visitReadVarExpr(ast, ctx) { if (ast.builtin === BuiltinVar.This) { ctx.print(ast, 'self'); } else if (ast.builtin === BuiltinVar.Super) { throw new Error(`'super' needs to be handled at a parent ast node, not at the variable level!`); } else { super.visitReadVarExpr(ast, ctx); } return null; } visitDeclareVarStmt(stmt, ctx) { ctx.print(stmt, `var ${stmt.name}`); if (stmt.value) { ctx.print(stmt, ' = '); stmt.value.visitExpression(this, ctx); } ctx.println(stmt, `;`); return null; } visitCastExpr(ast, ctx) { ast.value.visitExpression(this, ctx); return null; } visitInvokeFunctionExpr(expr, ctx) { const fnExpr = expr.fn; if (fnExpr instanceof ReadVarExpr && fnExpr.builtin === BuiltinVar.Super) { ctx.currentClass.parent.visitExpression(this, ctx); ctx.print(expr, `.call(this`); if (expr.args.length > 0) { ctx.print(expr, `, `); this.visitAllExpressions(expr.args, ctx, ','); } ctx.print(expr, `)`); } else { super.visitInvokeFunctionExpr(expr, ctx); } return null; } visitTaggedTemplateExpr(ast, ctx) { // The following convoluted piece of code is effectively the downlevelled equivalent of // ``` // tag`...` // ``` // which is effectively like: // ``` // tag(__makeTemplateObject(cooked, raw), expression1, expression2, ...); // ``` const elements = ast.template.elements; ast.tag.visitExpression(this, ctx); ctx.print(ast, `(${makeTemplateObjectPolyfill}(`); ctx.print(ast, `[${elements.map(part => escapeIdentifier(part.text, false)).join(', ')}], `); ctx.print(ast, `[${elements.map(part => escapeIdentifier(part.rawText, false)).join(', ')}])`); ast.template.expressions.forEach(expression => { ctx.print(ast, ', '); expression.visitExpression(this, ctx); }); ctx.print(ast, ')'); return null; } visitFunctionExpr(ast, ctx) { ctx.print(ast, `function${ast.name ? ' ' + ast.name : ''}(`); this._visitParams(ast.params, ctx); ctx.println(ast, `) {`); ctx.incIndent(); this.visitAllStatements(ast.statements, ctx); ctx.decIndent(); ctx.print(ast, `}`); return null; } visitDeclareFunctionStmt(stmt, ctx) { ctx.print(stmt, `function ${stmt.name}(`); this._visitParams(stmt.params, ctx); ctx.println(stmt, `) {`); ctx.incIndent(); this.visitAllStatements(stmt.statements, ctx); ctx.decIndent(); ctx.println(stmt, `}`); return null; } visitTryCatchStmt(stmt, ctx) { ctx.println(stmt, `try {`); ctx.incIndent(); this.visitAllStatements(stmt.bodyStmts, ctx); ctx.decIndent(); ctx.println(stmt, `} catch (${CATCH_ERROR_VAR$1.name}) {`); ctx.incIndent(); const catchStmts = [CATCH_STACK_VAR$1.set(CATCH_ERROR_VAR$1.prop('stack')).toDeclStmt(null, [ StmtModifier.Final ])].concat(stmt.catchStmts); this.visitAllStatements(catchStmts, ctx); ctx.decIndent(); ctx.println(stmt, `}`); return null; } visitLocalizedString(ast, ctx) { // The following convoluted piece of code is effectively the downlevelled equivalent of // ``` // $localize `...` // ``` // which is effectively like: // ``` // $localize(__makeTemplateObject(cooked, raw), expression1, expression2, ...); // ``` ctx.print(ast, `$localize(${makeTemplateObjectPolyfill}(`); const parts = [ast.serializeI18nHead()]; for (let i = 1; i < ast.messageParts.length; i++) { parts.push(ast.serializeI18nTemplatePart(i)); } ctx.print(ast, `[${parts.map(part => escapeIdentifier(part.cooked, false)).join(', ')}], `); ctx.print(ast, `[${parts.map(part => escapeIdentifier(part.raw, false)).join(', ')}])`); ast.expressions.forEach(expression => { ctx.print(ast, ', '); expression.visitExpression(this, ctx); }); ctx.print(ast, ')'); return null; } _visitParams(params, ctx) { this.visitAllObjects(param => ctx.print(null, param.name), params, ctx, ','); } getBuiltinMethodName(method) { let name; switch (method) { case BuiltinMethod.ConcatArray: name = 'concat'; break; case BuiltinMethod.SubscribeObservable: name = 'subscribe'; break; case BuiltinMethod.Bind: name = 'bind'; break; default: throw new Error(`Unknown builtin method: ${method}`); } return name; } } /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ /** * The Trusted Types policy, or null if Trusted Types are not * enabled/supported, or undefined if the policy has not been created yet. */ let policy; /** * Returns the Trusted Types policy, or null if Trusted Types are not * enabled/supported. The first call to this function will create the policy. */ function getPolicy() { if (policy === undefined) { policy = null; if (_global.trustedTypes) { try { policy = _global.trustedTypes.createPolicy('angular#unsafe-jit', { createScript: (s) => s, }); } catch (_a) { // trustedTypes.createPolicy throws if called with a name that is // already registered, even in report-only mode. Until the API changes, // catch the error not to break the applications functionally. In such // cases, the code will fall back to using strings. } } } return policy; } /** * Unsafely promote a string to a TrustedScript, falling back to strings when * Trusted Types are not available. * @security In particular, it must be assured that the provided string will * never cause an XSS vulnerability if used in a context that will be * interpreted and executed as a script by a browser, e.g. when calling eval. */ function trustedScriptFromString(script) { var _a; return ((_a = getPolicy()) === null || _a === void 0 ? void 0 : _a.createScript(script)) || script; } /** * Unsafely call the Function constructor with the given string arguments. * @security This is a security-sensitive function; any use of this function * must go through security review. In particular, it must be assured that it * is only called from the JIT compiler, as use in other code can lead to XSS * vulnerabilities. */ function newTrustedFunctionForJIT(...args) { if (!_global.trustedTypes) { // In environments that don't support Trusted Types, fall back to the most // straightforward implementation: return new Function(...args); } // Chrome currently does not support passing TrustedScript to the Function // constructor. The following implements the workaround proposed on the page // below, where the Chromium bug is also referenced: // https://github.com/w3c/webappsec-trusted-types/wiki/Trusted-Types-for-function-constructor const fnArgs = args.slice(0, -1).join(','); const fnBody = args[args.length - 1]; const body = `(function anonymous(${fnArgs} ) { ${fnBody} })`; // Using eval directly confuses the compiler and prevents this module from // being stripped out of JS binaries even if not used. The global['eval'] // indirection fixes that. const fn = _global['eval'](trustedScriptFromString(body)); if (fn.bind === undefined) { // Workaround for a browser bug that only exists in Chrome 83, where passing // a TrustedScript to eval just returns the TrustedScript back without // evaluating it. In that case, fall back to the most straightforward // implementation: return new Function(...args); } // To completely mimic the behavior of calling "new Function", two more // things need to happen: // 1. Stringifying the resulting function should return its source code fn.toString = () => body; // 2. When calling the resulting function, `this` should refer to `global` return fn.bind(_global); // When Trusted Types support in Function constructors is widely available, // the implementation of this function can be simplified to: // return new Function(...args.map(a => trustedScriptFromString(a))); } /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ /** * A helper class to manage the evaluation of JIT generated code. */ class JitEvaluator { /** * * @param sourceUrl The URL of the generated code. * @param statements An array of Angular statement AST nodes to be evaluated. * @param reflector A helper used when converting the statements to executable code. * @param createSourceMaps If true then create a source-map for the generated code and include it * inline as a source-map comment. * @returns A map of all the variables in the generated code. */ evaluateStatements(sourceUrl, statements, reflector, createSourceMaps) { const converter = new JitEmitterVisitor(reflector); const ctx = EmitterVisitorContext.createRoot(); // Ensure generated code is in strict mode if (statements.length > 0 && !isUseStrictStatement(statements[0])) { statements = [ literal('use strict').toStmt(), ...statements, ]; } converter.visitAllStatements(statements, ctx); converter.createReturnStmt(ctx); return this.evaluateCode(sourceUrl, ctx, converter.getArgs(), createSourceMaps); } /** * Evaluate a piece of JIT generated code. * @param sourceUrl The URL of this generated code. * @param ctx A context object that contains an AST of the code to be evaluated. * @param vars A map containing the names and values of variables that the evaluated code might * reference. * @param createSourceMap If true then create a source-map for the generated code and include it * inline as a source-map comment. * @returns The result of evaluating the code. */ evaluateCode(sourceUrl, ctx, vars, createSourceMap) { let fnBody = `"use strict";${ctx.toSource()}\n//# sourceURL=${sourceUrl}`; const fnArgNames = []; const fnArgValues = []; for (const argName in vars) { fnArgValues.push(vars[argName]); fnArgNames.push(argName); } if (createSourceMap) { // using `new Function(...)` generates a header, 1 line of no arguments, 2 lines otherwise // E.g. ``` // function anonymous(a,b,c // /**/) { ... }``` // We don't want to hard code this fact, so we auto detect it via an empty function first. const emptyFn = newTrustedFunctionForJIT(...fnArgNames.concat('return null;')).toString(); const headerLines = emptyFn.slice(0, emptyFn.indexOf('return null;')).split('\n').length - 1; fnBody += `\n${ctx.toSourceMapGenerator(sourceUrl, headerLines).toJsComment()}`; } const fn = newTrustedFunctionForJIT(...fnArgNames.concat(fnBody)); return this.executeFunction(fn, fnArgValues); } /** * Execute a JIT generated function by calling it. * * This method can be overridden in tests to capture the functions that are generated * by this `JitEvaluator` class. * * @param fn A function to execute. * @param args The arguments to pass to the function being executed. * @returns The return value of the executed function. */ executeFunction(fn, args) { return fn(...args); } } /** * An Angular AST visitor that converts AST nodes into executable JavaScript code. */ class JitEmitterVisitor extends AbstractJsEmitterVisitor { constructor(reflector) { super(); this.reflector = reflector; this._evalArgNames = []; this._evalArgValues = []; this._evalExportedVars = []; } createReturnStmt(ctx) { const stmt = new ReturnStatement(new LiteralMapExpr(this._evalExportedVars.map(resultVar => new LiteralMapEntry(resultVar, variable(resultVar), false)))); stmt.visitStatement(this, ctx); } getArgs() { const result = {}; for (let i = 0; i < this._evalArgNames.length; i++) { result[this._evalArgNames[i]] = this._evalArgValues[i]; } return result; } visitExternalExpr(ast, ctx) { this._emitReferenceToExternal(ast, this.reflector.resolveExternalReference(ast.value), ctx); return null; } visitWrappedNodeExpr(ast, ctx) { this._emitReferenceToExternal(ast, ast.node, ctx); return null; } visitDeclareVarStmt(stmt, ctx) { if (stmt.hasModifier(StmtModifier.Exported)) { this._evalExportedVars.push(stmt.name); } return super.visitDeclareVarStmt(stmt, ctx); } visitDeclareFunctionStmt(stmt, ctx) { if (stmt.hasModifier(StmtModifier.Exported)) { this._evalExportedVars.push(stmt.name); } return super.visitDeclareFunctionStmt(stmt, ctx); } visitDeclareClassStmt(stmt, ctx) { if (stmt.hasModifier(StmtModifier.Exported)) { this._evalExportedVars.push(stmt.name); } return super.visitDeclareClassStmt(stmt, ctx); } _emitReferenceToExternal(ast, value, ctx) { let id = this._evalArgValues.indexOf(value); if (id === -1) { id = this._evalArgValues.length; this._evalArgValues.push(value); const name = identifierName({ reference: value }) || 'val'; this._evalArgNames.push(`jit_${name}_${id}`); } ctx.print(ast, this._evalArgNames[id]); } } function isUseStrictStatement(statement) { return statement.isEquivalent(literal('use strict').toStmt()); } /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ function compileInjector(meta) { const definitionMap = new DefinitionMap(); if (meta.providers !== null) { definitionMap.set('providers', meta.providers); } if (meta.imports.length > 0) { definitionMap.set('imports', literalArr(meta.imports)); } const expression = importExpr(Identifiers.defineInjector).callFn([definitionMap.toLiteralMap()], undefined, true); const type = createInjectorType(meta); return { expression, type, statements: [] }; } function createInjectorType(meta) { return new ExpressionType(importExpr(Identifiers.InjectorDeclaration, [new ExpressionType(meta.type.type)])); } /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ /** * Implementation of `CompileReflector` which resolves references to @angular/core * symbols at runtime, according to a consumer-provided mapping. * * Only supports `resolveExternalReference`, all other methods throw. */ class R3JitReflector { constructor(context) { this.context = context; } resolveExternalReference(ref) { // This reflector only handles @angular/core imports. if (ref.moduleName !== '@angular/core') { throw new Error(`Cannot resolve external reference to ${ref.moduleName}, only references to @angular/core are supported.`); } if (!this.context.hasOwnProperty(ref.name)) { throw new Error(`No value provided for @angular/core symbol '${ref.name}'.`); } return this.context[ref.name]; } parameters(typeOrFunc) { throw new Error('Not implemented.'); } annotations(typeOrFunc) { throw new Error('Not implemented.'); } shallowAnnotations(typeOrFunc) { throw new Error('Not implemented.'); } tryAnnotations(typeOrFunc) { throw new Error('Not implemented.'); } propMetadata(typeOrFunc) { throw new Error('Not implemented.'); } hasLifecycleHook(type, lcProperty) { throw new Error('Not implemented.'); } guards(typeOrFunc) { throw new Error('Not implemented.'); } componentModuleUrl(type, cmpMetadata) { throw new Error('Not implemented.'); } } /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ /** * Construct an `R3NgModuleDef` for the given `R3NgModuleMetadata`. */ function compileNgModule(meta) { const { internalType, bootstrap, declarations, imports, exports, schemas, containsForwardDecls, emitInline, id } = meta; const statements = []; const definitionMap = new DefinitionMap(); definitionMap.set('type', internalType); if (bootstrap.length > 0) { definitionMap.set('bootstrap', refsToArray(bootstrap, containsForwardDecls)); } // If requested to emit scope information inline, pass the `declarations`, `imports` and `exports` // to the `ɵɵdefineNgModule()` call. The JIT compilation uses this. if (emitInline) { if (declarations.length > 0) { definitionMap.set('declarations', refsToArray(declarations, containsForwardDecls)); } if (imports.length > 0) { definitionMap.set('imports', refsToArray(imports, containsForwardDecls)); } if (exports.length > 0) { definitionMap.set('exports', refsToArray(exports, containsForwardDecls)); } } // If not emitting inline, the scope information is not passed into `ɵɵdefineNgModule` as it would // prevent tree-shaking of the declarations, imports and exports references. else { const setNgModuleScopeCall = generateSetNgModuleScopeCall(meta); if (setNgModuleScopeCall !== null) { statements.push(setNgModuleScopeCall); } } if (schemas !== null && schemas.length > 0) { definitionMap.set('schemas', literalArr(schemas.map(ref => ref.value))); } if (id !== null) { definitionMap.set('id', id); } const expression = importExpr(Identifiers.defineNgModule).callFn([definitionMap.toLiteralMap()], undefined, true); const type = createNgModuleType(meta); return { expression, type, statements }; } /** * This function is used in JIT mode to generate the call to `ɵɵdefineNgModule()` from a call to * `ɵɵngDeclareNgModule()`. */ function compileNgModuleDeclarationExpression(meta) { const definitionMap = new DefinitionMap(); definitionMap.set('type', new WrappedNodeExpr(meta.type)); if (meta.bootstrap !== undefined) { definitionMap.set('bootstrap', new WrappedNodeExpr(meta.bootstrap)); } if (meta.declarations !== undefined) { definitionMap.set('declarations', new WrappedNodeExpr(meta.declarations)); } if (meta.imports !== undefined) { definitionMap.set('imports', new WrappedNodeExpr(meta.imports)); } if (meta.exports !== undefined) { definitionMap.set('exports', new WrappedNodeExpr(meta.exports)); } if (meta.schemas !== undefined) { definitionMap.set('schemas', new WrappedNodeExpr(meta.schemas)); } if (meta.id !== undefined) { definitionMap.set('id', new WrappedNodeExpr(meta.id)); } return importExpr(Identifiers.defineNgModule).callFn([definitionMap.toLiteralMap()]); } function createNgModuleType({ type: moduleType, declarations, imports, exports }) { return new ExpressionType(importExpr(Identifiers.NgModuleDeclaration, [ new ExpressionType(moduleType.type), tupleTypeOf(declarations), tupleTypeOf(imports), tupleTypeOf(exports) ])); } /** * Generates a function call to `ɵɵsetNgModuleScope` with all necessary information so that the * transitive module scope can be computed during runtime in JIT mode. This call is marked pure * such that the references to declarations, imports and exports may be elided causing these * symbols to become tree-shakeable. */ function generateSetNgModuleScopeCall(meta) { const { adjacentType: moduleType, declarations, imports, exports, containsForwardDecls } = meta; const scopeMap = new DefinitionMap(); if (declarations.length > 0) { scopeMap.set('declarations', refsToArray(declarations, containsForwardDecls)); } if (imports.length > 0) { scopeMap.set('imports', refsToArray(imports, containsForwardDecls)); } if (exports.length > 0) { scopeMap.set('exports', refsToArray(exports, containsForwardDecls)); } if (Object.keys(scopeMap.values).length === 0) { return null; } // setNgModuleScope(...) const fnCall = new InvokeFunctionExpr( /* fn */ importExpr(Identifiers.setNgModuleScope), /* args */ [moduleType, scopeMap.toLiteralMap()]); // (ngJitMode guard) && setNgModuleScope(...) const guardedCall = jitOnlyGuardedExpression(fnCall); // function() { (ngJitMode guard) && setNgModuleScope(...); } const iife = new FunctionExpr( /* params */ [], /* statements */ [guardedCall.toStmt()]); // (function() { (ngJitMode guard) && setNgModuleScope(...); })() const iifeCall = new InvokeFunctionExpr( /* fn */ iife, /* args */ []); return iifeCall.toStmt(); } function tupleTypeOf(exp) { const types = exp.map(ref => typeofExpr(ref.type)); return exp.length > 0 ? expressionType(literalArr(types)) : NONE_TYPE; } /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ function compilePipeFromMetadata(metadata) { const definitionMapValues = []; // e.g. `name: 'myPipe'` definitionMapValues.push({ key: 'name', value: literal(metadata.pipeName), quoted: false }); // e.g. `type: MyPipe` definitionMapValues.push({ key: 'type', value: metadata.type.value, quoted: false }); // e.g. `pure: true` definitionMapValues.push({ key: 'pure', value: literal(metadata.pure), quoted: false }); const expression = importExpr(Identifiers.definePipe).callFn([literalMap(definitionMapValues)], undefined, true); const type = createPipeType(metadata); return { expression, type, statements: [] }; } function createPipeType(metadata) { return new ExpressionType(importExpr(Identifiers.PipeDeclaration, [ typeWithParameters(metadata.type.type, metadata.typeArgumentCount), new ExpressionType(new LiteralExpr(metadata.pipeName)), ])); } /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ class ParserError { constructor(message, input, errLocation, ctxLocation) { this.input = input; this.errLocation = errLocation; this.ctxLocation = ctxLocation; this.message = `Parser Error: ${message} ${errLocation} [${input}] in ${ctxLocation}`; } } class ParseSpan { constructor(start, end) { this.start = start; this.end = end; } toAbsolute(absoluteOffset) { return new AbsoluteSourceSpan(absoluteOffset + this.start, absoluteOffset + this.end); } } class AST { constructor(span, /** * Absolute location of the expression AST in a source code file. */ sourceSpan) { this.span = span; this.sourceSpan = sourceSpan; } toString() { return 'AST'; } } class ASTWithName extends AST { constructor(span, sourceSpan, nameSpan) { super(span, sourceSpan); this.nameSpan = nameSpan; } } /** * Represents a quoted expression of the form: * * quote = prefix `:` uninterpretedExpression * prefix = identifier * uninterpretedExpression = arbitrary string * * A quoted expression is meant to be pre-processed by an AST transformer that * converts it into another AST that no longer contains quoted expressions. * It is meant to allow third-party developers to extend Angular template * expression language. The `uninterpretedExpression` part of the quote is * therefore not interpreted by the Angular's own expression parser. */ class Quote extends AST { constructor(span, sourceSpan, prefix, uninterpretedExpression, location) { super(span, sourceSpan); this.prefix = prefix; this.uninterpretedExpression = uninterpretedExpression; this.location = location; } visit(visitor, context = null) { return visitor.visitQuote(this, context); } toString() { return 'Quote'; } } class EmptyExpr extends AST { visit(visitor, context = null) { // do nothing } } class ImplicitReceiver extends AST { visit(visitor, context = null) { return visitor.visitImplicitReceiver(this, context); } } /** * Receiver when something is accessed through `this` (e.g. `this.foo`). Note that this class * inherits from `ImplicitReceiver`, because accessing something through `this` is treated the * same as accessing it implicitly inside of an Angular template (e.g. `[attr.title]="this.title"` * is the same as `[attr.title]="title"`.). Inheriting allows for the `this` accesses to be treated * the same as implicit ones, except for a couple of exceptions like `$event` and `$any`. * TODO: we should find a way for this class not to extend from `ImplicitReceiver` in the future. */ class ThisReceiver extends ImplicitReceiver { visit(visitor, context = null) { var _a; return (_a = visitor.visitThisReceiver) === null || _a === void 0 ? void 0 : _a.call(visitor, this, context); } } /** * Multiple expressions separated by a semicolon. */ class Chain extends AST { constructor(span, sourceSpan, expressions) { super(span, sourceSpan); this.expressions = expressions; } visit(visitor, context = null) { return visitor.visitChain(this, context); } } class Conditional extends AST { constructor(span, sourceSpan, condition, trueExp, falseExp) { super(span, sourceSpan); this.condition = condition; this.trueExp = trueExp; this.falseExp = falseExp; } visit(visitor, context = null) { return visitor.visitConditional(this, context); } } class PropertyRead extends ASTWithName { constructor(span, sourceSpan, nameSpan, receiver, name) { super(span, sourceSpan, nameSpan); this.receiver = receiver; this.name = name; } visit(visitor, context = null) { return visitor.visitPropertyRead(this, context); } } class PropertyWrite extends ASTWithName { constructor(span, sourceSpan, nameSpan, receiver, name, value) { super(span, sourceSpan, nameSpan); this.receiver = receiver; this.name = name; this.value = value; } visit(visitor, context = null) { return visitor.visitPropertyWrite(this, context); } } class SafePropertyRead extends ASTWithName { constructor(span, sourceSpan, nameSpan, receiver, name) { super(span, sourceSpan, nameSpan); this.receiver = receiver; this.name = name; } visit(visitor, context = null) { return visitor.visitSafePropertyRead(this, context); } } class KeyedRead extends AST { constructor(span, sourceSpan, receiver, key) { super(span, sourceSpan); this.receiver = receiver; this.key = key; } visit(visitor, context = null) { return visitor.visitKeyedRead(this, context); } } class SafeKeyedRead extends AST { constructor(span, sourceSpan, receiver, key) { super(span, sourceSpan); this.receiver = receiver; this.key = key; } visit(visitor, context = null) { return visitor.visitSafeKeyedRead(this, context); } } class KeyedWrite extends AST { constructor(span, sourceSpan, receiver, key, value) { super(span, sourceSpan); this.receiver = receiver; this.key = key; this.value = value; } visit(visitor, context = null) { return visitor.visitKeyedWrite(this, context); } } class BindingPipe extends ASTWithName { constructor(span, sourceSpan, exp, name, args, nameSpan) { super(span, sourceSpan, nameSpan); this.exp = exp; this.name = name; this.args = args; } visit(visitor, context = null) { return visitor.visitPipe(this, context); } } class LiteralPrimitive extends AST { constructor(span, sourceSpan, value) { super(span, sourceSpan); this.value = value; } visit(visitor, context = null) { return visitor.visitLiteralPrimitive(this, context); } } class LiteralArray extends AST { constructor(span, sourceSpan, expressions) { super(span, sourceSpan); this.expressions = expressions; } visit(visitor, context = null) { return visitor.visitLiteralArray(this, context); } } class LiteralMap extends AST { constructor(span, sourceSpan, keys, values) { super(span, sourceSpan); this.keys = keys; this.values = values; } visit(visitor, context = null) { return visitor.visitLiteralMap(this, context); } } class Interpolation extends AST { constructor(span, sourceSpan, strings, expressions) { super(span, sourceSpan); this.strings = strings; this.expressions = expressions; } visit(visitor, context = null) { return visitor.visitInterpolation(this, context); } } class Binary extends AST { constructor(span, sourceSpan, operation, left, right) { super(span, sourceSpan); this.operation = operation; this.left = left; this.right = right; } visit(visitor, context = null) { return visitor.visitBinary(this, context); } } /** * For backwards compatibility reasons, `Unary` inherits from `Binary` and mimics the binary AST * node that was originally used. This inheritance relation can be deleted in some future major, * after consumers have been given a chance to fully support Unary. */ class Unary extends Binary { /** * During the deprecation period this constructor is private, to avoid consumers from creating * a `Unary` with the fallback properties for `Binary`. */ constructor(span, sourceSpan, operator, expr, binaryOp, binaryLeft, binaryRight) { super(span, sourceSpan, binaryOp, binaryLeft, binaryRight); this.operator = operator; this.expr = expr; } /** * Creates a unary minus expression "-x", represented as `Binary` using "0 - x". */ static createMinus(span, sourceSpan, expr) { return new Unary(span, sourceSpan, '-', expr, '-', new LiteralPrimitive(span, sourceSpan, 0), expr); } /** * Creates a unary plus expression "+x", represented as `Binary` using "x - 0". */ static createPlus(span, sourceSpan, expr) { return new Unary(span, sourceSpan, '+', expr, '-', expr, new LiteralPrimitive(span, sourceSpan, 0)); } visit(visitor, context = null) { if (visitor.visitUnary !== undefined) { return visitor.visitUnary(this, context); } return visitor.visitBinary(this, context); } } class PrefixNot extends AST { constructor(span, sourceSpan, expression) { super(span, sourceSpan); this.expression = expression; } visit(visitor, context = null) { return visitor.visitPrefixNot(this, context); } } class NonNullAssert extends AST { constructor(span, sourceSpan, expression) { super(span, sourceSpan); this.expression = expression; } visit(visitor, context = null) { return visitor.visitNonNullAssert(this, context); } } class MethodCall extends ASTWithName { constructor(span, sourceSpan, nameSpan, receiver, name, args, argumentSpan) { super(span, sourceSpan, nameSpan); this.receiver = receiver; this.name = name; this.args = args; this.argumentSpan = argumentSpan; } visit(visitor, context = null) { return visitor.visitMethodCall(this, context); } } class SafeMethodCall extends ASTWithName { constructor(span, sourceSpan, nameSpan, receiver, name, args, argumentSpan) { super(span, sourceSpan, nameSpan); this.receiver = receiver; this.name = name; this.args = args; this.argumentSpan = argumentSpan; } visit(visitor, context = null) { return visitor.visitSafeMethodCall(this, context); } } class FunctionCall extends AST { constructor(span, sourceSpan, target, args) { super(span, sourceSpan); this.target = target; this.args = args; } visit(visitor, context = null) { return visitor.visitFunctionCall(this, context); } } /** * Records the absolute position of a text span in a source file, where `start` and `end` are the * starting and ending byte offsets, respectively, of the text span in a source file. */ class AbsoluteSourceSpan { constructor(start, end) { this.start = start; this.end = end; } } class ASTWithSource extends AST { constructor(ast, source, location, absoluteOffset, errors) { super(new ParseSpan(0, source === null ? 0 : source.length), new AbsoluteSourceSpan(absoluteOffset, source === null ? absoluteOffset : absoluteOffset + source.length)); this.ast = ast; this.source = source; this.location = location; this.errors = errors; } visit(visitor, context = null) { if (visitor.visitASTWithSource) { return visitor.visitASTWithSource(this, context); } return this.ast.visit(visitor, context); } toString() { return `${this.source} in ${this.location}`; } } class VariableBinding { /** * @param sourceSpan entire span of the binding. * @param key name of the LHS along with its span. * @param value optional value for the RHS along with its span. */ constructor(sourceSpan, key, value) { this.sourceSpan = sourceSpan; this.key = key; this.value = value; } } class ExpressionBinding { /** * @param sourceSpan entire span of the binding. * @param key binding name, like ngForOf, ngForTrackBy, ngIf, along with its * span. Note that the length of the span may not be the same as * `key.source.length`. For example, * 1. key.source = ngFor, key.span is for "ngFor" * 2. key.source = ngForOf, key.span is for "of" * 3. key.source = ngForTrackBy, key.span is for "trackBy" * @param value optional expression for the RHS. */ constructor(sourceSpan, key, value) { this.sourceSpan = sourceSpan; this.key = key; this.value = value; } } class RecursiveAstVisitor$1 { visit(ast, context) { // The default implementation just visits every node. // Classes that extend RecursiveAstVisitor should override this function // to selectively visit the specified node. ast.visit(this, context); } visitUnary(ast, context) { this.visit(ast.expr, context); } visitBinary(ast, context) { this.visit(ast.left, context); this.visit(ast.right, context); } visitChain(ast, context) { this.visitAll(ast.expressions, context); } visitConditional(ast, context) { this.visit(ast.condition, context); this.visit(ast.trueExp, context); this.visit(ast.falseExp, context); } visitPipe(ast, context) { this.visit(ast.exp, context); this.visitAll(ast.args, context); } visitFunctionCall(ast, context) { if (ast.target) { this.visit(ast.target, context); } this.visitAll(ast.args, context); } visitImplicitReceiver(ast, context) { } visitThisReceiver(ast, context) { } visitInterpolation(ast, context) { this.visitAll(ast.expressions, context); } visitKeyedRead(ast, context) { this.visit(ast.receiver, context); this.visit(ast.key, context); } visitKeyedWrite(ast, context) { this.visit(ast.receiver, context); this.visit(ast.key, context); this.visit(ast.value, context); } visitLiteralArray(ast, context) { this.visitAll(ast.expressions, context); } visitLiteralMap(ast, context) { this.visitAll(ast.values, context); } visitLiteralPrimitive(ast, context) { } visitMethodCall(ast, context) { this.visit(ast.receiver, context); this.visitAll(ast.args, context); } visitPrefixNot(ast, context) { this.visit(ast.expression, context); } visitNonNullAssert(ast, context) { this.visit(ast.expression, context); } visitPropertyRead(ast, context) { this.visit(ast.receiver, context); } visitPropertyWrite(ast, context) { this.visit(ast.receiver, context); this.visit(ast.value, context); } visitSafePropertyRead(ast, context) { this.visit(ast.receiver, context); } visitSafeMethodCall(ast, context) { this.visit(ast.receiver, context); this.visitAll(ast.args, context); } visitSafeKeyedRead(ast, context) { this.visit(ast.receiver, context); this.visit(ast.key, context); } visitQuote(ast, context) { } // This is not part of the AstVisitor interface, just a helper method visitAll(asts, context) { for (const ast of asts) { this.visit(ast, context); } } } class AstTransformer$1 { visitImplicitReceiver(ast, context) { return ast; } visitThisReceiver(ast, context) { return ast; } visitInterpolation(ast, context) { return new Interpolation(ast.span, ast.sourceSpan, ast.strings, this.visitAll(ast.expressions)); } visitLiteralPrimitive(ast, context) { return new LiteralPrimitive(ast.span, ast.sourceSpan, ast.value); } visitPropertyRead(ast, context) { return new PropertyRead(ast.span, ast.sourceSpan, ast.nameSpan, ast.receiver.visit(this), ast.name); } visitPropertyWrite(ast, context) { return new PropertyWrite(ast.span, ast.sourceSpan, ast.nameSpan, ast.receiver.visit(this), ast.name, ast.value.visit(this)); } visitSafePropertyRead(ast, context) { return new SafePropertyRead(ast.span, ast.sourceSpan, ast.nameSpan, ast.receiver.visit(this), ast.name); } visitMethodCall(ast, context) { return new MethodCall(ast.span, ast.sourceSpan, ast.nameSpan, ast.receiver.visit(this), ast.name, this.visitAll(ast.args), ast.argumentSpan); } visitSafeMethodCall(ast, context) { return new SafeMethodCall(ast.span, ast.sourceSpan, ast.nameSpan, ast.receiver.visit(this), ast.name, this.visitAll(ast.args), ast.argumentSpan); } visitFunctionCall(ast, context) { return new FunctionCall(ast.span, ast.sourceSpan, ast.target.visit(this), this.visitAll(ast.args)); } visitLiteralArray(ast, context) { return new LiteralArray(ast.span, ast.sourceSpan, this.visitAll(ast.expressions)); } visitLiteralMap(ast, context) { return new LiteralMap(ast.span, ast.sourceSpan, ast.keys, this.visitAll(ast.values)); } visitUnary(ast, context) { switch (ast.operator) { case '+': return Unary.createPlus(ast.span, ast.sourceSpan, ast.expr.visit(this)); case '-': return Unary.createMinus(ast.span, ast.sourceSpan, ast.expr.visit(this)); default: throw new Error(`Unknown unary operator ${ast.operator}`); } } visitBinary(ast, context) { return new Binary(ast.span, ast.sourceSpan, ast.operation, ast.left.visit(this), ast.right.visit(this)); } visitPrefixNot(ast, context) { return new PrefixNot(ast.span, ast.sourceSpan, ast.expression.visit(this)); } visitNonNullAssert(ast, context) { return new NonNullAssert(ast.span, ast.sourceSpan, ast.expression.visit(this)); } visitConditional(ast, context) { return new Conditional(ast.span, ast.sourceSpan, ast.condition.visit(this), ast.trueExp.visit(this), ast.falseExp.visit(this)); } visitPipe(ast, context) { return new BindingPipe(ast.span, ast.sourceSpan, ast.exp.visit(this), ast.name, this.visitAll(ast.args), ast.nameSpan); } visitKeyedRead(ast, context) { return new KeyedRead(ast.span, ast.sourceSpan, ast.receiver.visit(this), ast.key.visit(this)); } visitKeyedWrite(ast, context) { return new KeyedWrite(ast.span, ast.sourceSpan, ast.receiver.visit(this), ast.key.visit(this), ast.value.visit(this)); } visitAll(asts) { const res = []; for (let i = 0; i < asts.length; ++i) { res[i] = asts[i].visit(this); } return res; } visitChain(ast, context) { return new Chain(ast.span, ast.sourceSpan, this.visitAll(ast.expressions)); } visitQuote(ast, context) { return new Quote(ast.span, ast.sourceSpan, ast.prefix, ast.uninterpretedExpression, ast.location); } visitSafeKeyedRead(ast, context) { return new SafeKeyedRead(ast.span, ast.sourceSpan, ast.receiver.visit(this), ast.key.visit(this)); } } // A transformer that only creates new nodes if the transformer makes a change or // a change is made a child node. class AstMemoryEfficientTransformer { visitImplicitReceiver(ast, context) { return ast; } visitThisReceiver(ast, context) { return ast; } visitInterpolation(ast, context) { const expressions = this.visitAll(ast.expressions); if (expressions !== ast.expressions) return new Interpolation(ast.span, ast.sourceSpan, ast.strings, expressions); return ast; } visitLiteralPrimitive(ast, context) { return ast; } visitPropertyRead(ast, context) { const receiver = ast.receiver.visit(this); if (receiver !== ast.receiver) { return new PropertyRead(ast.span, ast.sourceSpan, ast.nameSpan, receiver, ast.name); } return ast; } visitPropertyWrite(ast, context) { const receiver = ast.receiver.visit(this); const value = ast.value.visit(this); if (receiver !== ast.receiver || value !== ast.value) { return new PropertyWrite(ast.span, ast.sourceSpan, ast.nameSpan, receiver, ast.name, value); } return ast; } visitSafePropertyRead(ast, context) { const receiver = ast.receiver.visit(this); if (receiver !== ast.receiver) { return new SafePropertyRead(ast.span, ast.sourceSpan, ast.nameSpan, receiver, ast.name); } return ast; } visitMethodCall(ast, context) { const receiver = ast.receiver.visit(this); const args = this.visitAll(ast.args); if (receiver !== ast.receiver || args !== ast.args) { return new MethodCall(ast.span, ast.sourceSpan, ast.nameSpan, receiver, ast.name, args, ast.argumentSpan); } return ast; } visitSafeMethodCall(ast, context) { const receiver = ast.receiver.visit(this); const args = this.visitAll(ast.args); if (receiver !== ast.receiver || args !== ast.args) { return new SafeMethodCall(ast.span, ast.sourceSpan, ast.nameSpan, receiver, ast.name, args, ast.argumentSpan); } return ast; } visitFunctionCall(ast, context) { const target = ast.target && ast.target.visit(this); const args = this.visitAll(ast.args); if (target !== ast.target || args !== ast.args) { return new FunctionCall(ast.span, ast.sourceSpan, target, args); } return ast; } visitLiteralArray(ast, context) { const expressions = this.visitAll(ast.expressions); if (expressions !== ast.expressions) { return new LiteralArray(ast.span, ast.sourceSpan, expressions); } return ast; } visitLiteralMap(ast, context) { const values = this.visitAll(ast.values); if (values !== ast.values) { return new LiteralMap(ast.span, ast.sourceSpan, ast.keys, values); } return ast; } visitUnary(ast, context) { const expr = ast.expr.visit(this); if (expr !== ast.expr) { switch (ast.operator) { case '+': return Unary.createPlus(ast.span, ast.sourceSpan, expr); case '-': return Unary.createMinus(ast.span, ast.sourceSpan, expr); default: throw new Error(`Unknown unary operator ${ast.operator}`); } } return ast; } visitBinary(ast, context) { const left = ast.left.visit(this); const right = ast.right.visit(this); if (left !== ast.left || right !== ast.right) { return new Binary(ast.span, ast.sourceSpan, ast.operation, left, right); } return ast; } visitPrefixNot(ast, context) { const expression = ast.expression.visit(this); if (expression !== ast.expression) { return new PrefixNot(ast.span, ast.sourceSpan, expression); } return ast; } visitNonNullAssert(ast, context) { const expression = ast.expression.visit(this); if (expression !== ast.expression) { return new NonNullAssert(ast.span, ast.sourceSpan, expression); } return ast; } visitConditional(ast, context) { const condition = ast.condition.visit(this); const trueExp = ast.trueExp.visit(this); const falseExp = ast.falseExp.visit(this); if (condition !== ast.condition || trueExp !== ast.trueExp || falseExp !== ast.falseExp) { return new Conditional(ast.span, ast.sourceSpan, condition, trueExp, falseExp); } return ast; } visitPipe(ast, context) { const exp = ast.exp.visit(this); const args = this.visitAll(ast.args); if (exp !== ast.exp || args !== ast.args) { return new BindingPipe(ast.span, ast.sourceSpan, exp, ast.name, args, ast.nameSpan); } return ast; } visitKeyedRead(ast, context) { const obj = ast.receiver.visit(this); const key = ast.key.visit(this); if (obj !== ast.receiver || key !== ast.key) { return new KeyedRead(ast.span, ast.sourceSpan, obj, key); } return ast; } visitKeyedWrite(ast, context) { const obj = ast.receiver.visit(this); const key = ast.key.visit(this); const value = ast.value.visit(this); if (obj !== ast.receiver || key !== ast.key || value !== ast.value) { return new KeyedWrite(ast.span, ast.sourceSpan, obj, key, value); } return ast; } visitAll(asts) { const res = []; let modified = false; for (let i = 0; i < asts.length; ++i) { const original = asts[i]; const value = original.visit(this); res[i] = value; modified = modified || value !== original; } return modified ? res : asts; } visitChain(ast, context) { const expressions = this.visitAll(ast.expressions); if (expressions !== ast.expressions) { return new Chain(ast.span, ast.sourceSpan, expressions); } return ast; } visitQuote(ast, context) { return ast; } visitSafeKeyedRead(ast, context) { const obj = ast.receiver.visit(this); const key = ast.key.visit(this); if (obj !== ast.receiver || key !== ast.key) { return new SafeKeyedRead(ast.span, ast.sourceSpan, obj, key); } return ast; } } // Bindings class ParsedProperty { constructor(name, expression, type, // TODO(FW-2095): `keySpan` should really be required but allows `undefined` so VE does // not need to be updated. Make `keySpan` required when VE is removed. sourceSpan, keySpan, valueSpan) { this.name = name; this.expression = expression; this.type = type; this.sourceSpan = sourceSpan; this.keySpan = keySpan; this.valueSpan = valueSpan; this.isLiteral = this.type === ParsedPropertyType.LITERAL_ATTR; this.isAnimation = this.type === ParsedPropertyType.ANIMATION; } } var ParsedPropertyType; (function (ParsedPropertyType) { ParsedPropertyType[ParsedPropertyType["DEFAULT"] = 0] = "DEFAULT"; ParsedPropertyType[ParsedPropertyType["LITERAL_ATTR"] = 1] = "LITERAL_ATTR"; ParsedPropertyType[ParsedPropertyType["ANIMATION"] = 2] = "ANIMATION"; })(ParsedPropertyType || (ParsedPropertyType = {})); class ParsedEvent { // Regular events have a target // Animation events have a phase constructor(name, targetOrPhase, type, handler, sourceSpan, // TODO(FW-2095): keySpan should be required but was made optional to avoid changing VE handlerSpan, keySpan) { this.name = name; this.targetOrPhase = targetOrPhase; this.type = type; this.handler = handler; this.sourceSpan = sourceSpan; this.handlerSpan = handlerSpan; this.keySpan = keySpan; } } /** * ParsedVariable represents a variable declaration in a microsyntax expression. */ class ParsedVariable { constructor(name, value, sourceSpan, keySpan, valueSpan) { this.name = name; this.value = value; this.sourceSpan = sourceSpan; this.keySpan = keySpan; this.valueSpan = valueSpan; } } class BoundElementProperty { constructor(name, type, securityContext, value, unit, sourceSpan, keySpan, valueSpan) { this.name = name; this.type = type; this.securityContext = securityContext; this.value = value; this.unit = unit; this.sourceSpan = sourceSpan; this.keySpan = keySpan; this.valueSpan = valueSpan; } } /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ const CORE$1 = '@angular/core'; class Identifiers$1 { } Identifiers$1.ANALYZE_FOR_ENTRY_COMPONENTS = { name: 'ANALYZE_FOR_ENTRY_COMPONENTS', moduleName: CORE$1, }; Identifiers$1.ElementRef = { name: 'ElementRef', moduleName: CORE$1 }; Identifiers$1.NgModuleRef = { name: 'NgModuleRef', moduleName: CORE$1 }; Identifiers$1.ViewContainerRef = { name: 'ViewContainerRef', moduleName: CORE$1 }; Identifiers$1.ChangeDetectorRef = { name: 'ChangeDetectorRef', moduleName: CORE$1, }; Identifiers$1.QueryList = { name: 'QueryList', moduleName: CORE$1 }; Identifiers$1.TemplateRef = { name: 'TemplateRef', moduleName: CORE$1 }; Identifiers$1.Renderer2 = { name: 'Renderer2', moduleName: CORE$1 }; Identifiers$1.CodegenComponentFactoryResolver = { name: 'ɵCodegenComponentFactoryResolver', moduleName: CORE$1, }; Identifiers$1.ComponentFactoryResolver = { name: 'ComponentFactoryResolver', moduleName: CORE$1, }; Identifiers$1.ComponentFactory = { name: 'ComponentFactory', moduleName: CORE$1 }; Identifiers$1.ComponentRef = { name: 'ComponentRef', moduleName: CORE$1 }; Identifiers$1.NgModuleFactory = { name: 'NgModuleFactory', moduleName: CORE$1 }; Identifiers$1.createModuleFactory = { name: 'ɵcmf', moduleName: CORE$1, }; Identifiers$1.moduleDef = { name: 'ɵmod', moduleName: CORE$1, }; Identifiers$1.moduleProviderDef = { name: 'ɵmpd', moduleName: CORE$1, }; Identifiers$1.RegisterModuleFactoryFn = { name: 'ɵregisterModuleFactory', moduleName: CORE$1, }; Identifiers$1.inject = { name: 'ɵɵinject', moduleName: CORE$1 }; Identifiers$1.directiveInject = { name: 'ɵɵdirectiveInject', moduleName: CORE$1 }; Identifiers$1.INJECTOR = { name: 'INJECTOR', moduleName: CORE$1 }; Identifiers$1.Injector = { name: 'Injector', moduleName: CORE$1 }; Identifiers$1.ViewEncapsulation = { name: 'ViewEncapsulation', moduleName: CORE$1, }; Identifiers$1.ChangeDetectionStrategy = { name: 'ChangeDetectionStrategy', moduleName: CORE$1, }; Identifiers$1.SecurityContext = { name: 'SecurityContext', moduleName: CORE$1, }; Identifiers$1.LOCALE_ID = { name: 'LOCALE_ID', moduleName: CORE$1 }; Identifiers$1.TRANSLATIONS_FORMAT = { name: 'TRANSLATIONS_FORMAT', moduleName: CORE$1, }; Identifiers$1.inlineInterpolate = { name: 'ɵinlineInterpolate', moduleName: CORE$1, }; Identifiers$1.interpolate = { name: 'ɵinterpolate', moduleName: CORE$1 }; Identifiers$1.EMPTY_ARRAY = { name: 'ɵEMPTY_ARRAY', moduleName: CORE$1 }; Identifiers$1.EMPTY_MAP = { name: 'ɵEMPTY_MAP', moduleName: CORE$1 }; Identifiers$1.Renderer = { name: 'Renderer', moduleName: CORE$1 }; Identifiers$1.viewDef = { name: 'ɵvid', moduleName: CORE$1 }; Identifiers$1.elementDef = { name: 'ɵeld', moduleName: CORE$1 }; Identifiers$1.anchorDef = { name: 'ɵand', moduleName: CORE$1 }; Identifiers$1.textDef = { name: 'ɵted', moduleName: CORE$1 }; Identifiers$1.directiveDef = { name: 'ɵdid', moduleName: CORE$1 }; Identifiers$1.providerDef = { name: 'ɵprd', moduleName: CORE$1 }; Identifiers$1.queryDef = { name: 'ɵqud', moduleName: CORE$1 }; Identifiers$1.pureArrayDef = { name: 'ɵpad', moduleName: CORE$1 }; Identifiers$1.pureObjectDef = { name: 'ɵpod', moduleName: CORE$1 }; Identifiers$1.purePipeDef = { name: 'ɵppd', moduleName: CORE$1 }; Identifiers$1.pipeDef = { name: 'ɵpid', moduleName: CORE$1 }; Identifiers$1.nodeValue = { name: 'ɵnov', moduleName: CORE$1 }; Identifiers$1.ngContentDef = { name: 'ɵncd', moduleName: CORE$1 }; Identifiers$1.unwrapValue = { name: 'ɵunv', moduleName: CORE$1 }; Identifiers$1.createRendererType2 = { name: 'ɵcrt', moduleName: CORE$1 }; // type only Identifiers$1.RendererType2 = { name: 'RendererType2', moduleName: CORE$1, }; // type only Identifiers$1.ViewDefinition = { name: 'ɵViewDefinition', moduleName: CORE$1, }; Identifiers$1.createComponentFactory = { name: 'ɵccf', moduleName: CORE$1 }; function createTokenForReference(reference) { return { identifier: { reference: reference } }; } function createTokenForExternalReference(reflector, reference) { return createTokenForReference(reflector.resolveExternalReference(reference)); } /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ class EventHandlerVars { } EventHandlerVars.event = variable('$event'); class ConvertActionBindingResult { constructor( /** * Render2 compatible statements, */ stmts, /** * Variable name used with render2 compatible statements. */ allowDefault) { this.stmts = stmts; this.allowDefault = allowDefault; /** * This is bit of a hack. It converts statements which render2 expects to statements which are * expected by render3. * * Example: `
` will generate: * * Render3: * ``` * const pd_b:any = ((ctx.doSomething($event)) !== false); * return pd_b; * ``` * * but render2 expects: * ``` * return ctx.doSomething($event); * ``` */ // TODO(misko): remove this hack once we no longer support ViewEngine. this.render3Stmts = stmts.map((statement) => { if (statement instanceof DeclareVarStmt && statement.name == allowDefault.name && statement.value instanceof BinaryOperatorExpr) { const lhs = statement.value.lhs; return new ReturnStatement(lhs.value); } return statement; }); } } /** * Converts the given expression AST into an executable output AST, assuming the expression is * used in an action binding (e.g. an event handler). */ function convertActionBinding(localResolver, implicitReceiver, action, bindingId, interpolationFunction, baseSourceSpan, implicitReceiverAccesses, globals) { if (!localResolver) { localResolver = new DefaultLocalResolver(globals); } const actionWithoutBuiltins = convertPropertyBindingBuiltins({ createLiteralArrayConverter: (argCount) => { // Note: no caching for literal arrays in actions. return (args) => literalArr(args); }, createLiteralMapConverter: (keys) => { // Note: no caching for literal maps in actions. return (values) => { const entries = keys.map((k, i) => ({ key: k.key, value: values[i], quoted: k.quoted, })); return literalMap(entries); }; }, createPipeConverter: (name) => { throw new Error(`Illegal State: Actions are not allowed to contain pipes. Pipe: ${name}`); } }, action); const visitor = new _AstToIrVisitor(localResolver, implicitReceiver, bindingId, interpolationFunction, baseSourceSpan, implicitReceiverAccesses); const actionStmts = []; flattenStatements(actionWithoutBuiltins.visit(visitor, _Mode.Statement), actionStmts); prependTemporaryDecls(visitor.temporaryCount, bindingId, actionStmts); if (visitor.usesImplicitReceiver) { localResolver.notifyImplicitReceiverUse(); } const lastIndex = actionStmts.length - 1; let preventDefaultVar = null; if (lastIndex >= 0) { const lastStatement = actionStmts[lastIndex]; const returnExpr = convertStmtIntoExpression(lastStatement); if (returnExpr) { // Note: We need to cast the result of the method call to dynamic, // as it might be a void method! preventDefaultVar = createPreventDefaultVar(bindingId); actionStmts[lastIndex] = preventDefaultVar.set(returnExpr.cast(DYNAMIC_TYPE).notIdentical(literal(false))) .toDeclStmt(null, [StmtModifier.Final]); } } return new ConvertActionBindingResult(actionStmts, preventDefaultVar); } function convertPropertyBindingBuiltins(converterFactory, ast) { return convertBuiltins(converterFactory, ast); } class ConvertPropertyBindingResult { constructor(stmts, currValExpr) { this.stmts = stmts; this.currValExpr = currValExpr; } } var BindingForm; (function (BindingForm) { // The general form of binding expression, supports all expressions. BindingForm[BindingForm["General"] = 0] = "General"; // Try to generate a simple binding (no temporaries or statements) // otherwise generate a general binding BindingForm[BindingForm["TrySimple"] = 1] = "TrySimple"; // Inlines assignment of temporaries into the generated expression. The result may still // have statements attached for declarations of temporary variables. // This is the only relevant form for Ivy, the other forms are only used in ViewEngine. BindingForm[BindingForm["Expression"] = 2] = "Expression"; })(BindingForm || (BindingForm = {})); /** * Converts the given expression AST into an executable output AST, assuming the expression * is used in property binding. The expression has to be preprocessed via * `convertPropertyBindingBuiltins`. */ function convertPropertyBinding(localResolver, implicitReceiver, expressionWithoutBuiltins, bindingId, form, interpolationFunction) { if (!localResolver) { localResolver = new DefaultLocalResolver(); } const visitor = new _AstToIrVisitor(localResolver, implicitReceiver, bindingId, interpolationFunction); const outputExpr = expressionWithoutBuiltins.visit(visitor, _Mode.Expression); const stmts = getStatementsFromVisitor(visitor, bindingId); if (visitor.usesImplicitReceiver) { localResolver.notifyImplicitReceiverUse(); } if (visitor.temporaryCount === 0 && form == BindingForm.TrySimple) { return new ConvertPropertyBindingResult([], outputExpr); } else if (form === BindingForm.Expression) { return new ConvertPropertyBindingResult(stmts, outputExpr); } const currValExpr = createCurrValueExpr(bindingId); stmts.push(currValExpr.set(outputExpr).toDeclStmt(DYNAMIC_TYPE, [StmtModifier.Final])); return new ConvertPropertyBindingResult(stmts, currValExpr); } /** * Given some expression, such as a binding or interpolation expression, and a context expression to * look values up on, visit each facet of the given expression resolving values from the context * expression such that a list of arguments can be derived from the found values that can be used as * arguments to an external update instruction. * * @param localResolver The resolver to use to look up expressions by name appropriately * @param contextVariableExpression The expression representing the context variable used to create * the final argument expressions * @param expressionWithArgumentsToExtract The expression to visit to figure out what values need to * be resolved and what arguments list to build. * @param bindingId A name prefix used to create temporary variable names if they're needed for the * arguments generated * @returns An array of expressions that can be passed as arguments to instruction expressions like * `o.importExpr(R3.propertyInterpolate).callFn(result)` */ function convertUpdateArguments(localResolver, contextVariableExpression, expressionWithArgumentsToExtract, bindingId) { const visitor = new _AstToIrVisitor(localResolver, contextVariableExpression, bindingId, undefined); const outputExpr = expressionWithArgumentsToExtract.visit(visitor, _Mode.Expression); if (visitor.usesImplicitReceiver) { localResolver.notifyImplicitReceiverUse(); } const stmts = getStatementsFromVisitor(visitor, bindingId); // Removing the first argument, because it was a length for ViewEngine, not Ivy. let args = outputExpr.args.slice(1); if (expressionWithArgumentsToExtract instanceof Interpolation) { // If we're dealing with an interpolation of 1 value with an empty prefix and suffix, reduce the // args returned to just the value, because we're going to pass it to a special instruction. const strings = expressionWithArgumentsToExtract.strings; if (args.length === 3 && strings[0] === '' && strings[1] === '') { // Single argument interpolate instructions. args = [args[1]]; } else if (args.length >= 19) { // 19 or more arguments must be passed to the `interpolateV`-style instructions, which accept // an array of arguments args = [literalArr(args)]; } } return { stmts, args }; } function getStatementsFromVisitor(visitor, bindingId) { const stmts = []; for (let i = 0; i < visitor.temporaryCount; i++) { stmts.push(temporaryDeclaration(bindingId, i)); } return stmts; } function convertBuiltins(converterFactory, ast) { const visitor = new _BuiltinAstConverter(converterFactory); return ast.visit(visitor); } function temporaryName(bindingId, temporaryNumber) { return `tmp_${bindingId}_${temporaryNumber}`; } function temporaryDeclaration(bindingId, temporaryNumber) { return new DeclareVarStmt(temporaryName(bindingId, temporaryNumber)); } function prependTemporaryDecls(temporaryCount, bindingId, statements) { for (let i = temporaryCount - 1; i >= 0; i--) { statements.unshift(temporaryDeclaration(bindingId, i)); } } var _Mode; (function (_Mode) { _Mode[_Mode["Statement"] = 0] = "Statement"; _Mode[_Mode["Expression"] = 1] = "Expression"; })(_Mode || (_Mode = {})); function ensureStatementMode(mode, ast) { if (mode !== _Mode.Statement) { throw new Error(`Expected a statement, but saw ${ast}`); } } function ensureExpressionMode(mode, ast) { if (mode !== _Mode.Expression) { throw new Error(`Expected an expression, but saw ${ast}`); } } function convertToStatementIfNeeded(mode, expr) { if (mode === _Mode.Statement) { return expr.toStmt(); } else { return expr; } } class _BuiltinAstConverter extends AstTransformer$1 { constructor(_converterFactory) { super(); this._converterFactory = _converterFactory; } visitPipe(ast, context) { const args = [ast.exp, ...ast.args].map(ast => ast.visit(this, context)); return new BuiltinFunctionCall(ast.span, ast.sourceSpan, args, this._converterFactory.createPipeConverter(ast.name, args.length)); } visitLiteralArray(ast, context) { const args = ast.expressions.map(ast => ast.visit(this, context)); return new BuiltinFunctionCall(ast.span, ast.sourceSpan, args, this._converterFactory.createLiteralArrayConverter(ast.expressions.length)); } visitLiteralMap(ast, context) { const args = ast.values.map(ast => ast.visit(this, context)); return new BuiltinFunctionCall(ast.span, ast.sourceSpan, args, this._converterFactory.createLiteralMapConverter(ast.keys)); } } class _AstToIrVisitor { constructor(_localResolver, _implicitReceiver, bindingId, interpolationFunction, baseSourceSpan, implicitReceiverAccesses) { this._localResolver = _localResolver; this._implicitReceiver = _implicitReceiver; this.bindingId = bindingId; this.interpolationFunction = interpolationFunction; this.baseSourceSpan = baseSourceSpan; this.implicitReceiverAccesses = implicitReceiverAccesses; this._nodeMap = new Map(); this._resultMap = new Map(); this._currentTemporary = 0; this.temporaryCount = 0; this.usesImplicitReceiver = false; } visitUnary(ast, mode) { let op; switch (ast.operator) { case '+': op = UnaryOperator.Plus; break; case '-': op = UnaryOperator.Minus; break; default: throw new Error(`Unsupported operator ${ast.operator}`); } return convertToStatementIfNeeded(mode, new UnaryOperatorExpr(op, this._visit(ast.expr, _Mode.Expression), undefined, this.convertSourceSpan(ast.span))); } visitBinary(ast, mode) { let op; switch (ast.operation) { case '+': op = BinaryOperator.Plus; break; case '-': op = BinaryOperator.Minus; break; case '*': op = BinaryOperator.Multiply; break; case '/': op = BinaryOperator.Divide; break; case '%': op = BinaryOperator.Modulo; break; case '&&': op = BinaryOperator.And; break; case '||': op = BinaryOperator.Or; break; case '==': op = BinaryOperator.Equals; break; case '!=': op = BinaryOperator.NotEquals; break; case '===': op = BinaryOperator.Identical; break; case '!==': op = BinaryOperator.NotIdentical; break; case '<': op = BinaryOperator.Lower; break; case '>': op = BinaryOperator.Bigger; break; case '<=': op = BinaryOperator.LowerEquals; break; case '>=': op = BinaryOperator.BiggerEquals; break; case '??': return this.convertNullishCoalesce(ast, mode); default: throw new Error(`Unsupported operation ${ast.operation}`); } return convertToStatementIfNeeded(mode, new BinaryOperatorExpr(op, this._visit(ast.left, _Mode.Expression), this._visit(ast.right, _Mode.Expression), undefined, this.convertSourceSpan(ast.span))); } visitChain(ast, mode) { ensureStatementMode(mode, ast); return this.visitAll(ast.expressions, mode); } visitConditional(ast, mode) { const value = this._visit(ast.condition, _Mode.Expression); return convertToStatementIfNeeded(mode, value.conditional(this._visit(ast.trueExp, _Mode.Expression), this._visit(ast.falseExp, _Mode.Expression), this.convertSourceSpan(ast.span))); } visitPipe(ast, mode) { throw new Error(`Illegal state: Pipes should have been converted into functions. Pipe: ${ast.name}`); } visitFunctionCall(ast, mode) { const convertedArgs = this.visitAll(ast.args, _Mode.Expression); let fnResult; if (ast instanceof BuiltinFunctionCall) { fnResult = ast.converter(convertedArgs); } else { fnResult = this._visit(ast.target, _Mode.Expression) .callFn(convertedArgs, this.convertSourceSpan(ast.span)); } return convertToStatementIfNeeded(mode, fnResult); } visitImplicitReceiver(ast, mode) { ensureExpressionMode(mode, ast); this.usesImplicitReceiver = true; return this._implicitReceiver; } visitThisReceiver(ast, mode) { return this.visitImplicitReceiver(ast, mode); } visitInterpolation(ast, mode) { ensureExpressionMode(mode, ast); const args = [literal(ast.expressions.length)]; for (let i = 0; i < ast.strings.length - 1; i++) { args.push(literal(ast.strings[i])); args.push(this._visit(ast.expressions[i], _Mode.Expression)); } args.push(literal(ast.strings[ast.strings.length - 1])); if (this.interpolationFunction) { return this.interpolationFunction(args); } return ast.expressions.length <= 9 ? importExpr(Identifiers$1.inlineInterpolate).callFn(args) : importExpr(Identifiers$1.interpolate).callFn([ args[0], literalArr(args.slice(1), undefined, this.convertSourceSpan(ast.span)) ]); } visitKeyedRead(ast, mode) { const leftMostSafe = this.leftMostSafeNode(ast); if (leftMostSafe) { return this.convertSafeAccess(ast, leftMostSafe, mode); } else { return convertToStatementIfNeeded(mode, this._visit(ast.receiver, _Mode.Expression).key(this._visit(ast.key, _Mode.Expression))); } } visitKeyedWrite(ast, mode) { const obj = this._visit(ast.receiver, _Mode.Expression); const key = this._visit(ast.key, _Mode.Expression); const value = this._visit(ast.value, _Mode.Expression); if (obj === this._implicitReceiver) { this._localResolver.maybeRestoreView(); } return convertToStatementIfNeeded(mode, obj.key(key).set(value)); } visitLiteralArray(ast, mode) { throw new Error(`Illegal State: literal arrays should have been converted into functions`); } visitLiteralMap(ast, mode) { throw new Error(`Illegal State: literal maps should have been converted into functions`); } visitLiteralPrimitive(ast, mode) { // For literal values of null, undefined, true, or false allow type interference // to infer the type. const type = ast.value === null || ast.value === undefined || ast.value === true || ast.value === true ? INFERRED_TYPE : undefined; return convertToStatementIfNeeded(mode, literal(ast.value, type, this.convertSourceSpan(ast.span))); } _getLocal(name, receiver) { var _a; if (((_a = this._localResolver.globals) === null || _a === void 0 ? void 0 : _a.has(name)) && receiver instanceof ThisReceiver) { return null; } return this._localResolver.getLocal(name); } visitMethodCall(ast, mode) { if (ast.receiver instanceof ImplicitReceiver && !(ast.receiver instanceof ThisReceiver) && ast.name === '$any') { const args = this.visitAll(ast.args, _Mode.Expression); if (args.length != 1) { throw new Error(`Invalid call to $any, expected 1 argument but received ${args.length || 'none'}`); } return args[0].cast(DYNAMIC_TYPE, this.convertSourceSpan(ast.span)); } const leftMostSafe = this.leftMostSafeNode(ast); if (leftMostSafe) { return this.convertSafeAccess(ast, leftMostSafe, mode); } else { const args = this.visitAll(ast.args, _Mode.Expression); const prevUsesImplicitReceiver = this.usesImplicitReceiver; let result = null; const receiver = this._visit(ast.receiver, _Mode.Expression); if (receiver === this._implicitReceiver) { const varExpr = this._getLocal(ast.name, ast.receiver); if (varExpr) { // Restore the previous "usesImplicitReceiver" state since the implicit // receiver has been replaced with a resolved local expression. this.usesImplicitReceiver = prevUsesImplicitReceiver; result = varExpr.callFn(args); this.addImplicitReceiverAccess(ast.name); } } if (result == null) { result = receiver.callMethod(ast.name, args, this.convertSourceSpan(ast.span)); } return convertToStatementIfNeeded(mode, result); } } visitPrefixNot(ast, mode) { return convertToStatementIfNeeded(mode, not(this._visit(ast.expression, _Mode.Expression))); } visitNonNullAssert(ast, mode) { return convertToStatementIfNeeded(mode, assertNotNull(this._visit(ast.expression, _Mode.Expression))); } visitPropertyRead(ast, mode) { const leftMostSafe = this.leftMostSafeNode(ast); if (leftMostSafe) { return this.convertSafeAccess(ast, leftMostSafe, mode); } else { let result = null; const prevUsesImplicitReceiver = this.usesImplicitReceiver; const receiver = this._visit(ast.receiver, _Mode.Expression); if (receiver === this._implicitReceiver) { result = this._getLocal(ast.name, ast.receiver); if (result) { // Restore the previous "usesImplicitReceiver" state since the implicit // receiver has been replaced with a resolved local expression. this.usesImplicitReceiver = prevUsesImplicitReceiver; this.addImplicitReceiverAccess(ast.name); } } if (result == null) { result = receiver.prop(ast.name); } return convertToStatementIfNeeded(mode, result); } } visitPropertyWrite(ast, mode) { const receiver = this._visit(ast.receiver, _Mode.Expression); const prevUsesImplicitReceiver = this.usesImplicitReceiver; let varExpr = null; if (receiver === this._implicitReceiver) { const localExpr = this._getLocal(ast.name, ast.receiver); if (localExpr) { if (localExpr instanceof ReadPropExpr) { // If the local variable is a property read expression, it's a reference // to a 'context.property' value and will be used as the target of the // write expression. varExpr = localExpr; // Restore the previous "usesImplicitReceiver" state since the implicit // receiver has been replaced with a resolved local expression. this.usesImplicitReceiver = prevUsesImplicitReceiver; this.addImplicitReceiverAccess(ast.name); } else { // Otherwise it's an error. const receiver = ast.name; const value = (ast.value instanceof PropertyRead) ? ast.value.name : undefined; throw new Error(`Cannot assign value "${value}" to template variable "${receiver}". Template variables are read-only.`); } } } // If no local expression could be produced, use the original receiver's // property as the target. if (varExpr === null) { varExpr = receiver.prop(ast.name); } return convertToStatementIfNeeded(mode, varExpr.set(this._visit(ast.value, _Mode.Expression))); } visitSafePropertyRead(ast, mode) { return this.convertSafeAccess(ast, this.leftMostSafeNode(ast), mode); } visitSafeMethodCall(ast, mode) { return this.convertSafeAccess(ast, this.leftMostSafeNode(ast), mode); } visitSafeKeyedRead(ast, mode) { return this.convertSafeAccess(ast, this.leftMostSafeNode(ast), mode); } visitAll(asts, mode) { return asts.map(ast => this._visit(ast, mode)); } visitQuote(ast, mode) { throw new Error(`Quotes are not supported for evaluation! Statement: ${ast.uninterpretedExpression} located at ${ast.location}`); } _visit(ast, mode) { const result = this._resultMap.get(ast); if (result) return result; return (this._nodeMap.get(ast) || ast).visit(this, mode); } convertSafeAccess(ast, leftMostSafe, mode) { // If the expression contains a safe access node on the left it needs to be converted to // an expression that guards the access to the member by checking the receiver for blank. As // execution proceeds from left to right, the left most part of the expression must be guarded // first but, because member access is left associative, the right side of the expression is at // the top of the AST. The desired result requires lifting a copy of the left part of the // expression up to test it for blank before generating the unguarded version. // Consider, for example the following expression: a?.b.c?.d.e // This results in the ast: // . // / \ // ?. e // / \ // . d // / \ // ?. c // / \ // a b // The following tree should be generated: // // /---- ? ----\ // / | \ // a /--- ? ---\ null // / | \ // . . null // / \ / \ // . c . e // / \ / \ // a b . d // / \ // . c // / \ // a b // // Notice that the first guard condition is the left hand of the left most safe access node // which comes in as leftMostSafe to this routine. let guardedExpression = this._visit(leftMostSafe.receiver, _Mode.Expression); let temporary = undefined; if (this.needsTemporaryInSafeAccess(leftMostSafe.receiver)) { // If the expression has method calls or pipes then we need to save the result into a // temporary variable to avoid calling stateful or impure code more than once. temporary = this.allocateTemporary(); // Preserve the result in the temporary variable guardedExpression = temporary.set(guardedExpression); // Ensure all further references to the guarded expression refer to the temporary instead. this._resultMap.set(leftMostSafe.receiver, temporary); } const condition = guardedExpression.isBlank(); // Convert the ast to an unguarded access to the receiver's member. The map will substitute // leftMostNode with its unguarded version in the call to `this.visit()`. if (leftMostSafe instanceof SafeMethodCall) { this._nodeMap.set(leftMostSafe, new MethodCall(leftMostSafe.span, leftMostSafe.sourceSpan, leftMostSafe.nameSpan, leftMostSafe.receiver, leftMostSafe.name, leftMostSafe.args, leftMostSafe.argumentSpan)); } else if (leftMostSafe instanceof SafeKeyedRead) { this._nodeMap.set(leftMostSafe, new KeyedRead(leftMostSafe.span, leftMostSafe.sourceSpan, leftMostSafe.receiver, leftMostSafe.key)); } else { this._nodeMap.set(leftMostSafe, new PropertyRead(leftMostSafe.span, leftMostSafe.sourceSpan, leftMostSafe.nameSpan, leftMostSafe.receiver, leftMostSafe.name)); } // Recursively convert the node now without the guarded member access. const access = this._visit(ast, _Mode.Expression); // Remove the mapping. This is not strictly required as the converter only traverses each node // once but is safer if the conversion is changed to traverse the nodes more than once. this._nodeMap.delete(leftMostSafe); // If we allocated a temporary, release it. if (temporary) { this.releaseTemporary(temporary); } // Produce the conditional return convertToStatementIfNeeded(mode, condition.conditional(NULL_EXPR, access)); } convertNullishCoalesce(ast, mode) { const left = this._visit(ast.left, _Mode.Expression); const right = this._visit(ast.right, _Mode.Expression); const temporary = this.allocateTemporary(); this.releaseTemporary(temporary); // Generate the following expression. It is identical to how TS // transpiles binary expressions with a nullish coalescing operator. // let temp; // (temp = a) !== null && temp !== undefined ? temp : b; return convertToStatementIfNeeded(mode, temporary.set(left) .notIdentical(NULL_EXPR) .and(temporary.notIdentical(literal(undefined))) .conditional(temporary, right)); } // Given an expression of the form a?.b.c?.d.e then the left most safe node is // the (a?.b). The . and ?. are left associative thus can be rewritten as: // ((((a?.c).b).c)?.d).e. This returns the most deeply nested safe read or // safe method call as this needs to be transformed initially to: // a == null ? null : a.c.b.c?.d.e // then to: // a == null ? null : a.b.c == null ? null : a.b.c.d.e leftMostSafeNode(ast) { const visit = (visitor, ast) => { return (this._nodeMap.get(ast) || ast).visit(visitor); }; return ast.visit({ visitUnary(ast) { return null; }, visitBinary(ast) { return null; }, visitChain(ast) { return null; }, visitConditional(ast) { return null; }, visitFunctionCall(ast) { return null; }, visitImplicitReceiver(ast) { return null; }, visitThisReceiver(ast) { return null; }, visitInterpolation(ast) { return null; }, visitKeyedRead(ast) { return visit(this, ast.receiver); }, visitKeyedWrite(ast) { return null; }, visitLiteralArray(ast) { return null; }, visitLiteralMap(ast) { return null; }, visitLiteralPrimitive(ast) { return null; }, visitMethodCall(ast) { return visit(this, ast.receiver); }, visitPipe(ast) { return null; }, visitPrefixNot(ast) { return null; }, visitNonNullAssert(ast) { return null; }, visitPropertyRead(ast) { return visit(this, ast.receiver); }, visitPropertyWrite(ast) { return null; }, visitQuote(ast) { return null; }, visitSafeMethodCall(ast) { return visit(this, ast.receiver) || ast; }, visitSafePropertyRead(ast) { return visit(this, ast.receiver) || ast; }, visitSafeKeyedRead(ast) { return visit(this, ast.receiver) || ast; } }); } // Returns true of the AST includes a method or a pipe indicating that, if the // expression is used as the target of a safe property or method access then // the expression should be stored into a temporary variable. needsTemporaryInSafeAccess(ast) { const visit = (visitor, ast) => { return ast && (this._nodeMap.get(ast) || ast).visit(visitor); }; const visitSome = (visitor, ast) => { return ast.some(ast => visit(visitor, ast)); }; return ast.visit({ visitUnary(ast) { return visit(this, ast.expr); }, visitBinary(ast) { return visit(this, ast.left) || visit(this, ast.right); }, visitChain(ast) { return false; }, visitConditional(ast) { return visit(this, ast.condition) || visit(this, ast.trueExp) || visit(this, ast.falseExp); }, visitFunctionCall(ast) { return true; }, visitImplicitReceiver(ast) { return false; }, visitThisReceiver(ast) { return false; }, visitInterpolation(ast) { return visitSome(this, ast.expressions); }, visitKeyedRead(ast) { return false; }, visitKeyedWrite(ast) { return false; }, visitLiteralArray(ast) { return true; }, visitLiteralMap(ast) { return true; }, visitLiteralPrimitive(ast) { return false; }, visitMethodCall(ast) { return true; }, visitPipe(ast) { return true; }, visitPrefixNot(ast) { return visit(this, ast.expression); }, visitNonNullAssert(ast) { return visit(this, ast.expression); }, visitPropertyRead(ast) { return false; }, visitPropertyWrite(ast) { return false; }, visitQuote(ast) { return false; }, visitSafeMethodCall(ast) { return true; }, visitSafePropertyRead(ast) { return false; }, visitSafeKeyedRead(ast) { return false; } }); } allocateTemporary() { const tempNumber = this._currentTemporary++; this.temporaryCount = Math.max(this._currentTemporary, this.temporaryCount); return new ReadVarExpr(temporaryName(this.bindingId, tempNumber)); } releaseTemporary(temporary) { this._currentTemporary--; if (temporary.name != temporaryName(this.bindingId, this._currentTemporary)) { throw new Error(`Temporary ${temporary.name} released out of order`); } } /** * Creates an absolute `ParseSourceSpan` from the relative `ParseSpan`. * * `ParseSpan` objects are relative to the start of the expression. * This method converts these to full `ParseSourceSpan` objects that * show where the span is within the overall source file. * * @param span the relative span to convert. * @returns a `ParseSourceSpan` for the given span or null if no * `baseSourceSpan` was provided to this class. */ convertSourceSpan(span) { if (this.baseSourceSpan) { const start = this.baseSourceSpan.start.moveBy(span.start); const end = this.baseSourceSpan.start.moveBy(span.end); const fullStart = this.baseSourceSpan.fullStart.moveBy(span.start); return new ParseSourceSpan(start, end, fullStart); } else { return null; } } /** Adds the name of an AST to the list of implicit receiver accesses. */ addImplicitReceiverAccess(name) { if (this.implicitReceiverAccesses) { this.implicitReceiverAccesses.add(name); } } } function flattenStatements(arg, output) { if (Array.isArray(arg)) { arg.forEach((entry) => flattenStatements(entry, output)); } else { output.push(arg); } } class DefaultLocalResolver { constructor(globals) { this.globals = globals; } notifyImplicitReceiverUse() { } maybeRestoreView() { } getLocal(name) { if (name === EventHandlerVars.event.name) { return EventHandlerVars.event; } return null; } } function createCurrValueExpr(bindingId) { return variable(`currVal_${bindingId}`); // fix syntax highlighting: ` } function createPreventDefaultVar(bindingId) { return variable(`pd_${bindingId}`); } function convertStmtIntoExpression(stmt) { if (stmt instanceof ExpressionStatement) { return stmt.expr; } else if (stmt instanceof ReturnStatement) { return stmt.value; } return null; } class BuiltinFunctionCall extends FunctionCall { constructor(span, sourceSpan, args, converter) { super(span, sourceSpan, null, args); this.converter = converter; } } /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ // ================================================================================================= // ================================================================================================= // =========== S T O P - S T O P - S T O P - S T O P - S T O P - S T O P =========== // ================================================================================================= // ================================================================================================= // // DO NOT EDIT THIS LIST OF SECURITY SENSITIVE PROPERTIES WITHOUT A SECURITY REVIEW! // Reach out to mprobst for details. // // ================================================================================================= /** Map from tagName|propertyName to SecurityContext. Properties applying to all tags use '*'. */ let _SECURITY_SCHEMA; function SECURITY_SCHEMA() { if (!_SECURITY_SCHEMA) { _SECURITY_SCHEMA = {}; // Case is insignificant below, all element and attribute names are lower-cased for lookup. registerContext(SecurityContext.HTML, [ 'iframe|srcdoc', '*|innerHTML', '*|outerHTML', ]); registerContext(SecurityContext.STYLE, ['*|style']); // NB: no SCRIPT contexts here, they are never allowed due to the parser stripping them. registerContext(SecurityContext.URL, [ '*|formAction', 'area|href', 'area|ping', 'audio|src', 'a|href', 'a|ping', 'blockquote|cite', 'body|background', 'del|cite', 'form|action', 'img|src', 'img|srcset', 'input|src', 'ins|cite', 'q|cite', 'source|src', 'source|srcset', 'track|src', 'video|poster', 'video|src', ]); registerContext(SecurityContext.RESOURCE_URL, [ 'applet|code', 'applet|codebase', 'base|href', 'embed|src', 'frame|src', 'head|profile', 'html|manifest', 'iframe|src', 'link|href', 'media|src', 'object|codebase', 'object|data', 'script|src', ]); } return _SECURITY_SCHEMA; } function registerContext(ctx, specs) { for (const spec of specs) _SECURITY_SCHEMA[spec.toLowerCase()] = ctx; } /** * The set of security-sensitive attributes of an `