From c1bb2a4d3bbdaa41d7d564a51f181c34e484207d Mon Sep 17 00:00:00 2001 From: zoe Date: Sun, 25 Jun 2023 09:22:15 +0200 Subject: [PATCH] e --- helix/settings.nix | 20 +- home.nix | 1 - node_modules/.package-lock.json | 16 + .../@angular/language-service/api.d.ts | 55 + .../@angular/language-service/api_bundle.js | 35 + .../language-service/api_bundle.js.map | 7 + .../bundles/language-service.js | 49552 ++++++++++++++++ .../language-service/factory_bundle.js | 49 + .../language-service/factory_bundle.js.map | 7 + .../@angular/language-service/index.d.ts | 13 + .../@angular/language-service/index.js | 13 + .../@angular/language-service/package.json | 50 + .../language-service/plugin-factory.d.ts | 9 + package-lock.json | 21 + package.json | 5 + 15 files changed, 49847 insertions(+), 6 deletions(-) create mode 100644 node_modules/.package-lock.json create mode 100755 node_modules/@angular/language-service/api.d.ts create mode 100755 node_modules/@angular/language-service/api_bundle.js create mode 100755 node_modules/@angular/language-service/api_bundle.js.map create mode 100755 node_modules/@angular/language-service/bundles/language-service.js create mode 100755 node_modules/@angular/language-service/factory_bundle.js create mode 100755 node_modules/@angular/language-service/factory_bundle.js.map create mode 100755 node_modules/@angular/language-service/index.d.ts create mode 100755 node_modules/@angular/language-service/index.js create mode 100755 node_modules/@angular/language-service/package.json create mode 100755 node_modules/@angular/language-service/plugin-factory.d.ts create mode 100644 package-lock.json create mode 100644 package.json diff --git a/helix/settings.nix b/helix/settings.nix index 0483ff1..c5b76d3 100644 --- a/helix/settings.nix +++ b/helix/settings.nix @@ -24,15 +24,25 @@ }; languages.language = [ { - name = "html"; - language-server = { command = "html-languageserver"; }; - formatter = { - command = "prettier"; - args = [ "--parser" "html" ]; + name = "angular-html"; + scope = "text.angular"; + roots = [ "angular.json" ]; + grammar = "html"; + language-server = { + command = "ngserver"; + args = [ + "--stdio" + "--tsProbeLocations" + "$(npm -g root)" + "--ngProbeLocations" + "$(npm -g root)" + ]; }; + file-types = [ "html" "component.html"]; } { name = "typescript"; + auto-format = true; formatter = { command = "prettier"; args = [ "--parser" "typescript" ]; diff --git a/home.nix b/home.nix index 90513b5..ab1599a 100644 --- a/home.nix +++ b/home.nix @@ -34,7 +34,6 @@ in enable = true; ytdl-format = "bestvideo[height<=?720]+bestaudio/best"; save-position-on-quit = true; - scripts = with pkgs.mpvScripts; [ mpris sponsorblock uosc ]; }; programs.yt-dlp = { enable = true; diff --git a/node_modules/.package-lock.json b/node_modules/.package-lock.json new file mode 100644 index 0000000..0940675 --- /dev/null +++ b/node_modules/.package-lock.json @@ -0,0 +1,16 @@ +{ + "name": "nixos", + "lockfileVersion": 3, + "requires": true, + "packages": { + "node_modules/@angular/language-service": { + "version": "16.1.1", + "resolved": "https://registry.npmjs.org/@angular/language-service/-/language-service-16.1.1.tgz", + "integrity": "sha512-3ZifAA15eV9TIHHdNuOBDYQRTA9HGqh1EIYe8JgkRDm9ImlIG7l747VuFs4SoBeTlEBlwyjAIt/47aYHx0R+wg==", + "dev": true, + "engines": { + "node": "^16.14.0 || >=18.10.0" + } + } + } +} diff --git a/node_modules/@angular/language-service/api.d.ts b/node_modules/@angular/language-service/api.d.ts new file mode 100755 index 0000000..8753925 --- /dev/null +++ b/node_modules/@angular/language-service/api.d.ts @@ -0,0 +1,55 @@ +/** + * @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 + */ +/** + * @module + * @description + * Entry point for all public APIs of the language service package. + */ +import ts from 'typescript'; +export interface PluginConfig { + /** + * If true, return only Angular results. Otherwise, return Angular + TypeScript + * results. + */ + angularOnly: boolean; + /** + * If true, enable `strictTemplates` in Angular compiler options regardless + * of its value in tsconfig.json. + */ + forceStrictTemplates?: true; +} +export type GetTcbResponse = { + /** + * The filename of the SourceFile this typecheck block belongs to. + * The filename is entirely opaque and unstable, useful only for debugging + * purposes. + */ + fileName: string; + /** The content of the SourceFile this typecheck block belongs to. */ + content: string; + /** + * Spans over node(s) in the typecheck block corresponding to the + * TS code generated for template node under the current cursor position. + * + * When the cursor position is over a source for which there is no generated + * code, `selections` is empty. + */ + selections: ts.TextSpan[]; +}; +export type GetComponentLocationsForTemplateResponse = ts.DocumentSpan[]; +export type GetTemplateLocationForComponentResponse = ts.DocumentSpan | undefined; +/** + * `NgLanguageService` describes an instance of an Angular language service, + * whose API surface is a strict superset of TypeScript's language service. + */ +export interface NgLanguageService extends ts.LanguageService { + getTcb(fileName: string, position: number): GetTcbResponse | undefined; + getComponentLocationsForTemplate(fileName: string): GetComponentLocationsForTemplateResponse; + getTemplateLocationForComponent(fileName: string, position: number): GetTemplateLocationForComponentResponse; +} +export declare function isNgLanguageService(ls: ts.LanguageService | NgLanguageService): ls is NgLanguageService; diff --git a/node_modules/@angular/language-service/api_bundle.js b/node_modules/@angular/language-service/api_bundle.js new file mode 100755 index 0000000..3acf95b --- /dev/null +++ b/node_modules/@angular/language-service/api_bundle.js @@ -0,0 +1,35 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); + +// bazel-out/darwin_arm64-fastbuild/bin/packages/language-service/api.mjs +var api_exports = {}; +__export(api_exports, { + isNgLanguageService: () => isNgLanguageService +}); +module.exports = __toCommonJS(api_exports); +function isNgLanguageService(ls) { + return "getTcb" in ls; +} +/** + * @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 + */ +//# sourceMappingURL=api_bundle.js.map diff --git a/node_modules/@angular/language-service/api_bundle.js.map b/node_modules/@angular/language-service/api_bundle.js.map new file mode 100755 index 0000000..a9c8e4a --- /dev/null +++ b/node_modules/@angular/language-service/api_bundle.js.map @@ -0,0 +1,7 @@ +{ + "version": 3, + "sources": ["../../../../../packages/language-service/api.ts"], + "sourcesContent": ["/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.io/license\n */\n\n/**\n * @module\n * @description\n * Entry point for all public APIs of the language service package.\n */\n\nimport ts from 'typescript';\n\nexport interface PluginConfig {\n /**\n * If true, return only Angular results. Otherwise, return Angular + TypeScript\n * results.\n */\n angularOnly: boolean;\n /**\n * If true, enable `strictTemplates` in Angular compiler options regardless\n * of its value in tsconfig.json.\n */\n forceStrictTemplates?: true;\n}\n\nexport type GetTcbResponse = {\n /**\n * The filename of the SourceFile this typecheck block belongs to.\n * The filename is entirely opaque and unstable, useful only for debugging\n * purposes.\n */\n fileName: string,\n /** The content of the SourceFile this typecheck block belongs to. */\n content: string,\n /**\n * Spans over node(s) in the typecheck block corresponding to the\n * TS code generated for template node under the current cursor position.\n *\n * When the cursor position is over a source for which there is no generated\n * code, `selections` is empty.\n */\n selections: ts.TextSpan[],\n};\n\nexport type GetComponentLocationsForTemplateResponse = ts.DocumentSpan[];\nexport type GetTemplateLocationForComponentResponse = ts.DocumentSpan|undefined;\n\n/**\n * `NgLanguageService` describes an instance of an Angular language service,\n * whose API surface is a strict superset of TypeScript's language service.\n */\nexport interface NgLanguageService extends ts.LanguageService {\n getTcb(fileName: string, position: number): GetTcbResponse|undefined;\n getComponentLocationsForTemplate(fileName: string): GetComponentLocationsForTemplateResponse;\n getTemplateLocationForComponent(fileName: string, position: number):\n GetTemplateLocationForComponentResponse;\n}\n\nexport function isNgLanguageService(ls: ts.LanguageService|\n NgLanguageService): ls is NgLanguageService {\n return 'getTcb' in ls;\n}\n"], + "mappings": ";;;;;;;;;;;;;;;;;;;AAAA;;;;;AA8DM,SAAU,oBAAoB,IACiB;AACnD,SAAO,YAAY;AACrB;", + "names": [] +} diff --git a/node_modules/@angular/language-service/bundles/language-service.js b/node_modules/@angular/language-service/bundles/language-service.js new file mode 100755 index 0000000..412d105 --- /dev/null +++ b/node_modules/@angular/language-service/bundles/language-service.js @@ -0,0 +1,49552 @@ + +/** + * @license Angular v16.1.1 + * 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(['module', 'exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', 'module', 'path', 'url'], (function (module, exports, ts$1, os, ts, fs$1, module$1, 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__default$1 = /*#__PURE__*/_interopDefaultLegacy(ts$1); + var ts__default = /*#__PURE__*/_interopDefaultLegacy(ts); + var fs__default = /*#__PURE__*/_interopDefaultLegacy(fs$1); + var module__default = /*#__PURE__*/_interopDefaultLegacy(module$1); + 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, '/'); + } + } + // G3-ESM-MARKER: G3 uses CommonJS, but externally everything in ESM. + // CommonJS/ESM interop for determining the current file name and containing dir. + const isCommonJS = typeof __filename !== 'undefined'; + const currentFileUrl = isCommonJS ? null : new URL(module.uri, document.baseURI).href; + 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__default["default"].existsSync(this.normalize(toggleCase(currentFileName))); + } + return this._caseSensitive; + } + exists(path) { + return fs__default["default"].existsSync(path); + } + readFile(path) { + return fs__default["default"].readFileSync(path, 'utf8'); + } + readFileBuffer(path) { + return fs__default["default"].readFileSync(path); + } + readdir(path) { + return fs__default["default"].readdirSync(path); + } + lstat(path) { + return fs__default["default"].lstatSync(path); + } + stat(path) { + return fs__default["default"].statSync(path); + } + realpath(path) { + return this.resolve(fs__default["default"].realpathSync(path)); + } + getDefaultLibLocation() { + // G3-ESM-MARKER: G3 uses CommonJS, but externally everything in ESM. + 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__default["default"].writeFileSync(path, data, exclusive ? { flag: 'wx' } : undefined); + } + removeFile(path) { + fs__default["default"].unlinkSync(path); + } + symlink(target, path) { + fs__default["default"].symlinkSync(target, path); + } + copyFile(from, to) { + fs__default["default"].copyFileSync(from, to); + } + moveFile(from, to) { + fs__default["default"].renameSync(from, to); + } + ensureDir(path) { + fs__default["default"].mkdirSync(path, { recursive: true }); + } + removeDeep(path) { + fs__default["default"].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 + */ + 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; + } + 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 + */ + /** + * 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 { + static zero() { + return new BigInteger([0]); + } + static one() { + return new BigInteger([1]); + } + /** + * Creates a big integer using its individual digits in little endian storage. + */ + constructor(digits) { + this.digits = digits; + } + /** + * 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 + */ + /** + * A lazily created TextEncoder instance for converting strings into UTF-8 bytes + */ + let textEncoder; + /** + * 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) { + textEncoder ??= new TextEncoder(); + const utf8 = [...textEncoder.encode(str)]; + const words32 = bytesToWords32(utf8, Endian.Big); + const len = utf8.length * 8; + const w = new Uint32Array(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); + } + // Convert the output parts to a 160-bit hexadecimal string + return toHexU32(a) + toHexU32(b) + toHexU32(c) + toHexU32(d) + toHexU32(e); + } + /** + * Convert and format a number as a string representing a 32-bit unsigned hexadecimal number. + * @param value The value to format as a string. + * @returns A hexadecimal string representing the value. + */ + function toHexU32(value) { + // unsigned right shift of zero ensures an unsigned 32-bit number + return (value >>> 0).toString(16).padStart(8, '0'); + } + 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) { + textEncoder ??= new TextEncoder(); + const utf8 = textEncoder.encode(str); + const view = new DataView(utf8.buffer, utf8.byteOffset, utf8.byteLength); + let hi = hash32(view, utf8.length, 0); + let lo = hash32(view, utf8.length, 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(view, length, c) { + let a = 0x9e3779b9, b = 0x9e3779b9; + let index = 0; + const end = length - 12; + for (; index <= end; index += 12) { + a += view.getUint32(index, true); + b += view.getUint32(index + 4, true); + c += view.getUint32(index + 8, true); + const res = mix(a, b, c); + a = res[0], b = res[1], c = res[2]; + } + const remainder = length - index; + // the first byte of c is reserved for the length + c += length; + if (remainder >= 4) { + a += view.getUint32(index, true); + index += 4; + if (remainder >= 8) { + b += view.getUint32(index, true); + index += 4; + // Partial 32-bit word for c + if (remainder >= 9) { + c += view.getUint8(index++) << 8; + } + if (remainder >= 10) { + c += view.getUint8(index++) << 16; + } + if (remainder === 11) { + c += view.getUint8(index++) << 24; + } + } + else { + // Partial 32-bit word for b + if (remainder >= 5) { + b += view.getUint8(index++); + } + if (remainder >= 6) { + b += view.getUint8(index++) << 8; + } + if (remainder === 7) { + b += view.getUint8(index++) << 16; + } + } + } + else { + // Partial 32-bit word for a + if (remainder >= 1) { + a += view.getUint8(index++); + } + if (remainder >= 2) { + a += view.getUint8(index++) << 8; + } + if (remainder === 3) { + a += view.getUint8(index++) << 16; + } + } + return mix(a, b, c)[2]; + } + // clang-format off + function mix(a, b, c) { + a -= b; + a -= c; + a ^= c >>> 13; + b -= c; + b -= a; + b ^= a << 8; + c -= a; + c -= b; + c ^= b >>> 13; + a -= b; + a -= c; + a ^= c >>> 12; + b -= c; + b -= a; + b ^= a << 16; + c -= a; + c -= b; + c ^= b >>> 5; + a -= b; + a -= c; + a ^= c >>> 3; + b -= c; + b -= a; + b ^= a << 10; + c -= a; + 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]; + } + // 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; + } + /** + * 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); + } + } + class TransplantedType extends Type { + constructor(type, modifiers) { + super(modifiers); + this.type = type; + } + visitType(visitor, context) { + return visitor.visitTransplantedType(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 transplantedType(type, typeModifiers) { + return new TransplantedType(type, typeModifiers); + } + 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.shared = false; + 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.sharedConstants = 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 = GenericKeyFn.INSTANCE.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; + } + getSharedConstant(def, expr) { + const key = def.keyOf(expr); + if (!this.sharedConstants.has(key)) { + const id = this.freshName(); + this.sharedConstants.set(key, variable(id)); + this.statements.push(def.toSharedConstantDeclaration(id, expr)); + } + return this.sharedConstants.get(key); + } + 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 = GenericKeyFn.INSTANCE.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 = GenericKeyFn.INSTANCE.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); + } + } + class GenericKeyFn { + static { this.INSTANCE = new GenericKeyFn(); } + keyOf(expr) { + if (expr instanceof LiteralExpr && typeof expr.value === 'string') { + return `"${expr.value}"`; + } + else if (expr instanceof LiteralExpr) { + return String(expr.value); + } + else if (expr instanceof LiteralArrayExpr) { + const entries = []; + for (const entry of expr.entries) { + entries.push(this.keyOf(entry)); + } + return `[${entries.join(',')}]`; + } + else if (expr instanceof LiteralMapExpr) { + const entries = []; + for (const entry of expr.entries) { + let key = entry.key; + if (entry.quoted) { + key = `"${key}"`; + } + entries.push(key + ':' + this.keyOf(entry.value)); + } + return `{${entries.join(',')}}`; + } + else if (expr instanceof ExternalExpr) { + return `import("${expr.value.moduleName}", ${expr.value.name})`; + } + else if (expr instanceof ReadVarExpr) { + return `read(${expr.name})`; + } + else if (expr instanceof TypeofExpr) { + return `typeof(${this.keyOf(expr.expr)})`; + } + else { + throw new Error(`${this.constructor.name} does not handle expressions of type ${expr.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 */ + static { this.NEW_METHOD = 'factory'; } + static { this.TRANSFORM_METHOD = 'transform'; } + static { this.PATCH_DEPS = 'patchedDeps'; } + static { this.core = { name: null, moduleName: CORE }; } + /* Instructions */ + static { this.namespaceHTML = { name: 'ɵɵnamespaceHTML', moduleName: CORE }; } + static { this.namespaceMathML = { name: 'ɵɵnamespaceMathML', moduleName: CORE }; } + static { this.namespaceSVG = { name: 'ɵɵnamespaceSVG', moduleName: CORE }; } + static { this.element = { name: 'ɵɵelement', moduleName: CORE }; } + static { this.elementStart = { name: 'ɵɵelementStart', moduleName: CORE }; } + static { this.elementEnd = { name: 'ɵɵelementEnd', moduleName: CORE }; } + static { this.advance = { name: 'ɵɵadvance', moduleName: CORE }; } + static { this.syntheticHostProperty = { name: 'ɵɵsyntheticHostProperty', moduleName: CORE }; } + static { this.syntheticHostListener = { name: 'ɵɵsyntheticHostListener', moduleName: CORE }; } + static { this.attribute = { name: 'ɵɵattribute', moduleName: CORE }; } + static { this.attributeInterpolate1 = { name: 'ɵɵattributeInterpolate1', moduleName: CORE }; } + static { this.attributeInterpolate2 = { name: 'ɵɵattributeInterpolate2', moduleName: CORE }; } + static { this.attributeInterpolate3 = { name: 'ɵɵattributeInterpolate3', moduleName: CORE }; } + static { this.attributeInterpolate4 = { name: 'ɵɵattributeInterpolate4', moduleName: CORE }; } + static { this.attributeInterpolate5 = { name: 'ɵɵattributeInterpolate5', moduleName: CORE }; } + static { this.attributeInterpolate6 = { name: 'ɵɵattributeInterpolate6', moduleName: CORE }; } + static { this.attributeInterpolate7 = { name: 'ɵɵattributeInterpolate7', moduleName: CORE }; } + static { this.attributeInterpolate8 = { name: 'ɵɵattributeInterpolate8', moduleName: CORE }; } + static { this.attributeInterpolateV = { name: 'ɵɵattributeInterpolateV', moduleName: CORE }; } + static { this.classProp = { name: 'ɵɵclassProp', moduleName: CORE }; } + static { this.elementContainerStart = { name: 'ɵɵelementContainerStart', moduleName: CORE }; } + static { this.elementContainerEnd = { name: 'ɵɵelementContainerEnd', moduleName: CORE }; } + static { this.elementContainer = { name: 'ɵɵelementContainer', moduleName: CORE }; } + static { this.styleMap = { name: 'ɵɵstyleMap', moduleName: CORE }; } + static { this.styleMapInterpolate1 = { name: 'ɵɵstyleMapInterpolate1', moduleName: CORE }; } + static { this.styleMapInterpolate2 = { name: 'ɵɵstyleMapInterpolate2', moduleName: CORE }; } + static { this.styleMapInterpolate3 = { name: 'ɵɵstyleMapInterpolate3', moduleName: CORE }; } + static { this.styleMapInterpolate4 = { name: 'ɵɵstyleMapInterpolate4', moduleName: CORE }; } + static { this.styleMapInterpolate5 = { name: 'ɵɵstyleMapInterpolate5', moduleName: CORE }; } + static { this.styleMapInterpolate6 = { name: 'ɵɵstyleMapInterpolate6', moduleName: CORE }; } + static { this.styleMapInterpolate7 = { name: 'ɵɵstyleMapInterpolate7', moduleName: CORE }; } + static { this.styleMapInterpolate8 = { name: 'ɵɵstyleMapInterpolate8', moduleName: CORE }; } + static { this.styleMapInterpolateV = { name: 'ɵɵstyleMapInterpolateV', moduleName: CORE }; } + static { this.classMap = { name: 'ɵɵclassMap', moduleName: CORE }; } + static { this.classMapInterpolate1 = { name: 'ɵɵclassMapInterpolate1', moduleName: CORE }; } + static { this.classMapInterpolate2 = { name: 'ɵɵclassMapInterpolate2', moduleName: CORE }; } + static { this.classMapInterpolate3 = { name: 'ɵɵclassMapInterpolate3', moduleName: CORE }; } + static { this.classMapInterpolate4 = { name: 'ɵɵclassMapInterpolate4', moduleName: CORE }; } + static { this.classMapInterpolate5 = { name: 'ɵɵclassMapInterpolate5', moduleName: CORE }; } + static { this.classMapInterpolate6 = { name: 'ɵɵclassMapInterpolate6', moduleName: CORE }; } + static { this.classMapInterpolate7 = { name: 'ɵɵclassMapInterpolate7', moduleName: CORE }; } + static { this.classMapInterpolate8 = { name: 'ɵɵclassMapInterpolate8', moduleName: CORE }; } + static { this.classMapInterpolateV = { name: 'ɵɵclassMapInterpolateV', moduleName: CORE }; } + static { this.styleProp = { name: 'ɵɵstyleProp', moduleName: CORE }; } + static { this.stylePropInterpolate1 = { name: 'ɵɵstylePropInterpolate1', moduleName: CORE }; } + static { this.stylePropInterpolate2 = { name: 'ɵɵstylePropInterpolate2', moduleName: CORE }; } + static { this.stylePropInterpolate3 = { name: 'ɵɵstylePropInterpolate3', moduleName: CORE }; } + static { this.stylePropInterpolate4 = { name: 'ɵɵstylePropInterpolate4', moduleName: CORE }; } + static { this.stylePropInterpolate5 = { name: 'ɵɵstylePropInterpolate5', moduleName: CORE }; } + static { this.stylePropInterpolate6 = { name: 'ɵɵstylePropInterpolate6', moduleName: CORE }; } + static { this.stylePropInterpolate7 = { name: 'ɵɵstylePropInterpolate7', moduleName: CORE }; } + static { this.stylePropInterpolate8 = { name: 'ɵɵstylePropInterpolate8', moduleName: CORE }; } + static { this.stylePropInterpolateV = { name: 'ɵɵstylePropInterpolateV', moduleName: CORE }; } + static { this.nextContext = { name: 'ɵɵnextContext', moduleName: CORE }; } + static { this.resetView = { name: 'ɵɵresetView', moduleName: CORE }; } + static { this.templateCreate = { name: 'ɵɵtemplate', moduleName: CORE }; } + static { this.text = { name: 'ɵɵtext', moduleName: CORE }; } + static { this.enableBindings = { name: 'ɵɵenableBindings', moduleName: CORE }; } + static { this.disableBindings = { name: 'ɵɵdisableBindings', moduleName: CORE }; } + static { this.getCurrentView = { name: 'ɵɵgetCurrentView', moduleName: CORE }; } + static { this.textInterpolate = { name: 'ɵɵtextInterpolate', moduleName: CORE }; } + static { this.textInterpolate1 = { name: 'ɵɵtextInterpolate1', moduleName: CORE }; } + static { this.textInterpolate2 = { name: 'ɵɵtextInterpolate2', moduleName: CORE }; } + static { this.textInterpolate3 = { name: 'ɵɵtextInterpolate3', moduleName: CORE }; } + static { this.textInterpolate4 = { name: 'ɵɵtextInterpolate4', moduleName: CORE }; } + static { this.textInterpolate5 = { name: 'ɵɵtextInterpolate5', moduleName: CORE }; } + static { this.textInterpolate6 = { name: 'ɵɵtextInterpolate6', moduleName: CORE }; } + static { this.textInterpolate7 = { name: 'ɵɵtextInterpolate7', moduleName: CORE }; } + static { this.textInterpolate8 = { name: 'ɵɵtextInterpolate8', moduleName: CORE }; } + static { this.textInterpolateV = { name: 'ɵɵtextInterpolateV', moduleName: CORE }; } + static { this.restoreView = { name: 'ɵɵrestoreView', moduleName: CORE }; } + static { this.pureFunction0 = { name: 'ɵɵpureFunction0', moduleName: CORE }; } + static { this.pureFunction1 = { name: 'ɵɵpureFunction1', moduleName: CORE }; } + static { this.pureFunction2 = { name: 'ɵɵpureFunction2', moduleName: CORE }; } + static { this.pureFunction3 = { name: 'ɵɵpureFunction3', moduleName: CORE }; } + static { this.pureFunction4 = { name: 'ɵɵpureFunction4', moduleName: CORE }; } + static { this.pureFunction5 = { name: 'ɵɵpureFunction5', moduleName: CORE }; } + static { this.pureFunction6 = { name: 'ɵɵpureFunction6', moduleName: CORE }; } + static { this.pureFunction7 = { name: 'ɵɵpureFunction7', moduleName: CORE }; } + static { this.pureFunction8 = { name: 'ɵɵpureFunction8', moduleName: CORE }; } + static { this.pureFunctionV = { name: 'ɵɵpureFunctionV', moduleName: CORE }; } + static { this.pipeBind1 = { name: 'ɵɵpipeBind1', moduleName: CORE }; } + static { this.pipeBind2 = { name: 'ɵɵpipeBind2', moduleName: CORE }; } + static { this.pipeBind3 = { name: 'ɵɵpipeBind3', moduleName: CORE }; } + static { this.pipeBind4 = { name: 'ɵɵpipeBind4', moduleName: CORE }; } + static { this.pipeBindV = { name: 'ɵɵpipeBindV', moduleName: CORE }; } + static { this.hostProperty = { name: 'ɵɵhostProperty', moduleName: CORE }; } + static { this.property = { name: 'ɵɵproperty', moduleName: CORE }; } + static { this.propertyInterpolate = { name: 'ɵɵpropertyInterpolate', moduleName: CORE }; } + static { this.propertyInterpolate1 = { name: 'ɵɵpropertyInterpolate1', moduleName: CORE }; } + static { this.propertyInterpolate2 = { name: 'ɵɵpropertyInterpolate2', moduleName: CORE }; } + static { this.propertyInterpolate3 = { name: 'ɵɵpropertyInterpolate3', moduleName: CORE }; } + static { this.propertyInterpolate4 = { name: 'ɵɵpropertyInterpolate4', moduleName: CORE }; } + static { this.propertyInterpolate5 = { name: 'ɵɵpropertyInterpolate5', moduleName: CORE }; } + static { this.propertyInterpolate6 = { name: 'ɵɵpropertyInterpolate6', moduleName: CORE }; } + static { this.propertyInterpolate7 = { name: 'ɵɵpropertyInterpolate7', moduleName: CORE }; } + static { this.propertyInterpolate8 = { name: 'ɵɵpropertyInterpolate8', moduleName: CORE }; } + static { this.propertyInterpolateV = { name: 'ɵɵpropertyInterpolateV', moduleName: CORE }; } + static { this.i18n = { name: 'ɵɵi18n', moduleName: CORE }; } + static { this.i18nAttributes = { name: 'ɵɵi18nAttributes', moduleName: CORE }; } + static { this.i18nExp = { name: 'ɵɵi18nExp', moduleName: CORE }; } + static { this.i18nStart = { name: 'ɵɵi18nStart', moduleName: CORE }; } + static { this.i18nEnd = { name: 'ɵɵi18nEnd', moduleName: CORE }; } + static { this.i18nApply = { name: 'ɵɵi18nApply', moduleName: CORE }; } + static { this.i18nPostprocess = { name: 'ɵɵi18nPostprocess', moduleName: CORE }; } + static { this.pipe = { name: 'ɵɵpipe', moduleName: CORE }; } + static { this.projection = { name: 'ɵɵprojection', moduleName: CORE }; } + static { this.projectionDef = { name: 'ɵɵprojectionDef', moduleName: CORE }; } + static { this.reference = { name: 'ɵɵreference', moduleName: CORE }; } + static { this.inject = { name: 'ɵɵinject', moduleName: CORE }; } + static { this.injectAttribute = { name: 'ɵɵinjectAttribute', moduleName: CORE }; } + static { this.directiveInject = { name: 'ɵɵdirectiveInject', moduleName: CORE }; } + static { this.invalidFactory = { name: 'ɵɵinvalidFactory', moduleName: CORE }; } + static { this.invalidFactoryDep = { name: 'ɵɵinvalidFactoryDep', moduleName: CORE }; } + static { this.templateRefExtractor = { name: 'ɵɵtemplateRefExtractor', moduleName: CORE }; } + static { this.forwardRef = { name: 'forwardRef', moduleName: CORE }; } + static { this.resolveForwardRef = { name: 'resolveForwardRef', moduleName: CORE }; } + static { this.ɵɵdefineInjectable = { name: 'ɵɵdefineInjectable', moduleName: CORE }; } + static { this.declareInjectable = { name: 'ɵɵngDeclareInjectable', moduleName: CORE }; } + static { this.InjectableDeclaration = { name: 'ɵɵInjectableDeclaration', moduleName: CORE }; } + static { this.resolveWindow = { name: 'ɵɵresolveWindow', moduleName: CORE }; } + static { this.resolveDocument = { name: 'ɵɵresolveDocument', moduleName: CORE }; } + static { this.resolveBody = { name: 'ɵɵresolveBody', moduleName: CORE }; } + static { this.defineComponent = { name: 'ɵɵdefineComponent', moduleName: CORE }; } + static { this.declareComponent = { name: 'ɵɵngDeclareComponent', moduleName: CORE }; } + static { this.setComponentScope = { name: 'ɵɵsetComponentScope', moduleName: CORE }; } + static { this.ChangeDetectionStrategy = { + name: 'ChangeDetectionStrategy', + moduleName: CORE, + }; } + static { this.ViewEncapsulation = { + name: 'ViewEncapsulation', + moduleName: CORE, + }; } + static { this.ComponentDeclaration = { + name: 'ɵɵComponentDeclaration', + moduleName: CORE, + }; } + static { this.FactoryDeclaration = { + name: 'ɵɵFactoryDeclaration', + moduleName: CORE, + }; } + static { this.declareFactory = { name: 'ɵɵngDeclareFactory', moduleName: CORE }; } + static { this.FactoryTarget = { name: 'ɵɵFactoryTarget', moduleName: CORE }; } + static { this.defineDirective = { name: 'ɵɵdefineDirective', moduleName: CORE }; } + static { this.declareDirective = { name: 'ɵɵngDeclareDirective', moduleName: CORE }; } + static { this.DirectiveDeclaration = { + name: 'ɵɵDirectiveDeclaration', + moduleName: CORE, + }; } + static { this.InjectorDef = { name: 'ɵɵInjectorDef', moduleName: CORE }; } + static { this.InjectorDeclaration = { name: 'ɵɵInjectorDeclaration', moduleName: CORE }; } + static { this.defineInjector = { name: 'ɵɵdefineInjector', moduleName: CORE }; } + static { this.declareInjector = { name: 'ɵɵngDeclareInjector', moduleName: CORE }; } + static { this.NgModuleDeclaration = { + name: 'ɵɵNgModuleDeclaration', + moduleName: CORE, + }; } + static { this.ModuleWithProviders = { + name: 'ModuleWithProviders', + moduleName: CORE, + }; } + static { this.defineNgModule = { name: 'ɵɵdefineNgModule', moduleName: CORE }; } + static { this.declareNgModule = { name: 'ɵɵngDeclareNgModule', moduleName: CORE }; } + static { this.setNgModuleScope = { name: 'ɵɵsetNgModuleScope', moduleName: CORE }; } + static { this.registerNgModuleType = { name: 'ɵɵregisterNgModuleType', moduleName: CORE }; } + static { this.PipeDeclaration = { name: 'ɵɵPipeDeclaration', moduleName: CORE }; } + static { this.definePipe = { name: 'ɵɵdefinePipe', moduleName: CORE }; } + static { this.declarePipe = { name: 'ɵɵngDeclarePipe', moduleName: CORE }; } + static { this.declareClassMetadata = { name: 'ɵɵngDeclareClassMetadata', moduleName: CORE }; } + static { this.setClassMetadata = { name: 'ɵsetClassMetadata', moduleName: CORE }; } + static { this.queryRefresh = { name: 'ɵɵqueryRefresh', moduleName: CORE }; } + static { this.viewQuery = { name: 'ɵɵviewQuery', moduleName: CORE }; } + static { this.loadQuery = { name: 'ɵɵloadQuery', moduleName: CORE }; } + static { this.contentQuery = { name: 'ɵɵcontentQuery', moduleName: CORE }; } + static { this.NgOnChangesFeature = { name: 'ɵɵNgOnChangesFeature', moduleName: CORE }; } + static { this.InheritDefinitionFeature = { name: 'ɵɵInheritDefinitionFeature', moduleName: CORE }; } + static { this.CopyDefinitionFeature = { name: 'ɵɵCopyDefinitionFeature', moduleName: CORE }; } + static { this.StandaloneFeature = { name: 'ɵɵStandaloneFeature', moduleName: CORE }; } + static { this.ProvidersFeature = { name: 'ɵɵProvidersFeature', moduleName: CORE }; } + static { this.HostDirectivesFeature = { name: 'ɵɵHostDirectivesFeature', moduleName: CORE }; } + static { this.InputTransformsFeatureFeature = { name: 'ɵɵInputTransformsFeature', moduleName: CORE }; } + static { this.listener = { name: 'ɵɵlistener', moduleName: CORE }; } + static { this.getInheritedFactory = { + name: 'ɵɵgetInheritedFactory', + moduleName: CORE, + }; } + // sanitization-related functions + static { this.sanitizeHtml = { name: 'ɵɵsanitizeHtml', moduleName: CORE }; } + static { this.sanitizeStyle = { name: 'ɵɵsanitizeStyle', moduleName: CORE }; } + static { this.sanitizeResourceUrl = { name: 'ɵɵsanitizeResourceUrl', moduleName: CORE }; } + static { this.sanitizeScript = { name: 'ɵɵsanitizeScript', moduleName: CORE }; } + static { this.sanitizeUrl = { name: 'ɵɵsanitizeUrl', moduleName: CORE }; } + static { this.sanitizeUrlOrResourceUrl = { name: 'ɵɵsanitizeUrlOrResourceUrl', moduleName: CORE }; } + static { this.trustConstantHtml = { name: 'ɵɵtrustConstantHtml', moduleName: CORE }; } + static { this.trustConstantResourceUrl = { name: 'ɵɵtrustConstantResourceUrl', moduleName: CORE }; } + static { this.validateIframeAttribute = { name: 'ɵɵvalidateIframeAttribute', moduleName: CORE }; } + } + + /** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + const DASH_CASE_REGEXP = /-+([a-z0-9])/g; + function dashCaseToCamelCase(input) { + return input.replace(DASH_CASE_REGEXP, (...m) => m[1].toUpperCase()); + } + function splitAtColon(input, defaultValues) { + return _splitAt(input, ':', defaultValues); + } + function splitAtPeriod(input, defaultValues) { + return _splitAt(input, '.', defaultValues); + } + function _splitAt(input, character, defaultValues) { + const characterIndex = input.indexOf(character); + if (characterIndex == -1) + return defaultValues; + return [input.slice(0, characterIndex).trim(), input.slice(characterIndex + 1).trim()]; + } + function 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))()); + /** + * Partitions a given array into 2 arrays, based on a boolean value returned by the condition + * function. + * + * @param arr Input array that should be partitioned + * @param conditionFn Condition function that is called for each item in a given array and returns a + * boolean value. + */ + function partitionArray(arr, conditionFn) { + const truthy = []; + const falsy = []; + for (const item of arr) { + (conditionFn(item) ? truthy : falsy).push(item); + } + return [truthy, falsy]; + } + + /** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + // https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit + const VERSION = 3; + const JS_B64_PREFIX = '# sourceMappingURL=data:application/json;base64,'; + class SourceMapGenerator { + constructor(file = null) { + this.file = file; + this.sourcesContent = new Map(); + this.lines = []; + this.lastCol0 = 0; + this.hasMappings = false; + } + // The content is `null` when the content is expected to be loaded using the URL + addSource(url, content = null) { + if (!this.sourcesContent.has(url)) { + this.sourcesContent.set(url, content); + } + return this; + } + addLine() { + this.lines.push([]); + this.lastCol0 = 0; + return this; + } + addMapping(col0, sourceUrl, sourceLine0, sourceCol0) { + if (!this.currentLine) { + throw new Error(`A line must be added before mappings can be added`); + } + if (sourceUrl != null && !this.sourcesContent.has(sourceUrl)) { + throw new Error(`Unknown source file "${sourceUrl}"`); + } + if (col0 == null) { + throw new Error(`The column in the generated code must be provided`); + } + if (col0 < this.lastCol0) { + throw new Error(`Mapping should be added in output order`); + } + if (sourceUrl && (sourceLine0 == null || sourceCol0 == null)) { + throw new Error(`The source location must be provided when a source url is provided`); + } + this.hasMappings = true; + this.lastCol0 = col0; + this.currentLine.push({ col0, sourceUrl, sourceLine0, sourceCol0 }); + return this; + } + /** + * @internal strip this from published d.ts files due to + * https://github.com/microsoft/TypeScript/issues/36216 + */ + get currentLine() { + return this.lines.slice(-1)[0]; + } + toJSON() { + if (!this.hasMappings) { + return null; + } + const sourcesIndex = new Map(); + const sources = []; + const sourcesContent = []; + Array.from(this.sourcesContent.keys()).forEach((url, i) => { + sourcesIndex.set(url, i); + sources.push(url); + sourcesContent.push(this.sourcesContent.get(url) || null); + }); + let mappings = ''; + let lastCol0 = 0; + let lastSourceIndex = 0; + let lastSourceLine0 = 0; + let lastSourceCol0 = 0; + this.lines.forEach(segments => { + lastCol0 = 0; + mappings += segments + .map(segment => { + // zero-based starting column of the line in the generated code + let segAsStr = toBase64VLQ(segment.col0 - lastCol0); + lastCol0 = segment.col0; + if (segment.sourceUrl != null) { + // zero-based index into the “sources” list + segAsStr += + toBase64VLQ(sourcesIndex.get(segment.sourceUrl) - lastSourceIndex); + lastSourceIndex = sourcesIndex.get(segment.sourceUrl); + // the zero-based starting line in the original source + segAsStr += toBase64VLQ(segment.sourceLine0 - lastSourceLine0); + lastSourceLine0 = segment.sourceLine0; + // the zero-based starting column in the original source + segAsStr += toBase64VLQ(segment.sourceCol0 - lastSourceCol0); + lastSourceCol0 = segment.sourceCol0; + } + return segAsStr; + }) + .join(','); + mappings += ';'; + }); + mappings = mappings.slice(0, -1); + return { + 'file': this.file || '', + 'version': VERSION, + 'sourceRoot': '', + 'sources': sources, + 'sourcesContent': sourcesContent, + 'mappings': mappings, + }; + } + toJsComment() { + return this.hasMappings ? '//' + JS_B64_PREFIX + toBase64String(JSON.stringify(this, null, 0)) : + ''; + } + } + function toBase64String(value) { + let b64 = ''; + const encoded = utf8Encode(value); + for (let i = 0; i < encoded.length;) { + const i1 = encoded[i++]; + const i2 = i < encoded.length ? encoded[i++] : null; + const i3 = i < encoded.length ? encoded[i++] : null; + b64 += toBase64Digit(i1 >> 2); + b64 += toBase64Digit(((i1 & 3) << 4) | (i2 === null ? 0 : i2 >> 4)); + b64 += i2 === null ? '=' : toBase64Digit(((i2 & 15) << 2) | (i3 === null ? 0 : i3 >> 6)); + b64 += i2 === null || i3 === null ? '=' : toBase64Digit(i3 & 63); + } + return b64; + } + function toBase64VLQ(value) { + value = value < 0 ? ((-value) << 1) + 1 : value << 1; + let out = ''; + do { + let digit = value & 31; + value = value >> 5; + if (value > 0) { + digit = digit | 32; + } + out += toBase64Digit(digit); + } while (value > 0); + return out; + } + const B64_DIGITS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; + function toBase64Digit(value) { + if (value < 0 || value >= 64) { + throw new Error(`Can only encode value in the range [0, 63]`); + } + return B64_DIGITS[value]; + } + + /** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + const _SINGLE_QUOTE_ESCAPE_STRING_RE = /'|\\|\n|\r|\$/g; + const _LEGAL_IDENTIFIER_RE = /^[$A-Z_][0-9A-Z_$]*$/i; + const _INDENT_WITH = ' '; + class _EmittedLine { + constructor(indent) { + this.indent = indent; + this.partsLength = 0; + this.parts = []; + this.srcSpans = []; + } + } + class EmitterVisitorContext { + static createRoot() { + return new EmitterVisitorContext(0); + } + constructor(_indent) { + this._indent = _indent; + this._lines = [new _EmittedLine(_indent)]; + } + /** + * @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.type.value) : + 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.type.value]); + // 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; + /** The ids to use if there are no custom id and if `i18nLegacyMessageIdFormat` is not empty */ + this.legacyIds = []; + this.id = this.customId; + 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, expressionPlaceholder) { + this.expression = expression; + this.type = type; + this.cases = cases; + this.sourceSpan = sourceSpan; + this.expressionPlaceholder = expressionPlaceholder; + } + 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 conditionallyCreateDirectiveBindingLiteral(map, keepDeclared) { + const keys = Object.getOwnPropertyNames(map); + if (keys.length === 0) { + return null; + } + return literalMap(keys.map(key => { + const value = map[key]; + let declaredName; + let publicName; + let minifiedName; + let expressionValue; + if (typeof value === 'string') { + // canonical syntax: `dirProp: publicProp` + declaredName = key; + minifiedName = key; + publicName = value; + expressionValue = asLiteral(publicName); + } + else { + minifiedName = key; + declaredName = value.classPropertyName; + publicName = value.bindingPropertyName; + if (keepDeclared && (publicName !== declaredName || value.transformFunction != null)) { + const expressionKeys = [asLiteral(publicName), asLiteral(declaredName)]; + if (value.transformFunction != null) { + expressionKeys.push(value.transformFunction); + } + expressionValue = literalArr(expressionKeys); + } + else { + expressionValue = asLiteral(publicName); + } + } + return { + key: minifiedName, + // put quotes around keys that contain potentially unsafe characters + quoted: UNSAFE_OBJECT_KEY_NAME_REGEXP.test(minifiedName), + value: expressionValue, + }; + })); + } + /** + * 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 => { + if (i.type === 0 /* BindingType.Property */) { + 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, + 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.type.value); + 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.type.value, resolveForwardRefs) + }; + } + const token = meta.type.value; + 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, useType, unwrapForwardRefs) { + if (type.node === useType.node) { + // The types are the same, so we can simply delegate directly to the type's factory. + // ``` + // factory: type.ɵfac + // ``` + return useType.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 useType.ɵfac(t); } + // ``` + return createFactoryFunction(useType); + } + // The useType 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([useType]); + 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 { + static fromArray(markers) { + if (!markers) { + return DEFAULT_INTERPOLATION_CONFIG; + } + assertInterpolationSymbols('interpolation', markers); + return new InterpolationConfig(markers[0], markers[1]); + } + constructor(start, end) { + this.start = start; + this.end = end; + } + } + 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 { type: moduleType, bootstrap, declarations, imports, exports, schemas, containsForwardDecls, selectorScopeMode, id } = meta; + const statements = []; + const definitionMap = new DefinitionMap(); + definitionMap.set('type', moduleType.value); + 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([moduleType.value, 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 { type: 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.value, 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 { + /** + * 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)); + } + /** + * 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; + } + 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 { + static { this.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 visit(this, ast.expression); + }, + 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 `