/** * @license Angular v15.0.4 * Copyright Google LLC All Rights Reserved. * License: MIT */ let $deferred; function define(modules, callback) { $deferred = {modules, callback}; } module.exports = function(provided) { const ts = provided['typescript']; if (!ts) { throw new Error('Caller does not provide typescript module'); } const results = {}; const resolvedModules = $deferred.modules.map(m => { if (m === 'exports') { return results; } if (m === 'typescript' || m === 'typescript/lib/tsserverlibrary') { return ts; } return require(m); }); $deferred.callback(...resolvedModules); return results; }; define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', 'module', 'path', 'url'], (function (exports, ts$1, os, ts, fs$1, module, p, url) { 'use strict'; function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } function _interopNamespace(e) { if (e && e.__esModule) return e; var n = Object.create(null); if (e) { Object.keys(e).forEach(function (k) { if (k !== 'default') { var d = Object.getOwnPropertyDescriptor(e, k); Object.defineProperty(n, k, d.get ? d : { enumerable: true, get: function () { return e[k]; } }); } }); } n["default"] = e; return Object.freeze(n); } var ts__namespace = /*#__PURE__*/_interopNamespace(ts$1); var ts__default = /*#__PURE__*/_interopDefaultLegacy(ts); var fs__namespace = /*#__PURE__*/_interopNamespace(fs$1); var module__default = /*#__PURE__*/_interopDefaultLegacy(module); var p__namespace = /*#__PURE__*/_interopNamespace(p); /** * The default `FileSystem` that will always fail. * * This is a way of ensuring that the developer consciously chooses and * configures the `FileSystem` before using it; particularly important when * considering static functions like `absoluteFrom()` which rely on * the `FileSystem` under the hood. */ class InvalidFileSystem { exists(path) { throw makeError(); } readFile(path) { throw makeError(); } readFileBuffer(path) { throw makeError(); } writeFile(path, data, exclusive) { throw makeError(); } removeFile(path) { throw makeError(); } symlink(target, path) { throw makeError(); } readdir(path) { throw makeError(); } lstat(path) { throw makeError(); } stat(path) { throw makeError(); } pwd() { throw makeError(); } chdir(path) { throw makeError(); } extname(path) { throw makeError(); } copyFile(from, to) { throw makeError(); } moveFile(from, to) { throw makeError(); } ensureDir(path) { throw makeError(); } removeDeep(path) { throw makeError(); } isCaseSensitive() { throw makeError(); } resolve(...paths) { throw makeError(); } dirname(file) { throw makeError(); } join(basePath, ...paths) { throw makeError(); } isRoot(path) { throw makeError(); } isRooted(path) { throw makeError(); } relative(from, to) { throw makeError(); } basename(filePath, extension) { throw makeError(); } realpath(filePath) { throw makeError(); } getDefaultLibLocation() { throw makeError(); } normalize(path) { throw makeError(); } } function makeError() { return new Error('FileSystem has not been configured. Please call `setFileSystem()` before calling this method.'); } const TS_DTS_JS_EXTENSION = /(?:\.d)?\.ts$|\.js$/; /** * Remove a .ts, .d.ts, or .js extension from a file name. */ function stripExtension(path) { return path.replace(TS_DTS_JS_EXTENSION, ''); } function getSourceFileOrError(program, fileName) { const sf = program.getSourceFile(fileName); if (sf === undefined) { throw new Error(`Program does not contain "${fileName}" - available files are ${program.getSourceFiles().map(sf => sf.fileName).join(', ')}`); } return sf; } let fs = new InvalidFileSystem(); function getFileSystem() { return fs; } function setFileSystem(fileSystem) { fs = fileSystem; } /** * Convert the path `path` to an `AbsoluteFsPath`, throwing an error if it's not an absolute path. */ function absoluteFrom(path) { if (!fs.isRooted(path)) { throw new Error(`Internal Error: absoluteFrom(${path}): path is not absolute`); } return fs.resolve(path); } const ABSOLUTE_PATH = Symbol('AbsolutePath'); /** * Extract an `AbsoluteFsPath` from a `ts.SourceFile`-like object. */ function absoluteFromSourceFile(sf) { const sfWithPatch = sf; if (sfWithPatch[ABSOLUTE_PATH] === undefined) { sfWithPatch[ABSOLUTE_PATH] = fs.resolve(sfWithPatch.fileName); } // Non-null assertion needed since TS doesn't narrow the type of fields that use a symbol as a key // apparently. return sfWithPatch[ABSOLUTE_PATH]; } /** * Static access to `dirname`. */ function dirname(file) { return fs.dirname(file); } /** * Static access to `join`. */ function join(basePath, ...paths) { return fs.join(basePath, ...paths); } /** * Static access to `resolve`s. */ function resolve(basePath, ...paths) { return fs.resolve(basePath, ...paths); } /** * Static access to `isRooted`. */ function isRooted(path) { return fs.isRooted(path); } /** * Static access to `relative`. */ function relative(from, to) { return fs.relative(from, to); } /** * Returns true if the given path is locally relative. * * This is used to work out if the given path is relative (i.e. not absolute) but also is not * escaping the current directory. */ function isLocalRelativePath(relativePath) { return !isRooted(relativePath) && !relativePath.startsWith('..'); } /** * Converts a path to a form suitable for use as a relative module import specifier. * * In other words it adds the `./` to the path if it is locally relative. */ function toRelativeImport(relativePath) { return isLocalRelativePath(relativePath) ? `./${relativePath}` : relativePath; } const LogicalProjectPath = { /** * Get the relative path between two `LogicalProjectPath`s. * * This will return a `PathSegment` which would be a valid module specifier to use in `from` when * importing from `to`. */ relativePathBetween: function (from, to) { const relativePath = relative(dirname(resolve(from)), resolve(to)); return toRelativeImport(relativePath); }, }; /** * A utility class which can translate absolute paths to source files into logical paths in * TypeScript's logical file system, based on the root directories of the project. */ class LogicalFileSystem { constructor(rootDirs, compilerHost) { this.compilerHost = compilerHost; /** * A cache of file paths to project paths, because computation of these paths is slightly * expensive. */ this.cache = new Map(); // Make a copy and sort it by length in reverse order (longest first). This speeds up lookups, // since there's no need to keep going through the array once a match is found. this.rootDirs = rootDirs.concat([]).sort((a, b) => b.length - a.length); this.canonicalRootDirs = this.rootDirs.map(dir => this.compilerHost.getCanonicalFileName(dir)); } /** * Get the logical path in the project of a `ts.SourceFile`. * * This method is provided as a convenient alternative to calling * `logicalPathOfFile(absoluteFromSourceFile(sf))`. */ logicalPathOfSf(sf) { return this.logicalPathOfFile(absoluteFromSourceFile(sf)); } /** * Get the logical path in the project of a source file. * * @returns A `LogicalProjectPath` to the source file, or `null` if the source file is not in any * of the TS project's root directories. */ logicalPathOfFile(physicalFile) { if (!this.cache.has(physicalFile)) { const canonicalFilePath = this.compilerHost.getCanonicalFileName(physicalFile); let logicalFile = null; for (let i = 0; i < this.rootDirs.length; i++) { const rootDir = this.rootDirs[i]; const canonicalRootDir = this.canonicalRootDirs[i]; if (isWithinBasePath(canonicalRootDir, canonicalFilePath)) { // Note that we match against canonical paths but then create the logical path from // original paths. logicalFile = this.createLogicalProjectPath(physicalFile, rootDir); // The logical project does not include any special "node_modules" nested directories. if (logicalFile.indexOf('/node_modules/') !== -1) { logicalFile = null; } else { break; } } } this.cache.set(physicalFile, logicalFile); } return this.cache.get(physicalFile); } createLogicalProjectPath(file, rootDir) { const logicalPath = stripExtension(file.slice(rootDir.length)); return (logicalPath.startsWith('/') ? logicalPath : '/' + logicalPath); } } /** * Is the `path` a descendant of the `base`? * E.g. `foo/bar/zee` is within `foo/bar` but not within `foo/car`. */ function isWithinBasePath(base, path) { return isLocalRelativePath(relative(base, path)); } /** * @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 wrapper around the Node.js file-system that supports path manipulation. */ class NodeJSPathManipulation { pwd() { return this.normalize(process.cwd()); } chdir(dir) { process.chdir(dir); } resolve(...paths) { return this.normalize(p__namespace.resolve(...paths)); } dirname(file) { return this.normalize(p__namespace.dirname(file)); } join(basePath, ...paths) { return this.normalize(p__namespace.join(basePath, ...paths)); } isRoot(path) { return this.dirname(path) === this.normalize(path); } isRooted(path) { return p__namespace.isAbsolute(path); } relative(from, to) { return this.normalize(p__namespace.relative(from, to)); } basename(filePath, extension) { return p__namespace.basename(filePath, extension); } extname(path) { return p__namespace.extname(path); } normalize(path) { // Convert backslashes to forward slashes return path.replace(/\\/g, '/'); } } // CommonJS/ESM interop for determining the current file name and containing // directory. These paths are needed for detecting whether the file system // is case sensitive, or for finding the TypeScript default libraries. // TODO(devversion): Simplify this in the future if devmode uses ESM as well. const isCommonJS = typeof __filename !== 'undefined'; const currentFileUrl = isCommonJS ? null : __ESM_IMPORT_META_URL__; const currentFileName = isCommonJS ? __filename : url.fileURLToPath(currentFileUrl); /** * A wrapper around the Node.js file-system that supports readonly operations and path manipulation. */ class NodeJSReadonlyFileSystem extends NodeJSPathManipulation { constructor() { super(...arguments); this._caseSensitive = undefined; } isCaseSensitive() { if (this._caseSensitive === undefined) { // Note the use of the real file-system is intentional: // `this.exists()` relies upon `isCaseSensitive()` so that would cause an infinite recursion. this._caseSensitive = !fs__namespace.existsSync(this.normalize(toggleCase(currentFileName))); } return this._caseSensitive; } exists(path) { return fs__namespace.existsSync(path); } readFile(path) { return fs__namespace.readFileSync(path, 'utf8'); } readFileBuffer(path) { return fs__namespace.readFileSync(path); } readdir(path) { return fs__namespace.readdirSync(path); } lstat(path) { return fs__namespace.lstatSync(path); } stat(path) { return fs__namespace.statSync(path); } realpath(path) { return this.resolve(fs__namespace.realpathSync(path)); } getDefaultLibLocation() { // TODO(devversion): Once devmode output uses ESM, we can simplify this. const requireFn = isCommonJS ? require : module__default["default"].createRequire(currentFileUrl); return this.resolve(requireFn.resolve('typescript'), '..'); } } /** * A wrapper around the Node.js file-system (i.e. the `fs` package). */ class NodeJSFileSystem extends NodeJSReadonlyFileSystem { writeFile(path, data, exclusive = false) { fs__namespace.writeFileSync(path, data, exclusive ? { flag: 'wx' } : undefined); } removeFile(path) { fs__namespace.unlinkSync(path); } symlink(target, path) { fs__namespace.symlinkSync(target, path); } copyFile(from, to) { fs__namespace.copyFileSync(from, to); } moveFile(from, to) { fs__namespace.renameSync(from, to); } ensureDir(path) { fs__namespace.mkdirSync(path, { recursive: true }); } removeDeep(path) { fs__namespace.rmdirSync(path, { recursive: true }); } } /** * Toggle the case of each character in a string. */ function toggleCase(str) { return str.replace(/\w/g, ch => ch.toUpperCase() === ch ? ch.toLowerCase() : ch.toUpperCase()); } /** * @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 ?? 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) { 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-insensitive lookup, because // HTML tag names are case insensitive, whereas some SVG tags are case sensitive. return TAG_DEFINITIONS[tagName] ?? TAG_DEFINITIONS[tagName.toLowerCase()] ?? _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 /* SelectorRegexp.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 /* SelectorRegexp.TAG */]; if (tag) { const prefix = match[3 /* SelectorRegexp.PREFIX */]; if (prefix === '#') { // #hash current.addAttribute('id', tag.slice(1)); } else if (prefix === '.') { // Class current.addClassName(tag.slice(1)); } else { // Element current.setElement(tag); } } const attribute = match[4 /* SelectorRegexp.ATTRIBUTE */]; if (attribute) { current.addAttribute(current.unescapeAttribute(attribute), match[6 /* SelectorRegexp.ATTRIBUTE_VALUE */]); } if (match[7 /* SelectorRegexp.NOT_END */]) { inNot = false; current = cssSelector; } if (match[8 /* SelectorRegexp.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 */ // Stores the default value of `emitDistinctChangesOnly` when the `emitDistinctChangesOnly` is not // explicitly set. const emitDistinctChangesOnlyDefaultValue = true; 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 CUSTOM_ELEMENTS_SCHEMA = { name: 'custom-elements' }; const NO_ERRORS_SCHEMA = { name: 'no-errors-schema' }; 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 parserSelectorToSimpleSelector(selector) { const classes = selector.classNames && selector.classNames.length ? [8 /* SelectorFlags.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 /* SelectorFlags.CLASS */, ...selector.classNames] : []; if (selector.element) { return [ 1 /* SelectorFlags.NOT */ | 4 /* SelectorFlags.ELEMENT */, selector.element, ...selector.attrs, ...classes ]; } else if (selector.attrs.length) { return [1 /* SelectorFlags.NOT */ | 2 /* SelectorFlags.ATTRIBUTE */, ...selector.attrs, ...classes]; } else { return selector.classNames && selector.classNames.length ? [1 /* SelectorFlags.NOT */ | 8 /* SelectorFlags.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) : []; } /** * @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 error(msg) { throw new Error(`Internal Error: ${msg}`); } 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); } 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('.'); } } // Check `global` first, because in Node tests both `global` and `window` may be defined and our // `_global` variable should point to the NodeJS `global` in that case. Note: Typeof/Instanceof // checks are considered side-effects in Terser. We explicitly mark this as side-effect free: // https://github.com/terser/terser/issues/250. const _global = ( /* @__PURE__ */(() => (typeof global !== 'undefined' && global) || (typeof window !== 'undefined' && window) || (typeof self !== 'undefined' && typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope && 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 */ /** * 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 */ /** * 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$1 = new _SerializerVisitor(); function serializeNodes(nodes) { return nodes.map(a => a.visit(serializerVisitor$1, 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 */ //// Types var TypeModifier; (function (TypeModifier) { TypeModifier[TypeModifier["None"] = 0] = "None"; TypeModifier[TypeModifier["Const"] = 1] = "Const"; })(TypeModifier || (TypeModifier = {})); class Type { constructor(modifiers = TypeModifier.None) { this.modifiers = modifiers; } hasModifier(modifier) { return (this.modifiers & modifier) !== 0; } } 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 { constructor(name, modifiers) { super(modifiers); this.name = name; } visitType(visitor, context) { return visitor.visitBuiltinType(this, context); } } class ExpressionType extends Type { constructor(value, modifiers, typeParams = null) { super(modifiers); this.value = value; this.typeParams = typeParams; } visitType(visitor, context) { return visitor.visitExpressionType(this, context); } } const DYNAMIC_TYPE = new BuiltinType(BuiltinTypeName.Dynamic); const INFERRED_TYPE = new BuiltinType(BuiltinTypeName.Inferred); const BOOL_TYPE = new BuiltinType(BuiltinTypeName.Bool); new BuiltinType(BuiltinTypeName.Int); const NUMBER_TYPE = new BuiltinType(BuiltinTypeName.Number); const STRING_TYPE = new BuiltinType(BuiltinTypeName.String); 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); } 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); } nullishCoalesce(rhs, sourceSpan) { return new BinaryOperatorExpr(BinaryOperator.NullishCoalesce, this, rhs, null, sourceSpan); } toStmt() { return new ExpressionStatement(this, null); } } class ReadVarExpr extends Expression { constructor(name, type, sourceSpan) { super(type, sourceSpan); this.name = name; } isEquivalent(e) { return e instanceof ReadVarExpr && this.name === e.name; } isConstant() { return false; } visitExpression(visitor, context) { return visitor.visitReadVarExpr(this, context); } set(value) { 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); } } 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) { 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 = rawText ?? sourceSpan?.toString() ?? escapeForTemplateLiteral(escapeSlashes(text)); } } class LiteralPiece { constructor(text, sourceSpan) { this.text = text; this.sourceSpan = sourceSpan; } } class PlaceholderPiece { /** * Create a new instance of a `PlaceholderPiece`. * * @param text the name of this placeholder (e.g. `PH_1`). * @param sourceSpan the location of this placeholder in its localized message the source code. * @param associatedMessage reference to another message that this placeholder is associated with. * The `associatedMessage` is mainly used to provide a relationship to an ICU message that has * been extracted out from the message containing the placeholder. */ constructor(text, sourceSpan, associatedMessage) { this.text = text; this.sourceSpan = sourceSpan; this.associatedMessage = associatedMessage; } } const MEANING_SEPARATOR = '|'; const ID_SEPARATOR = '@@'; const LEGACY_ID_INDICATOR = '␟'; 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() { 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) { return this.messageParts[i]?.sourceSpan ?? this.sourceSpan; } getPlaceholderSourceSpan(i) { return this.placeHolderNames[i]?.sourceSpan ?? this.expressions[i]?.sourceSpan ?? this.sourceSpan; } /** * Serialize the given `placeholderName` and `messagePart` into "cooked" and "raw" strings that * can be used in a `$localize` tagged string. * * The format is `:[@@]:`. * * The `associated-id` is the message id of the (usually an ICU) message to which this placeholder * refers. * * @param partIndex The index of the message part to serialize. */ serializeI18nTemplatePart(partIndex) { const placeholder = this.placeHolderNames[partIndex - 1]; const messagePart = this.messageParts[partIndex]; let metaBlock = placeholder.text; if (placeholder.associatedMessage?.legacyIds.length === 0) { metaBlock += `${ID_SEPARATOR}${computeMsgId(placeholder.associatedMessage.messageString, placeholder.associatedMessage.meaning)}`; } return createCookedRawString(metaBlock, 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 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); } } 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["None"] = 0] = "None"; StmtModifier[StmtModifier["Final"] = 1] = "Final"; StmtModifier[StmtModifier["Private"] = 2] = "Private"; StmtModifier[StmtModifier["Exported"] = 4] = "Exported"; StmtModifier[StmtModifier["Static"] = 8] = "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 = StmtModifier.None, sourceSpan = null, leadingComments) { this.modifiers = modifiers; this.sourceSpan = sourceSpan; this.leadingComments = leadingComments; } hasModifier(modifier) { return (this.modifiers & modifier) !== 0; } addLeadingComment(leadingComment) { this.leadingComments = this.leadingComments ?? []; 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(StmtModifier.None, 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(StmtModifier.None, 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 IfStmt extends Statement { constructor(condition, trueCase, falseCase = [], sourceSpan, leadingComments) { super(StmtModifier.None, 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); } } 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 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 not(expr, sourceSpan) { return new NotExpr(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$1(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.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 unnecessary call. definition = variable(name).set(literal); usage = variable(name); } this.statements.push(definition.toDeclStmt(INFERRED_TYPE, StmtModifier.Final)); fixup.fixup(usage); } 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++}`; } 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$1; this.visitWriteVarExpr = invalid$1; this.visitWriteKeyExpr = invalid$1; this.visitWritePropExpr = invalid$1; this.visitInvokeFunctionExpr = invalid$1; this.visitTaggedTemplateExpr = invalid$1; this.visitInstantiateExpr = invalid$1; this.visitConditionalExpr = invalid$1; this.visitNotExpr = invalid$1; this.visitAssertNotNullExpr = invalid$1; this.visitCastExpr = invalid$1; this.visitFunctionExpr = invalid$1; this.visitUnaryOperatorExpr = invalid$1; this.visitBinaryOperatorExpr = invalid$1; this.visitReadPropExpr = invalid$1; this.visitReadKeyExpr = invalid$1; this.visitCommaExpr = invalid$1; this.visitLocalizedString = invalid$1; } 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$1(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.resetView = { name: 'ɵɵresetView', 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.registerNgModuleType = { name: 'ɵɵregisterNgModuleType', 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.StandaloneFeature = { name: 'ɵɵStandaloneFeature', moduleName: CORE }; Identifiers.ProvidersFeature = { name: 'ɵɵProvidersFeature', moduleName: CORE }; Identifiers.HostDirectivesFeature = { name: 'ɵɵHostDirectivesFeature', 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 */ // 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 = ' '; class _EmittedLine { constructor(indent) { this.indent = indent; this.partsLength = 0; this.parts = []; this.srcSpans = []; } } class EmitterVisitorContext { constructor(_indent) { this._indent = _indent; 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; } } 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; } spanOf(line, column) { const emittedLine = this._lines[line]; 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; } 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; } 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) { ctx.print(ast, ast.name); 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; } 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$1('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 /* ForwardRefHandling.None */: case 1 /* ForwardRefHandling.Wrapped */: return expression; case 2 /* ForwardRefHandling.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$1; (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$1 || (FactoryTarget$1 = {})); /** * 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$1(index)]); } else if (dep.attributeNameType === null) { // Build up the injection flags according to the metadata. const flags = 0 /* InjectFlags.Default */ | (dep.self ? 2 /* InjectFlags.Self */ : 0) | (dep.skipSelf ? 4 /* InjectFlags.SkipSelf */ : 0) | (dep.host ? 1 /* InjectFlags.Host */ : 0) | (dep.optional ? 8 /* InjectFlags.Optional */ : 0) | (target === FactoryTarget$1.Pipe ? 16 /* InjectFlags.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 /* InjectFlags.Default */ || dep.optional) ? literal$1(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$1(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$1(true), quoted: false }); } if (dep.host) { entries.push({ key: 'host', value: literal$1(true), quoted: false }); } if (dep.self) { entries.push({ key: 'self', value: literal$1(true), quoted: false }); } if (dep.skipSelf) { entries.push({ key: 'skipSelf', value: literal$1(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$1.Component: case FactoryTarget$1.Directive: case FactoryTarget$1.Pipe: return Identifiers.directiveInject; case FactoryTarget$1.NgModule: case FactoryTarget$1.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$1 { constructor(value, sourceSpan) { this.value = value; this.sourceSpan = sourceSpan; } visit(_visitor) { throw new Error('visit() not implemented for Comment'); } } class Text$2 { 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 /* ParsedEventType.Regular */ ? event.targetOrPhase : null; const phase = event.type === 1 /* ParsedEventType.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$1 { 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 is the name of the container element, if applicable. // `null` is a special case for when there is a structural directive on an `ng-template` so // the renderer can differentiate between the synthetic template and the one written in the // file. 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$1 { 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$1 { constructor(vars, placeholders, sourceSpan, i18n) { this.vars = vars; this.placeholders = placeholders; this.sourceSpan = sourceSpan; this.i18n = i18n; } visit(visitor) { return visitor.visitIcu(this); } } class RecursiveVisitor { visitElement(element) { visitAll$1(this, element.attributes); visitAll$1(this, element.inputs); visitAll$1(this, element.outputs); visitAll$1(this, element.children); visitAll$1(this, element.references); } visitTemplate(template) { visitAll$1(this, template.attributes); visitAll$1(this, template.inputs); visitAll$1(this, template.outputs); visitAll$1(this, template.children); visitAll$1(this, template.references); visitAll$1(this, template.variables); } visitContent(content) { } visitVariable(variable) { } visitReference(reference) { } visitTextAttribute(attribute) { } visitBoundAttribute(attribute) { } visitBoundEvent(attribute) { } visitText(text) { } visitBoundText(text) { } visitIcu(icu) { } } function visitAll$1(visitor, nodes) { const result = []; if (visitor.visit) { for (const node of nodes) { visitor.visit(node) || node.visit(visitor); } } else { for (const node of nodes) { const newNode = node.visit(visitor); if (newNode) { result.push(newNode); } } } 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 */ 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 = []; this.messageString = serializeMessage(this.nodes); 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 { 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); } } /** * Serialize the message to the Localize backtick string format that would appear in compiled code. */ function serializeMessage(messageNodes) { const visitor = new LocalizeMessageStringVisitor(); const str = messageNodes.map(n => n.visit(visitor)).join(''); return str; } class LocalizeMessageStringVisitor { visitText(text) { return text.value; } visitContainer(container) { return container.children.map(child => child.visit(this)).join(''); } visitIcu(icu) { const strCases = Object.keys(icu.cases).map((k) => `${k} {${icu.cases[k].visit(this)}}`); return `{${icu.expressionPlaceholder}, ${icu.type}, ${strCases.join(' ')}}`; } visitTagPlaceholder(ph) { const children = ph.children.map(child => child.visit(this)).join(''); return `{$${ph.startName}}${children}{$${ph.closeName}}`; } visitPlaceholder(ph) { return `{$${ph.name}}`; } visitIcuPlaceholder(ph) { return `{$${ph.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 */ // 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; } 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$1(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 formatI18nPlaceholderNamesInMap(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'; /** * Maximum length of a single instruction chain. Because our output AST uses recursion, we're * limited in how many expressions we can nest before we reach the call stack limit. This * length is set very conservatively in order to reduce the chance of problems. */ const MAX_CHAIN_LENGTH = 500; /** Instructions that support chaining. */ const CHAINABLE_INSTRUCTIONS = new Set([ Identifiers.element, Identifiers.elementStart, Identifiers.elementEnd, Identifiers.elementContainer, Identifiers.elementContainerStart, Identifiers.elementContainerEnd, Identifiers.i18nExp, Identifiers.listener, Identifiers.classProp, Identifiers.syntheticHostListener, Identifiers.hostProperty, Identifiers.syntheticHostProperty, Identifiers.property, Identifiers.propertyInterpolate1, Identifiers.propertyInterpolate2, Identifiers.propertyInterpolate3, Identifiers.propertyInterpolate4, Identifiers.propertyInterpolate5, Identifiers.propertyInterpolate6, Identifiers.propertyInterpolate7, Identifiers.propertyInterpolate8, Identifiers.propertyInterpolateV, Identifiers.attribute, Identifiers.attributeInterpolate1, Identifiers.attributeInterpolate2, Identifiers.attributeInterpolate3, Identifiers.attributeInterpolate4, Identifiers.attributeInterpolate5, Identifiers.attributeInterpolate6, Identifiers.attributeInterpolate7, Identifiers.attributeInterpolate8, Identifiers.attributeInterpolateV, Identifiers.styleProp, Identifiers.stylePropInterpolate1, Identifiers.stylePropInterpolate2, Identifiers.stylePropInterpolate3, Identifiers.stylePropInterpolate4, Identifiers.stylePropInterpolate5, Identifiers.stylePropInterpolate6, Identifiers.stylePropInterpolate7, Identifiers.stylePropInterpolate8, Identifiers.stylePropInterpolateV, Identifiers.textInterpolate, Identifiers.textInterpolate1, Identifiers.textInterpolate2, Identifiers.textInterpolate3, Identifiers.textInterpolate4, Identifiers.textInterpolate5, Identifiers.textInterpolate6, Identifiers.textInterpolate7, Identifiers.textInterpolate8, Identifiers.textInterpolateV, ]); /** Generates a call to a single instruction. */ function invokeInstruction(span, reference, params) { return importExpr(reference, null, span).callFn(params, span); } /** * 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 invalid(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$1(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` 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 { minifiedName = declaredName = key; publicName = value; needsDeclaredName = false; } 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$1(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 /* ForwardRefHandling.None */: case 2 /* ForwardRefHandling.Unwrapped */: return query.predicate.expression; case 1 /* ForwardRefHandling.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; } /** * 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; } } /** * Generates the final instruction call statements based on the passed in configuration. * Will try to chain instructions as much as possible, if chaining is supported. */ function getInstructionStatements(instructions) { const statements = []; let pendingExpression = null; let pendingExpressionType = null; let chainLength = 0; for (const current of instructions) { const resolvedParams = (typeof current.paramsOrFn === 'function' ? current.paramsOrFn() : current.paramsOrFn) ?? []; const params = Array.isArray(resolvedParams) ? resolvedParams : [resolvedParams]; // If the current instruction is the same as the previous one // and it can be chained, add another call to the chain. if (chainLength < MAX_CHAIN_LENGTH && pendingExpressionType === current.reference && CHAINABLE_INSTRUCTIONS.has(pendingExpressionType)) { // We'll always have a pending expression when there's a pending expression type. pendingExpression = pendingExpression.callFn(params, pendingExpression.sourceSpan); chainLength++; } else { if (pendingExpression !== null) { statements.push(pendingExpression.toStmt()); } pendingExpression = invokeInstruction(current.span, current.reference, params); pendingExpressionType = current.reference; chainLength = 0; } } // Since the current instruction adds the previous one to the statements, // we may be left with the final one at the end that is still pending. if (pendingExpression !== null) { statements.push(pendingExpression.toStmt()); } return statements; } /** * @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$1.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({ ...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({ ...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({ ...factoryMeta, expression: meta.useValue.expression, }); } else if (meta.useExisting !== undefined) { // useExisting is an `inject` call on the existing token. result = compileFactoryFunction({ ...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.prop('ɵfac').callFn([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 */ 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 */ 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 $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.substring(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}`; } } /** * 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)); } let _anonymousTypeIndex = 0; function identifierName(compileIdentifier) { if (!compileIdentifier || !compileIdentifier.reference) { return null; } const ref = compileIdentifier.reference; 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 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); } visitWrappedNodeExpr(ast, ctx) { throw new Error('Cannot emit a WrappedNodeExpr in Javascript.'); } 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; } 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; } 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, ','); } } /** * @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 { // 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) { return getPolicy()?.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 refResolver Resolves `o.ExternalReference`s into values. * @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, refResolver, createSourceMaps) { const converter = new JitEmitterVisitor(refResolver); const ctx = EmitterVisitorContext.createRoot(); // Ensure generated code is in strict mode if (statements.length > 0 && !isUseStrictStatement(statements[0])) { statements = [ literal$1('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(refResolver) { super(); this.refResolver = refResolver; 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.refResolver.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); } _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$1('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]; } } /** * @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 */ /** * How the selector scope of an NgModule (its declarations, imports, and exports) should be emitted * as a part of the NgModule definition. */ var R3SelectorScopeMode; (function (R3SelectorScopeMode) { /** * Emit the declarations inline into the module definition. * * This option is useful in certain contexts where it's known that JIT support is required. The * tradeoff here is that this emit style prevents directives and pipes from being tree-shaken if * they are unused, but the NgModule is used. */ R3SelectorScopeMode[R3SelectorScopeMode["Inline"] = 0] = "Inline"; /** * Emit the declarations using a side effectful function call, `ɵɵsetNgModuleScope`, that is * guarded with the `ngJitMode` flag. * * This form of emit supports JIT and can be optimized away if the `ngJitMode` flag is set to * false, which allows unused directives and pipes to be tree-shaken. */ R3SelectorScopeMode[R3SelectorScopeMode["SideEffect"] = 1] = "SideEffect"; /** * Don't generate selector scopes at all. * * This is useful for contexts where JIT support is known to be unnecessary. */ R3SelectorScopeMode[R3SelectorScopeMode["Omit"] = 2] = "Omit"; })(R3SelectorScopeMode || (R3SelectorScopeMode = {})); /** * Construct an `R3NgModuleDef` for the given `R3NgModuleMetadata`. */ function compileNgModule(meta) { const { adjacentType, internalType, bootstrap, declarations, imports, exports, schemas, containsForwardDecls, selectorScopeMode, id } = meta; const statements = []; const definitionMap = new DefinitionMap(); definitionMap.set('type', internalType); if (bootstrap.length > 0) { definitionMap.set('bootstrap', refsToArray(bootstrap, containsForwardDecls)); } if (selectorScopeMode === R3SelectorScopeMode.Inline) { // If requested to emit scope information inline, pass the `declarations`, `imports` and // `exports` to the `ɵɵdefineNgModule()` call directly. 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)); } } else if (selectorScopeMode === R3SelectorScopeMode.SideEffect) { // In this mode, scope information is not passed into `ɵɵdefineNgModule` as it // would prevent tree-shaking of the declarations, imports and exports references. Instead, it's // patched onto the NgModule definition with a `ɵɵsetNgModuleScope` call that's guarded by the // `ngJitMode` flag. const setNgModuleScopeCall = generateSetNgModuleScopeCall(meta); if (setNgModuleScopeCall !== null) { statements.push(setNgModuleScopeCall); } } else ; if (schemas !== null && schemas.length > 0) { definitionMap.set('schemas', literalArr(schemas.map(ref => ref.value))); } if (id !== null) { definitionMap.set('id', id); // Generate a side-effectful call to register this NgModule by its id, as per the semantics of // NgModule ids. statements.push(importExpr(Identifiers.registerNgModuleType).callFn([adjacentType, id]).toStmt()); } 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, exports, imports, includeImportTypes, publicDeclarationTypes }) { return new ExpressionType(importExpr(Identifiers.NgModuleDeclaration, [ new ExpressionType(moduleType.type), publicDeclarationTypes === null ? tupleTypeOf(declarations) : tupleOfTypes(publicDeclarationTypes), includeImportTypes ? tupleTypeOf(imports) : NONE_TYPE, 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; } function tupleOfTypes(types) { const typeofTypes = types.map(type => typeofExpr(type)); return types.length > 0 ? expressionType(literalArr(typeofTypes)) : 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$1(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$1(metadata.pure), quoted: false }); if (metadata.isStandalone) { definitionMapValues.push({ key: 'standalone', value: literal$1(true), 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)), new ExpressionType(new LiteralExpr(metadata.isStandalone)), ])); } /** * @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 R3TemplateDependencyKind; (function (R3TemplateDependencyKind) { R3TemplateDependencyKind[R3TemplateDependencyKind["Directive"] = 0] = "Directive"; R3TemplateDependencyKind[R3TemplateDependencyKind["Pipe"] = 1] = "Pipe"; R3TemplateDependencyKind[R3TemplateDependencyKind["NgModule"] = 2] = "NgModule"; })(R3TemplateDependencyKind || (R3TemplateDependencyKind = {})); /** * @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$1(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; } } 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) { return visitor.visitThisReceiver?.(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; // Redeclare the properties that are inherited from `Binary` as `never`, as consumers should not // depend on these fields when operating on `Unary`. this.left = null; this.right = null; this.operation = null; } /** * 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 Call extends AST { constructor(span, sourceSpan, receiver, args, argumentSpan) { super(span, sourceSpan); this.receiver = receiver; this.args = args; this.argumentSpan = argumentSpan; } visit(visitor, context = null) { return visitor.visitCall(this, context); } } class SafeCall extends AST { constructor(span, sourceSpan, receiver, args, argumentSpan) { super(span, sourceSpan); this.receiver = receiver; this.args = args; this.argumentSpan = argumentSpan; } visit(visitor, context = null) { return visitor.visitSafeCall(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$1 { 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$1(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 { 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); } 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) { } 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); } visitSafeKeyedRead(ast, context) { this.visit(ast.receiver, context); this.visit(ast.key, context); } visitCall(ast, context) { this.visit(ast.receiver, context); this.visitAll(ast.args, context); } visitSafeCall(ast, context) { this.visit(ast.receiver, context); this.visitAll(ast.args, 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 { 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); } 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)); } visitCall(ast, context) { return new Call(ast.span, ast.sourceSpan, ast.receiver.visit(this), this.visitAll(ast.args), ast.argumentSpan); } visitSafeCall(ast, context) { return new SafeCall(ast.span, ast.sourceSpan, ast.receiver.visit(this), this.visitAll(ast.args), ast.argumentSpan); } 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)); } 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; } 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; } visitCall(ast, context) { const receiver = ast.receiver.visit(this); const args = this.visitAll(ast.args); if (receiver !== ast.receiver || args !== ast.args) { return new Call(ast.span, ast.sourceSpan, receiver, args, ast.argumentSpan); } return ast; } visitSafeCall(ast, context) { const receiver = ast.receiver.visit(this); const args = this.visitAll(ast.args); if (receiver !== ast.receiver || args !== ast.args) { return new SafeCall(ast.span, ast.sourceSpan, receiver, args, ast.argumentSpan); } 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, 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, 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 */ class EventHandlerVars { } EventHandlerVars.event = variable('$event'); /** * 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, 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, /* supportsInterpolation */ false, 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; if (lastIndex >= 0) { const lastStatement = actionStmts[lastIndex]; // Ensure that the value of the last expression statement is returned if (lastStatement instanceof ExpressionStatement) { actionStmts[lastIndex] = new ReturnStatement(lastStatement.expr); } } return actionStmts; } function convertPropertyBindingBuiltins(converterFactory, ast) { return convertBuiltins(converterFactory, ast); } class ConvertPropertyBindingResult { constructor(stmts, currValExpr) { this.stmts = stmts; this.currValExpr = currValExpr; } } /** * 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) { if (!localResolver) { localResolver = new DefaultLocalResolver(); } const visitor = new _AstToIrVisitor(localResolver, implicitReceiver, bindingId, /* supportsInterpolation */ false); const outputExpr = expressionWithoutBuiltins.visit(visitor, _Mode.Expression); const stmts = getStatementsFromVisitor(visitor, bindingId); if (visitor.usesImplicitReceiver) { localResolver.notifyImplicitReceiverUse(); } return new ConvertPropertyBindingResult(stmts, outputExpr); } /** * 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, /* supportsInterpolation */ true); const outputExpr = visitor.visitInterpolation(expressionWithArgumentsToExtract, _Mode.Expression); if (visitor.usesImplicitReceiver) { localResolver.notifyImplicitReceiverUse(); } const stmts = getStatementsFromVisitor(visitor, bindingId); const args = outputExpr.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 { 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, supportsInterpolation, baseSourceSpan, implicitReceiverAccesses) { this._localResolver = _localResolver; this._implicitReceiver = _implicitReceiver; this.bindingId = bindingId; this.supportsInterpolation = supportsInterpolation; 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}`); } visitImplicitReceiver(ast, mode) { ensureExpressionMode(mode, ast); this.usesImplicitReceiver = true; return this._implicitReceiver; } visitThisReceiver(ast, mode) { return this.visitImplicitReceiver(ast, mode); } visitInterpolation(ast, mode) { if (!this.supportsInterpolation) { throw new Error('Unexpected interpolation'); } ensureExpressionMode(mode, ast); let args = []; for (let i = 0; i < ast.strings.length - 1; i++) { args.push(literal$1(ast.strings[i])); args.push(this._visit(ast.expressions[i], _Mode.Expression)); } args.push(literal$1(ast.strings[ast.strings.length - 1])); // 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 = ast.strings; if (strings.length === 2 && strings[0] === '' && strings[1] === '') { // Single argument interpolate instructions. args = [args[1]]; } else if (ast.expressions.length >= 9) { // 9 or more arguments must be passed to the `interpolateV`-style instructions, which accept // an array of arguments args = [literalArr(args)]; } return new InterpolationExpression(args); } 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$1(ast.value, type, this.convertSourceSpan(ast.span))); } _getLocal(name, receiver) { if (this._localResolver.globals?.has(name) && receiver instanceof ThisReceiver) { return null; } return this._localResolver.getLocal(name); } visitPrefixNot(ast, mode) { return convertToStatementIfNeeded(mode, not(this._visit(ast.expression, _Mode.Expression))); } visitNonNullAssert(ast, mode) { return convertToStatementIfNeeded(mode, 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, this.convertSourceSpan(ast.span)); } 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, this.convertSourceSpan(ast.span)); } return convertToStatementIfNeeded(mode, varExpr.set(this._visit(ast.value, _Mode.Expression))); } visitSafePropertyRead(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)); } visitCall(ast, mode) { const leftMostSafe = this.leftMostSafeNode(ast); if (leftMostSafe) { return this.convertSafeAccess(ast, leftMostSafe, mode); } const convertedArgs = this.visitAll(ast.args, _Mode.Expression); if (ast instanceof BuiltinFunctionCall) { return convertToStatementIfNeeded(mode, ast.converter(convertedArgs)); } const receiver = ast.receiver; if (receiver instanceof PropertyRead && receiver.receiver instanceof ImplicitReceiver && !(receiver.receiver instanceof ThisReceiver) && receiver.name === '$any') { if (convertedArgs.length !== 1) { throw new Error(`Invalid call to $any, expected 1 argument but received ${convertedArgs.length || 'none'}`); } return convertToStatementIfNeeded(mode, convertedArgs[0]); } const call = this._visit(receiver, _Mode.Expression) .callFn(convertedArgs, this.convertSourceSpan(ast.span)); return convertToStatementIfNeeded(mode, call); } visitSafeCall(ast, mode) { return this.convertSafeAccess(ast, this.leftMostSafeNode(ast), mode); } _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 SafeCall) { this._nodeMap.set(leftMostSafe, new Call(leftMostSafe.span, leftMostSafe.sourceSpan, leftMostSafe.receiver, 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$1(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; }, visitCall(ast) { return visit(this, ast.receiver); }, visitSafeCall(ast) { return visit(this, ast.receiver) || ast; }, 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; }, visitPipe(ast) { return null; }, visitPrefixNot(ast) { return null; }, visitNonNullAssert(ast) { return null; }, visitPropertyRead(ast) { return visit(this, ast.receiver); }, visitPropertyWrite(ast) { return null; }, 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); }, visitCall(ast) { return true; }, visitSafeCall(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; }, 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; }, 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); } } function unsupported() { throw new Error('Unsupported operation'); } class InterpolationExpression extends Expression { constructor(args) { super(null, null); this.args = args; this.isConstant = unsupported; this.isEquivalent = unsupported; this.visitExpression = unsupported; } } class DefaultLocalResolver { constructor(globals) { this.globals = globals; } notifyImplicitReceiverUse() { } maybeRestoreView() { } getLocal(name) { if (name === EventHandlerVars.event.name) { return EventHandlerVars.event; } return null; } } class BuiltinFunctionCall extends Call { constructor(span, sourceSpan, args, converter) { super(span, sourceSpan, new EmptyExpr(span, sourceSpan), args, null); 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', 'input|src', 'ins|cite', 'q|cite', 'source|src', '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 `