You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
34944 lines
1.6 MiB
34944 lines
1.6 MiB
/**
|
|
* @license Angular v12.2.16
|
|
* (c) 2010-2021 Google LLC. https://angular.io/
|
|
* License: MIT
|
|
*/
|
|
|
|
(function (global, factory) {
|
|
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
|
|
typeof define === 'function' && define.amd ? define('@angular/compiler', ['exports'], factory) :
|
|
(global = global || self, factory((global.ng = global.ng || {}, global.ng.compiler = {})));
|
|
}(this, (function (exports) { 'use strict';
|
|
|
|
/*! *****************************************************************************
|
|
Copyright (c) Microsoft Corporation.
|
|
|
|
Permission to use, copy, modify, and/or distribute this software for any
|
|
purpose with or without fee is hereby granted.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
PERFORMANCE OF THIS SOFTWARE.
|
|
***************************************************************************** */
|
|
/* global Reflect, Promise */
|
|
var extendStatics = function (d, b) {
|
|
extendStatics = Object.setPrototypeOf ||
|
|
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
|
|
function (d, b) { for (var p in b)
|
|
if (Object.prototype.hasOwnProperty.call(b, p))
|
|
d[p] = b[p]; };
|
|
return extendStatics(d, b);
|
|
};
|
|
function __extends(d, b) {
|
|
if (typeof b !== "function" && b !== null)
|
|
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
|
|
extendStatics(d, b);
|
|
function __() { this.constructor = d; }
|
|
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
|
}
|
|
var __assign = function () {
|
|
__assign = Object.assign || function __assign(t) {
|
|
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
s = arguments[i];
|
|
for (var p in s)
|
|
if (Object.prototype.hasOwnProperty.call(s, p))
|
|
t[p] = s[p];
|
|
}
|
|
return t;
|
|
};
|
|
return __assign.apply(this, arguments);
|
|
};
|
|
function __rest(s, e) {
|
|
var t = {};
|
|
for (var p in s)
|
|
if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
t[p] = s[p];
|
|
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
t[p[i]] = s[p[i]];
|
|
}
|
|
return t;
|
|
}
|
|
function __decorate(decorators, target, key, desc) {
|
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
|
|
r = Reflect.decorate(decorators, target, key, desc);
|
|
else
|
|
for (var i = decorators.length - 1; i >= 0; i--)
|
|
if (d = decorators[i])
|
|
r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
}
|
|
function __param(paramIndex, decorator) {
|
|
return function (target, key) { decorator(target, key, paramIndex); };
|
|
}
|
|
function __metadata(metadataKey, metadataValue) {
|
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function")
|
|
return Reflect.metadata(metadataKey, metadataValue);
|
|
}
|
|
function __awaiter(thisArg, _arguments, P, generator) {
|
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
return new (P || (P = Promise))(function (resolve, reject) {
|
|
function fulfilled(value) { try {
|
|
step(generator.next(value));
|
|
}
|
|
catch (e) {
|
|
reject(e);
|
|
} }
|
|
function rejected(value) { try {
|
|
step(generator["throw"](value));
|
|
}
|
|
catch (e) {
|
|
reject(e);
|
|
} }
|
|
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
});
|
|
}
|
|
function __generator(thisArg, body) {
|
|
var _ = { label: 0, sent: function () { if (t[0] & 1)
|
|
throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function () { return this; }), g;
|
|
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
function step(op) {
|
|
if (f)
|
|
throw new TypeError("Generator is already executing.");
|
|
while (_)
|
|
try {
|
|
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done)
|
|
return t;
|
|
if (y = 0, t)
|
|
op = [op[0] & 2, t.value];
|
|
switch (op[0]) {
|
|
case 0:
|
|
case 1:
|
|
t = op;
|
|
break;
|
|
case 4:
|
|
_.label++;
|
|
return { value: op[1], done: false };
|
|
case 5:
|
|
_.label++;
|
|
y = op[1];
|
|
op = [0];
|
|
continue;
|
|
case 7:
|
|
op = _.ops.pop();
|
|
_.trys.pop();
|
|
continue;
|
|
default:
|
|
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) {
|
|
_ = 0;
|
|
continue;
|
|
}
|
|
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) {
|
|
_.label = op[1];
|
|
break;
|
|
}
|
|
if (op[0] === 6 && _.label < t[1]) {
|
|
_.label = t[1];
|
|
t = op;
|
|
break;
|
|
}
|
|
if (t && _.label < t[2]) {
|
|
_.label = t[2];
|
|
_.ops.push(op);
|
|
break;
|
|
}
|
|
if (t[2])
|
|
_.ops.pop();
|
|
_.trys.pop();
|
|
continue;
|
|
}
|
|
op = body.call(thisArg, _);
|
|
}
|
|
catch (e) {
|
|
op = [6, e];
|
|
y = 0;
|
|
}
|
|
finally {
|
|
f = t = 0;
|
|
}
|
|
if (op[0] & 5)
|
|
throw op[1];
|
|
return { value: op[0] ? op[1] : void 0, done: true };
|
|
}
|
|
}
|
|
var __createBinding = Object.create ? (function (o, m, k, k2) {
|
|
if (k2 === undefined)
|
|
k2 = k;
|
|
Object.defineProperty(o, k2, { enumerable: true, get: function () { return m[k]; } });
|
|
}) : (function (o, m, k, k2) {
|
|
if (k2 === undefined)
|
|
k2 = k;
|
|
o[k2] = m[k];
|
|
});
|
|
function __exportStar(m, o) {
|
|
for (var p in m)
|
|
if (p !== "default" && !Object.prototype.hasOwnProperty.call(o, p))
|
|
__createBinding(o, m, p);
|
|
}
|
|
function __values(o) {
|
|
var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
|
|
if (m)
|
|
return m.call(o);
|
|
if (o && typeof o.length === "number")
|
|
return {
|
|
next: function () {
|
|
if (o && i >= o.length)
|
|
o = void 0;
|
|
return { value: o && o[i++], done: !o };
|
|
}
|
|
};
|
|
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
|
|
}
|
|
function __read(o, n) {
|
|
var m = typeof Symbol === "function" && o[Symbol.iterator];
|
|
if (!m)
|
|
return o;
|
|
var i = m.call(o), r, ar = [], e;
|
|
try {
|
|
while ((n === void 0 || n-- > 0) && !(r = i.next()).done)
|
|
ar.push(r.value);
|
|
}
|
|
catch (error) {
|
|
e = { error: error };
|
|
}
|
|
finally {
|
|
try {
|
|
if (r && !r.done && (m = i["return"]))
|
|
m.call(i);
|
|
}
|
|
finally {
|
|
if (e)
|
|
throw e.error;
|
|
}
|
|
}
|
|
return ar;
|
|
}
|
|
/** @deprecated */
|
|
function __spread() {
|
|
for (var ar = [], i = 0; i < arguments.length; i++)
|
|
ar = ar.concat(__read(arguments[i]));
|
|
return ar;
|
|
}
|
|
/** @deprecated */
|
|
function __spreadArrays() {
|
|
for (var s = 0, i = 0, il = arguments.length; i < il; i++)
|
|
s += arguments[i].length;
|
|
for (var r = Array(s), k = 0, i = 0; i < il; i++)
|
|
for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)
|
|
r[k] = a[j];
|
|
return r;
|
|
}
|
|
function __spreadArray(to, from, pack) {
|
|
if (pack || arguments.length === 2)
|
|
for (var i = 0, l = from.length, ar; i < l; i++) {
|
|
if (ar || !(i in from)) {
|
|
if (!ar)
|
|
ar = Array.prototype.slice.call(from, 0, i);
|
|
ar[i] = from[i];
|
|
}
|
|
}
|
|
return to.concat(ar || Array.prototype.slice.call(from));
|
|
}
|
|
function __await(v) {
|
|
return this instanceof __await ? (this.v = v, this) : new __await(v);
|
|
}
|
|
function __asyncGenerator(thisArg, _arguments, generator) {
|
|
if (!Symbol.asyncIterator)
|
|
throw new TypeError("Symbol.asyncIterator is not defined.");
|
|
var g = generator.apply(thisArg, _arguments || []), i, q = [];
|
|
return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i;
|
|
function verb(n) { if (g[n])
|
|
i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; }
|
|
function resume(n, v) { try {
|
|
step(g[n](v));
|
|
}
|
|
catch (e) {
|
|
settle(q[0][3], e);
|
|
} }
|
|
function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }
|
|
function fulfill(value) { resume("next", value); }
|
|
function reject(value) { resume("throw", value); }
|
|
function settle(f, v) { if (f(v), q.shift(), q.length)
|
|
resume(q[0][0], q[0][1]); }
|
|
}
|
|
function __asyncDelegator(o) {
|
|
var i, p;
|
|
return i = {}, verb("next"), verb("throw", function (e) { throw e; }), verb("return"), i[Symbol.iterator] = function () { return this; }, i;
|
|
function verb(n, f) { i[n] = o[n] ? function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === "return" } : f ? f(v) : v; } : f; }
|
|
}
|
|
function __asyncValues(o) {
|
|
if (!Symbol.asyncIterator)
|
|
throw new TypeError("Symbol.asyncIterator is not defined.");
|
|
var m = o[Symbol.asyncIterator], i;
|
|
return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
|
|
function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
|
|
function settle(resolve, reject, d, v) { Promise.resolve(v).then(function (v) { resolve({ value: v, done: d }); }, reject); }
|
|
}
|
|
function __makeTemplateObject(cooked, raw) {
|
|
if (Object.defineProperty) {
|
|
Object.defineProperty(cooked, "raw", { value: raw });
|
|
}
|
|
else {
|
|
cooked.raw = raw;
|
|
}
|
|
return cooked;
|
|
}
|
|
;
|
|
var __setModuleDefault = Object.create ? (function (o, v) {
|
|
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
}) : function (o, v) {
|
|
o["default"] = v;
|
|
};
|
|
function __importStar(mod) {
|
|
if (mod && mod.__esModule)
|
|
return mod;
|
|
var result = {};
|
|
if (mod != null)
|
|
for (var k in mod)
|
|
if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k))
|
|
__createBinding(result, mod, k);
|
|
__setModuleDefault(result, mod);
|
|
return result;
|
|
}
|
|
function __importDefault(mod) {
|
|
return (mod && mod.__esModule) ? mod : { default: mod };
|
|
}
|
|
function __classPrivateFieldGet(receiver, state, kind, f) {
|
|
if (kind === "a" && !f)
|
|
throw new TypeError("Private accessor was defined without a getter");
|
|
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver))
|
|
throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
}
|
|
function __classPrivateFieldSet(receiver, state, value, kind, f) {
|
|
if (kind === "m")
|
|
throw new TypeError("Private method is not writable");
|
|
if (kind === "a" && !f)
|
|
throw new TypeError("Private accessor was defined without a setter");
|
|
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver))
|
|
throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), 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
|
|
*/
|
|
(function (TagContentType) {
|
|
TagContentType[TagContentType["RAW_TEXT"] = 0] = "RAW_TEXT";
|
|
TagContentType[TagContentType["ESCAPABLE_RAW_TEXT"] = 1] = "ESCAPABLE_RAW_TEXT";
|
|
TagContentType[TagContentType["PARSABLE_DATA"] = 2] = "PARSABLE_DATA";
|
|
})(exports.TagContentType || (exports.TagContentType = {}));
|
|
function splitNsName(elementName) {
|
|
if (elementName[0] != ':') {
|
|
return [null, elementName];
|
|
}
|
|
var colonIndex = elementName.indexOf(':', 1);
|
|
if (colonIndex === -1) {
|
|
throw new Error("Unsupported format \"" + elementName + "\" expecting \":namespace:name\"");
|
|
}
|
|
return [elementName.slice(1, colonIndex), elementName.slice(colonIndex + 1)];
|
|
}
|
|
// `<ng-container>` tags work the same regardless the namespace
|
|
function isNgContainer(tagName) {
|
|
return splitNsName(tagName)[1] === 'ng-container';
|
|
}
|
|
// `<ng-content>` tags work the same regardless the namespace
|
|
function isNgContent(tagName) {
|
|
return splitNsName(tagName)[1] === 'ng-content';
|
|
}
|
|
// `<ng-template>` tags work the same regardless the namespace
|
|
function isNgTemplate(tagName) {
|
|
return splitNsName(tagName)[1] === 'ng-template';
|
|
}
|
|
function getNsPrefix(fullName) {
|
|
return fullName === null ? null : splitNsName(fullName)[0];
|
|
}
|
|
function mergeNsAndName(prefix, localName) {
|
|
return prefix ? ":" + prefix + ":" + localName : localName;
|
|
}
|
|
|
|
/**
|
|
* @license
|
|
* Copyright Google LLC All Rights Reserved.
|
|
*
|
|
* Use of this source code is governed by an MIT-style license that can be
|
|
* found in the LICENSE file at https://angular.io/license
|
|
*/
|
|
var HtmlTagDefinition = /** @class */ (function () {
|
|
function HtmlTagDefinition(_c) {
|
|
var _this = this;
|
|
var _d = _c === void 0 ? {} : _c, closedByChildren = _d.closedByChildren, implicitNamespacePrefix = _d.implicitNamespacePrefix, _e = _d.contentType, contentType = _e === void 0 ? exports.TagContentType.PARSABLE_DATA : _e, _f = _d.closedByParent, closedByParent = _f === void 0 ? false : _f, _g = _d.isVoid, isVoid = _g === void 0 ? false : _g, _h = _d.ignoreFirstLf, ignoreFirstLf = _h === void 0 ? false : _h, _j = _d.preventNamespaceInheritance, preventNamespaceInheritance = _j === void 0 ? false : _j;
|
|
this.closedByChildren = {};
|
|
this.closedByParent = false;
|
|
this.canSelfClose = false;
|
|
if (closedByChildren && closedByChildren.length > 0) {
|
|
closedByChildren.forEach(function (tagName) { return _this.closedByChildren[tagName] = true; });
|
|
}
|
|
this.isVoid = isVoid;
|
|
this.closedByParent = closedByParent || isVoid;
|
|
this.implicitNamespacePrefix = implicitNamespacePrefix || null;
|
|
this.contentType = contentType;
|
|
this.ignoreFirstLf = ignoreFirstLf;
|
|
this.preventNamespaceInheritance = preventNamespaceInheritance;
|
|
}
|
|
HtmlTagDefinition.prototype.isClosedByChild = function (name) {
|
|
return this.isVoid || name.toLowerCase() in this.closedByChildren;
|
|
};
|
|
HtmlTagDefinition.prototype.getContentType = function (prefix) {
|
|
if (typeof this.contentType === 'object') {
|
|
var overrideType = prefix === undefined ? undefined : this.contentType[prefix];
|
|
return overrideType !== null && overrideType !== void 0 ? overrideType : this.contentType.default;
|
|
}
|
|
return this.contentType;
|
|
};
|
|
return HtmlTagDefinition;
|
|
}());
|
|
var _DEFAULT_TAG_DEFINITION;
|
|
// see https://www.w3.org/TR/html51/syntax.html#optional-tags
|
|
// This implementation does not fully conform to the HTML5 spec.
|
|
var TAG_DEFINITIONS;
|
|
function getHtmlTagDefinition(tagName) {
|
|
var _a, _b;
|
|
if (!TAG_DEFINITIONS) {
|
|
_DEFAULT_TAG_DEFINITION = new HtmlTagDefinition();
|
|
TAG_DEFINITIONS = {
|
|
'base': new HtmlTagDefinition({ isVoid: true }),
|
|
'meta': new HtmlTagDefinition({ isVoid: true }),
|
|
'area': new HtmlTagDefinition({ isVoid: true }),
|
|
'embed': new HtmlTagDefinition({ isVoid: true }),
|
|
'link': new HtmlTagDefinition({ isVoid: true }),
|
|
'img': new HtmlTagDefinition({ isVoid: true }),
|
|
'input': new HtmlTagDefinition({ isVoid: true }),
|
|
'param': new HtmlTagDefinition({ isVoid: true }),
|
|
'hr': new HtmlTagDefinition({ isVoid: true }),
|
|
'br': new HtmlTagDefinition({ isVoid: true }),
|
|
'source': new HtmlTagDefinition({ isVoid: true }),
|
|
'track': new HtmlTagDefinition({ isVoid: true }),
|
|
'wbr': new HtmlTagDefinition({ isVoid: true }),
|
|
'p': new HtmlTagDefinition({
|
|
closedByChildren: [
|
|
'address', 'article', 'aside', 'blockquote', 'div', 'dl', 'fieldset',
|
|
'footer', 'form', 'h1', 'h2', 'h3', 'h4', 'h5',
|
|
'h6', 'header', 'hgroup', 'hr', 'main', 'nav', 'ol',
|
|
'p', 'pre', 'section', 'table', 'ul'
|
|
],
|
|
closedByParent: true
|
|
}),
|
|
'thead': new HtmlTagDefinition({ closedByChildren: ['tbody', 'tfoot'] }),
|
|
'tbody': new HtmlTagDefinition({ closedByChildren: ['tbody', 'tfoot'], closedByParent: true }),
|
|
'tfoot': new HtmlTagDefinition({ closedByChildren: ['tbody'], closedByParent: true }),
|
|
'tr': new HtmlTagDefinition({ closedByChildren: ['tr'], closedByParent: true }),
|
|
'td': new HtmlTagDefinition({ closedByChildren: ['td', 'th'], closedByParent: true }),
|
|
'th': new HtmlTagDefinition({ closedByChildren: ['td', 'th'], closedByParent: true }),
|
|
'col': new HtmlTagDefinition({ isVoid: true }),
|
|
'svg': new HtmlTagDefinition({ implicitNamespacePrefix: 'svg' }),
|
|
'foreignObject': new HtmlTagDefinition({
|
|
// Usually the implicit namespace here would be redundant since it will be inherited from
|
|
// the parent `svg`, but we have to do it for `foreignObject`, because the way the parser
|
|
// works is that the parent node of an end tag is its own start tag which means that
|
|
// the `preventNamespaceInheritance` on `foreignObject` would have it default to the
|
|
// implicit namespace which is `html`, unless specified otherwise.
|
|
implicitNamespacePrefix: 'svg',
|
|
// We want to prevent children of foreignObject from inheriting its namespace, because
|
|
// the point of the element is to allow nodes from other namespaces to be inserted.
|
|
preventNamespaceInheritance: true,
|
|
}),
|
|
'math': new HtmlTagDefinition({ implicitNamespacePrefix: 'math' }),
|
|
'li': new HtmlTagDefinition({ closedByChildren: ['li'], closedByParent: true }),
|
|
'dt': new HtmlTagDefinition({ closedByChildren: ['dt', 'dd'] }),
|
|
'dd': new HtmlTagDefinition({ closedByChildren: ['dt', 'dd'], closedByParent: true }),
|
|
'rb': new HtmlTagDefinition({ closedByChildren: ['rb', 'rt', 'rtc', 'rp'], closedByParent: true }),
|
|
'rt': new HtmlTagDefinition({ closedByChildren: ['rb', 'rt', 'rtc', 'rp'], closedByParent: true }),
|
|
'rtc': new HtmlTagDefinition({ closedByChildren: ['rb', 'rtc', 'rp'], closedByParent: true }),
|
|
'rp': new HtmlTagDefinition({ closedByChildren: ['rb', 'rt', 'rtc', 'rp'], closedByParent: true }),
|
|
'optgroup': new HtmlTagDefinition({ closedByChildren: ['optgroup'], closedByParent: true }),
|
|
'option': new HtmlTagDefinition({ closedByChildren: ['option', 'optgroup'], closedByParent: true }),
|
|
'pre': new HtmlTagDefinition({ ignoreFirstLf: true }),
|
|
'listing': new HtmlTagDefinition({ ignoreFirstLf: true }),
|
|
'style': new HtmlTagDefinition({ contentType: exports.TagContentType.RAW_TEXT }),
|
|
'script': new HtmlTagDefinition({ contentType: exports.TagContentType.RAW_TEXT }),
|
|
'title': new HtmlTagDefinition({
|
|
// The browser supports two separate `title` tags which have to use
|
|
// a different content type: `HTMLTitleElement` and `SVGTitleElement`
|
|
contentType: { default: exports.TagContentType.ESCAPABLE_RAW_TEXT, svg: exports.TagContentType.PARSABLE_DATA }
|
|
}),
|
|
'textarea': new HtmlTagDefinition({ contentType: exports.TagContentType.ESCAPABLE_RAW_TEXT, ignoreFirstLf: true }),
|
|
};
|
|
}
|
|
// We have to make both a case-sensitive and a case-insesitive lookup, because
|
|
// HTML tag names are case insensitive, whereas some SVG tags are case sensitive.
|
|
return (_b = (_a = TAG_DEFINITIONS[tagName]) !== null && _a !== void 0 ? _a : TAG_DEFINITIONS[tagName.toLowerCase()]) !== null && _b !== void 0 ? _b : _DEFAULT_TAG_DEFINITION;
|
|
}
|
|
|
|
/**
|
|
* @license
|
|
* Copyright Google LLC All Rights Reserved.
|
|
*
|
|
* Use of this source code is governed by an MIT-style license that can be
|
|
* found in the LICENSE file at https://angular.io/license
|
|
*/
|
|
var _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.
|
|
*/
|
|
var CssSelector = /** @class */ (function () {
|
|
function CssSelector() {
|
|
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 = [];
|
|
}
|
|
CssSelector.parse = function (selector) {
|
|
var results = [];
|
|
var _addResult = function (res, cssSel) {
|
|
if (cssSel.notSelectors.length > 0 && !cssSel.element && cssSel.classNames.length == 0 &&
|
|
cssSel.attrs.length == 0) {
|
|
cssSel.element = '*';
|
|
}
|
|
res.push(cssSel);
|
|
};
|
|
var cssSelector = new CssSelector();
|
|
var match;
|
|
var current = cssSelector;
|
|
var inNot = false;
|
|
_SELECTOR_REGEXP.lastIndex = 0;
|
|
while (match = _SELECTOR_REGEXP.exec(selector)) {
|
|
if (match[1 /* NOT */]) {
|
|
if (inNot) {
|
|
throw new Error('Nesting :not in a selector is not allowed');
|
|
}
|
|
inNot = true;
|
|
current = new CssSelector();
|
|
cssSelector.notSelectors.push(current);
|
|
}
|
|
var tag = match[2 /* TAG */];
|
|
if (tag) {
|
|
var prefix = match[3 /* PREFIX */];
|
|
if (prefix === '#') {
|
|
// #hash
|
|
current.addAttribute('id', tag.substr(1));
|
|
}
|
|
else if (prefix === '.') {
|
|
// Class
|
|
current.addClassName(tag.substr(1));
|
|
}
|
|
else {
|
|
// Element
|
|
current.setElement(tag);
|
|
}
|
|
}
|
|
var attribute = match[4 /* ATTRIBUTE */];
|
|
if (attribute) {
|
|
current.addAttribute(current.unescapeAttribute(attribute), match[6 /* ATTRIBUTE_VALUE */]);
|
|
}
|
|
if (match[7 /* NOT_END */]) {
|
|
inNot = false;
|
|
current = cssSelector;
|
|
}
|
|
if (match[8 /* SEPARATOR */]) {
|
|
if (inNot) {
|
|
throw new Error('Multiple selectors in :not are not supported');
|
|
}
|
|
_addResult(results, cssSelector);
|
|
cssSelector = current = new CssSelector();
|
|
}
|
|
}
|
|
_addResult(results, cssSelector);
|
|
return results;
|
|
};
|
|
/**
|
|
* Unescape `\$` sequences from the CSS attribute selector.
|
|
*
|
|
* This is needed because `$` can have a special meaning in CSS selectors,
|
|
* but we might want to match an attribute that contains `$`.
|
|
* [MDN web link for more
|
|
* info](https://developer.mozilla.org/en-US/docs/Web/CSS/Attribute_selectors).
|
|
* @param attr the attribute to unescape.
|
|
* @returns the unescaped string.
|
|
*/
|
|
CssSelector.prototype.unescapeAttribute = function (attr) {
|
|
var result = '';
|
|
var escaping = false;
|
|
for (var i = 0; i < attr.length; i++) {
|
|
var 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.
|
|
*/
|
|
CssSelector.prototype.escapeAttribute = function (attr) {
|
|
return attr.replace(/\\/g, '\\\\').replace(/\$/g, '\\$');
|
|
};
|
|
CssSelector.prototype.isElementSelector = function () {
|
|
return this.hasElementSelector() && this.classNames.length == 0 && this.attrs.length == 0 &&
|
|
this.notSelectors.length === 0;
|
|
};
|
|
CssSelector.prototype.hasElementSelector = function () {
|
|
return !!this.element;
|
|
};
|
|
CssSelector.prototype.setElement = function (element) {
|
|
if (element === void 0) { element = null; }
|
|
this.element = element;
|
|
};
|
|
/** Gets a template string for an element that matches the selector. */
|
|
CssSelector.prototype.getMatchingElementTemplate = function () {
|
|
var tagName = this.element || 'div';
|
|
var classAttr = this.classNames.length > 0 ? " class=\"" + this.classNames.join(' ') + "\"" : '';
|
|
var attrs = '';
|
|
for (var i = 0; i < this.attrs.length; i += 2) {
|
|
var attrName = this.attrs[i];
|
|
var attrValue = this.attrs[i + 1] !== '' ? "=\"" + this.attrs[i + 1] + "\"" : '';
|
|
attrs += " " + attrName + attrValue;
|
|
}
|
|
return getHtmlTagDefinition(tagName).isVoid ? "<" + tagName + classAttr + attrs + "/>" :
|
|
"<" + tagName + classAttr + attrs + "></" + tagName + ">";
|
|
};
|
|
CssSelector.prototype.getAttrs = function () {
|
|
var result = [];
|
|
if (this.classNames.length > 0) {
|
|
result.push('class', this.classNames.join(' '));
|
|
}
|
|
return result.concat(this.attrs);
|
|
};
|
|
CssSelector.prototype.addAttribute = function (name, value) {
|
|
if (value === void 0) { value = ''; }
|
|
this.attrs.push(name, value && value.toLowerCase() || '');
|
|
};
|
|
CssSelector.prototype.addClassName = function (name) {
|
|
this.classNames.push(name.toLowerCase());
|
|
};
|
|
CssSelector.prototype.toString = function () {
|
|
var res = this.element || '';
|
|
if (this.classNames) {
|
|
this.classNames.forEach(function (klass) { return res += "." + klass; });
|
|
}
|
|
if (this.attrs) {
|
|
for (var i = 0; i < this.attrs.length; i += 2) {
|
|
var name = this.escapeAttribute(this.attrs[i]);
|
|
var value = this.attrs[i + 1];
|
|
res += "[" + name + (value ? '=' + value : '') + "]";
|
|
}
|
|
}
|
|
this.notSelectors.forEach(function (notSelector) { return res += ":not(" + notSelector + ")"; });
|
|
return res;
|
|
};
|
|
return CssSelector;
|
|
}());
|
|
/**
|
|
* Reads a list of CssSelectors and allows to calculate which ones
|
|
* are contained in a given CssSelector.
|
|
*/
|
|
var SelectorMatcher = /** @class */ (function () {
|
|
function SelectorMatcher() {
|
|
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 = [];
|
|
}
|
|
SelectorMatcher.createNotMatcher = function (notSelectors) {
|
|
var notMatcher = new SelectorMatcher();
|
|
notMatcher.addSelectables(notSelectors, null);
|
|
return notMatcher;
|
|
};
|
|
SelectorMatcher.prototype.addSelectables = function (cssSelectors, callbackCtxt) {
|
|
var listContext = null;
|
|
if (cssSelectors.length > 1) {
|
|
listContext = new SelectorListContext(cssSelectors);
|
|
this._listContexts.push(listContext);
|
|
}
|
|
for (var 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
|
|
*/
|
|
SelectorMatcher.prototype._addSelectable = function (cssSelector, callbackCtxt, listContext) {
|
|
var matcher = this;
|
|
var element = cssSelector.element;
|
|
var classNames = cssSelector.classNames;
|
|
var attrs = cssSelector.attrs;
|
|
var selectable = new SelectorContext(cssSelector, callbackCtxt, listContext);
|
|
if (element) {
|
|
var 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 (var i = 0; i < classNames.length; i++) {
|
|
var isTerminal = attrs.length === 0 && i === classNames.length - 1;
|
|
var className = classNames[i];
|
|
if (isTerminal) {
|
|
this._addTerminal(matcher._classMap, className, selectable);
|
|
}
|
|
else {
|
|
matcher = this._addPartial(matcher._classPartialMap, className);
|
|
}
|
|
}
|
|
}
|
|
if (attrs) {
|
|
for (var i = 0; i < attrs.length; i += 2) {
|
|
var isTerminal = i === attrs.length - 2;
|
|
var name = attrs[i];
|
|
var value = attrs[i + 1];
|
|
if (isTerminal) {
|
|
var terminalMap = matcher._attrValueMap;
|
|
var terminalValuesMap = terminalMap.get(name);
|
|
if (!terminalValuesMap) {
|
|
terminalValuesMap = new Map();
|
|
terminalMap.set(name, terminalValuesMap);
|
|
}
|
|
this._addTerminal(terminalValuesMap, value, selectable);
|
|
}
|
|
else {
|
|
var partialMap = matcher._attrValuePartialMap;
|
|
var partialValuesMap = partialMap.get(name);
|
|
if (!partialValuesMap) {
|
|
partialValuesMap = new Map();
|
|
partialMap.set(name, partialValuesMap);
|
|
}
|
|
matcher = this._addPartial(partialValuesMap, value);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
SelectorMatcher.prototype._addTerminal = function (map, name, selectable) {
|
|
var terminalList = map.get(name);
|
|
if (!terminalList) {
|
|
terminalList = [];
|
|
map.set(name, terminalList);
|
|
}
|
|
terminalList.push(selectable);
|
|
};
|
|
SelectorMatcher.prototype._addPartial = function (map, name) {
|
|
var 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
|
|
*/
|
|
SelectorMatcher.prototype.match = function (cssSelector, matchedCallback) {
|
|
var result = false;
|
|
var element = cssSelector.element;
|
|
var classNames = cssSelector.classNames;
|
|
var attrs = cssSelector.attrs;
|
|
for (var 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 (var i = 0; i < classNames.length; i++) {
|
|
var className = classNames[i];
|
|
result =
|
|
this._matchTerminal(this._classMap, className, cssSelector, matchedCallback) || result;
|
|
result =
|
|
this._matchPartial(this._classPartialMap, className, cssSelector, matchedCallback) ||
|
|
result;
|
|
}
|
|
}
|
|
if (attrs) {
|
|
for (var i = 0; i < attrs.length; i += 2) {
|
|
var name = attrs[i];
|
|
var value = attrs[i + 1];
|
|
var terminalValuesMap = this._attrValueMap.get(name);
|
|
if (value) {
|
|
result =
|
|
this._matchTerminal(terminalValuesMap, '', cssSelector, matchedCallback) || result;
|
|
}
|
|
result =
|
|
this._matchTerminal(terminalValuesMap, value, cssSelector, matchedCallback) || result;
|
|
var 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 */
|
|
SelectorMatcher.prototype._matchTerminal = function (map, name, cssSelector, matchedCallback) {
|
|
if (!map || typeof name !== 'string') {
|
|
return false;
|
|
}
|
|
var selectables = map.get(name) || [];
|
|
var starSelectables = map.get('*');
|
|
if (starSelectables) {
|
|
selectables = selectables.concat(starSelectables);
|
|
}
|
|
if (selectables.length === 0) {
|
|
return false;
|
|
}
|
|
var selectable;
|
|
var result = false;
|
|
for (var i = 0; i < selectables.length; i++) {
|
|
selectable = selectables[i];
|
|
result = selectable.finalize(cssSelector, matchedCallback) || result;
|
|
}
|
|
return result;
|
|
};
|
|
/** @internal */
|
|
SelectorMatcher.prototype._matchPartial = function (map, name, cssSelector, matchedCallback) {
|
|
if (!map || typeof name !== 'string') {
|
|
return false;
|
|
}
|
|
var 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);
|
|
};
|
|
return SelectorMatcher;
|
|
}());
|
|
var SelectorListContext = /** @class */ (function () {
|
|
function SelectorListContext(selectors) {
|
|
this.selectors = selectors;
|
|
this.alreadyMatched = false;
|
|
}
|
|
return SelectorListContext;
|
|
}());
|
|
// Store context to pass back selector and context when a selector is matched
|
|
var SelectorContext = /** @class */ (function () {
|
|
function SelectorContext(selector, cbContext, listContext) {
|
|
this.selector = selector;
|
|
this.cbContext = cbContext;
|
|
this.listContext = listContext;
|
|
this.notSelectors = selector.notSelectors;
|
|
}
|
|
SelectorContext.prototype.finalize = function (cssSelector, callback) {
|
|
var result = true;
|
|
if (this.notSelectors.length > 0 && (!this.listContext || !this.listContext.alreadyMatched)) {
|
|
var 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;
|
|
};
|
|
return SelectorContext;
|
|
}());
|
|
|
|
var createInject = makeMetadataFactory('Inject', function (token) { return ({ token: token }); });
|
|
var createInjectionToken = makeMetadataFactory('InjectionToken', function (desc) { return ({ _desc: desc, ɵprov: undefined }); });
|
|
var createAttribute = makeMetadataFactory('Attribute', function (attributeName) { return ({ attributeName: attributeName }); });
|
|
// Stores the default value of `emitDistinctChangesOnly` when the `emitDistinctChangesOnly` is not
|
|
// explicitly set.
|
|
var emitDistinctChangesOnlyDefaultValue = true;
|
|
var createContentChildren = makeMetadataFactory('ContentChildren', function (selector, data) {
|
|
if (data === void 0) { data = {}; }
|
|
return (Object.assign({ selector: selector, first: false, isViewQuery: false, descendants: false, emitDistinctChangesOnly: emitDistinctChangesOnlyDefaultValue }, data));
|
|
});
|
|
var createContentChild = makeMetadataFactory('ContentChild', function (selector, data) {
|
|
if (data === void 0) { data = {}; }
|
|
return (Object.assign({ selector: selector, first: true, isViewQuery: false, descendants: true }, data));
|
|
});
|
|
var createViewChildren = makeMetadataFactory('ViewChildren', function (selector, data) {
|
|
if (data === void 0) { data = {}; }
|
|
return (Object.assign({ selector: selector, first: false, isViewQuery: true, descendants: true, emitDistinctChangesOnly: emitDistinctChangesOnlyDefaultValue }, data));
|
|
});
|
|
var createViewChild = makeMetadataFactory('ViewChild', function (selector, data) { return (Object.assign({ selector: selector, first: true, isViewQuery: true, descendants: true }, data)); });
|
|
var createDirective = makeMetadataFactory('Directive', function (dir) {
|
|
if (dir === void 0) { dir = {}; }
|
|
return dir;
|
|
});
|
|
var ViewEncapsulation;
|
|
(function (ViewEncapsulation) {
|
|
ViewEncapsulation[ViewEncapsulation["Emulated"] = 0] = "Emulated";
|
|
// Historically the 1 value was for `Native` encapsulation which has been removed as of v11.
|
|
ViewEncapsulation[ViewEncapsulation["None"] = 2] = "None";
|
|
ViewEncapsulation[ViewEncapsulation["ShadowDom"] = 3] = "ShadowDom";
|
|
})(ViewEncapsulation || (ViewEncapsulation = {}));
|
|
var ChangeDetectionStrategy;
|
|
(function (ChangeDetectionStrategy) {
|
|
ChangeDetectionStrategy[ChangeDetectionStrategy["OnPush"] = 0] = "OnPush";
|
|
ChangeDetectionStrategy[ChangeDetectionStrategy["Default"] = 1] = "Default";
|
|
})(ChangeDetectionStrategy || (ChangeDetectionStrategy = {}));
|
|
var createComponent = makeMetadataFactory('Component', function (c) {
|
|
if (c === void 0) { c = {}; }
|
|
return (Object.assign({ changeDetection: ChangeDetectionStrategy.Default }, c));
|
|
});
|
|
var createPipe = makeMetadataFactory('Pipe', function (p) { return (Object.assign({ pure: true }, p)); });
|
|
var createInput = makeMetadataFactory('Input', function (bindingPropertyName) { return ({ bindingPropertyName: bindingPropertyName }); });
|
|
var createOutput = makeMetadataFactory('Output', function (bindingPropertyName) { return ({ bindingPropertyName: bindingPropertyName }); });
|
|
var createHostBinding = makeMetadataFactory('HostBinding', function (hostPropertyName) { return ({ hostPropertyName: hostPropertyName }); });
|
|
var createHostListener = makeMetadataFactory('HostListener', function (eventName, args) { return ({ eventName: eventName, args: args }); });
|
|
var createNgModule = makeMetadataFactory('NgModule', function (ngModule) { return ngModule; });
|
|
var createInjectable = makeMetadataFactory('Injectable', function (injectable) {
|
|
if (injectable === void 0) { injectable = {}; }
|
|
return injectable;
|
|
});
|
|
var CUSTOM_ELEMENTS_SCHEMA = {
|
|
name: 'custom-elements'
|
|
};
|
|
var NO_ERRORS_SCHEMA = {
|
|
name: 'no-errors-schema'
|
|
};
|
|
var createOptional = makeMetadataFactory('Optional');
|
|
var createSelf = makeMetadataFactory('Self');
|
|
var createSkipSelf = makeMetadataFactory('SkipSelf');
|
|
var createHost = makeMetadataFactory('Host');
|
|
var Type = Function;
|
|
var SecurityContext;
|
|
(function (SecurityContext) {
|
|
SecurityContext[SecurityContext["NONE"] = 0] = "NONE";
|
|
SecurityContext[SecurityContext["HTML"] = 1] = "HTML";
|
|
SecurityContext[SecurityContext["STYLE"] = 2] = "STYLE";
|
|
SecurityContext[SecurityContext["SCRIPT"] = 3] = "SCRIPT";
|
|
SecurityContext[SecurityContext["URL"] = 4] = "URL";
|
|
SecurityContext[SecurityContext["RESOURCE_URL"] = 5] = "RESOURCE_URL";
|
|
})(SecurityContext || (SecurityContext = {}));
|
|
var MissingTranslationStrategy;
|
|
(function (MissingTranslationStrategy) {
|
|
MissingTranslationStrategy[MissingTranslationStrategy["Error"] = 0] = "Error";
|
|
MissingTranslationStrategy[MissingTranslationStrategy["Warning"] = 1] = "Warning";
|
|
MissingTranslationStrategy[MissingTranslationStrategy["Ignore"] = 2] = "Ignore";
|
|
})(MissingTranslationStrategy || (MissingTranslationStrategy = {}));
|
|
function makeMetadataFactory(name, props) {
|
|
// This must be declared as a function, not a fat arrow, so that ES2015 devmode produces code
|
|
// that works with the static_reflector.ts in the ViewEngine compiler.
|
|
// In particular, `_registerDecoratorOrConstructor` assumes that the value returned here can be
|
|
// new'ed.
|
|
function factory() {
|
|
var args = [];
|
|
for (var _i = 0; _i < arguments.length; _i++) {
|
|
args[_i] = arguments[_i];
|
|
}
|
|
var values = props ? props.apply(void 0, __spreadArray([], __read(args))) : {};
|
|
return Object.assign({ ngMetadataName: name }, values);
|
|
}
|
|
factory.isTypeOf = function (obj) { return obj && obj.ngMetadataName === name; };
|
|
factory.ngMetadataName = name;
|
|
return factory;
|
|
}
|
|
function parserSelectorToSimpleSelector(selector) {
|
|
var classes = selector.classNames && selector.classNames.length ? __spreadArray([8 /* CLASS */], __read(selector.classNames)) :
|
|
[];
|
|
var elementName = selector.element && selector.element !== '*' ? selector.element : '';
|
|
return __spreadArray(__spreadArray([elementName], __read(selector.attrs)), __read(classes));
|
|
}
|
|
function parserSelectorToNegativeSelector(selector) {
|
|
var classes = selector.classNames && selector.classNames.length ? __spreadArray([8 /* CLASS */], __read(selector.classNames)) :
|
|
[];
|
|
if (selector.element) {
|
|
return __spreadArray(__spreadArray([
|
|
1 /* NOT */ | 4 /* ELEMENT */, selector.element
|
|
], __read(selector.attrs)), __read(classes));
|
|
}
|
|
else if (selector.attrs.length) {
|
|
return __spreadArray(__spreadArray([1 /* NOT */ | 2 /* ATTRIBUTE */], __read(selector.attrs)), __read(classes));
|
|
}
|
|
else {
|
|
return selector.classNames && selector.classNames.length ? __spreadArray([1 /* NOT */ | 8 /* CLASS */], __read(selector.classNames)) :
|
|
[];
|
|
}
|
|
}
|
|
function parserSelectorToR3Selector(selector) {
|
|
var positive = parserSelectorToSimpleSelector(selector);
|
|
var negative = selector.notSelectors && selector.notSelectors.length ?
|
|
selector.notSelectors.map(function (notSelector) { return parserSelectorToNegativeSelector(notSelector); }) :
|
|
[];
|
|
return positive.concat.apply(positive, __spreadArray([], __read(negative)));
|
|
}
|
|
function parseSelectorToR3Selector(selector) {
|
|
return selector ? CssSelector.parse(selector).map(parserSelectorToR3Selector) : [];
|
|
}
|
|
|
|
var core = /*#__PURE__*/Object.freeze({
|
|
__proto__: null,
|
|
createInject: createInject,
|
|
createInjectionToken: createInjectionToken,
|
|
createAttribute: createAttribute,
|
|
emitDistinctChangesOnlyDefaultValue: emitDistinctChangesOnlyDefaultValue,
|
|
createContentChildren: createContentChildren,
|
|
createContentChild: createContentChild,
|
|
createViewChildren: createViewChildren,
|
|
createViewChild: createViewChild,
|
|
createDirective: createDirective,
|
|
get ViewEncapsulation () { return ViewEncapsulation; },
|
|
get ChangeDetectionStrategy () { return ChangeDetectionStrategy; },
|
|
createComponent: createComponent,
|
|
createPipe: createPipe,
|
|
createInput: createInput,
|
|
createOutput: createOutput,
|
|
createHostBinding: createHostBinding,
|
|
createHostListener: createHostListener,
|
|
createNgModule: createNgModule,
|
|
createInjectable: createInjectable,
|
|
CUSTOM_ELEMENTS_SCHEMA: CUSTOM_ELEMENTS_SCHEMA,
|
|
NO_ERRORS_SCHEMA: NO_ERRORS_SCHEMA,
|
|
createOptional: createOptional,
|
|
createSelf: createSelf,
|
|
createSkipSelf: createSkipSelf,
|
|
createHost: createHost,
|
|
Type: Type,
|
|
get SecurityContext () { return SecurityContext; },
|
|
get MissingTranslationStrategy () { return MissingTranslationStrategy; },
|
|
parseSelectorToR3Selector: parseSelectorToR3Selector
|
|
});
|
|
|
|
/**
|
|
* @license
|
|
* Copyright Google LLC All Rights Reserved.
|
|
*
|
|
* Use of this source code is governed by an MIT-style license that can be
|
|
* found in the LICENSE file at https://angular.io/license
|
|
*/
|
|
//// Types
|
|
var TypeModifier;
|
|
(function (TypeModifier) {
|
|
TypeModifier[TypeModifier["Const"] = 0] = "Const";
|
|
})(TypeModifier || (TypeModifier = {}));
|
|
var Type$1 = /** @class */ (function () {
|
|
function Type(modifiers) {
|
|
if (modifiers === void 0) { modifiers = []; }
|
|
this.modifiers = modifiers;
|
|
}
|
|
Type.prototype.hasModifier = function (modifier) {
|
|
return this.modifiers.indexOf(modifier) !== -1;
|
|
};
|
|
return Type;
|
|
}());
|
|
(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";
|
|
})(exports.BuiltinTypeName || (exports.BuiltinTypeName = {}));
|
|
var BuiltinType = /** @class */ (function (_super) {
|
|
__extends(BuiltinType, _super);
|
|
function BuiltinType(name, modifiers) {
|
|
var _this = _super.call(this, modifiers) || this;
|
|
_this.name = name;
|
|
return _this;
|
|
}
|
|
BuiltinType.prototype.visitType = function (visitor, context) {
|
|
return visitor.visitBuiltinType(this, context);
|
|
};
|
|
return BuiltinType;
|
|
}(Type$1));
|
|
var ExpressionType = /** @class */ (function (_super) {
|
|
__extends(ExpressionType, _super);
|
|
function ExpressionType(value, modifiers, typeParams) {
|
|
if (typeParams === void 0) { typeParams = null; }
|
|
var _this = _super.call(this, modifiers) || this;
|
|
_this.value = value;
|
|
_this.typeParams = typeParams;
|
|
return _this;
|
|
}
|
|
ExpressionType.prototype.visitType = function (visitor, context) {
|
|
return visitor.visitExpressionType(this, context);
|
|
};
|
|
return ExpressionType;
|
|
}(Type$1));
|
|
var ArrayType = /** @class */ (function (_super) {
|
|
__extends(ArrayType, _super);
|
|
function ArrayType(of, modifiers) {
|
|
var _this = _super.call(this, modifiers) || this;
|
|
_this.of = of;
|
|
return _this;
|
|
}
|
|
ArrayType.prototype.visitType = function (visitor, context) {
|
|
return visitor.visitArrayType(this, context);
|
|
};
|
|
return ArrayType;
|
|
}(Type$1));
|
|
var MapType = /** @class */ (function (_super) {
|
|
__extends(MapType, _super);
|
|
function MapType(valueType, modifiers) {
|
|
var _this = _super.call(this, modifiers) || this;
|
|
_this.valueType = valueType || null;
|
|
return _this;
|
|
}
|
|
MapType.prototype.visitType = function (visitor, context) {
|
|
return visitor.visitMapType(this, context);
|
|
};
|
|
return MapType;
|
|
}(Type$1));
|
|
var DYNAMIC_TYPE = new BuiltinType(exports.BuiltinTypeName.Dynamic);
|
|
var INFERRED_TYPE = new BuiltinType(exports.BuiltinTypeName.Inferred);
|
|
var BOOL_TYPE = new BuiltinType(exports.BuiltinTypeName.Bool);
|
|
var INT_TYPE = new BuiltinType(exports.BuiltinTypeName.Int);
|
|
var NUMBER_TYPE = new BuiltinType(exports.BuiltinTypeName.Number);
|
|
var STRING_TYPE = new BuiltinType(exports.BuiltinTypeName.String);
|
|
var FUNCTION_TYPE = new BuiltinType(exports.BuiltinTypeName.Function);
|
|
var NONE_TYPE = new BuiltinType(exports.BuiltinTypeName.None);
|
|
(function (UnaryOperator) {
|
|
UnaryOperator[UnaryOperator["Minus"] = 0] = "Minus";
|
|
UnaryOperator[UnaryOperator["Plus"] = 1] = "Plus";
|
|
})(exports.UnaryOperator || (exports.UnaryOperator = {}));
|
|
(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";
|
|
})(exports.BinaryOperator || (exports.BinaryOperator = {}));
|
|
function nullSafeIsEquivalent(base, other) {
|
|
if (base == null || other == null) {
|
|
return base == other;
|
|
}
|
|
return base.isEquivalent(other);
|
|
}
|
|
function areAllEquivalentPredicate(base, other, equivalentPredicate) {
|
|
var len = base.length;
|
|
if (len !== other.length) {
|
|
return false;
|
|
}
|
|
for (var i = 0; i < len; i++) {
|
|
if (!equivalentPredicate(base[i], other[i])) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
function areAllEquivalent(base, other) {
|
|
return areAllEquivalentPredicate(base, other, function (baseElement, otherElement) { return baseElement.isEquivalent(otherElement); });
|
|
}
|
|
var Expression = /** @class */ (function () {
|
|
function Expression(type, sourceSpan) {
|
|
this.type = type || null;
|
|
this.sourceSpan = sourceSpan || null;
|
|
}
|
|
Expression.prototype.prop = function (name, sourceSpan) {
|
|
return new ReadPropExpr(this, name, null, sourceSpan);
|
|
};
|
|
Expression.prototype.key = function (index, type, sourceSpan) {
|
|
return new ReadKeyExpr(this, index, type, sourceSpan);
|
|
};
|
|
Expression.prototype.callMethod = function (name, params, sourceSpan) {
|
|
return new InvokeMethodExpr(this, name, params, null, sourceSpan);
|
|
};
|
|
Expression.prototype.callFn = function (params, sourceSpan, pure) {
|
|
return new InvokeFunctionExpr(this, params, null, sourceSpan, pure);
|
|
};
|
|
Expression.prototype.instantiate = function (params, type, sourceSpan) {
|
|
return new InstantiateExpr(this, params, type, sourceSpan);
|
|
};
|
|
Expression.prototype.conditional = function (trueCase, falseCase, sourceSpan) {
|
|
if (falseCase === void 0) { falseCase = null; }
|
|
return new ConditionalExpr(this, trueCase, falseCase, null, sourceSpan);
|
|
};
|
|
Expression.prototype.equals = function (rhs, sourceSpan) {
|
|
return new BinaryOperatorExpr(exports.BinaryOperator.Equals, this, rhs, null, sourceSpan);
|
|
};
|
|
Expression.prototype.notEquals = function (rhs, sourceSpan) {
|
|
return new BinaryOperatorExpr(exports.BinaryOperator.NotEquals, this, rhs, null, sourceSpan);
|
|
};
|
|
Expression.prototype.identical = function (rhs, sourceSpan) {
|
|
return new BinaryOperatorExpr(exports.BinaryOperator.Identical, this, rhs, null, sourceSpan);
|
|
};
|
|
Expression.prototype.notIdentical = function (rhs, sourceSpan) {
|
|
return new BinaryOperatorExpr(exports.BinaryOperator.NotIdentical, this, rhs, null, sourceSpan);
|
|
};
|
|
Expression.prototype.minus = function (rhs, sourceSpan) {
|
|
return new BinaryOperatorExpr(exports.BinaryOperator.Minus, this, rhs, null, sourceSpan);
|
|
};
|
|
Expression.prototype.plus = function (rhs, sourceSpan) {
|
|
return new BinaryOperatorExpr(exports.BinaryOperator.Plus, this, rhs, null, sourceSpan);
|
|
};
|
|
Expression.prototype.divide = function (rhs, sourceSpan) {
|
|
return new BinaryOperatorExpr(exports.BinaryOperator.Divide, this, rhs, null, sourceSpan);
|
|
};
|
|
Expression.prototype.multiply = function (rhs, sourceSpan) {
|
|
return new BinaryOperatorExpr(exports.BinaryOperator.Multiply, this, rhs, null, sourceSpan);
|
|
};
|
|
Expression.prototype.modulo = function (rhs, sourceSpan) {
|
|
return new BinaryOperatorExpr(exports.BinaryOperator.Modulo, this, rhs, null, sourceSpan);
|
|
};
|
|
Expression.prototype.and = function (rhs, sourceSpan) {
|
|
return new BinaryOperatorExpr(exports.BinaryOperator.And, this, rhs, null, sourceSpan);
|
|
};
|
|
Expression.prototype.bitwiseAnd = function (rhs, sourceSpan, parens) {
|
|
if (parens === void 0) { parens = true; }
|
|
return new BinaryOperatorExpr(exports.BinaryOperator.BitwiseAnd, this, rhs, null, sourceSpan, parens);
|
|
};
|
|
Expression.prototype.or = function (rhs, sourceSpan) {
|
|
return new BinaryOperatorExpr(exports.BinaryOperator.Or, this, rhs, null, sourceSpan);
|
|
};
|
|
Expression.prototype.lower = function (rhs, sourceSpan) {
|
|
return new BinaryOperatorExpr(exports.BinaryOperator.Lower, this, rhs, null, sourceSpan);
|
|
};
|
|
Expression.prototype.lowerEquals = function (rhs, sourceSpan) {
|
|
return new BinaryOperatorExpr(exports.BinaryOperator.LowerEquals, this, rhs, null, sourceSpan);
|
|
};
|
|
Expression.prototype.bigger = function (rhs, sourceSpan) {
|
|
return new BinaryOperatorExpr(exports.BinaryOperator.Bigger, this, rhs, null, sourceSpan);
|
|
};
|
|
Expression.prototype.biggerEquals = function (rhs, sourceSpan) {
|
|
return new BinaryOperatorExpr(exports.BinaryOperator.BiggerEquals, this, rhs, null, sourceSpan);
|
|
};
|
|
Expression.prototype.isBlank = function (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);
|
|
};
|
|
Expression.prototype.cast = function (type, sourceSpan) {
|
|
return new CastExpr(this, type, sourceSpan);
|
|
};
|
|
Expression.prototype.nullishCoalesce = function (rhs, sourceSpan) {
|
|
return new BinaryOperatorExpr(exports.BinaryOperator.NullishCoalesce, this, rhs, null, sourceSpan);
|
|
};
|
|
Expression.prototype.toStmt = function () {
|
|
return new ExpressionStatement(this, null);
|
|
};
|
|
return Expression;
|
|
}());
|
|
(function (BuiltinVar) {
|
|
BuiltinVar[BuiltinVar["This"] = 0] = "This";
|
|
BuiltinVar[BuiltinVar["Super"] = 1] = "Super";
|
|
BuiltinVar[BuiltinVar["CatchError"] = 2] = "CatchError";
|
|
BuiltinVar[BuiltinVar["CatchStack"] = 3] = "CatchStack";
|
|
})(exports.BuiltinVar || (exports.BuiltinVar = {}));
|
|
var ReadVarExpr = /** @class */ (function (_super) {
|
|
__extends(ReadVarExpr, _super);
|
|
function ReadVarExpr(name, type, sourceSpan) {
|
|
var _this = _super.call(this, type, sourceSpan) || this;
|
|
if (typeof name === 'string') {
|
|
_this.name = name;
|
|
_this.builtin = null;
|
|
}
|
|
else {
|
|
_this.name = null;
|
|
_this.builtin = name;
|
|
}
|
|
return _this;
|
|
}
|
|
ReadVarExpr.prototype.isEquivalent = function (e) {
|
|
return e instanceof ReadVarExpr && this.name === e.name && this.builtin === e.builtin;
|
|
};
|
|
ReadVarExpr.prototype.isConstant = function () {
|
|
return false;
|
|
};
|
|
ReadVarExpr.prototype.visitExpression = function (visitor, context) {
|
|
return visitor.visitReadVarExpr(this, context);
|
|
};
|
|
ReadVarExpr.prototype.set = function (value) {
|
|
if (!this.name) {
|
|
throw new Error("Built in variable " + this.builtin + " can not be assigned to.");
|
|
}
|
|
return new WriteVarExpr(this.name, value, null, this.sourceSpan);
|
|
};
|
|
return ReadVarExpr;
|
|
}(Expression));
|
|
var TypeofExpr = /** @class */ (function (_super) {
|
|
__extends(TypeofExpr, _super);
|
|
function TypeofExpr(expr, type, sourceSpan) {
|
|
var _this = _super.call(this, type, sourceSpan) || this;
|
|
_this.expr = expr;
|
|
return _this;
|
|
}
|
|
TypeofExpr.prototype.visitExpression = function (visitor, context) {
|
|
return visitor.visitTypeofExpr(this, context);
|
|
};
|
|
TypeofExpr.prototype.isEquivalent = function (e) {
|
|
return e instanceof TypeofExpr && e.expr.isEquivalent(this.expr);
|
|
};
|
|
TypeofExpr.prototype.isConstant = function () {
|
|
return this.expr.isConstant();
|
|
};
|
|
return TypeofExpr;
|
|
}(Expression));
|
|
var WrappedNodeExpr = /** @class */ (function (_super) {
|
|
__extends(WrappedNodeExpr, _super);
|
|
function WrappedNodeExpr(node, type, sourceSpan) {
|
|
var _this = _super.call(this, type, sourceSpan) || this;
|
|
_this.node = node;
|
|
return _this;
|
|
}
|
|
WrappedNodeExpr.prototype.isEquivalent = function (e) {
|
|
return e instanceof WrappedNodeExpr && this.node === e.node;
|
|
};
|
|
WrappedNodeExpr.prototype.isConstant = function () {
|
|
return false;
|
|
};
|
|
WrappedNodeExpr.prototype.visitExpression = function (visitor, context) {
|
|
return visitor.visitWrappedNodeExpr(this, context);
|
|
};
|
|
return WrappedNodeExpr;
|
|
}(Expression));
|
|
var WriteVarExpr = /** @class */ (function (_super) {
|
|
__extends(WriteVarExpr, _super);
|
|
function WriteVarExpr(name, value, type, sourceSpan) {
|
|
var _this = _super.call(this, type || value.type, sourceSpan) || this;
|
|
_this.name = name;
|
|
_this.value = value;
|
|
return _this;
|
|
}
|
|
WriteVarExpr.prototype.isEquivalent = function (e) {
|
|
return e instanceof WriteVarExpr && this.name === e.name && this.value.isEquivalent(e.value);
|
|
};
|
|
WriteVarExpr.prototype.isConstant = function () {
|
|
return false;
|
|
};
|
|
WriteVarExpr.prototype.visitExpression = function (visitor, context) {
|
|
return visitor.visitWriteVarExpr(this, context);
|
|
};
|
|
WriteVarExpr.prototype.toDeclStmt = function (type, modifiers) {
|
|
return new DeclareVarStmt(this.name, this.value, type, modifiers, this.sourceSpan);
|
|
};
|
|
WriteVarExpr.prototype.toConstDecl = function () {
|
|
return this.toDeclStmt(INFERRED_TYPE, [exports.StmtModifier.Final]);
|
|
};
|
|
return WriteVarExpr;
|
|
}(Expression));
|
|
var WriteKeyExpr = /** @class */ (function (_super) {
|
|
__extends(WriteKeyExpr, _super);
|
|
function WriteKeyExpr(receiver, index, value, type, sourceSpan) {
|
|
var _this = _super.call(this, type || value.type, sourceSpan) || this;
|
|
_this.receiver = receiver;
|
|
_this.index = index;
|
|
_this.value = value;
|
|
return _this;
|
|
}
|
|
WriteKeyExpr.prototype.isEquivalent = function (e) {
|
|
return e instanceof WriteKeyExpr && this.receiver.isEquivalent(e.receiver) &&
|
|
this.index.isEquivalent(e.index) && this.value.isEquivalent(e.value);
|
|
};
|
|
WriteKeyExpr.prototype.isConstant = function () {
|
|
return false;
|
|
};
|
|
WriteKeyExpr.prototype.visitExpression = function (visitor, context) {
|
|
return visitor.visitWriteKeyExpr(this, context);
|
|
};
|
|
return WriteKeyExpr;
|
|
}(Expression));
|
|
var WritePropExpr = /** @class */ (function (_super) {
|
|
__extends(WritePropExpr, _super);
|
|
function WritePropExpr(receiver, name, value, type, sourceSpan) {
|
|
var _this = _super.call(this, type || value.type, sourceSpan) || this;
|
|
_this.receiver = receiver;
|
|
_this.name = name;
|
|
_this.value = value;
|
|
return _this;
|
|
}
|
|
WritePropExpr.prototype.isEquivalent = function (e) {
|
|
return e instanceof WritePropExpr && this.receiver.isEquivalent(e.receiver) &&
|
|
this.name === e.name && this.value.isEquivalent(e.value);
|
|
};
|
|
WritePropExpr.prototype.isConstant = function () {
|
|
return false;
|
|
};
|
|
WritePropExpr.prototype.visitExpression = function (visitor, context) {
|
|
return visitor.visitWritePropExpr(this, context);
|
|
};
|
|
return WritePropExpr;
|
|
}(Expression));
|
|
(function (BuiltinMethod) {
|
|
BuiltinMethod[BuiltinMethod["ConcatArray"] = 0] = "ConcatArray";
|
|
BuiltinMethod[BuiltinMethod["SubscribeObservable"] = 1] = "SubscribeObservable";
|
|
BuiltinMethod[BuiltinMethod["Bind"] = 2] = "Bind";
|
|
})(exports.BuiltinMethod || (exports.BuiltinMethod = {}));
|
|
var InvokeMethodExpr = /** @class */ (function (_super) {
|
|
__extends(InvokeMethodExpr, _super);
|
|
function InvokeMethodExpr(receiver, method, args, type, sourceSpan) {
|
|
var _this = _super.call(this, type, sourceSpan) || this;
|
|
_this.receiver = receiver;
|
|
_this.args = args;
|
|
if (typeof method === 'string') {
|
|
_this.name = method;
|
|
_this.builtin = null;
|
|
}
|
|
else {
|
|
_this.name = null;
|
|
_this.builtin = method;
|
|
}
|
|
return _this;
|
|
}
|
|
InvokeMethodExpr.prototype.isEquivalent = function (e) {
|
|
return e instanceof InvokeMethodExpr && this.receiver.isEquivalent(e.receiver) &&
|
|
this.name === e.name && this.builtin === e.builtin && areAllEquivalent(this.args, e.args);
|
|
};
|
|
InvokeMethodExpr.prototype.isConstant = function () {
|
|
return false;
|
|
};
|
|
InvokeMethodExpr.prototype.visitExpression = function (visitor, context) {
|
|
return visitor.visitInvokeMethodExpr(this, context);
|
|
};
|
|
return InvokeMethodExpr;
|
|
}(Expression));
|
|
var InvokeFunctionExpr = /** @class */ (function (_super) {
|
|
__extends(InvokeFunctionExpr, _super);
|
|
function InvokeFunctionExpr(fn, args, type, sourceSpan, pure) {
|
|
if (pure === void 0) { pure = false; }
|
|
var _this = _super.call(this, type, sourceSpan) || this;
|
|
_this.fn = fn;
|
|
_this.args = args;
|
|
_this.pure = pure;
|
|
return _this;
|
|
}
|
|
InvokeFunctionExpr.prototype.isEquivalent = function (e) {
|
|
return e instanceof InvokeFunctionExpr && this.fn.isEquivalent(e.fn) &&
|
|
areAllEquivalent(this.args, e.args) && this.pure === e.pure;
|
|
};
|
|
InvokeFunctionExpr.prototype.isConstant = function () {
|
|
return false;
|
|
};
|
|
InvokeFunctionExpr.prototype.visitExpression = function (visitor, context) {
|
|
return visitor.visitInvokeFunctionExpr(this, context);
|
|
};
|
|
return InvokeFunctionExpr;
|
|
}(Expression));
|
|
var TaggedTemplateExpr = /** @class */ (function (_super) {
|
|
__extends(TaggedTemplateExpr, _super);
|
|
function TaggedTemplateExpr(tag, template, type, sourceSpan) {
|
|
var _this = _super.call(this, type, sourceSpan) || this;
|
|
_this.tag = tag;
|
|
_this.template = template;
|
|
return _this;
|
|
}
|
|
TaggedTemplateExpr.prototype.isEquivalent = function (e) {
|
|
return e instanceof TaggedTemplateExpr && this.tag.isEquivalent(e.tag) &&
|
|
areAllEquivalentPredicate(this.template.elements, e.template.elements, function (a, b) { return a.text === b.text; }) &&
|
|
areAllEquivalent(this.template.expressions, e.template.expressions);
|
|
};
|
|
TaggedTemplateExpr.prototype.isConstant = function () {
|
|
return false;
|
|
};
|
|
TaggedTemplateExpr.prototype.visitExpression = function (visitor, context) {
|
|
return visitor.visitTaggedTemplateExpr(this, context);
|
|
};
|
|
return TaggedTemplateExpr;
|
|
}(Expression));
|
|
var InstantiateExpr = /** @class */ (function (_super) {
|
|
__extends(InstantiateExpr, _super);
|
|
function InstantiateExpr(classExpr, args, type, sourceSpan) {
|
|
var _this = _super.call(this, type, sourceSpan) || this;
|
|
_this.classExpr = classExpr;
|
|
_this.args = args;
|
|
return _this;
|
|
}
|
|
InstantiateExpr.prototype.isEquivalent = function (e) {
|
|
return e instanceof InstantiateExpr && this.classExpr.isEquivalent(e.classExpr) &&
|
|
areAllEquivalent(this.args, e.args);
|
|
};
|
|
InstantiateExpr.prototype.isConstant = function () {
|
|
return false;
|
|
};
|
|
InstantiateExpr.prototype.visitExpression = function (visitor, context) {
|
|
return visitor.visitInstantiateExpr(this, context);
|
|
};
|
|
return InstantiateExpr;
|
|
}(Expression));
|
|
var LiteralExpr = /** @class */ (function (_super) {
|
|
__extends(LiteralExpr, _super);
|
|
function LiteralExpr(value, type, sourceSpan) {
|
|
var _this = _super.call(this, type, sourceSpan) || this;
|
|
_this.value = value;
|
|
return _this;
|
|
}
|
|
LiteralExpr.prototype.isEquivalent = function (e) {
|
|
return e instanceof LiteralExpr && this.value === e.value;
|
|
};
|
|
LiteralExpr.prototype.isConstant = function () {
|
|
return true;
|
|
};
|
|
LiteralExpr.prototype.visitExpression = function (visitor, context) {
|
|
return visitor.visitLiteralExpr(this, context);
|
|
};
|
|
return LiteralExpr;
|
|
}(Expression));
|
|
var TemplateLiteral = /** @class */ (function () {
|
|
function TemplateLiteral(elements, expressions) {
|
|
this.elements = elements;
|
|
this.expressions = expressions;
|
|
}
|
|
return TemplateLiteral;
|
|
}());
|
|
var TemplateLiteralElement = /** @class */ (function () {
|
|
function TemplateLiteralElement(text, sourceSpan, rawText) {
|
|
var _a;
|
|
this.text = text;
|
|
this.sourceSpan = sourceSpan;
|
|
// If `rawText` is not provided, try to extract the raw string from its
|
|
// associated `sourceSpan`. If that is also not available, "fake" the raw
|
|
// string instead by escaping the following control sequences:
|
|
// - "\" would otherwise indicate that the next character is a control character.
|
|
// - "`" and "${" are template string control sequences that would otherwise prematurely
|
|
// indicate the end of the template literal element.
|
|
this.rawText =
|
|
(_a = rawText !== null && rawText !== void 0 ? rawText : sourceSpan === null || sourceSpan === void 0 ? void 0 : sourceSpan.toString()) !== null && _a !== void 0 ? _a : escapeForTemplateLiteral(escapeSlashes(text));
|
|
}
|
|
return TemplateLiteralElement;
|
|
}());
|
|
var MessagePiece = /** @class */ (function () {
|
|
function MessagePiece(text, sourceSpan) {
|
|
this.text = text;
|
|
this.sourceSpan = sourceSpan;
|
|
}
|
|
return MessagePiece;
|
|
}());
|
|
var LiteralPiece = /** @class */ (function (_super) {
|
|
__extends(LiteralPiece, _super);
|
|
function LiteralPiece() {
|
|
return _super !== null && _super.apply(this, arguments) || this;
|
|
}
|
|
return LiteralPiece;
|
|
}(MessagePiece));
|
|
var PlaceholderPiece = /** @class */ (function (_super) {
|
|
__extends(PlaceholderPiece, _super);
|
|
function PlaceholderPiece() {
|
|
return _super !== null && _super.apply(this, arguments) || this;
|
|
}
|
|
return PlaceholderPiece;
|
|
}(MessagePiece));
|
|
var LocalizedString = /** @class */ (function (_super) {
|
|
__extends(LocalizedString, _super);
|
|
function LocalizedString(metaBlock, messageParts, placeHolderNames, expressions, sourceSpan) {
|
|
var _this = _super.call(this, STRING_TYPE, sourceSpan) || this;
|
|
_this.metaBlock = metaBlock;
|
|
_this.messageParts = messageParts;
|
|
_this.placeHolderNames = placeHolderNames;
|
|
_this.expressions = expressions;
|
|
return _this;
|
|
}
|
|
LocalizedString.prototype.isEquivalent = function (e) {
|
|
// return e instanceof LocalizedString && this.message === e.message;
|
|
return false;
|
|
};
|
|
LocalizedString.prototype.isConstant = function () {
|
|
return false;
|
|
};
|
|
LocalizedString.prototype.visitExpression = function (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
|
|
*/
|
|
LocalizedString.prototype.serializeI18nHead = function () {
|
|
var MEANING_SEPARATOR = '|';
|
|
var ID_SEPARATOR = '@@';
|
|
var LEGACY_ID_INDICATOR = '␟';
|
|
var 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(function (legacyId) {
|
|
metaBlock = "" + metaBlock + LEGACY_ID_INDICATOR + legacyId;
|
|
});
|
|
}
|
|
return createCookedRawString(metaBlock, this.messageParts[0].text, this.getMessagePartSourceSpan(0));
|
|
};
|
|
LocalizedString.prototype.getMessagePartSourceSpan = function (i) {
|
|
var _a, _b;
|
|
return (_b = (_a = this.messageParts[i]) === null || _a === void 0 ? void 0 : _a.sourceSpan) !== null && _b !== void 0 ? _b : this.sourceSpan;
|
|
};
|
|
LocalizedString.prototype.getPlaceholderSourceSpan = function (i) {
|
|
var _a, _b, _c, _d;
|
|
return (_d = (_b = (_a = this.placeHolderNames[i]) === null || _a === void 0 ? void 0 : _a.sourceSpan) !== null && _b !== void 0 ? _b : (_c = this.expressions[i]) === null || _c === void 0 ? void 0 : _c.sourceSpan) !== null && _d !== void 0 ? _d : this.sourceSpan;
|
|
};
|
|
/**
|
|
* Serialize the given `placeholderName` and `messagePart` into "cooked" and "raw" strings that
|
|
* can be used in a `$localize` tagged string.
|
|
*
|
|
* @param placeholderName The placeholder name to serialize
|
|
* @param messagePart The following message string after this placeholder
|
|
*/
|
|
LocalizedString.prototype.serializeI18nTemplatePart = function (partIndex) {
|
|
var placeholderName = this.placeHolderNames[partIndex - 1].text;
|
|
var messagePart = this.messageParts[partIndex];
|
|
return createCookedRawString(placeholderName, messagePart.text, this.getMessagePartSourceSpan(partIndex));
|
|
};
|
|
return LocalizedString;
|
|
}(Expression));
|
|
var escapeSlashes = function (str) { return str.replace(/\\/g, '\\\\'); };
|
|
var escapeStartingColon = function (str) { return str.replace(/^:/, '\\:'); };
|
|
var escapeColons = function (str) { return str.replace(/:/g, '\\:'); };
|
|
var escapeForTemplateLiteral = function (str) { return 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: range,
|
|
};
|
|
}
|
|
else {
|
|
return {
|
|
cooked: ":" + metaBlock + ":" + messagePart,
|
|
raw: escapeForTemplateLiteral(":" + escapeColons(escapeSlashes(metaBlock)) + ":" + escapeSlashes(messagePart)),
|
|
range: range,
|
|
};
|
|
}
|
|
}
|
|
var ExternalExpr = /** @class */ (function (_super) {
|
|
__extends(ExternalExpr, _super);
|
|
function ExternalExpr(value, type, typeParams, sourceSpan) {
|
|
if (typeParams === void 0) { typeParams = null; }
|
|
var _this = _super.call(this, type, sourceSpan) || this;
|
|
_this.value = value;
|
|
_this.typeParams = typeParams;
|
|
return _this;
|
|
}
|
|
ExternalExpr.prototype.isEquivalent = function (e) {
|
|
return e instanceof ExternalExpr && this.value.name === e.value.name &&
|
|
this.value.moduleName === e.value.moduleName && this.value.runtime === e.value.runtime;
|
|
};
|
|
ExternalExpr.prototype.isConstant = function () {
|
|
return false;
|
|
};
|
|
ExternalExpr.prototype.visitExpression = function (visitor, context) {
|
|
return visitor.visitExternalExpr(this, context);
|
|
};
|
|
return ExternalExpr;
|
|
}(Expression));
|
|
var ExternalReference = /** @class */ (function () {
|
|
function ExternalReference(moduleName, name, runtime) {
|
|
this.moduleName = moduleName;
|
|
this.name = name;
|
|
this.runtime = runtime;
|
|
}
|
|
return ExternalReference;
|
|
}());
|
|
var ConditionalExpr = /** @class */ (function (_super) {
|
|
__extends(ConditionalExpr, _super);
|
|
function ConditionalExpr(condition, trueCase, falseCase, type, sourceSpan) {
|
|
if (falseCase === void 0) { falseCase = null; }
|
|
var _this = _super.call(this, type || trueCase.type, sourceSpan) || this;
|
|
_this.condition = condition;
|
|
_this.falseCase = falseCase;
|
|
_this.trueCase = trueCase;
|
|
return _this;
|
|
}
|
|
ConditionalExpr.prototype.isEquivalent = function (e) {
|
|
return e instanceof ConditionalExpr && this.condition.isEquivalent(e.condition) &&
|
|
this.trueCase.isEquivalent(e.trueCase) && nullSafeIsEquivalent(this.falseCase, e.falseCase);
|
|
};
|
|
ConditionalExpr.prototype.isConstant = function () {
|
|
return false;
|
|
};
|
|
ConditionalExpr.prototype.visitExpression = function (visitor, context) {
|
|
return visitor.visitConditionalExpr(this, context);
|
|
};
|
|
return ConditionalExpr;
|
|
}(Expression));
|
|
var NotExpr = /** @class */ (function (_super) {
|
|
__extends(NotExpr, _super);
|
|
function NotExpr(condition, sourceSpan) {
|
|
var _this = _super.call(this, BOOL_TYPE, sourceSpan) || this;
|
|
_this.condition = condition;
|
|
return _this;
|
|
}
|
|
NotExpr.prototype.isEquivalent = function (e) {
|
|
return e instanceof NotExpr && this.condition.isEquivalent(e.condition);
|
|
};
|
|
NotExpr.prototype.isConstant = function () {
|
|
return false;
|
|
};
|
|
NotExpr.prototype.visitExpression = function (visitor, context) {
|
|
return visitor.visitNotExpr(this, context);
|
|
};
|
|
return NotExpr;
|
|
}(Expression));
|
|
var AssertNotNull = /** @class */ (function (_super) {
|
|
__extends(AssertNotNull, _super);
|
|
function AssertNotNull(condition, sourceSpan) {
|
|
var _this = _super.call(this, condition.type, sourceSpan) || this;
|
|
_this.condition = condition;
|
|
return _this;
|
|
}
|
|
AssertNotNull.prototype.isEquivalent = function (e) {
|
|
return e instanceof AssertNotNull && this.condition.isEquivalent(e.condition);
|
|
};
|
|
AssertNotNull.prototype.isConstant = function () {
|
|
return false;
|
|
};
|
|
AssertNotNull.prototype.visitExpression = function (visitor, context) {
|
|
return visitor.visitAssertNotNullExpr(this, context);
|
|
};
|
|
return AssertNotNull;
|
|
}(Expression));
|
|
var CastExpr = /** @class */ (function (_super) {
|
|
__extends(CastExpr, _super);
|
|
function CastExpr(value, type, sourceSpan) {
|
|
var _this = _super.call(this, type, sourceSpan) || this;
|
|
_this.value = value;
|
|
return _this;
|
|
}
|
|
CastExpr.prototype.isEquivalent = function (e) {
|
|
return e instanceof CastExpr && this.value.isEquivalent(e.value);
|
|
};
|
|
CastExpr.prototype.isConstant = function () {
|
|
return false;
|
|
};
|
|
CastExpr.prototype.visitExpression = function (visitor, context) {
|
|
return visitor.visitCastExpr(this, context);
|
|
};
|
|
return CastExpr;
|
|
}(Expression));
|
|
var FnParam = /** @class */ (function () {
|
|
function FnParam(name, type) {
|
|
if (type === void 0) { type = null; }
|
|
this.name = name;
|
|
this.type = type;
|
|
}
|
|
FnParam.prototype.isEquivalent = function (param) {
|
|
return this.name === param.name;
|
|
};
|
|
return FnParam;
|
|
}());
|
|
var FunctionExpr = /** @class */ (function (_super) {
|
|
__extends(FunctionExpr, _super);
|
|
function FunctionExpr(params, statements, type, sourceSpan, name) {
|
|
var _this = _super.call(this, type, sourceSpan) || this;
|
|
_this.params = params;
|
|
_this.statements = statements;
|
|
_this.name = name;
|
|
return _this;
|
|
}
|
|
FunctionExpr.prototype.isEquivalent = function (e) {
|
|
return e instanceof FunctionExpr && areAllEquivalent(this.params, e.params) &&
|
|
areAllEquivalent(this.statements, e.statements);
|
|
};
|
|
FunctionExpr.prototype.isConstant = function () {
|
|
return false;
|
|
};
|
|
FunctionExpr.prototype.visitExpression = function (visitor, context) {
|
|
return visitor.visitFunctionExpr(this, context);
|
|
};
|
|
FunctionExpr.prototype.toDeclStmt = function (name, modifiers) {
|
|
return new DeclareFunctionStmt(name, this.params, this.statements, this.type, modifiers, this.sourceSpan);
|
|
};
|
|
return FunctionExpr;
|
|
}(Expression));
|
|
var UnaryOperatorExpr = /** @class */ (function (_super) {
|
|
__extends(UnaryOperatorExpr, _super);
|
|
function UnaryOperatorExpr(operator, expr, type, sourceSpan, parens) {
|
|
if (parens === void 0) { parens = true; }
|
|
var _this = _super.call(this, type || NUMBER_TYPE, sourceSpan) || this;
|
|
_this.operator = operator;
|
|
_this.expr = expr;
|
|
_this.parens = parens;
|
|
return _this;
|
|
}
|
|
UnaryOperatorExpr.prototype.isEquivalent = function (e) {
|
|
return e instanceof UnaryOperatorExpr && this.operator === e.operator &&
|
|
this.expr.isEquivalent(e.expr);
|
|
};
|
|
UnaryOperatorExpr.prototype.isConstant = function () {
|
|
return false;
|
|
};
|
|
UnaryOperatorExpr.prototype.visitExpression = function (visitor, context) {
|
|
return visitor.visitUnaryOperatorExpr(this, context);
|
|
};
|
|
return UnaryOperatorExpr;
|
|
}(Expression));
|
|
var BinaryOperatorExpr = /** @class */ (function (_super) {
|
|
__extends(BinaryOperatorExpr, _super);
|
|
function BinaryOperatorExpr(operator, lhs, rhs, type, sourceSpan, parens) {
|
|
if (parens === void 0) { parens = true; }
|
|
var _this = _super.call(this, type || lhs.type, sourceSpan) || this;
|
|
_this.operator = operator;
|
|
_this.rhs = rhs;
|
|
_this.parens = parens;
|
|
_this.lhs = lhs;
|
|
return _this;
|
|
}
|
|
BinaryOperatorExpr.prototype.isEquivalent = function (e) {
|
|
return e instanceof BinaryOperatorExpr && this.operator === e.operator &&
|
|
this.lhs.isEquivalent(e.lhs) && this.rhs.isEquivalent(e.rhs);
|
|
};
|
|
BinaryOperatorExpr.prototype.isConstant = function () {
|
|
return false;
|
|
};
|
|
BinaryOperatorExpr.prototype.visitExpression = function (visitor, context) {
|
|
return visitor.visitBinaryOperatorExpr(this, context);
|
|
};
|
|
return BinaryOperatorExpr;
|
|
}(Expression));
|
|
var ReadPropExpr = /** @class */ (function (_super) {
|
|
__extends(ReadPropExpr, _super);
|
|
function ReadPropExpr(receiver, name, type, sourceSpan) {
|
|
var _this = _super.call(this, type, sourceSpan) || this;
|
|
_this.receiver = receiver;
|
|
_this.name = name;
|
|
return _this;
|
|
}
|
|
ReadPropExpr.prototype.isEquivalent = function (e) {
|
|
return e instanceof ReadPropExpr && this.receiver.isEquivalent(e.receiver) &&
|
|
this.name === e.name;
|
|
};
|
|
ReadPropExpr.prototype.isConstant = function () {
|
|
return false;
|
|
};
|
|
ReadPropExpr.prototype.visitExpression = function (visitor, context) {
|
|
return visitor.visitReadPropExpr(this, context);
|
|
};
|
|
ReadPropExpr.prototype.set = function (value) {
|
|
return new WritePropExpr(this.receiver, this.name, value, null, this.sourceSpan);
|
|
};
|
|
return ReadPropExpr;
|
|
}(Expression));
|
|
var ReadKeyExpr = /** @class */ (function (_super) {
|
|
__extends(ReadKeyExpr, _super);
|
|
function ReadKeyExpr(receiver, index, type, sourceSpan) {
|
|
var _this = _super.call(this, type, sourceSpan) || this;
|
|
_this.receiver = receiver;
|
|
_this.index = index;
|
|
return _this;
|
|
}
|
|
ReadKeyExpr.prototype.isEquivalent = function (e) {
|
|
return e instanceof ReadKeyExpr && this.receiver.isEquivalent(e.receiver) &&
|
|
this.index.isEquivalent(e.index);
|
|
};
|
|
ReadKeyExpr.prototype.isConstant = function () {
|
|
return false;
|
|
};
|
|
ReadKeyExpr.prototype.visitExpression = function (visitor, context) {
|
|
return visitor.visitReadKeyExpr(this, context);
|
|
};
|
|
ReadKeyExpr.prototype.set = function (value) {
|
|
return new WriteKeyExpr(this.receiver, this.index, value, null, this.sourceSpan);
|
|
};
|
|
return ReadKeyExpr;
|
|
}(Expression));
|
|
var LiteralArrayExpr = /** @class */ (function (_super) {
|
|
__extends(LiteralArrayExpr, _super);
|
|
function LiteralArrayExpr(entries, type, sourceSpan) {
|
|
var _this = _super.call(this, type, sourceSpan) || this;
|
|
_this.entries = entries;
|
|
return _this;
|
|
}
|
|
LiteralArrayExpr.prototype.isConstant = function () {
|
|
return this.entries.every(function (e) { return e.isConstant(); });
|
|
};
|
|
LiteralArrayExpr.prototype.isEquivalent = function (e) {
|
|
return e instanceof LiteralArrayExpr && areAllEquivalent(this.entries, e.entries);
|
|
};
|
|
LiteralArrayExpr.prototype.visitExpression = function (visitor, context) {
|
|
return visitor.visitLiteralArrayExpr(this, context);
|
|
};
|
|
return LiteralArrayExpr;
|
|
}(Expression));
|
|
var LiteralMapEntry = /** @class */ (function () {
|
|
function LiteralMapEntry(key, value, quoted) {
|
|
this.key = key;
|
|
this.value = value;
|
|
this.quoted = quoted;
|
|
}
|
|
LiteralMapEntry.prototype.isEquivalent = function (e) {
|
|
return this.key === e.key && this.value.isEquivalent(e.value);
|
|
};
|
|
return LiteralMapEntry;
|
|
}());
|
|
var LiteralMapExpr = /** @class */ (function (_super) {
|
|
__extends(LiteralMapExpr, _super);
|
|
function LiteralMapExpr(entries, type, sourceSpan) {
|
|
var _this = _super.call(this, type, sourceSpan) || this;
|
|
_this.entries = entries;
|
|
_this.valueType = null;
|
|
if (type) {
|
|
_this.valueType = type.valueType;
|
|
}
|
|
return _this;
|
|
}
|
|
LiteralMapExpr.prototype.isEquivalent = function (e) {
|
|
return e instanceof LiteralMapExpr && areAllEquivalent(this.entries, e.entries);
|
|
};
|
|
LiteralMapExpr.prototype.isConstant = function () {
|
|
return this.entries.every(function (e) { return e.value.isConstant(); });
|
|
};
|
|
LiteralMapExpr.prototype.visitExpression = function (visitor, context) {
|
|
return visitor.visitLiteralMapExpr(this, context);
|
|
};
|
|
return LiteralMapExpr;
|
|
}(Expression));
|
|
var CommaExpr = /** @class */ (function (_super) {
|
|
__extends(CommaExpr, _super);
|
|
function CommaExpr(parts, sourceSpan) {
|
|
var _this = _super.call(this, parts[parts.length - 1].type, sourceSpan) || this;
|
|
_this.parts = parts;
|
|
return _this;
|
|
}
|
|
CommaExpr.prototype.isEquivalent = function (e) {
|
|
return e instanceof CommaExpr && areAllEquivalent(this.parts, e.parts);
|
|
};
|
|
CommaExpr.prototype.isConstant = function () {
|
|
return false;
|
|
};
|
|
CommaExpr.prototype.visitExpression = function (visitor, context) {
|
|
return visitor.visitCommaExpr(this, context);
|
|
};
|
|
return CommaExpr;
|
|
}(Expression));
|
|
var THIS_EXPR = new ReadVarExpr(exports.BuiltinVar.This, null, null);
|
|
var SUPER_EXPR = new ReadVarExpr(exports.BuiltinVar.Super, null, null);
|
|
var CATCH_ERROR_VAR = new ReadVarExpr(exports.BuiltinVar.CatchError, null, null);
|
|
var CATCH_STACK_VAR = new ReadVarExpr(exports.BuiltinVar.CatchStack, null, null);
|
|
var NULL_EXPR = new LiteralExpr(null, null, null);
|
|
var TYPED_NULL_EXPR = new LiteralExpr(null, INFERRED_TYPE, null);
|
|
(function (StmtModifier) {
|
|
StmtModifier[StmtModifier["Final"] = 0] = "Final";
|
|
StmtModifier[StmtModifier["Private"] = 1] = "Private";
|
|
StmtModifier[StmtModifier["Exported"] = 2] = "Exported";
|
|
StmtModifier[StmtModifier["Static"] = 3] = "Static";
|
|
})(exports.StmtModifier || (exports.StmtModifier = {}));
|
|
var LeadingComment = /** @class */ (function () {
|
|
function LeadingComment(text, multiline, trailingNewline) {
|
|
this.text = text;
|
|
this.multiline = multiline;
|
|
this.trailingNewline = trailingNewline;
|
|
}
|
|
LeadingComment.prototype.toString = function () {
|
|
return this.multiline ? " " + this.text + " " : this.text;
|
|
};
|
|
return LeadingComment;
|
|
}());
|
|
var JSDocComment = /** @class */ (function (_super) {
|
|
__extends(JSDocComment, _super);
|
|
function JSDocComment(tags) {
|
|
var _this = _super.call(this, '', /* multiline */ true, /* trailingNewline */ true) || this;
|
|
_this.tags = tags;
|
|
return _this;
|
|
}
|
|
JSDocComment.prototype.toString = function () {
|
|
return serializeTags(this.tags);
|
|
};
|
|
return JSDocComment;
|
|
}(LeadingComment));
|
|
var Statement = /** @class */ (function () {
|
|
function Statement(modifiers, sourceSpan, leadingComments) {
|
|
if (modifiers === void 0) { modifiers = []; }
|
|
if (sourceSpan === void 0) { sourceSpan = null; }
|
|
this.modifiers = modifiers;
|
|
this.sourceSpan = sourceSpan;
|
|
this.leadingComments = leadingComments;
|
|
}
|
|
Statement.prototype.hasModifier = function (modifier) {
|
|
return this.modifiers.indexOf(modifier) !== -1;
|
|
};
|
|
Statement.prototype.addLeadingComment = function (leadingComment) {
|
|
var _a;
|
|
this.leadingComments = (_a = this.leadingComments) !== null && _a !== void 0 ? _a : [];
|
|
this.leadingComments.push(leadingComment);
|
|
};
|
|
return Statement;
|
|
}());
|
|
var DeclareVarStmt = /** @class */ (function (_super) {
|
|
__extends(DeclareVarStmt, _super);
|
|
function DeclareVarStmt(name, value, type, modifiers, sourceSpan, leadingComments) {
|
|
var _this = _super.call(this, modifiers, sourceSpan, leadingComments) || this;
|
|
_this.name = name;
|
|
_this.value = value;
|
|
_this.type = type || (value && value.type) || null;
|
|
return _this;
|
|
}
|
|
DeclareVarStmt.prototype.isEquivalent = function (stmt) {
|
|
return stmt instanceof DeclareVarStmt && this.name === stmt.name &&
|
|
(this.value ? !!stmt.value && this.value.isEquivalent(stmt.value) : !stmt.value);
|
|
};
|
|
DeclareVarStmt.prototype.visitStatement = function (visitor, context) {
|
|
return visitor.visitDeclareVarStmt(this, context);
|
|
};
|
|
return DeclareVarStmt;
|
|
}(Statement));
|
|
var DeclareFunctionStmt = /** @class */ (function (_super) {
|
|
__extends(DeclareFunctionStmt, _super);
|
|
function DeclareFunctionStmt(name, params, statements, type, modifiers, sourceSpan, leadingComments) {
|
|
var _this = _super.call(this, modifiers, sourceSpan, leadingComments) || this;
|
|
_this.name = name;
|
|
_this.params = params;
|
|
_this.statements = statements;
|
|
_this.type = type || null;
|
|
return _this;
|
|
}
|
|
DeclareFunctionStmt.prototype.isEquivalent = function (stmt) {
|
|
return stmt instanceof DeclareFunctionStmt && areAllEquivalent(this.params, stmt.params) &&
|
|
areAllEquivalent(this.statements, stmt.statements);
|
|
};
|
|
DeclareFunctionStmt.prototype.visitStatement = function (visitor, context) {
|
|
return visitor.visitDeclareFunctionStmt(this, context);
|
|
};
|
|
return DeclareFunctionStmt;
|
|
}(Statement));
|
|
var ExpressionStatement = /** @class */ (function (_super) {
|
|
__extends(ExpressionStatement, _super);
|
|
function ExpressionStatement(expr, sourceSpan, leadingComments) {
|
|
var _this = _super.call(this, [], sourceSpan, leadingComments) || this;
|
|
_this.expr = expr;
|
|
return _this;
|
|
}
|
|
ExpressionStatement.prototype.isEquivalent = function (stmt) {
|
|
return stmt instanceof ExpressionStatement && this.expr.isEquivalent(stmt.expr);
|
|
};
|
|
ExpressionStatement.prototype.visitStatement = function (visitor, context) {
|
|
return visitor.visitExpressionStmt(this, context);
|
|
};
|
|
return ExpressionStatement;
|
|
}(Statement));
|
|
var ReturnStatement = /** @class */ (function (_super) {
|
|
__extends(ReturnStatement, _super);
|
|
function ReturnStatement(value, sourceSpan, leadingComments) {
|
|
if (sourceSpan === void 0) { sourceSpan = null; }
|
|
var _this = _super.call(this, [], sourceSpan, leadingComments) || this;
|
|
_this.value = value;
|
|
return _this;
|
|
}
|
|
ReturnStatement.prototype.isEquivalent = function (stmt) {
|
|
return stmt instanceof ReturnStatement && this.value.isEquivalent(stmt.value);
|
|
};
|
|
ReturnStatement.prototype.visitStatement = function (visitor, context) {
|
|
return visitor.visitReturnStmt(this, context);
|
|
};
|
|
return ReturnStatement;
|
|
}(Statement));
|
|
var AbstractClassPart = /** @class */ (function () {
|
|
function AbstractClassPart(type, modifiers) {
|
|
if (type === void 0) { type = null; }
|
|
if (modifiers === void 0) { modifiers = []; }
|
|
this.type = type;
|
|
this.modifiers = modifiers;
|
|
}
|
|
AbstractClassPart.prototype.hasModifier = function (modifier) {
|
|
return this.modifiers.indexOf(modifier) !== -1;
|
|
};
|
|
return AbstractClassPart;
|
|
}());
|
|
var ClassField = /** @class */ (function (_super) {
|
|
__extends(ClassField, _super);
|
|
function ClassField(name, type, modifiers, initializer) {
|
|
var _this = _super.call(this, type, modifiers) || this;
|
|
_this.name = name;
|
|
_this.initializer = initializer;
|
|
return _this;
|
|
}
|
|
ClassField.prototype.isEquivalent = function (f) {
|
|
return this.name === f.name;
|
|
};
|
|
return ClassField;
|
|
}(AbstractClassPart));
|
|
var ClassMethod = /** @class */ (function (_super) {
|
|
__extends(ClassMethod, _super);
|
|
function ClassMethod(name, params, body, type, modifiers) {
|
|
var _this = _super.call(this, type, modifiers) || this;
|
|
_this.name = name;
|
|
_this.params = params;
|
|
_this.body = body;
|
|
return _this;
|
|
}
|
|
ClassMethod.prototype.isEquivalent = function (m) {
|
|
return this.name === m.name && areAllEquivalent(this.body, m.body);
|
|
};
|
|
return ClassMethod;
|
|
}(AbstractClassPart));
|
|
var ClassGetter = /** @class */ (function (_super) {
|
|
__extends(ClassGetter, _super);
|
|
function ClassGetter(name, body, type, modifiers) {
|
|
var _this = _super.call(this, type, modifiers) || this;
|
|
_this.name = name;
|
|
_this.body = body;
|
|
return _this;
|
|
}
|
|
ClassGetter.prototype.isEquivalent = function (m) {
|
|
return this.name === m.name && areAllEquivalent(this.body, m.body);
|
|
};
|
|
return ClassGetter;
|
|
}(AbstractClassPart));
|
|
var ClassStmt = /** @class */ (function (_super) {
|
|
__extends(ClassStmt, _super);
|
|
function ClassStmt(name, parent, fields, getters, constructorMethod, methods, modifiers, sourceSpan, leadingComments) {
|
|
var _this = _super.call(this, modifiers, sourceSpan, leadingComments) || this;
|
|
_this.name = name;
|
|
_this.parent = parent;
|
|
_this.fields = fields;
|
|
_this.getters = getters;
|
|
_this.constructorMethod = constructorMethod;
|
|
_this.methods = methods;
|
|
return _this;
|
|
}
|
|
ClassStmt.prototype.isEquivalent = function (stmt) {
|
|
return stmt instanceof ClassStmt && this.name === stmt.name &&
|
|
nullSafeIsEquivalent(this.parent, stmt.parent) &&
|
|
areAllEquivalent(this.fields, stmt.fields) &&
|
|
areAllEquivalent(this.getters, stmt.getters) &&
|
|
this.constructorMethod.isEquivalent(stmt.constructorMethod) &&
|
|
areAllEquivalent(this.methods, stmt.methods);
|
|
};
|
|
ClassStmt.prototype.visitStatement = function (visitor, context) {
|
|
return visitor.visitDeclareClassStmt(this, context);
|
|
};
|
|
return ClassStmt;
|
|
}(Statement));
|
|
var IfStmt = /** @class */ (function (_super) {
|
|
__extends(IfStmt, _super);
|
|
function IfStmt(condition, trueCase, falseCase, sourceSpan, leadingComments) {
|
|
if (falseCase === void 0) { falseCase = []; }
|
|
var _this = _super.call(this, [], sourceSpan, leadingComments) || this;
|
|
_this.condition = condition;
|
|
_this.trueCase = trueCase;
|
|
_this.falseCase = falseCase;
|
|
return _this;
|
|
}
|
|
IfStmt.prototype.isEquivalent = function (stmt) {
|
|
return stmt instanceof IfStmt && this.condition.isEquivalent(stmt.condition) &&
|
|
areAllEquivalent(this.trueCase, stmt.trueCase) &&
|
|
areAllEquivalent(this.falseCase, stmt.falseCase);
|
|
};
|
|
IfStmt.prototype.visitStatement = function (visitor, context) {
|
|
return visitor.visitIfStmt(this, context);
|
|
};
|
|
return IfStmt;
|
|
}(Statement));
|
|
var TryCatchStmt = /** @class */ (function (_super) {
|
|
__extends(TryCatchStmt, _super);
|
|
function TryCatchStmt(bodyStmts, catchStmts, sourceSpan, leadingComments) {
|
|
if (sourceSpan === void 0) { sourceSpan = null; }
|
|
var _this = _super.call(this, [], sourceSpan, leadingComments) || this;
|
|
_this.bodyStmts = bodyStmts;
|
|
_this.catchStmts = catchStmts;
|
|
return _this;
|
|
}
|
|
TryCatchStmt.prototype.isEquivalent = function (stmt) {
|
|
return stmt instanceof TryCatchStmt && areAllEquivalent(this.bodyStmts, stmt.bodyStmts) &&
|
|
areAllEquivalent(this.catchStmts, stmt.catchStmts);
|
|
};
|
|
TryCatchStmt.prototype.visitStatement = function (visitor, context) {
|
|
return visitor.visitTryCatchStmt(this, context);
|
|
};
|
|
return TryCatchStmt;
|
|
}(Statement));
|
|
var ThrowStmt = /** @class */ (function (_super) {
|
|
__extends(ThrowStmt, _super);
|
|
function ThrowStmt(error, sourceSpan, leadingComments) {
|
|
if (sourceSpan === void 0) { sourceSpan = null; }
|
|
var _this = _super.call(this, [], sourceSpan, leadingComments) || this;
|
|
_this.error = error;
|
|
return _this;
|
|
}
|
|
ThrowStmt.prototype.isEquivalent = function (stmt) {
|
|
return stmt instanceof TryCatchStmt && this.error.isEquivalent(stmt.error);
|
|
};
|
|
ThrowStmt.prototype.visitStatement = function (visitor, context) {
|
|
return visitor.visitThrowStmt(this, context);
|
|
};
|
|
return ThrowStmt;
|
|
}(Statement));
|
|
var AstTransformer = /** @class */ (function () {
|
|
function AstTransformer() {
|
|
}
|
|
AstTransformer.prototype.transformExpr = function (expr, context) {
|
|
return expr;
|
|
};
|
|
AstTransformer.prototype.transformStmt = function (stmt, context) {
|
|
return stmt;
|
|
};
|
|
AstTransformer.prototype.visitReadVarExpr = function (ast, context) {
|
|
return this.transformExpr(ast, context);
|
|
};
|
|
AstTransformer.prototype.visitWrappedNodeExpr = function (ast, context) {
|
|
return this.transformExpr(ast, context);
|
|
};
|
|
AstTransformer.prototype.visitTypeofExpr = function (expr, context) {
|
|
return this.transformExpr(new TypeofExpr(expr.expr.visitExpression(this, context), expr.type, expr.sourceSpan), context);
|
|
};
|
|
AstTransformer.prototype.visitWriteVarExpr = function (expr, context) {
|
|
return this.transformExpr(new WriteVarExpr(expr.name, expr.value.visitExpression(this, context), expr.type, expr.sourceSpan), context);
|
|
};
|
|
AstTransformer.prototype.visitWriteKeyExpr = function (expr, context) {
|
|
return this.transformExpr(new WriteKeyExpr(expr.receiver.visitExpression(this, context), expr.index.visitExpression(this, context), expr.value.visitExpression(this, context), expr.type, expr.sourceSpan), context);
|
|
};
|
|
AstTransformer.prototype.visitWritePropExpr = function (expr, context) {
|
|
return this.transformExpr(new WritePropExpr(expr.receiver.visitExpression(this, context), expr.name, expr.value.visitExpression(this, context), expr.type, expr.sourceSpan), context);
|
|
};
|
|
AstTransformer.prototype.visitInvokeMethodExpr = function (ast, context) {
|
|
var method = ast.builtin || ast.name;
|
|
return this.transformExpr(new InvokeMethodExpr(ast.receiver.visitExpression(this, context), method, this.visitAllExpressions(ast.args, context), ast.type, ast.sourceSpan), context);
|
|
};
|
|
AstTransformer.prototype.visitInvokeFunctionExpr = function (ast, context) {
|
|
return this.transformExpr(new InvokeFunctionExpr(ast.fn.visitExpression(this, context), this.visitAllExpressions(ast.args, context), ast.type, ast.sourceSpan), context);
|
|
};
|
|
AstTransformer.prototype.visitTaggedTemplateExpr = function (ast, context) {
|
|
var _this = this;
|
|
return this.transformExpr(new TaggedTemplateExpr(ast.tag.visitExpression(this, context), new TemplateLiteral(ast.template.elements, ast.template.expressions.map(function (e) { return e.visitExpression(_this, context); })), ast.type, ast.sourceSpan), context);
|
|
};
|
|
AstTransformer.prototype.visitInstantiateExpr = function (ast, context) {
|
|
return this.transformExpr(new InstantiateExpr(ast.classExpr.visitExpression(this, context), this.visitAllExpressions(ast.args, context), ast.type, ast.sourceSpan), context);
|
|
};
|
|
AstTransformer.prototype.visitLiteralExpr = function (ast, context) {
|
|
return this.transformExpr(ast, context);
|
|
};
|
|
AstTransformer.prototype.visitLocalizedString = function (ast, context) {
|
|
return this.transformExpr(new LocalizedString(ast.metaBlock, ast.messageParts, ast.placeHolderNames, this.visitAllExpressions(ast.expressions, context), ast.sourceSpan), context);
|
|
};
|
|
AstTransformer.prototype.visitExternalExpr = function (ast, context) {
|
|
return this.transformExpr(ast, context);
|
|
};
|
|
AstTransformer.prototype.visitConditionalExpr = function (ast, context) {
|
|
return this.transformExpr(new ConditionalExpr(ast.condition.visitExpression(this, context), ast.trueCase.visitExpression(this, context), ast.falseCase.visitExpression(this, context), ast.type, ast.sourceSpan), context);
|
|
};
|
|
AstTransformer.prototype.visitNotExpr = function (ast, context) {
|
|
return this.transformExpr(new NotExpr(ast.condition.visitExpression(this, context), ast.sourceSpan), context);
|
|
};
|
|
AstTransformer.prototype.visitAssertNotNullExpr = function (ast, context) {
|
|
return this.transformExpr(new AssertNotNull(ast.condition.visitExpression(this, context), ast.sourceSpan), context);
|
|
};
|
|
AstTransformer.prototype.visitCastExpr = function (ast, context) {
|
|
return this.transformExpr(new CastExpr(ast.value.visitExpression(this, context), ast.type, ast.sourceSpan), context);
|
|
};
|
|
AstTransformer.prototype.visitFunctionExpr = function (ast, context) {
|
|
return this.transformExpr(new FunctionExpr(ast.params, this.visitAllStatements(ast.statements, context), ast.type, ast.sourceSpan), context);
|
|
};
|
|
AstTransformer.prototype.visitUnaryOperatorExpr = function (ast, context) {
|
|
return this.transformExpr(new UnaryOperatorExpr(ast.operator, ast.expr.visitExpression(this, context), ast.type, ast.sourceSpan), context);
|
|
};
|
|
AstTransformer.prototype.visitBinaryOperatorExpr = function (ast, context) {
|
|
return this.transformExpr(new BinaryOperatorExpr(ast.operator, ast.lhs.visitExpression(this, context), ast.rhs.visitExpression(this, context), ast.type, ast.sourceSpan), context);
|
|
};
|
|
AstTransformer.prototype.visitReadPropExpr = function (ast, context) {
|
|
return this.transformExpr(new ReadPropExpr(ast.receiver.visitExpression(this, context), ast.name, ast.type, ast.sourceSpan), context);
|
|
};
|
|
AstTransformer.prototype.visitReadKeyExpr = function (ast, context) {
|
|
return this.transformExpr(new ReadKeyExpr(ast.receiver.visitExpression(this, context), ast.index.visitExpression(this, context), ast.type, ast.sourceSpan), context);
|
|
};
|
|
AstTransformer.prototype.visitLiteralArrayExpr = function (ast, context) {
|
|
return this.transformExpr(new LiteralArrayExpr(this.visitAllExpressions(ast.entries, context), ast.type, ast.sourceSpan), context);
|
|
};
|
|
AstTransformer.prototype.visitLiteralMapExpr = function (ast, context) {
|
|
var _this = this;
|
|
var entries = ast.entries.map(function (entry) { return new LiteralMapEntry(entry.key, entry.value.visitExpression(_this, context), entry.quoted); });
|
|
var mapType = new MapType(ast.valueType);
|
|
return this.transformExpr(new LiteralMapExpr(entries, mapType, ast.sourceSpan), context);
|
|
};
|
|
AstTransformer.prototype.visitCommaExpr = function (ast, context) {
|
|
return this.transformExpr(new CommaExpr(this.visitAllExpressions(ast.parts, context), ast.sourceSpan), context);
|
|
};
|
|
AstTransformer.prototype.visitAllExpressions = function (exprs, context) {
|
|
var _this = this;
|
|
return exprs.map(function (expr) { return expr.visitExpression(_this, context); });
|
|
};
|
|
AstTransformer.prototype.visitDeclareVarStmt = function (stmt, context) {
|
|
var value = stmt.value && stmt.value.visitExpression(this, context);
|
|
return this.transformStmt(new DeclareVarStmt(stmt.name, value, stmt.type, stmt.modifiers, stmt.sourceSpan, stmt.leadingComments), context);
|
|
};
|
|
AstTransformer.prototype.visitDeclareFunctionStmt = function (stmt, context) {
|
|
return this.transformStmt(new DeclareFunctionStmt(stmt.name, stmt.params, this.visitAllStatements(stmt.statements, context), stmt.type, stmt.modifiers, stmt.sourceSpan, stmt.leadingComments), context);
|
|
};
|
|
AstTransformer.prototype.visitExpressionStmt = function (stmt, context) {
|
|
return this.transformStmt(new ExpressionStatement(stmt.expr.visitExpression(this, context), stmt.sourceSpan, stmt.leadingComments), context);
|
|
};
|
|
AstTransformer.prototype.visitReturnStmt = function (stmt, context) {
|
|
return this.transformStmt(new ReturnStatement(stmt.value.visitExpression(this, context), stmt.sourceSpan, stmt.leadingComments), context);
|
|
};
|
|
AstTransformer.prototype.visitDeclareClassStmt = function (stmt, context) {
|
|
var _this = this;
|
|
var parent = stmt.parent.visitExpression(this, context);
|
|
var getters = stmt.getters.map(function (getter) { return new ClassGetter(getter.name, _this.visitAllStatements(getter.body, context), getter.type, getter.modifiers); });
|
|
var ctorMethod = stmt.constructorMethod &&
|
|
new ClassMethod(stmt.constructorMethod.name, stmt.constructorMethod.params, this.visitAllStatements(stmt.constructorMethod.body, context), stmt.constructorMethod.type, stmt.constructorMethod.modifiers);
|
|
var methods = stmt.methods.map(function (method) { return new ClassMethod(method.name, method.params, _this.visitAllStatements(method.body, context), method.type, method.modifiers); });
|
|
return this.transformStmt(new ClassStmt(stmt.name, parent, stmt.fields, getters, ctorMethod, methods, stmt.modifiers, stmt.sourceSpan), context);
|
|
};
|
|
AstTransformer.prototype.visitIfStmt = function (stmt, context) {
|
|
return this.transformStmt(new IfStmt(stmt.condition.visitExpression(this, context), this.visitAllStatements(stmt.trueCase, context), this.visitAllStatements(stmt.falseCase, context), stmt.sourceSpan, stmt.leadingComments), context);
|
|
};
|
|
AstTransformer.prototype.visitTryCatchStmt = function (stmt, context) {
|
|
return this.transformStmt(new TryCatchStmt(this.visitAllStatements(stmt.bodyStmts, context), this.visitAllStatements(stmt.catchStmts, context), stmt.sourceSpan, stmt.leadingComments), context);
|
|
};
|
|
AstTransformer.prototype.visitThrowStmt = function (stmt, context) {
|
|
return this.transformStmt(new ThrowStmt(stmt.error.visitExpression(this, context), stmt.sourceSpan, stmt.leadingComments), context);
|
|
};
|
|
AstTransformer.prototype.visitAllStatements = function (stmts, context) {
|
|
var _this = this;
|
|
return stmts.map(function (stmt) { return stmt.visitStatement(_this, context); });
|
|
};
|
|
return AstTransformer;
|
|
}());
|
|
var RecursiveAstVisitor = /** @class */ (function () {
|
|
function RecursiveAstVisitor() {
|
|
}
|
|
RecursiveAstVisitor.prototype.visitType = function (ast, context) {
|
|
return ast;
|
|
};
|
|
RecursiveAstVisitor.prototype.visitExpression = function (ast, context) {
|
|
if (ast.type) {
|
|
ast.type.visitType(this, context);
|
|
}
|
|
return ast;
|
|
};
|
|
RecursiveAstVisitor.prototype.visitBuiltinType = function (type, context) {
|
|
return this.visitType(type, context);
|
|
};
|
|
RecursiveAstVisitor.prototype.visitExpressionType = function (type, context) {
|
|
var _this = this;
|
|
type.value.visitExpression(this, context);
|
|
if (type.typeParams !== null) {
|
|
type.typeParams.forEach(function (param) { return _this.visitType(param, context); });
|
|
}
|
|
return this.visitType(type, context);
|
|
};
|
|
RecursiveAstVisitor.prototype.visitArrayType = function (type, context) {
|
|
return this.visitType(type, context);
|
|
};
|
|
RecursiveAstVisitor.prototype.visitMapType = function (type, context) {
|
|
return this.visitType(type, context);
|
|
};
|
|
RecursiveAstVisitor.prototype.visitWrappedNodeExpr = function (ast, context) {
|
|
return ast;
|
|
};
|
|
RecursiveAstVisitor.prototype.visitTypeofExpr = function (ast, context) {
|
|
return this.visitExpression(ast, context);
|
|
};
|
|
RecursiveAstVisitor.prototype.visitReadVarExpr = function (ast, context) {
|
|
return this.visitExpression(ast, context);
|
|
};
|
|
RecursiveAstVisitor.prototype.visitWriteVarExpr = function (ast, context) {
|
|
ast.value.visitExpression(this, context);
|
|
return this.visitExpression(ast, context);
|
|
};
|
|
RecursiveAstVisitor.prototype.visitWriteKeyExpr = function (ast, context) {
|
|
ast.receiver.visitExpression(this, context);
|
|
ast.index.visitExpression(this, context);
|
|
ast.value.visitExpression(this, context);
|
|
return this.visitExpression(ast, context);
|
|
};
|
|
RecursiveAstVisitor.prototype.visitWritePropExpr = function (ast, context) {
|
|
ast.receiver.visitExpression(this, context);
|
|
ast.value.visitExpression(this, context);
|
|
return this.visitExpression(ast, context);
|
|
};
|
|
RecursiveAstVisitor.prototype.visitInvokeMethodExpr = function (ast, context) {
|
|
ast.receiver.visitExpression(this, context);
|
|
this.visitAllExpressions(ast.args, context);
|
|
return this.visitExpression(ast, context);
|
|
};
|
|
RecursiveAstVisitor.prototype.visitInvokeFunctionExpr = function (ast, context) {
|
|
ast.fn.visitExpression(this, context);
|
|
this.visitAllExpressions(ast.args, context);
|
|
return this.visitExpression(ast, context);
|
|
};
|
|
RecursiveAstVisitor.prototype.visitTaggedTemplateExpr = function (ast, context) {
|
|
ast.tag.visitExpression(this, context);
|
|
this.visitAllExpressions(ast.template.expressions, context);
|
|
return this.visitExpression(ast, context);
|
|
};
|
|
RecursiveAstVisitor.prototype.visitInstantiateExpr = function (ast, context) {
|
|
ast.classExpr.visitExpression(this, context);
|
|
this.visitAllExpressions(ast.args, context);
|
|
return this.visitExpression(ast, context);
|
|
};
|
|
RecursiveAstVisitor.prototype.visitLiteralExpr = function (ast, context) {
|
|
return this.visitExpression(ast, context);
|
|
};
|
|
RecursiveAstVisitor.prototype.visitLocalizedString = function (ast, context) {
|
|
return this.visitExpression(ast, context);
|
|
};
|
|
RecursiveAstVisitor.prototype.visitExternalExpr = function (ast, context) {
|
|
var _this = this;
|
|
if (ast.typeParams) {
|
|
ast.typeParams.forEach(function (type) { return type.visitType(_this, context); });
|
|
}
|
|
return this.visitExpression(ast, context);
|
|
};
|
|
RecursiveAstVisitor.prototype.visitConditionalExpr = function (ast, context) {
|
|
ast.condition.visitExpression(this, context);
|
|
ast.trueCase.visitExpression(this, context);
|
|
ast.falseCase.visitExpression(this, context);
|
|
return this.visitExpression(ast, context);
|
|
};
|
|
RecursiveAstVisitor.prototype.visitNotExpr = function (ast, context) {
|
|
ast.condition.visitExpression(this, context);
|
|
return this.visitExpression(ast, context);
|
|
};
|
|
RecursiveAstVisitor.prototype.visitAssertNotNullExpr = function (ast, context) {
|
|
ast.condition.visitExpression(this, context);
|
|
return this.visitExpression(ast, context);
|
|
};
|
|
RecursiveAstVisitor.prototype.visitCastExpr = function (ast, context) {
|
|
ast.value.visitExpression(this, context);
|
|
return this.visitExpression(ast, context);
|
|
};
|
|
RecursiveAstVisitor.prototype.visitFunctionExpr = function (ast, context) {
|
|
this.visitAllStatements(ast.statements, context);
|
|
return this.visitExpression(ast, context);
|
|
};
|
|
RecursiveAstVisitor.prototype.visitUnaryOperatorExpr = function (ast, context) {
|
|
ast.expr.visitExpression(this, context);
|
|
return this.visitExpression(ast, context);
|
|
};
|
|
RecursiveAstVisitor.prototype.visitBinaryOperatorExpr = function (ast, context) {
|
|
ast.lhs.visitExpression(this, context);
|
|
ast.rhs.visitExpression(this, context);
|
|
return this.visitExpression(ast, context);
|
|
};
|
|
RecursiveAstVisitor.prototype.visitReadPropExpr = function (ast, context) {
|
|
ast.receiver.visitExpression(this, context);
|
|
return this.visitExpression(ast, context);
|
|
};
|
|
RecursiveAstVisitor.prototype.visitReadKeyExpr = function (ast, context) {
|
|
ast.receiver.visitExpression(this, context);
|
|
ast.index.visitExpression(this, context);
|
|
return this.visitExpression(ast, context);
|
|
};
|
|
RecursiveAstVisitor.prototype.visitLiteralArrayExpr = function (ast, context) {
|
|
this.visitAllExpressions(ast.entries, context);
|
|
return this.visitExpression(ast, context);
|
|
};
|
|
RecursiveAstVisitor.prototype.visitLiteralMapExpr = function (ast, context) {
|
|
var _this = this;
|
|
ast.entries.forEach(function (entry) { return entry.value.visitExpression(_this, context); });
|
|
return this.visitExpression(ast, context);
|
|
};
|
|
RecursiveAstVisitor.prototype.visitCommaExpr = function (ast, context) {
|
|
this.visitAllExpressions(ast.parts, context);
|
|
return this.visitExpression(ast, context);
|
|
};
|
|
RecursiveAstVisitor.prototype.visitAllExpressions = function (exprs, context) {
|
|
var _this = this;
|
|
exprs.forEach(function (expr) { return expr.visitExpression(_this, context); });
|
|
};
|
|
RecursiveAstVisitor.prototype.visitDeclareVarStmt = function (stmt, context) {
|
|
if (stmt.value) {
|
|
stmt.value.visitExpression(this, context);
|
|
}
|
|
if (stmt.type) {
|
|
stmt.type.visitType(this, context);
|
|
}
|
|
return stmt;
|
|
};
|
|
RecursiveAstVisitor.prototype.visitDeclareFunctionStmt = function (stmt, context) {
|
|
this.visitAllStatements(stmt.statements, context);
|
|
if (stmt.type) {
|
|
stmt.type.visitType(this, context);
|
|
}
|
|
return stmt;
|
|
};
|
|
RecursiveAstVisitor.prototype.visitExpressionStmt = function (stmt, context) {
|
|
stmt.expr.visitExpression(this, context);
|
|
return stmt;
|
|
};
|
|
RecursiveAstVisitor.prototype.visitReturnStmt = function (stmt, context) {
|
|
stmt.value.visitExpression(this, context);
|
|
return stmt;
|
|
};
|
|
RecursiveAstVisitor.prototype.visitDeclareClassStmt = function (stmt, context) {
|
|
var _this = this;
|
|
stmt.parent.visitExpression(this, context);
|
|
stmt.getters.forEach(function (getter) { return _this.visitAllStatements(getter.body, context); });
|
|
if (stmt.constructorMethod) {
|
|
this.visitAllStatements(stmt.constructorMethod.body, context);
|
|
}
|
|
stmt.methods.forEach(function (method) { return _this.visitAllStatements(method.body, context); });
|
|
return stmt;
|
|
};
|
|
RecursiveAstVisitor.prototype.visitIfStmt = function (stmt, context) {
|
|
stmt.condition.visitExpression(this, context);
|
|
this.visitAllStatements(stmt.trueCase, context);
|
|
this.visitAllStatements(stmt.falseCase, context);
|
|
return stmt;
|
|
};
|
|
RecursiveAstVisitor.prototype.visitTryCatchStmt = function (stmt, context) {
|
|
this.visitAllStatements(stmt.bodyStmts, context);
|
|
this.visitAllStatements(stmt.catchStmts, context);
|
|
return stmt;
|
|
};
|
|
RecursiveAstVisitor.prototype.visitThrowStmt = function (stmt, context) {
|
|
stmt.error.visitExpression(this, context);
|
|
return stmt;
|
|
};
|
|
RecursiveAstVisitor.prototype.visitAllStatements = function (stmts, context) {
|
|
var _this = this;
|
|
stmts.forEach(function (stmt) { return stmt.visitStatement(_this, context); });
|
|
};
|
|
return RecursiveAstVisitor;
|
|
}());
|
|
function findReadVarNames(stmts) {
|
|
var visitor = new _ReadVarVisitor();
|
|
visitor.visitAllStatements(stmts, null);
|
|
return visitor.varNames;
|
|
}
|
|
var _ReadVarVisitor = /** @class */ (function (_super) {
|
|
__extends(_ReadVarVisitor, _super);
|
|
function _ReadVarVisitor() {
|
|
var _this = _super.apply(this, __spreadArray([], __read(arguments))) || this;
|
|
_this.varNames = new Set();
|
|
return _this;
|
|
}
|
|
_ReadVarVisitor.prototype.visitDeclareFunctionStmt = function (stmt, context) {
|
|
// Don't descend into nested functions
|
|
return stmt;
|
|
};
|
|
_ReadVarVisitor.prototype.visitDeclareClassStmt = function (stmt, context) {
|
|
// Don't descend into nested classes
|
|
return stmt;
|
|
};
|
|
_ReadVarVisitor.prototype.visitReadVarExpr = function (ast, context) {
|
|
if (ast.name) {
|
|
this.varNames.add(ast.name);
|
|
}
|
|
return null;
|
|
};
|
|
return _ReadVarVisitor;
|
|
}(RecursiveAstVisitor));
|
|
function collectExternalReferences(stmts) {
|
|
var visitor = new _FindExternalReferencesVisitor();
|
|
visitor.visitAllStatements(stmts, null);
|
|
return visitor.externalReferences;
|
|
}
|
|
var _FindExternalReferencesVisitor = /** @class */ (function (_super) {
|
|
__extends(_FindExternalReferencesVisitor, _super);
|
|
function _FindExternalReferencesVisitor() {
|
|
var _this = _super.apply(this, __spreadArray([], __read(arguments))) || this;
|
|
_this.externalReferences = [];
|
|
return _this;
|
|
}
|
|
_FindExternalReferencesVisitor.prototype.visitExternalExpr = function (e, context) {
|
|
this.externalReferences.push(e.value);
|
|
return _super.prototype.visitExternalExpr.call(this, e, context);
|
|
};
|
|
return _FindExternalReferencesVisitor;
|
|
}(RecursiveAstVisitor));
|
|
function applySourceSpanToStatementIfNeeded(stmt, sourceSpan) {
|
|
if (!sourceSpan) {
|
|
return stmt;
|
|
}
|
|
var transformer = new _ApplySourceSpanTransformer(sourceSpan);
|
|
return stmt.visitStatement(transformer, null);
|
|
}
|
|
function applySourceSpanToExpressionIfNeeded(expr, sourceSpan) {
|
|
if (!sourceSpan) {
|
|
return expr;
|
|
}
|
|
var transformer = new _ApplySourceSpanTransformer(sourceSpan);
|
|
return expr.visitExpression(transformer, null);
|
|
}
|
|
var _ApplySourceSpanTransformer = /** @class */ (function (_super) {
|
|
__extends(_ApplySourceSpanTransformer, _super);
|
|
function _ApplySourceSpanTransformer(sourceSpan) {
|
|
var _this = _super.call(this) || this;
|
|
_this.sourceSpan = sourceSpan;
|
|
return _this;
|
|
}
|
|
_ApplySourceSpanTransformer.prototype._clone = function (obj) {
|
|
var e_1, _e;
|
|
var clone = Object.create(obj.constructor.prototype);
|
|
try {
|
|
for (var _f = __values(Object.keys(obj)), _g = _f.next(); !_g.done; _g = _f.next()) {
|
|
var prop = _g.value;
|
|
clone[prop] = obj[prop];
|
|
}
|
|
}
|
|
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
finally {
|
|
try {
|
|
if (_g && !_g.done && (_e = _f.return)) _e.call(_f);
|
|
}
|
|
finally { if (e_1) throw e_1.error; }
|
|
}
|
|
return clone;
|
|
};
|
|
_ApplySourceSpanTransformer.prototype.transformExpr = function (expr, context) {
|
|
if (!expr.sourceSpan) {
|
|
expr = this._clone(expr);
|
|
expr.sourceSpan = this.sourceSpan;
|
|
}
|
|
return expr;
|
|
};
|
|
_ApplySourceSpanTransformer.prototype.transformStmt = function (stmt, context) {
|
|
if (!stmt.sourceSpan) {
|
|
stmt = this._clone(stmt);
|
|
stmt.sourceSpan = this.sourceSpan;
|
|
}
|
|
return stmt;
|
|
};
|
|
return _ApplySourceSpanTransformer;
|
|
}(AstTransformer));
|
|
function leadingComment(text, multiline, trailingNewline) {
|
|
if (multiline === void 0) { multiline = false; }
|
|
if (trailingNewline === void 0) { trailingNewline = true; }
|
|
return new LeadingComment(text, multiline, trailingNewline);
|
|
}
|
|
function jsDocComment(tags) {
|
|
if (tags === void 0) { tags = []; }
|
|
return new JSDocComment(tags);
|
|
}
|
|
function variable(name, type, sourceSpan) {
|
|
return new ReadVarExpr(name, type, sourceSpan);
|
|
}
|
|
function importExpr(id, typeParams, sourceSpan) {
|
|
if (typeParams === void 0) { typeParams = null; }
|
|
return new ExternalExpr(id, null, typeParams, sourceSpan);
|
|
}
|
|
function importType(id, typeParams, typeModifiers) {
|
|
return id != null ? expressionType(importExpr(id, typeParams, null), typeModifiers) : null;
|
|
}
|
|
function expressionType(expr, typeModifiers, typeParams) {
|
|
return new ExpressionType(expr, typeModifiers, typeParams);
|
|
}
|
|
function typeofExpr(expr) {
|
|
return new TypeofExpr(expr);
|
|
}
|
|
function literalArr(values, type, sourceSpan) {
|
|
return new LiteralArrayExpr(values, type, sourceSpan);
|
|
}
|
|
function literalMap(values, type) {
|
|
if (type === void 0) { type = null; }
|
|
return new LiteralMapExpr(values.map(function (e) { return new LiteralMapEntry(e.key, e.value, e.quoted); }), type, null);
|
|
}
|
|
function unary(operator, expr, type, sourceSpan) {
|
|
return new UnaryOperatorExpr(operator, expr, type, sourceSpan);
|
|
}
|
|
function not(expr, sourceSpan) {
|
|
return new NotExpr(expr, sourceSpan);
|
|
}
|
|
function assertNotNull(expr, sourceSpan) {
|
|
return new AssertNotNull(expr, sourceSpan);
|
|
}
|
|
function fn(params, body, type, sourceSpan, name) {
|
|
return new FunctionExpr(params, body, type, sourceSpan, name);
|
|
}
|
|
function ifStmt(condition, thenClause, elseClause, sourceSpan, leadingComments) {
|
|
return new IfStmt(condition, thenClause, elseClause, sourceSpan, leadingComments);
|
|
}
|
|
function taggedTemplate(tag, template, type, sourceSpan) {
|
|
return new TaggedTemplateExpr(tag, template, type, sourceSpan);
|
|
}
|
|
function literal(value, type, sourceSpan) {
|
|
return new LiteralExpr(value, type, sourceSpan);
|
|
}
|
|
function localizedString(metaBlock, messageParts, placeholderNames, expressions, sourceSpan) {
|
|
return new LocalizedString(metaBlock, messageParts, placeholderNames, expressions, sourceSpan);
|
|
}
|
|
function isNull(exp) {
|
|
return exp instanceof LiteralExpr && exp.value === null;
|
|
}
|
|
/*
|
|
* Serializes a `Tag` into a string.
|
|
* Returns a string like " @foo {bar} baz" (note the leading whitespace before `@foo`).
|
|
*/
|
|
function tagToString(tag) {
|
|
var 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) {
|
|
var e_2, _e;
|
|
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]) + " ";
|
|
}
|
|
var out = '*\n';
|
|
try {
|
|
for (var tags_1 = __values(tags), tags_1_1 = tags_1.next(); !tags_1_1.done; tags_1_1 = tags_1.next()) {
|
|
var tag = tags_1_1.value;
|
|
out += ' *';
|
|
// If the tagToString is multi-line, insert " * " prefixes on lines.
|
|
out += tagToString(tag).replace(/\n/g, '\n * ');
|
|
out += '\n';
|
|
}
|
|
}
|
|
catch (e_2_1) { e_2 = { error: e_2_1 }; }
|
|
finally {
|
|
try {
|
|
if (tags_1_1 && !tags_1_1.done && (_e = tags_1.return)) _e.call(tags_1);
|
|
}
|
|
finally { if (e_2) throw e_2.error; }
|
|
}
|
|
out += ' ';
|
|
return out;
|
|
}
|
|
|
|
var 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: <unknown>}`. Note
|
|
* that we use a variable, rather than something like `null` in order to avoid collisions.
|
|
*/
|
|
var UNKNOWN_VALUE_KEY = variable('<unknown>');
|
|
/**
|
|
* Context to use when producing a key.
|
|
*
|
|
* This ensures we see the constant not the reference variable when producing
|
|
* a key.
|
|
*/
|
|
var 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.
|
|
*/
|
|
var 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.
|
|
*/
|
|
var FixupExpression = /** @class */ (function (_super) {
|
|
__extends(FixupExpression, _super);
|
|
function FixupExpression(resolved) {
|
|
var _this = _super.call(this, resolved.type) || this;
|
|
_this.resolved = resolved;
|
|
_this.original = resolved;
|
|
return _this;
|
|
}
|
|
FixupExpression.prototype.visitExpression = function (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);
|
|
}
|
|
};
|
|
FixupExpression.prototype.isEquivalent = function (e) {
|
|
return e instanceof FixupExpression && this.resolved.isEquivalent(e.resolved);
|
|
};
|
|
FixupExpression.prototype.isConstant = function () {
|
|
return true;
|
|
};
|
|
FixupExpression.prototype.fixup = function (expression) {
|
|
this.resolved = expression;
|
|
this.shared = true;
|
|
};
|
|
return FixupExpression;
|
|
}(Expression));
|
|
/**
|
|
* 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.
|
|
*/
|
|
var ConstantPool = /** @class */ (function () {
|
|
function ConstantPool(isClosureCompilerEnabled) {
|
|
if (isClosureCompilerEnabled === void 0) { isClosureCompilerEnabled = false; }
|
|
this.isClosureCompilerEnabled = isClosureCompilerEnabled;
|
|
this.statements = [];
|
|
this.literals = new Map();
|
|
this.literalFactories = new Map();
|
|
this.injectorDefinitions = new Map();
|
|
this.directiveDefinitions = new Map();
|
|
this.componentDefinitions = new Map();
|
|
this.pipeDefinitions = new Map();
|
|
this.nextNameIndex = 0;
|
|
}
|
|
ConstantPool.prototype.getConstLiteral = function (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;
|
|
}
|
|
var key = this.keyOf(literal);
|
|
var fixup = this.literals.get(key);
|
|
var 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
|
|
var name = this.freshName();
|
|
var definition = void 0;
|
|
var usage = void 0;
|
|
if (this.isClosureCompilerEnabled && isLongStringLiteral(literal)) {
|
|
// For string literals, Closure will **always** inline the string at
|
|
// **all** usages, duplicating it each time. For large strings, this
|
|
// unnecessarily bloats bundle size. To work around this restriction, we
|
|
// wrap the string in a function, and call that function for each usage.
|
|
// This tricks Closure into using inline logic for functions instead of
|
|
// string literals. Function calls are only inlined if the body is small
|
|
// enough to be worth it. By doing this, very large strings will be
|
|
// shared across multiple usages, rather than duplicating the string at
|
|
// each usage site.
|
|
//
|
|
// const myStr = function() { return "very very very long string"; };
|
|
// const usage1 = myStr();
|
|
// const usage2 = myStr();
|
|
definition = variable(name).set(new FunctionExpr([], // Params.
|
|
[
|
|
// Statements.
|
|
new ReturnStatement(literal),
|
|
]));
|
|
usage = variable(name).callFn([]);
|
|
}
|
|
else {
|
|
// Just declare and use the variable directly, without a function call
|
|
// indirection. This saves a few bytes and avoids an unncessary call.
|
|
definition = variable(name).set(literal);
|
|
usage = variable(name);
|
|
}
|
|
this.statements.push(definition.toDeclStmt(INFERRED_TYPE, [exports.StmtModifier.Final]));
|
|
fixup.fixup(usage);
|
|
}
|
|
return fixup;
|
|
};
|
|
ConstantPool.prototype.getDefinition = function (type, kind, ctx, forceShared) {
|
|
if (forceShared === void 0) { forceShared = false; }
|
|
var definitions = this.definitionsOf(kind);
|
|
var fixup = definitions.get(type);
|
|
var newValue = false;
|
|
if (!fixup) {
|
|
var property = this.propertyNameOf(kind);
|
|
fixup = new FixupExpression(ctx.importExpr(type).prop(property));
|
|
definitions.set(type, fixup);
|
|
newValue = true;
|
|
}
|
|
if ((!newValue && !fixup.shared) || (newValue && forceShared)) {
|
|
var name = this.freshName();
|
|
this.statements.push(variable(name).set(fixup.resolved).toDeclStmt(INFERRED_TYPE, [exports.StmtModifier.Final]));
|
|
fixup.fixup(variable(name));
|
|
}
|
|
return fixup;
|
|
};
|
|
ConstantPool.prototype.getLiteralFactory = function (literal) {
|
|
// Create a pure function that builds an array of a mix of constant and variable expressions
|
|
if (literal instanceof LiteralArrayExpr) {
|
|
var argumentsForKey = literal.entries.map(function (e) { return e.isConstant() ? e : UNKNOWN_VALUE_KEY; });
|
|
var key = this.keyOf(literalArr(argumentsForKey));
|
|
return this._getLiteralFactory(key, literal.entries, function (entries) { return literalArr(entries); });
|
|
}
|
|
else {
|
|
var expressionForKey = literalMap(literal.entries.map(function (e) { return ({
|
|
key: e.key,
|
|
value: e.value.isConstant() ? e.value : UNKNOWN_VALUE_KEY,
|
|
quoted: e.quoted
|
|
}); }));
|
|
var key = this.keyOf(expressionForKey);
|
|
return this._getLiteralFactory(key, literal.entries.map(function (e) { return e.value; }), function (entries) { return literalMap(entries.map(function (value, index) { return ({
|
|
key: literal.entries[index].key,
|
|
value: value,
|
|
quoted: literal.entries[index].quoted
|
|
}); })); });
|
|
}
|
|
};
|
|
ConstantPool.prototype._getLiteralFactory = function (key, values, resultMap) {
|
|
var _this = this;
|
|
var literalFactory = this.literalFactories.get(key);
|
|
var literalFactoryArguments = values.filter((function (e) { return !e.isConstant(); }));
|
|
if (!literalFactory) {
|
|
var resultExpressions = values.map(function (e, index) { return e.isConstant() ? _this.getConstLiteral(e, true) : variable("a" + index); });
|
|
var parameters = resultExpressions.filter(isVariable).map(function (e) { return new FnParam(e.name, DYNAMIC_TYPE); });
|
|
var pureFunctionDeclaration = fn(parameters, [new ReturnStatement(resultMap(resultExpressions))], INFERRED_TYPE);
|
|
var name = this.freshName();
|
|
this.statements.push(variable(name).set(pureFunctionDeclaration).toDeclStmt(INFERRED_TYPE, [
|
|
exports.StmtModifier.Final
|
|
]));
|
|
literalFactory = variable(name);
|
|
this.literalFactories.set(key, literalFactory);
|
|
}
|
|
return { literalFactory: literalFactory, literalFactoryArguments: 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.
|
|
*/
|
|
ConstantPool.prototype.uniqueName = function (prefix) {
|
|
return "" + prefix + this.nextNameIndex++;
|
|
};
|
|
ConstantPool.prototype.definitionsOf = function (kind) {
|
|
switch (kind) {
|
|
case 2 /* Component */:
|
|
return this.componentDefinitions;
|
|
case 1 /* Directive */:
|
|
return this.directiveDefinitions;
|
|
case 0 /* Injector */:
|
|
return this.injectorDefinitions;
|
|
case 3 /* Pipe */:
|
|
return this.pipeDefinitions;
|
|
}
|
|
};
|
|
ConstantPool.prototype.propertyNameOf = function (kind) {
|
|
switch (kind) {
|
|
case 2 /* Component */:
|
|
return 'ɵcmp';
|
|
case 1 /* Directive */:
|
|
return 'ɵdir';
|
|
case 0 /* Injector */:
|
|
return 'ɵinj';
|
|
case 3 /* Pipe */:
|
|
return 'ɵpipe';
|
|
}
|
|
};
|
|
ConstantPool.prototype.freshName = function () {
|
|
return this.uniqueName(CONSTANT_PREFIX);
|
|
};
|
|
ConstantPool.prototype.keyOf = function (expression) {
|
|
return expression.visitExpression(new KeyVisitor(), KEY_CONTEXT);
|
|
};
|
|
return ConstantPool;
|
|
}());
|
|
/**
|
|
* Visitor used to determine if 2 expressions are equivalent and can be shared in the
|
|
* `ConstantPool`.
|
|
*
|
|
* When the id (string) generated by the visitor is equal, expressions are considered equivalent.
|
|
*/
|
|
var KeyVisitor = /** @class */ (function () {
|
|
function KeyVisitor() {
|
|
this.visitWrappedNodeExpr = invalid;
|
|
this.visitWriteVarExpr = invalid;
|
|
this.visitWriteKeyExpr = invalid;
|
|
this.visitWritePropExpr = invalid;
|
|
this.visitInvokeMethodExpr = invalid;
|
|
this.visitInvokeFunctionExpr = invalid;
|
|
this.visitTaggedTemplateExpr = invalid;
|
|
this.visitInstantiateExpr = invalid;
|
|
this.visitConditionalExpr = invalid;
|
|
this.visitNotExpr = invalid;
|
|
this.visitAssertNotNullExpr = invalid;
|
|
this.visitCastExpr = invalid;
|
|
this.visitFunctionExpr = invalid;
|
|
this.visitUnaryOperatorExpr = invalid;
|
|
this.visitBinaryOperatorExpr = invalid;
|
|
this.visitReadPropExpr = invalid;
|
|
this.visitReadKeyExpr = invalid;
|
|
this.visitCommaExpr = invalid;
|
|
this.visitLocalizedString = invalid;
|
|
}
|
|
KeyVisitor.prototype.visitLiteralExpr = function (ast) {
|
|
return "" + (typeof ast.value === 'string' ? '"' + ast.value + '"' : ast.value);
|
|
};
|
|
KeyVisitor.prototype.visitLiteralArrayExpr = function (ast, context) {
|
|
var _this = this;
|
|
return "[" + ast.entries.map(function (entry) { return entry.visitExpression(_this, context); }).join(',') + "]";
|
|
};
|
|
KeyVisitor.prototype.visitLiteralMapExpr = function (ast, context) {
|
|
var _this = this;
|
|
var mapKey = function (entry) {
|
|
var quote = entry.quoted ? '"' : '';
|
|
return "" + quote + entry.key + quote;
|
|
};
|
|
var mapEntry = function (entry) { return mapKey(entry) + ":" + entry.value.visitExpression(_this, context); };
|
|
return "{" + ast.entries.map(mapEntry).join(',');
|
|
};
|
|
KeyVisitor.prototype.visitExternalExpr = function (ast) {
|
|
return ast.value.moduleName ? "EX:" + ast.value.moduleName + ":" + ast.value.name :
|
|
"EX:" + ast.value.runtime.name;
|
|
};
|
|
KeyVisitor.prototype.visitReadVarExpr = function (node) {
|
|
return "VAR:" + node.name;
|
|
};
|
|
KeyVisitor.prototype.visitTypeofExpr = function (node, context) {
|
|
return "TYPEOF:" + node.expr.visitExpression(this, context);
|
|
};
|
|
return KeyVisitor;
|
|
}());
|
|
function invalid(arg) {
|
|
throw new Error("Invalid state: Visitor " + this.constructor.name + " doesn't handle " + arg.constructor.name);
|
|
}
|
|
function isVariable(e) {
|
|
return e instanceof ReadVarExpr;
|
|
}
|
|
function isLongStringLiteral(expr) {
|
|
return expr instanceof LiteralExpr && typeof expr.value === 'string' &&
|
|
expr.value.length >= POOL_INCLUSION_LENGTH_THRESHOLD_FOR_STRINGS;
|
|
}
|
|
|
|
/**
|
|
* @license
|
|
* Copyright Google LLC All Rights Reserved.
|
|
*
|
|
* Use of this source code is governed by an MIT-style license that can be
|
|
* found in the LICENSE file at https://angular.io/license
|
|
*/
|
|
var CORE = '@angular/core';
|
|
var Identifiers = /** @class */ (function () {
|
|
function Identifiers() {
|
|
}
|
|
return Identifiers;
|
|
}());
|
|
/* Methods */
|
|
Identifiers.NEW_METHOD = 'factory';
|
|
Identifiers.TRANSFORM_METHOD = 'transform';
|
|
Identifiers.PATCH_DEPS = 'patchedDeps';
|
|
Identifiers.core = { name: null, moduleName: CORE };
|
|
/* Instructions */
|
|
Identifiers.namespaceHTML = { name: 'ɵɵnamespaceHTML', moduleName: CORE };
|
|
Identifiers.namespaceMathML = { name: 'ɵɵnamespaceMathML', moduleName: CORE };
|
|
Identifiers.namespaceSVG = { name: 'ɵɵnamespaceSVG', moduleName: CORE };
|
|
Identifiers.element = { name: 'ɵɵelement', moduleName: CORE };
|
|
Identifiers.elementStart = { name: 'ɵɵelementStart', moduleName: CORE };
|
|
Identifiers.elementEnd = { name: 'ɵɵelementEnd', moduleName: CORE };
|
|
Identifiers.advance = { name: 'ɵɵadvance', moduleName: CORE };
|
|
Identifiers.syntheticHostProperty = { name: 'ɵɵsyntheticHostProperty', moduleName: CORE };
|
|
Identifiers.syntheticHostListener = { name: 'ɵɵsyntheticHostListener', moduleName: CORE };
|
|
Identifiers.attribute = { name: 'ɵɵattribute', moduleName: CORE };
|
|
Identifiers.attributeInterpolate1 = { name: 'ɵɵattributeInterpolate1', moduleName: CORE };
|
|
Identifiers.attributeInterpolate2 = { name: 'ɵɵattributeInterpolate2', moduleName: CORE };
|
|
Identifiers.attributeInterpolate3 = { name: 'ɵɵattributeInterpolate3', moduleName: CORE };
|
|
Identifiers.attributeInterpolate4 = { name: 'ɵɵattributeInterpolate4', moduleName: CORE };
|
|
Identifiers.attributeInterpolate5 = { name: 'ɵɵattributeInterpolate5', moduleName: CORE };
|
|
Identifiers.attributeInterpolate6 = { name: 'ɵɵattributeInterpolate6', moduleName: CORE };
|
|
Identifiers.attributeInterpolate7 = { name: 'ɵɵattributeInterpolate7', moduleName: CORE };
|
|
Identifiers.attributeInterpolate8 = { name: 'ɵɵattributeInterpolate8', moduleName: CORE };
|
|
Identifiers.attributeInterpolateV = { name: 'ɵɵattributeInterpolateV', moduleName: CORE };
|
|
Identifiers.classProp = { name: 'ɵɵclassProp', moduleName: CORE };
|
|
Identifiers.elementContainerStart = { name: 'ɵɵelementContainerStart', moduleName: CORE };
|
|
Identifiers.elementContainerEnd = { name: 'ɵɵelementContainerEnd', moduleName: CORE };
|
|
Identifiers.elementContainer = { name: 'ɵɵelementContainer', moduleName: CORE };
|
|
Identifiers.styleMap = { name: 'ɵɵstyleMap', moduleName: CORE };
|
|
Identifiers.styleMapInterpolate1 = { name: 'ɵɵstyleMapInterpolate1', moduleName: CORE };
|
|
Identifiers.styleMapInterpolate2 = { name: 'ɵɵstyleMapInterpolate2', moduleName: CORE };
|
|
Identifiers.styleMapInterpolate3 = { name: 'ɵɵstyleMapInterpolate3', moduleName: CORE };
|
|
Identifiers.styleMapInterpolate4 = { name: 'ɵɵstyleMapInterpolate4', moduleName: CORE };
|
|
Identifiers.styleMapInterpolate5 = { name: 'ɵɵstyleMapInterpolate5', moduleName: CORE };
|
|
Identifiers.styleMapInterpolate6 = { name: 'ɵɵstyleMapInterpolate6', moduleName: CORE };
|
|
Identifiers.styleMapInterpolate7 = { name: 'ɵɵstyleMapInterpolate7', moduleName: CORE };
|
|
Identifiers.styleMapInterpolate8 = { name: 'ɵɵstyleMapInterpolate8', moduleName: CORE };
|
|
Identifiers.styleMapInterpolateV = { name: 'ɵɵstyleMapInterpolateV', moduleName: CORE };
|
|
Identifiers.classMap = { name: 'ɵɵclassMap', moduleName: CORE };
|
|
Identifiers.classMapInterpolate1 = { name: 'ɵɵclassMapInterpolate1', moduleName: CORE };
|
|
Identifiers.classMapInterpolate2 = { name: 'ɵɵclassMapInterpolate2', moduleName: CORE };
|
|
Identifiers.classMapInterpolate3 = { name: 'ɵɵclassMapInterpolate3', moduleName: CORE };
|
|
Identifiers.classMapInterpolate4 = { name: 'ɵɵclassMapInterpolate4', moduleName: CORE };
|
|
Identifiers.classMapInterpolate5 = { name: 'ɵɵclassMapInterpolate5', moduleName: CORE };
|
|
Identifiers.classMapInterpolate6 = { name: 'ɵɵclassMapInterpolate6', moduleName: CORE };
|
|
Identifiers.classMapInterpolate7 = { name: 'ɵɵclassMapInterpolate7', moduleName: CORE };
|
|
Identifiers.classMapInterpolate8 = { name: 'ɵɵclassMapInterpolate8', moduleName: CORE };
|
|
Identifiers.classMapInterpolateV = { name: 'ɵɵclassMapInterpolateV', moduleName: CORE };
|
|
Identifiers.styleProp = { name: 'ɵɵstyleProp', moduleName: CORE };
|
|
Identifiers.stylePropInterpolate1 = { name: 'ɵɵstylePropInterpolate1', moduleName: CORE };
|
|
Identifiers.stylePropInterpolate2 = { name: 'ɵɵstylePropInterpolate2', moduleName: CORE };
|
|
Identifiers.stylePropInterpolate3 = { name: 'ɵɵstylePropInterpolate3', moduleName: CORE };
|
|
Identifiers.stylePropInterpolate4 = { name: 'ɵɵstylePropInterpolate4', moduleName: CORE };
|
|
Identifiers.stylePropInterpolate5 = { name: 'ɵɵstylePropInterpolate5', moduleName: CORE };
|
|
Identifiers.stylePropInterpolate6 = { name: 'ɵɵstylePropInterpolate6', moduleName: CORE };
|
|
Identifiers.stylePropInterpolate7 = { name: 'ɵɵstylePropInterpolate7', moduleName: CORE };
|
|
Identifiers.stylePropInterpolate8 = { name: 'ɵɵstylePropInterpolate8', moduleName: CORE };
|
|
Identifiers.stylePropInterpolateV = { name: 'ɵɵstylePropInterpolateV', moduleName: CORE };
|
|
Identifiers.nextContext = { name: 'ɵɵnextContext', moduleName: CORE };
|
|
Identifiers.templateCreate = { name: 'ɵɵtemplate', moduleName: CORE };
|
|
Identifiers.text = { name: 'ɵɵtext', moduleName: CORE };
|
|
Identifiers.enableBindings = { name: 'ɵɵenableBindings', moduleName: CORE };
|
|
Identifiers.disableBindings = { name: 'ɵɵdisableBindings', moduleName: CORE };
|
|
Identifiers.getCurrentView = { name: 'ɵɵgetCurrentView', moduleName: CORE };
|
|
Identifiers.textInterpolate = { name: 'ɵɵtextInterpolate', moduleName: CORE };
|
|
Identifiers.textInterpolate1 = { name: 'ɵɵtextInterpolate1', moduleName: CORE };
|
|
Identifiers.textInterpolate2 = { name: 'ɵɵtextInterpolate2', moduleName: CORE };
|
|
Identifiers.textInterpolate3 = { name: 'ɵɵtextInterpolate3', moduleName: CORE };
|
|
Identifiers.textInterpolate4 = { name: 'ɵɵtextInterpolate4', moduleName: CORE };
|
|
Identifiers.textInterpolate5 = { name: 'ɵɵtextInterpolate5', moduleName: CORE };
|
|
Identifiers.textInterpolate6 = { name: 'ɵɵtextInterpolate6', moduleName: CORE };
|
|
Identifiers.textInterpolate7 = { name: 'ɵɵtextInterpolate7', moduleName: CORE };
|
|
Identifiers.textInterpolate8 = { name: 'ɵɵtextInterpolate8', moduleName: CORE };
|
|
Identifiers.textInterpolateV = { name: 'ɵɵtextInterpolateV', moduleName: CORE };
|
|
Identifiers.restoreView = { name: 'ɵɵrestoreView', moduleName: CORE };
|
|
Identifiers.pureFunction0 = { name: 'ɵɵpureFunction0', moduleName: CORE };
|
|
Identifiers.pureFunction1 = { name: 'ɵɵpureFunction1', moduleName: CORE };
|
|
Identifiers.pureFunction2 = { name: 'ɵɵpureFunction2', moduleName: CORE };
|
|
Identifiers.pureFunction3 = { name: 'ɵɵpureFunction3', moduleName: CORE };
|
|
Identifiers.pureFunction4 = { name: 'ɵɵpureFunction4', moduleName: CORE };
|
|
Identifiers.pureFunction5 = { name: 'ɵɵpureFunction5', moduleName: CORE };
|
|
Identifiers.pureFunction6 = { name: 'ɵɵpureFunction6', moduleName: CORE };
|
|
Identifiers.pureFunction7 = { name: 'ɵɵpureFunction7', moduleName: CORE };
|
|
Identifiers.pureFunction8 = { name: 'ɵɵpureFunction8', moduleName: CORE };
|
|
Identifiers.pureFunctionV = { name: 'ɵɵpureFunctionV', moduleName: CORE };
|
|
Identifiers.pipeBind1 = { name: 'ɵɵpipeBind1', moduleName: CORE };
|
|
Identifiers.pipeBind2 = { name: 'ɵɵpipeBind2', moduleName: CORE };
|
|
Identifiers.pipeBind3 = { name: 'ɵɵpipeBind3', moduleName: CORE };
|
|
Identifiers.pipeBind4 = { name: 'ɵɵpipeBind4', moduleName: CORE };
|
|
Identifiers.pipeBindV = { name: 'ɵɵpipeBindV', moduleName: CORE };
|
|
Identifiers.hostProperty = { name: 'ɵɵhostProperty', moduleName: CORE };
|
|
Identifiers.property = { name: 'ɵɵproperty', moduleName: CORE };
|
|
Identifiers.propertyInterpolate = { name: 'ɵɵpropertyInterpolate', moduleName: CORE };
|
|
Identifiers.propertyInterpolate1 = { name: 'ɵɵpropertyInterpolate1', moduleName: CORE };
|
|
Identifiers.propertyInterpolate2 = { name: 'ɵɵpropertyInterpolate2', moduleName: CORE };
|
|
Identifiers.propertyInterpolate3 = { name: 'ɵɵpropertyInterpolate3', moduleName: CORE };
|
|
Identifiers.propertyInterpolate4 = { name: 'ɵɵpropertyInterpolate4', moduleName: CORE };
|
|
Identifiers.propertyInterpolate5 = { name: 'ɵɵpropertyInterpolate5', moduleName: CORE };
|
|
Identifiers.propertyInterpolate6 = { name: 'ɵɵpropertyInterpolate6', moduleName: CORE };
|
|
Identifiers.propertyInterpolate7 = { name: 'ɵɵpropertyInterpolate7', moduleName: CORE };
|
|
Identifiers.propertyInterpolate8 = { name: 'ɵɵpropertyInterpolate8', moduleName: CORE };
|
|
Identifiers.propertyInterpolateV = { name: 'ɵɵpropertyInterpolateV', moduleName: CORE };
|
|
Identifiers.i18n = { name: 'ɵɵi18n', moduleName: CORE };
|
|
Identifiers.i18nAttributes = { name: 'ɵɵi18nAttributes', moduleName: CORE };
|
|
Identifiers.i18nExp = { name: 'ɵɵi18nExp', moduleName: CORE };
|
|
Identifiers.i18nStart = { name: 'ɵɵi18nStart', moduleName: CORE };
|
|
Identifiers.i18nEnd = { name: 'ɵɵi18nEnd', moduleName: CORE };
|
|
Identifiers.i18nApply = { name: 'ɵɵi18nApply', moduleName: CORE };
|
|
Identifiers.i18nPostprocess = { name: 'ɵɵi18nPostprocess', moduleName: CORE };
|
|
Identifiers.pipe = { name: 'ɵɵpipe', moduleName: CORE };
|
|
Identifiers.projection = { name: 'ɵɵprojection', moduleName: CORE };
|
|
Identifiers.projectionDef = { name: 'ɵɵprojectionDef', moduleName: CORE };
|
|
Identifiers.reference = { name: 'ɵɵreference', moduleName: CORE };
|
|
Identifiers.inject = { name: 'ɵɵinject', moduleName: CORE };
|
|
Identifiers.injectAttribute = { name: 'ɵɵinjectAttribute', moduleName: CORE };
|
|
Identifiers.directiveInject = { name: 'ɵɵdirectiveInject', moduleName: CORE };
|
|
Identifiers.invalidFactory = { name: 'ɵɵinvalidFactory', moduleName: CORE };
|
|
Identifiers.invalidFactoryDep = { name: 'ɵɵinvalidFactoryDep', moduleName: CORE };
|
|
Identifiers.templateRefExtractor = { name: 'ɵɵtemplateRefExtractor', moduleName: CORE };
|
|
Identifiers.forwardRef = { name: 'forwardRef', moduleName: CORE };
|
|
Identifiers.resolveForwardRef = { name: 'resolveForwardRef', moduleName: CORE };
|
|
Identifiers.ɵɵdefineInjectable = { name: 'ɵɵdefineInjectable', moduleName: CORE };
|
|
Identifiers.declareInjectable = { name: 'ɵɵngDeclareInjectable', moduleName: CORE };
|
|
Identifiers.InjectableDeclaration = { name: 'ɵɵInjectableDeclaration', moduleName: CORE };
|
|
Identifiers.resolveWindow = { name: 'ɵɵresolveWindow', moduleName: CORE };
|
|
Identifiers.resolveDocument = { name: 'ɵɵresolveDocument', moduleName: CORE };
|
|
Identifiers.resolveBody = { name: 'ɵɵresolveBody', moduleName: CORE };
|
|
Identifiers.defineComponent = { name: 'ɵɵdefineComponent', moduleName: CORE };
|
|
Identifiers.declareComponent = { name: 'ɵɵngDeclareComponent', moduleName: CORE };
|
|
Identifiers.setComponentScope = { name: 'ɵɵsetComponentScope', moduleName: CORE };
|
|
Identifiers.ChangeDetectionStrategy = {
|
|
name: 'ChangeDetectionStrategy',
|
|
moduleName: CORE,
|
|
};
|
|
Identifiers.ViewEncapsulation = {
|
|
name: 'ViewEncapsulation',
|
|
moduleName: CORE,
|
|
};
|
|
Identifiers.ComponentDeclaration = {
|
|
name: 'ɵɵComponentDeclaration',
|
|
moduleName: CORE,
|
|
};
|
|
Identifiers.FactoryDeclaration = {
|
|
name: 'ɵɵFactoryDeclaration',
|
|
moduleName: CORE,
|
|
};
|
|
Identifiers.declareFactory = { name: 'ɵɵngDeclareFactory', moduleName: CORE };
|
|
Identifiers.FactoryTarget = { name: 'ɵɵFactoryTarget', moduleName: CORE };
|
|
Identifiers.defineDirective = { name: 'ɵɵdefineDirective', moduleName: CORE };
|
|
Identifiers.declareDirective = { name: 'ɵɵngDeclareDirective', moduleName: CORE };
|
|
Identifiers.DirectiveDeclaration = {
|
|
name: 'ɵɵDirectiveDeclaration',
|
|
moduleName: CORE,
|
|
};
|
|
Identifiers.InjectorDef = { name: 'ɵɵInjectorDef', moduleName: CORE };
|
|
Identifiers.InjectorDeclaration = { name: 'ɵɵInjectorDeclaration', moduleName: CORE };
|
|
Identifiers.defineInjector = { name: 'ɵɵdefineInjector', moduleName: CORE };
|
|
Identifiers.declareInjector = { name: 'ɵɵngDeclareInjector', moduleName: CORE };
|
|
Identifiers.NgModuleDeclaration = {
|
|
name: 'ɵɵNgModuleDeclaration',
|
|
moduleName: CORE,
|
|
};
|
|
Identifiers.ModuleWithProviders = {
|
|
name: 'ModuleWithProviders',
|
|
moduleName: CORE,
|
|
};
|
|
Identifiers.defineNgModule = { name: 'ɵɵdefineNgModule', moduleName: CORE };
|
|
Identifiers.declareNgModule = { name: 'ɵɵngDeclareNgModule', moduleName: CORE };
|
|
Identifiers.setNgModuleScope = { name: 'ɵɵsetNgModuleScope', moduleName: CORE };
|
|
Identifiers.PipeDeclaration = { name: 'ɵɵPipeDeclaration', moduleName: CORE };
|
|
Identifiers.definePipe = { name: 'ɵɵdefinePipe', moduleName: CORE };
|
|
Identifiers.declarePipe = { name: 'ɵɵngDeclarePipe', moduleName: CORE };
|
|
Identifiers.declareClassMetadata = { name: 'ɵɵngDeclareClassMetadata', moduleName: CORE };
|
|
Identifiers.setClassMetadata = { name: 'ɵsetClassMetadata', moduleName: CORE };
|
|
Identifiers.queryRefresh = { name: 'ɵɵqueryRefresh', moduleName: CORE };
|
|
Identifiers.viewQuery = { name: 'ɵɵviewQuery', moduleName: CORE };
|
|
Identifiers.loadQuery = { name: 'ɵɵloadQuery', moduleName: CORE };
|
|
Identifiers.contentQuery = { name: 'ɵɵcontentQuery', moduleName: CORE };
|
|
Identifiers.NgOnChangesFeature = { name: 'ɵɵNgOnChangesFeature', moduleName: CORE };
|
|
Identifiers.InheritDefinitionFeature = { name: 'ɵɵInheritDefinitionFeature', moduleName: CORE };
|
|
Identifiers.CopyDefinitionFeature = { name: 'ɵɵCopyDefinitionFeature', moduleName: CORE };
|
|
Identifiers.ProvidersFeature = { name: 'ɵɵProvidersFeature', moduleName: CORE };
|
|
Identifiers.listener = { name: 'ɵɵlistener', moduleName: CORE };
|
|
Identifiers.getInheritedFactory = {
|
|
name: 'ɵɵgetInheritedFactory',
|
|
moduleName: CORE,
|
|
};
|
|
// sanitization-related functions
|
|
Identifiers.sanitizeHtml = { name: 'ɵɵsanitizeHtml', moduleName: CORE };
|
|
Identifiers.sanitizeStyle = { name: 'ɵɵsanitizeStyle', moduleName: CORE };
|
|
Identifiers.sanitizeResourceUrl = { name: 'ɵɵsanitizeResourceUrl', moduleName: CORE };
|
|
Identifiers.sanitizeScript = { name: 'ɵɵsanitizeScript', moduleName: CORE };
|
|
Identifiers.sanitizeUrl = { name: 'ɵɵsanitizeUrl', moduleName: CORE };
|
|
Identifiers.sanitizeUrlOrResourceUrl = { name: 'ɵɵsanitizeUrlOrResourceUrl', moduleName: CORE };
|
|
Identifiers.trustConstantHtml = { name: 'ɵɵtrustConstantHtml', moduleName: CORE };
|
|
Identifiers.trustConstantResourceUrl = { name: 'ɵɵtrustConstantResourceUrl', moduleName: CORE };
|
|
|
|
/**
|
|
* @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 DASH_CASE_REGEXP = /-+([a-z0-9])/g;
|
|
function dashCaseToCamelCase(input) {
|
|
return input.replace(DASH_CASE_REGEXP, function () {
|
|
var m = [];
|
|
for (var _i = 0; _i < arguments.length; _i++) {
|
|
m[_i] = arguments[_i];
|
|
}
|
|
return m[1].toUpperCase();
|
|
});
|
|
}
|
|
function splitAtColon(input, defaultValues) {
|
|
return _splitAt(input, ':', defaultValues);
|
|
}
|
|
function splitAtPeriod(input, defaultValues) {
|
|
return _splitAt(input, '.', defaultValues);
|
|
}
|
|
function _splitAt(input, character, defaultValues) {
|
|
var characterIndex = input.indexOf(character);
|
|
if (characterIndex == -1)
|
|
return defaultValues;
|
|
return [input.slice(0, characterIndex).trim(), input.slice(characterIndex + 1).trim()];
|
|
}
|
|
function visitValue(value, visitor, context) {
|
|
if (Array.isArray(value)) {
|
|
return visitor.visitArray(value, context);
|
|
}
|
|
if (isStrictStringMap(value)) {
|
|
return visitor.visitStringMap(value, context);
|
|
}
|
|
if (value == null || typeof value == 'string' || typeof value == 'number' ||
|
|
typeof value == 'boolean') {
|
|
return visitor.visitPrimitive(value, context);
|
|
}
|
|
return visitor.visitOther(value, context);
|
|
}
|
|
function isDefined(val) {
|
|
return val !== null && val !== undefined;
|
|
}
|
|
function noUndefined(val) {
|
|
return val === undefined ? null : val;
|
|
}
|
|
var ValueTransformer = /** @class */ (function () {
|
|
function ValueTransformer() {
|
|
}
|
|
ValueTransformer.prototype.visitArray = function (arr, context) {
|
|
var _this = this;
|
|
return arr.map(function (value) { return visitValue(value, _this, context); });
|
|
};
|
|
ValueTransformer.prototype.visitStringMap = function (map, context) {
|
|
var _this = this;
|
|
var result = {};
|
|
Object.keys(map).forEach(function (key) {
|
|
result[key] = visitValue(map[key], _this, context);
|
|
});
|
|
return result;
|
|
};
|
|
ValueTransformer.prototype.visitPrimitive = function (value, context) {
|
|
return value;
|
|
};
|
|
ValueTransformer.prototype.visitOther = function (value, context) {
|
|
return value;
|
|
};
|
|
return ValueTransformer;
|
|
}());
|
|
var SyncAsync = {
|
|
assertSync: function (value) {
|
|
if (isPromise(value)) {
|
|
throw new Error("Illegal state: value cannot be a promise");
|
|
}
|
|
return value;
|
|
},
|
|
then: function (value, cb) {
|
|
return isPromise(value) ? value.then(cb) : cb(value);
|
|
},
|
|
all: function (syncAsyncValues) {
|
|
return syncAsyncValues.some(isPromise) ? Promise.all(syncAsyncValues) : syncAsyncValues;
|
|
}
|
|
};
|
|
function error(msg) {
|
|
throw new Error("Internal Error: " + msg);
|
|
}
|
|
// Escape characters that have a special meaning in Regular Expressions
|
|
function escapeRegExp(s) {
|
|
return s.replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');
|
|
}
|
|
var STRING_MAP_PROTO = Object.getPrototypeOf({});
|
|
function isStrictStringMap(obj) {
|
|
return typeof obj === 'object' && obj !== null && Object.getPrototypeOf(obj) === STRING_MAP_PROTO;
|
|
}
|
|
function utf8Encode(str) {
|
|
var encoded = [];
|
|
for (var index = 0; index < str.length; index++) {
|
|
var codePoint = str.charCodeAt(index);
|
|
// decode surrogate
|
|
// see https://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae
|
|
if (codePoint >= 0xd800 && codePoint <= 0xdbff && str.length > (index + 1)) {
|
|
var 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
|
|
var res = token.toString();
|
|
if (res == null) {
|
|
return '' + res;
|
|
}
|
|
var newLineIndex = res.indexOf('\n');
|
|
return newLineIndex === -1 ? res : res.substring(0, newLineIndex);
|
|
}
|
|
/**
|
|
* Lazily retrieves the reference value from a forwardRef.
|
|
*/
|
|
function resolveForwardRef(type) {
|
|
if (typeof type === 'function' && type.hasOwnProperty('__forward_ref__')) {
|
|
return type();
|
|
}
|
|
else {
|
|
return type;
|
|
}
|
|
}
|
|
/**
|
|
* Determine if the argument is shaped like a Promise
|
|
*/
|
|
function isPromise(obj) {
|
|
// allow any Promise/A+ compliant thenable.
|
|
// It's up to the caller to ensure that obj.then conforms to the spec
|
|
return !!obj && typeof obj.then === 'function';
|
|
}
|
|
var Version = /** @class */ (function () {
|
|
function Version(full) {
|
|
this.full = full;
|
|
var splits = full.split('.');
|
|
this.major = splits[0];
|
|
this.minor = splits[1];
|
|
this.patch = splits.slice(2).join('.');
|
|
}
|
|
return Version;
|
|
}());
|
|
var __window = typeof window !== 'undefined' && window;
|
|
var __self = typeof self !== 'undefined' && typeof WorkerGlobalScope !== 'undefined' &&
|
|
self instanceof WorkerGlobalScope && self;
|
|
var __global = typeof global !== 'undefined' && global;
|
|
// Check __global first, because in Node tests both __global and __window may be defined and _global
|
|
// should be __global in that case.
|
|
var _global = __global || __window || __self;
|
|
function newArray(size, value) {
|
|
var list = [];
|
|
for (var i = 0; i < size; i++) {
|
|
list.push(value);
|
|
}
|
|
return list;
|
|
}
|
|
/**
|
|
* Partitions a given array into 2 arrays, based on a boolean value returned by the condition
|
|
* function.
|
|
*
|
|
* @param arr Input array that should be partitioned
|
|
* @param conditionFn Condition function that is called for each item in a given array and returns a
|
|
* boolean value.
|
|
*/
|
|
function partitionArray(arr, conditionFn) {
|
|
var e_1, _a;
|
|
var truthy = [];
|
|
var falsy = [];
|
|
try {
|
|
for (var arr_1 = __values(arr), arr_1_1 = arr_1.next(); !arr_1_1.done; arr_1_1 = arr_1.next()) {
|
|
var item = arr_1_1.value;
|
|
(conditionFn(item) ? truthy : falsy).push(item);
|
|
}
|
|
}
|
|
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
finally {
|
|
try {
|
|
if (arr_1_1 && !arr_1_1.done && (_a = arr_1.return)) _a.call(arr_1);
|
|
}
|
|
finally { if (e_1) throw e_1.error; }
|
|
}
|
|
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
|
|
var VERSION = 3;
|
|
var JS_B64_PREFIX = '# sourceMappingURL=data:application/json;base64,';
|
|
var SourceMapGenerator = /** @class */ (function () {
|
|
function SourceMapGenerator(file) {
|
|
if (file === void 0) { 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
|
|
SourceMapGenerator.prototype.addSource = function (url, content) {
|
|
if (content === void 0) { content = null; }
|
|
if (!this.sourcesContent.has(url)) {
|
|
this.sourcesContent.set(url, content);
|
|
}
|
|
return this;
|
|
};
|
|
SourceMapGenerator.prototype.addLine = function () {
|
|
this.lines.push([]);
|
|
this.lastCol0 = 0;
|
|
return this;
|
|
};
|
|
SourceMapGenerator.prototype.addMapping = function (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: col0, sourceUrl: sourceUrl, sourceLine0: sourceLine0, sourceCol0: sourceCol0 });
|
|
return this;
|
|
};
|
|
Object.defineProperty(SourceMapGenerator.prototype, "currentLine", {
|
|
/**
|
|
* @internal strip this from published d.ts files due to
|
|
* https://github.com/microsoft/TypeScript/issues/36216
|
|
*/
|
|
get: function () {
|
|
return this.lines.slice(-1)[0];
|
|
},
|
|
enumerable: false,
|
|
configurable: true
|
|
});
|
|
SourceMapGenerator.prototype.toJSON = function () {
|
|
var _this = this;
|
|
if (!this.hasMappings) {
|
|
return null;
|
|
}
|
|
var sourcesIndex = new Map();
|
|
var sources = [];
|
|
var sourcesContent = [];
|
|
Array.from(this.sourcesContent.keys()).forEach(function (url, i) {
|
|
sourcesIndex.set(url, i);
|
|
sources.push(url);
|
|
sourcesContent.push(_this.sourcesContent.get(url) || null);
|
|
});
|
|
var mappings = '';
|
|
var lastCol0 = 0;
|
|
var lastSourceIndex = 0;
|
|
var lastSourceLine0 = 0;
|
|
var lastSourceCol0 = 0;
|
|
this.lines.forEach(function (segments) {
|
|
lastCol0 = 0;
|
|
mappings += segments
|
|
.map(function (segment) {
|
|
// zero-based starting column of the line in the generated code
|
|
var 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,
|
|
};
|
|
};
|
|
SourceMapGenerator.prototype.toJsComment = function () {
|
|
return this.hasMappings ? '//' + JS_B64_PREFIX + toBase64String(JSON.stringify(this, null, 0)) :
|
|
'';
|
|
};
|
|
return SourceMapGenerator;
|
|
}());
|
|
function toBase64String(value) {
|
|
var b64 = '';
|
|
var encoded = utf8Encode(value);
|
|
for (var i = 0; i < encoded.length;) {
|
|
var i1 = encoded[i++];
|
|
var i2 = i < encoded.length ? encoded[i++] : null;
|
|
var 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;
|
|
var out = '';
|
|
do {
|
|
var digit = value & 31;
|
|
value = value >> 5;
|
|
if (value > 0) {
|
|
digit = digit | 32;
|
|
}
|
|
out += toBase64Digit(digit);
|
|
} while (value > 0);
|
|
return out;
|
|
}
|
|
var 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];
|
|
}
|
|
|
|
var _SINGLE_QUOTE_ESCAPE_STRING_RE = /'|\\|\n|\r|\$/g;
|
|
var _LEGAL_IDENTIFIER_RE = /^[$A-Z_][0-9A-Z_$]*$/i;
|
|
var _INDENT_WITH = ' ';
|
|
var CATCH_ERROR_VAR$1 = variable('error', null, null);
|
|
var CATCH_STACK_VAR$1 = variable('stack', null, null);
|
|
var _EmittedLine = /** @class */ (function () {
|
|
function _EmittedLine(indent) {
|
|
this.indent = indent;
|
|
this.partsLength = 0;
|
|
this.parts = [];
|
|
this.srcSpans = [];
|
|
}
|
|
return _EmittedLine;
|
|
}());
|
|
var EmitterVisitorContext = /** @class */ (function () {
|
|
function EmitterVisitorContext(_indent) {
|
|
this._indent = _indent;
|
|
this._classes = [];
|
|
this._preambleLineCount = 0;
|
|
this._lines = [new _EmittedLine(_indent)];
|
|
}
|
|
EmitterVisitorContext.createRoot = function () {
|
|
return new EmitterVisitorContext(0);
|
|
};
|
|
Object.defineProperty(EmitterVisitorContext.prototype, "_currentLine", {
|
|
/**
|
|
* @internal strip this from published d.ts files due to
|
|
* https://github.com/microsoft/TypeScript/issues/36216
|
|
*/
|
|
get: function () {
|
|
return this._lines[this._lines.length - 1];
|
|
},
|
|
enumerable: false,
|
|
configurable: true
|
|
});
|
|
EmitterVisitorContext.prototype.println = function (from, lastPart) {
|
|
if (lastPart === void 0) { lastPart = ''; }
|
|
this.print(from || null, lastPart, true);
|
|
};
|
|
EmitterVisitorContext.prototype.lineIsEmpty = function () {
|
|
return this._currentLine.parts.length === 0;
|
|
};
|
|
EmitterVisitorContext.prototype.lineLength = function () {
|
|
return this._currentLine.indent * _INDENT_WITH.length + this._currentLine.partsLength;
|
|
};
|
|
EmitterVisitorContext.prototype.print = function (from, part, newLine) {
|
|
if (newLine === void 0) { 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));
|
|
}
|
|
};
|
|
EmitterVisitorContext.prototype.removeEmptyLastLine = function () {
|
|
if (this.lineIsEmpty()) {
|
|
this._lines.pop();
|
|
}
|
|
};
|
|
EmitterVisitorContext.prototype.incIndent = function () {
|
|
this._indent++;
|
|
if (this.lineIsEmpty()) {
|
|
this._currentLine.indent = this._indent;
|
|
}
|
|
};
|
|
EmitterVisitorContext.prototype.decIndent = function () {
|
|
this._indent--;
|
|
if (this.lineIsEmpty()) {
|
|
this._currentLine.indent = this._indent;
|
|
}
|
|
};
|
|
EmitterVisitorContext.prototype.pushClass = function (clazz) {
|
|
this._classes.push(clazz);
|
|
};
|
|
EmitterVisitorContext.prototype.popClass = function () {
|
|
return this._classes.pop();
|
|
};
|
|
Object.defineProperty(EmitterVisitorContext.prototype, "currentClass", {
|
|
get: function () {
|
|
return this._classes.length > 0 ? this._classes[this._classes.length - 1] : null;
|
|
},
|
|
enumerable: false,
|
|
configurable: true
|
|
});
|
|
EmitterVisitorContext.prototype.toSource = function () {
|
|
return this.sourceLines
|
|
.map(function (l) { return l.parts.length > 0 ? _createIndent(l.indent) + l.parts.join('') : ''; })
|
|
.join('\n');
|
|
};
|
|
EmitterVisitorContext.prototype.toSourceMapGenerator = function (genFilePath, startsAtLine) {
|
|
if (startsAtLine === void 0) { startsAtLine = 0; }
|
|
var map = new SourceMapGenerator(genFilePath);
|
|
var firstOffsetMapped = false;
|
|
var mapFirstOffsetIfNeeded = function () {
|
|
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 (var i = 0; i < startsAtLine; i++) {
|
|
map.addLine();
|
|
mapFirstOffsetIfNeeded();
|
|
}
|
|
this.sourceLines.forEach(function (line, lineIdx) {
|
|
map.addLine();
|
|
var spans = line.srcSpans;
|
|
var parts = line.parts;
|
|
var col0 = line.indent * _INDENT_WITH.length;
|
|
var 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) {
|
|
var span = spans[spanIdx];
|
|
var source = span.start.file;
|
|
var sourceLine = span.start.line;
|
|
var 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;
|
|
};
|
|
EmitterVisitorContext.prototype.setPreambleLineCount = function (count) {
|
|
return this._preambleLineCount = count;
|
|
};
|
|
EmitterVisitorContext.prototype.spanOf = function (line, column) {
|
|
var emittedLine = this._lines[line - this._preambleLineCount];
|
|
if (emittedLine) {
|
|
var columnsLeft = column - _createIndent(emittedLine.indent).length;
|
|
for (var partIndex = 0; partIndex < emittedLine.parts.length; partIndex++) {
|
|
var part = emittedLine.parts[partIndex];
|
|
if (part.length > columnsLeft) {
|
|
return emittedLine.srcSpans[partIndex];
|
|
}
|
|
columnsLeft -= part.length;
|
|
}
|
|
}
|
|
return null;
|
|
};
|
|
Object.defineProperty(EmitterVisitorContext.prototype, "sourceLines", {
|
|
/**
|
|
* @internal strip this from published d.ts files due to
|
|
* https://github.com/microsoft/TypeScript/issues/36216
|
|
*/
|
|
get: function () {
|
|
if (this._lines.length && this._lines[this._lines.length - 1].parts.length === 0) {
|
|
return this._lines.slice(0, -1);
|
|
}
|
|
return this._lines;
|
|
},
|
|
enumerable: false,
|
|
configurable: true
|
|
});
|
|
return EmitterVisitorContext;
|
|
}());
|
|
var AbstractEmitterVisitor = /** @class */ (function () {
|
|
function AbstractEmitterVisitor(_escapeDollarInStrings) {
|
|
this._escapeDollarInStrings = _escapeDollarInStrings;
|
|
}
|
|
AbstractEmitterVisitor.prototype.printLeadingComments = function (stmt, ctx) {
|
|
var e_1, _a;
|
|
if (stmt.leadingComments === undefined) {
|
|
return;
|
|
}
|
|
try {
|
|
for (var _b = __values(stmt.leadingComments), _c = _b.next(); !_c.done; _c = _b.next()) {
|
|
var comment = _c.value;
|
|
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(function (line) {
|
|
ctx.println(stmt, "// " + line);
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
finally {
|
|
try {
|
|
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
|
|
}
|
|
finally { if (e_1) throw e_1.error; }
|
|
}
|
|
};
|
|
AbstractEmitterVisitor.prototype.visitExpressionStmt = function (stmt, ctx) {
|
|
this.printLeadingComments(stmt, ctx);
|
|
stmt.expr.visitExpression(this, ctx);
|
|
ctx.println(stmt, ';');
|
|
return null;
|
|
};
|
|
AbstractEmitterVisitor.prototype.visitReturnStmt = function (stmt, ctx) {
|
|
this.printLeadingComments(stmt, ctx);
|
|
ctx.print(stmt, "return ");
|
|
stmt.value.visitExpression(this, ctx);
|
|
ctx.println(stmt, ';');
|
|
return null;
|
|
};
|
|
AbstractEmitterVisitor.prototype.visitIfStmt = function (stmt, ctx) {
|
|
this.printLeadingComments(stmt, ctx);
|
|
ctx.print(stmt, "if (");
|
|
stmt.condition.visitExpression(this, ctx);
|
|
ctx.print(stmt, ") {");
|
|
var 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;
|
|
};
|
|
AbstractEmitterVisitor.prototype.visitThrowStmt = function (stmt, ctx) {
|
|
this.printLeadingComments(stmt, ctx);
|
|
ctx.print(stmt, "throw ");
|
|
stmt.error.visitExpression(this, ctx);
|
|
ctx.println(stmt, ";");
|
|
return null;
|
|
};
|
|
AbstractEmitterVisitor.prototype.visitWriteVarExpr = function (expr, ctx) {
|
|
var 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;
|
|
};
|
|
AbstractEmitterVisitor.prototype.visitWriteKeyExpr = function (expr, ctx) {
|
|
var 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;
|
|
};
|
|
AbstractEmitterVisitor.prototype.visitWritePropExpr = function (expr, ctx) {
|
|
var 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;
|
|
};
|
|
AbstractEmitterVisitor.prototype.visitInvokeMethodExpr = function (expr, ctx) {
|
|
expr.receiver.visitExpression(this, ctx);
|
|
var name = expr.name;
|
|
if (expr.builtin != null) {
|
|
name = this.getBuiltinMethodName(expr.builtin);
|
|
if (name == null) {
|
|
// some builtins just mean to skip the call.
|
|
return null;
|
|
}
|
|
}
|
|
ctx.print(expr, "." + name + "(");
|
|
this.visitAllExpressions(expr.args, ctx, ",");
|
|
ctx.print(expr, ")");
|
|
return null;
|
|
};
|
|
AbstractEmitterVisitor.prototype.visitInvokeFunctionExpr = function (expr, ctx) {
|
|
expr.fn.visitExpression(this, ctx);
|
|
ctx.print(expr, "(");
|
|
this.visitAllExpressions(expr.args, ctx, ',');
|
|
ctx.print(expr, ")");
|
|
return null;
|
|
};
|
|
AbstractEmitterVisitor.prototype.visitTaggedTemplateExpr = function (expr, ctx) {
|
|
expr.tag.visitExpression(this, ctx);
|
|
ctx.print(expr, '`' + expr.template.elements[0].rawText);
|
|
for (var 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;
|
|
};
|
|
AbstractEmitterVisitor.prototype.visitWrappedNodeExpr = function (ast, ctx) {
|
|
throw new Error('Abstract emitter cannot visit WrappedNodeExpr.');
|
|
};
|
|
AbstractEmitterVisitor.prototype.visitTypeofExpr = function (expr, ctx) {
|
|
ctx.print(expr, 'typeof ');
|
|
expr.expr.visitExpression(this, ctx);
|
|
};
|
|
AbstractEmitterVisitor.prototype.visitReadVarExpr = function (ast, ctx) {
|
|
var varName = ast.name;
|
|
if (ast.builtin != null) {
|
|
switch (ast.builtin) {
|
|
case exports.BuiltinVar.Super:
|
|
varName = 'super';
|
|
break;
|
|
case exports.BuiltinVar.This:
|
|
varName = 'this';
|
|
break;
|
|
case exports.BuiltinVar.CatchError:
|
|
varName = CATCH_ERROR_VAR$1.name;
|
|
break;
|
|
case exports.BuiltinVar.CatchStack:
|
|
varName = CATCH_STACK_VAR$1.name;
|
|
break;
|
|
default:
|
|
throw new Error("Unknown builtin variable " + ast.builtin);
|
|
}
|
|
}
|
|
ctx.print(ast, varName);
|
|
return null;
|
|
};
|
|
AbstractEmitterVisitor.prototype.visitInstantiateExpr = function (ast, ctx) {
|
|
ctx.print(ast, "new ");
|
|
ast.classExpr.visitExpression(this, ctx);
|
|
ctx.print(ast, "(");
|
|
this.visitAllExpressions(ast.args, ctx, ',');
|
|
ctx.print(ast, ")");
|
|
return null;
|
|
};
|
|
AbstractEmitterVisitor.prototype.visitLiteralExpr = function (ast, ctx) {
|
|
var value = ast.value;
|
|
if (typeof value === 'string') {
|
|
ctx.print(ast, escapeIdentifier(value, this._escapeDollarInStrings));
|
|
}
|
|
else {
|
|
ctx.print(ast, "" + value);
|
|
}
|
|
return null;
|
|
};
|
|
AbstractEmitterVisitor.prototype.visitLocalizedString = function (ast, ctx) {
|
|
var head = ast.serializeI18nHead();
|
|
ctx.print(ast, '$localize `' + head.raw);
|
|
for (var 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;
|
|
};
|
|
AbstractEmitterVisitor.prototype.visitConditionalExpr = function (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;
|
|
};
|
|
AbstractEmitterVisitor.prototype.visitNotExpr = function (ast, ctx) {
|
|
ctx.print(ast, '!');
|
|
ast.condition.visitExpression(this, ctx);
|
|
return null;
|
|
};
|
|
AbstractEmitterVisitor.prototype.visitAssertNotNullExpr = function (ast, ctx) {
|
|
ast.condition.visitExpression(this, ctx);
|
|
return null;
|
|
};
|
|
AbstractEmitterVisitor.prototype.visitUnaryOperatorExpr = function (ast, ctx) {
|
|
var opStr;
|
|
switch (ast.operator) {
|
|
case exports.UnaryOperator.Plus:
|
|
opStr = '+';
|
|
break;
|
|
case exports.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;
|
|
};
|
|
AbstractEmitterVisitor.prototype.visitBinaryOperatorExpr = function (ast, ctx) {
|
|
var opStr;
|
|
switch (ast.operator) {
|
|
case exports.BinaryOperator.Equals:
|
|
opStr = '==';
|
|
break;
|
|
case exports.BinaryOperator.Identical:
|
|
opStr = '===';
|
|
break;
|
|
case exports.BinaryOperator.NotEquals:
|
|
opStr = '!=';
|
|
break;
|
|
case exports.BinaryOperator.NotIdentical:
|
|
opStr = '!==';
|
|
break;
|
|
case exports.BinaryOperator.And:
|
|
opStr = '&&';
|
|
break;
|
|
case exports.BinaryOperator.BitwiseAnd:
|
|
opStr = '&';
|
|
break;
|
|
case exports.BinaryOperator.Or:
|
|
opStr = '||';
|
|
break;
|
|
case exports.BinaryOperator.Plus:
|
|
opStr = '+';
|
|
break;
|
|
case exports.BinaryOperator.Minus:
|
|
opStr = '-';
|
|
break;
|
|
case exports.BinaryOperator.Divide:
|
|
opStr = '/';
|
|
break;
|
|
case exports.BinaryOperator.Multiply:
|
|
opStr = '*';
|
|
break;
|
|
case exports.BinaryOperator.Modulo:
|
|
opStr = '%';
|
|
break;
|
|
case exports.BinaryOperator.Lower:
|
|
opStr = '<';
|
|
break;
|
|
case exports.BinaryOperator.LowerEquals:
|
|
opStr = '<=';
|
|
break;
|
|
case exports.BinaryOperator.Bigger:
|
|
opStr = '>';
|
|
break;
|
|
case exports.BinaryOperator.BiggerEquals:
|
|
opStr = '>=';
|
|
break;
|
|
case exports.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;
|
|
};
|
|
AbstractEmitterVisitor.prototype.visitReadPropExpr = function (ast, ctx) {
|
|
ast.receiver.visitExpression(this, ctx);
|
|
ctx.print(ast, ".");
|
|
ctx.print(ast, ast.name);
|
|
return null;
|
|
};
|
|
AbstractEmitterVisitor.prototype.visitReadKeyExpr = function (ast, ctx) {
|
|
ast.receiver.visitExpression(this, ctx);
|
|
ctx.print(ast, "[");
|
|
ast.index.visitExpression(this, ctx);
|
|
ctx.print(ast, "]");
|
|
return null;
|
|
};
|
|
AbstractEmitterVisitor.prototype.visitLiteralArrayExpr = function (ast, ctx) {
|
|
ctx.print(ast, "[");
|
|
this.visitAllExpressions(ast.entries, ctx, ',');
|
|
ctx.print(ast, "]");
|
|
return null;
|
|
};
|
|
AbstractEmitterVisitor.prototype.visitLiteralMapExpr = function (ast, ctx) {
|
|
var _this = this;
|
|
ctx.print(ast, "{");
|
|
this.visitAllObjects(function (entry) {
|
|
ctx.print(ast, escapeIdentifier(entry.key, _this._escapeDollarInStrings, entry.quoted) + ":");
|
|
entry.value.visitExpression(_this, ctx);
|
|
}, ast.entries, ctx, ',');
|
|
ctx.print(ast, "}");
|
|
return null;
|
|
};
|
|
AbstractEmitterVisitor.prototype.visitCommaExpr = function (ast, ctx) {
|
|
ctx.print(ast, '(');
|
|
this.visitAllExpressions(ast.parts, ctx, ',');
|
|
ctx.print(ast, ')');
|
|
return null;
|
|
};
|
|
AbstractEmitterVisitor.prototype.visitAllExpressions = function (expressions, ctx, separator) {
|
|
var _this = this;
|
|
this.visitAllObjects(function (expr) { return expr.visitExpression(_this, ctx); }, expressions, ctx, separator);
|
|
};
|
|
AbstractEmitterVisitor.prototype.visitAllObjects = function (handler, expressions, ctx, separator) {
|
|
var incrementedIndent = false;
|
|
for (var 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();
|
|
}
|
|
};
|
|
AbstractEmitterVisitor.prototype.visitAllStatements = function (statements, ctx) {
|
|
var _this = this;
|
|
statements.forEach(function (stmt) { return stmt.visitStatement(_this, ctx); });
|
|
};
|
|
return AbstractEmitterVisitor;
|
|
}());
|
|
function escapeIdentifier(input, escapeDollar, alwaysQuote) {
|
|
if (alwaysQuote === void 0) { alwaysQuote = true; }
|
|
if (input == null) {
|
|
return null;
|
|
}
|
|
var body = input.replace(_SINGLE_QUOTE_ESCAPE_STRING_RE, function () {
|
|
var match = [];
|
|
for (var _i = 0; _i < arguments.length; _i++) {
|
|
match[_i] = arguments[_i];
|
|
}
|
|
if (match[0] == '$') {
|
|
return escapeDollar ? '\\$' : '$';
|
|
}
|
|
else if (match[0] == '\n') {
|
|
return '\\n';
|
|
}
|
|
else if (match[0] == '\r') {
|
|
return '\\r';
|
|
}
|
|
else {
|
|
return "\\" + match[0];
|
|
}
|
|
});
|
|
var requiresQuotes = alwaysQuote || !_LEGAL_IDENTIFIER_RE.test(body);
|
|
return requiresQuotes ? "'" + body + "'" : body;
|
|
}
|
|
function _createIndent(count) {
|
|
var res = '';
|
|
for (var 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);
|
|
}
|
|
var params = [];
|
|
for (var i = 0; i < numParams; i++) {
|
|
params.push(DYNAMIC_TYPE);
|
|
}
|
|
return expressionType(type, undefined, params);
|
|
}
|
|
var 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) {
|
|
var 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) {
|
|
var guardExpr = new ExternalExpr({ name: guard, moduleName: null });
|
|
var guardNotDefined = new BinaryOperatorExpr(exports.BinaryOperator.Identical, new TypeofExpr(guardExpr), literal('undefined'));
|
|
var guardUndefinedOrTrue = new BinaryOperatorExpr(exports.BinaryOperator.Or, guardNotDefined, guardExpr, /* type */ undefined,
|
|
/* sourceSpan */ undefined, true);
|
|
return new BinaryOperatorExpr(exports.BinaryOperator.And, guardUndefinedOrTrue, expr);
|
|
}
|
|
function wrapReference(value) {
|
|
var wrapped = new WrappedNodeExpr(value);
|
|
return { value: wrapped, type: wrapped };
|
|
}
|
|
function refsToArray(refs, shouldForwardDeclare) {
|
|
var values = literalArr(refs.map(function (ref) { return ref.value; }));
|
|
return shouldForwardDeclare ? fn([], [new ReturnStatement(values)]) : values;
|
|
}
|
|
function createMayBeForwardRefExpression(expression, forwardRef) {
|
|
return { expression: expression, forwardRef: 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(_a) {
|
|
var expression = _a.expression, forwardRef = _a.forwardRef;
|
|
switch (forwardRef) {
|
|
case 0 /* None */:
|
|
case 1 /* Wrapped */:
|
|
return expression;
|
|
case 2 /* Unwrapped */:
|
|
return generateForwardRef(expression);
|
|
}
|
|
}
|
|
/**
|
|
* Generate an expression that has the given `expr` wrapped in the following form:
|
|
*
|
|
* ```
|
|
* forwardRef(() => expr)
|
|
* ```
|
|
*/
|
|
function generateForwardRef(expr) {
|
|
return importExpr(Identifiers.forwardRef).callFn([fn([], [new ReturnStatement(expr)])]);
|
|
}
|
|
|
|
var R3FactoryDelegateType;
|
|
(function (R3FactoryDelegateType) {
|
|
R3FactoryDelegateType[R3FactoryDelegateType["Class"] = 0] = "Class";
|
|
R3FactoryDelegateType[R3FactoryDelegateType["Function"] = 1] = "Function";
|
|
})(R3FactoryDelegateType || (R3FactoryDelegateType = {}));
|
|
(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";
|
|
})(exports.FactoryTarget || (exports.FactoryTarget = {}));
|
|
/**
|
|
* Construct a factory function expression for the given `R3FactoryMetadata`.
|
|
*/
|
|
function compileFactoryFunction(meta) {
|
|
var t = variable('t');
|
|
var 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).
|
|
var typeForCtor = !isDelegatedFactoryMetadata(meta) ?
|
|
new BinaryOperatorExpr(exports.BinaryOperator.Or, t, meta.internalType) :
|
|
t;
|
|
var 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("\u0275" + meta.name + "_BaseFactory");
|
|
ctorExpr = baseFactoryVar.callFn([typeForCtor]);
|
|
}
|
|
var body = [];
|
|
var retExpr = null;
|
|
function makeConditionalFactory(nonCtorExpr) {
|
|
var r = variable('r');
|
|
body.push(r.set(NULL_EXPR).toDeclStmt());
|
|
var 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.
|
|
var delegateArgs = injectDependencies(meta.delegateDeps, meta.target);
|
|
// Either call `new delegate(...)` or `delegate(...)` depending on meta.delegateType.
|
|
var 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.
|
|
var getInheritedFactoryCall = importExpr(Identifiers.getInheritedFactory).callFn([meta.internalType]);
|
|
// Memoize the base factoryFn: `baseFactory || (baseFactory = ɵɵgetInheritedFactory(...))`
|
|
var baseFactory = new BinaryOperatorExpr(exports.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));
|
|
}
|
|
var 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) {
|
|
var 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(function (dep, index) { return compileInjectDependency(dep, target, index); });
|
|
}
|
|
function compileInjectDependency(dep, target, index) {
|
|
// Interpret the dependency according to its resolved type.
|
|
if (dep.token === null) {
|
|
return importExpr(Identifiers.invalidFactoryDep).callFn([literal(index)]);
|
|
}
|
|
else if (dep.attributeNameType === null) {
|
|
// Build up the injection flags according to the metadata.
|
|
var flags = 0 /* Default */ | (dep.self ? 2 /* Self */ : 0) |
|
|
(dep.skipSelf ? 4 /* SkipSelf */ : 0) | (dep.host ? 1 /* Host */ : 0) |
|
|
(dep.optional ? 8 /* Optional */ : 0) |
|
|
(target === exports.FactoryTarget.Pipe ? 16 /* ForPipe */ : 0);
|
|
// If this dependency is optional or otherwise has non-default flags, then additional
|
|
// parameters describing how to inject the dependency must be passed to the inject function
|
|
// that's being used.
|
|
var flagsParam = (flags !== 0 /* Default */ || dep.optional) ? literal(flags) : null;
|
|
// Build up the arguments to the injectFn call.
|
|
var injectArgs = [dep.token];
|
|
if (flagsParam) {
|
|
injectArgs.push(flagsParam);
|
|
}
|
|
var 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) {
|
|
var hasTypes = false;
|
|
var attributeTypes = deps.map(function (dep) {
|
|
var type = createCtorDepType(dep);
|
|
if (type !== null) {
|
|
hasTypes = true;
|
|
return type;
|
|
}
|
|
else {
|
|
return literal(null);
|
|
}
|
|
});
|
|
if (hasTypes) {
|
|
return expressionType(literalArr(attributeTypes));
|
|
}
|
|
else {
|
|
return NONE_TYPE;
|
|
}
|
|
}
|
|
function createCtorDepType(dep) {
|
|
var entries = [];
|
|
if (dep.attributeNameType !== null) {
|
|
entries.push({ key: 'attribute', value: dep.attributeNameType, quoted: false });
|
|
}
|
|
if (dep.optional) {
|
|
entries.push({ key: 'optional', value: literal(true), quoted: false });
|
|
}
|
|
if (dep.host) {
|
|
entries.push({ key: 'host', value: literal(true), quoted: false });
|
|
}
|
|
if (dep.self) {
|
|
entries.push({ key: 'self', value: literal(true), quoted: false });
|
|
}
|
|
if (dep.skipSelf) {
|
|
entries.push({ key: 'skipSelf', value: literal(true), quoted: false });
|
|
}
|
|
return entries.length > 0 ? literalMap(entries) : null;
|
|
}
|
|
function isDelegatedFactoryMetadata(meta) {
|
|
return meta.delegateType !== undefined;
|
|
}
|
|
function isExpressionFactoryMetadata(meta) {
|
|
return meta.expression !== undefined;
|
|
}
|
|
function getInjectFn(target) {
|
|
switch (target) {
|
|
case exports.FactoryTarget.Component:
|
|
case exports.FactoryTarget.Directive:
|
|
case exports.FactoryTarget.Pipe:
|
|
return Identifiers.directiveInject;
|
|
case exports.FactoryTarget.NgModule:
|
|
case exports.FactoryTarget.Injectable:
|
|
default:
|
|
return Identifiers.inject;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @license
|
|
* Copyright Google LLC All Rights Reserved.
|
|
*
|
|
* Use of this source code is governed by an MIT-style license that can be
|
|
* found in the LICENSE file at https://angular.io/license
|
|
*/
|
|
/**
|
|
* This is an R3 `Node`-like wrapper for a raw `html.Comment` node. We do not currently
|
|
* require the implementation of a visitor for Comments as they are only collected at
|
|
* the top-level of the R3 AST, and only if `Render3ParseOptions['collectCommentNodes']`
|
|
* is true.
|
|
*/
|
|
var Comment = /** @class */ (function () {
|
|
function Comment(value, sourceSpan) {
|
|
this.value = value;
|
|
this.sourceSpan = sourceSpan;
|
|
}
|
|
Comment.prototype.visit = function (_visitor) {
|
|
throw new Error('visit() not implemented for Comment');
|
|
};
|
|
return Comment;
|
|
}());
|
|
var Text = /** @class */ (function () {
|
|
function Text(value, sourceSpan) {
|
|
this.value = value;
|
|
this.sourceSpan = sourceSpan;
|
|
}
|
|
Text.prototype.visit = function (visitor) {
|
|
return visitor.visitText(this);
|
|
};
|
|
return Text;
|
|
}());
|
|
var BoundText = /** @class */ (function () {
|
|
function BoundText(value, sourceSpan, i18n) {
|
|
this.value = value;
|
|
this.sourceSpan = sourceSpan;
|
|
this.i18n = i18n;
|
|
}
|
|
BoundText.prototype.visit = function (visitor) {
|
|
return visitor.visitBoundText(this);
|
|
};
|
|
return BoundText;
|
|
}());
|
|
/**
|
|
* Represents a text attribute in the template.
|
|
*
|
|
* `valueSpan` may not be present in cases where there is no value `<div a></div>`.
|
|
* `keySpan` may also not be present for synthetic attributes from ICU expansions.
|
|
*/
|
|
var TextAttribute = /** @class */ (function () {
|
|
function TextAttribute(name, value, sourceSpan, keySpan, valueSpan, i18n) {
|
|
this.name = name;
|
|
this.value = value;
|
|
this.sourceSpan = sourceSpan;
|
|
this.keySpan = keySpan;
|
|
this.valueSpan = valueSpan;
|
|
this.i18n = i18n;
|
|
}
|
|
TextAttribute.prototype.visit = function (visitor) {
|
|
return visitor.visitTextAttribute(this);
|
|
};
|
|
return TextAttribute;
|
|
}());
|
|
var BoundAttribute = /** @class */ (function () {
|
|
function BoundAttribute(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;
|
|
}
|
|
BoundAttribute.fromBoundElementProperty = function (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);
|
|
};
|
|
BoundAttribute.prototype.visit = function (visitor) {
|
|
return visitor.visitBoundAttribute(this);
|
|
};
|
|
return BoundAttribute;
|
|
}());
|
|
var BoundEvent = /** @class */ (function () {
|
|
function BoundEvent(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;
|
|
}
|
|
BoundEvent.fromParsedEvent = function (event) {
|
|
var target = event.type === 0 /* Regular */ ? event.targetOrPhase : null;
|
|
var phase = event.type === 1 /* Animation */ ? event.targetOrPhase : null;
|
|
if (event.keySpan === undefined) {
|
|
throw new Error("Unexpected state: keySpan must be defined for bound event but was not for " + event.name + ": " + event.sourceSpan);
|
|
}
|
|
return new BoundEvent(event.name, event.type, event.handler, target, phase, event.sourceSpan, event.handlerSpan, event.keySpan);
|
|
};
|
|
BoundEvent.prototype.visit = function (visitor) {
|
|
return visitor.visitBoundEvent(this);
|
|
};
|
|
return BoundEvent;
|
|
}());
|
|
var Element = /** @class */ (function () {
|
|
function Element(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;
|
|
}
|
|
Element.prototype.visit = function (visitor) {
|
|
return visitor.visitElement(this);
|
|
};
|
|
return Element;
|
|
}());
|
|
var Template = /** @class */ (function () {
|
|
function Template(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;
|
|
}
|
|
Template.prototype.visit = function (visitor) {
|
|
return visitor.visitTemplate(this);
|
|
};
|
|
return Template;
|
|
}());
|
|
var Content = /** @class */ (function () {
|
|
function Content(selector, attributes, sourceSpan, i18n) {
|
|
this.selector = selector;
|
|
this.attributes = attributes;
|
|
this.sourceSpan = sourceSpan;
|
|
this.i18n = i18n;
|
|
this.name = 'ng-content';
|
|
}
|
|
Content.prototype.visit = function (visitor) {
|
|
return visitor.visitContent(this);
|
|
};
|
|
return Content;
|
|
}());
|
|
var Variable = /** @class */ (function () {
|
|
function Variable(name, value, sourceSpan, keySpan, valueSpan) {
|
|
this.name = name;
|
|
this.value = value;
|
|
this.sourceSpan = sourceSpan;
|
|
this.keySpan = keySpan;
|
|
this.valueSpan = valueSpan;
|
|
}
|
|
Variable.prototype.visit = function (visitor) {
|
|
return visitor.visitVariable(this);
|
|
};
|
|
return Variable;
|
|
}());
|
|
var Reference = /** @class */ (function () {
|
|
function Reference(name, value, sourceSpan, keySpan, valueSpan) {
|
|
this.name = name;
|
|
this.value = value;
|
|
this.sourceSpan = sourceSpan;
|
|
this.keySpan = keySpan;
|
|
this.valueSpan = valueSpan;
|
|
}
|
|
Reference.prototype.visit = function (visitor) {
|
|
return visitor.visitReference(this);
|
|
};
|
|
return Reference;
|
|
}());
|
|
var Icu = /** @class */ (function () {
|
|
function Icu(vars, placeholders, sourceSpan, i18n) {
|
|
this.vars = vars;
|
|
this.placeholders = placeholders;
|
|
this.sourceSpan = sourceSpan;
|
|
this.i18n = i18n;
|
|
}
|
|
Icu.prototype.visit = function (visitor) {
|
|
return visitor.visitIcu(this);
|
|
};
|
|
return Icu;
|
|
}());
|
|
var NullVisitor = /** @class */ (function () {
|
|
function NullVisitor() {
|
|
}
|
|
NullVisitor.prototype.visitElement = function (element) { };
|
|
NullVisitor.prototype.visitTemplate = function (template) { };
|
|
NullVisitor.prototype.visitContent = function (content) { };
|
|
NullVisitor.prototype.visitVariable = function (variable) { };
|
|
NullVisitor.prototype.visitReference = function (reference) { };
|
|
NullVisitor.prototype.visitTextAttribute = function (attribute) { };
|
|
NullVisitor.prototype.visitBoundAttribute = function (attribute) { };
|
|
NullVisitor.prototype.visitBoundEvent = function (attribute) { };
|
|
NullVisitor.prototype.visitText = function (text) { };
|
|
NullVisitor.prototype.visitBoundText = function (text) { };
|
|
NullVisitor.prototype.visitIcu = function (icu) { };
|
|
return NullVisitor;
|
|
}());
|
|
var RecursiveVisitor = /** @class */ (function () {
|
|
function RecursiveVisitor() {
|
|
}
|
|
RecursiveVisitor.prototype.visitElement = function (element) {
|
|
visitAll(this, element.attributes);
|
|
visitAll(this, element.inputs);
|
|
visitAll(this, element.outputs);
|
|
visitAll(this, element.children);
|
|
visitAll(this, element.references);
|
|
};
|
|
RecursiveVisitor.prototype.visitTemplate = function (template) {
|
|
visitAll(this, template.attributes);
|
|
visitAll(this, template.inputs);
|
|
visitAll(this, template.outputs);
|
|
visitAll(this, template.children);
|
|
visitAll(this, template.references);
|
|
visitAll(this, template.variables);
|
|
};
|
|
RecursiveVisitor.prototype.visitContent = function (content) { };
|
|
RecursiveVisitor.prototype.visitVariable = function (variable) { };
|
|
RecursiveVisitor.prototype.visitReference = function (reference) { };
|
|
RecursiveVisitor.prototype.visitTextAttribute = function (attribute) { };
|
|
RecursiveVisitor.prototype.visitBoundAttribute = function (attribute) { };
|
|
RecursiveVisitor.prototype.visitBoundEvent = function (attribute) { };
|
|
RecursiveVisitor.prototype.visitText = function (text) { };
|
|
RecursiveVisitor.prototype.visitBoundText = function (text) { };
|
|
RecursiveVisitor.prototype.visitIcu = function (icu) { };
|
|
return RecursiveVisitor;
|
|
}());
|
|
var TransformVisitor = /** @class */ (function () {
|
|
function TransformVisitor() {
|
|
}
|
|
TransformVisitor.prototype.visitElement = function (element) {
|
|
var newAttributes = transformAll(this, element.attributes);
|
|
var newInputs = transformAll(this, element.inputs);
|
|
var newOutputs = transformAll(this, element.outputs);
|
|
var newChildren = transformAll(this, element.children);
|
|
var newReferences = transformAll(this, element.references);
|
|
if (newAttributes != element.attributes || newInputs != element.inputs ||
|
|
newOutputs != element.outputs || newChildren != element.children ||
|
|
newReferences != element.references) {
|
|
return new Element(element.name, newAttributes, newInputs, newOutputs, newChildren, newReferences, element.sourceSpan, element.startSourceSpan, element.endSourceSpan);
|
|
}
|
|
return element;
|
|
};
|
|
TransformVisitor.prototype.visitTemplate = function (template) {
|
|
var newAttributes = transformAll(this, template.attributes);
|
|
var newInputs = transformAll(this, template.inputs);
|
|
var newOutputs = transformAll(this, template.outputs);
|
|
var newTemplateAttrs = transformAll(this, template.templateAttrs);
|
|
var newChildren = transformAll(this, template.children);
|
|
var newReferences = transformAll(this, template.references);
|
|
var newVariables = transformAll(this, template.variables);
|
|
if (newAttributes != template.attributes || newInputs != template.inputs ||
|
|
newOutputs != template.outputs || newTemplateAttrs != template.templateAttrs ||
|
|
newChildren != template.children || newReferences != template.references ||
|
|
newVariables != template.variables) {
|
|
return new Template(template.tagName, newAttributes, newInputs, newOutputs, newTemplateAttrs, newChildren, newReferences, newVariables, template.sourceSpan, template.startSourceSpan, template.endSourceSpan);
|
|
}
|
|
return template;
|
|
};
|
|
TransformVisitor.prototype.visitContent = function (content) {
|
|
return content;
|
|
};
|
|
TransformVisitor.prototype.visitVariable = function (variable) {
|
|
return variable;
|
|
};
|
|
TransformVisitor.prototype.visitReference = function (reference) {
|
|
return reference;
|
|
};
|
|
TransformVisitor.prototype.visitTextAttribute = function (attribute) {
|
|
return attribute;
|
|
};
|
|
TransformVisitor.prototype.visitBoundAttribute = function (attribute) {
|
|
return attribute;
|
|
};
|
|
TransformVisitor.prototype.visitBoundEvent = function (attribute) {
|
|
return attribute;
|
|
};
|
|
TransformVisitor.prototype.visitText = function (text) {
|
|
return text;
|
|
};
|
|
TransformVisitor.prototype.visitBoundText = function (text) {
|
|
return text;
|
|
};
|
|
TransformVisitor.prototype.visitIcu = function (icu) {
|
|
return icu;
|
|
};
|
|
return TransformVisitor;
|
|
}());
|
|
function visitAll(visitor, nodes) {
|
|
var e_1, _a, e_2, _b;
|
|
var result = [];
|
|
if (visitor.visit) {
|
|
try {
|
|
for (var nodes_1 = __values(nodes), nodes_1_1 = nodes_1.next(); !nodes_1_1.done; nodes_1_1 = nodes_1.next()) {
|
|
var node = nodes_1_1.value;
|
|
var newNode = visitor.visit(node) || node.visit(visitor);
|
|
}
|
|
}
|
|
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
finally {
|
|
try {
|
|
if (nodes_1_1 && !nodes_1_1.done && (_a = nodes_1.return)) _a.call(nodes_1);
|
|
}
|
|
finally { if (e_1) throw e_1.error; }
|
|
}
|
|
}
|
|
else {
|
|
try {
|
|
for (var nodes_2 = __values(nodes), nodes_2_1 = nodes_2.next(); !nodes_2_1.done; nodes_2_1 = nodes_2.next()) {
|
|
var node = nodes_2_1.value;
|
|
var newNode = node.visit(visitor);
|
|
if (newNode) {
|
|
result.push(newNode);
|
|
}
|
|
}
|
|
}
|
|
catch (e_2_1) { e_2 = { error: e_2_1 }; }
|
|
finally {
|
|
try {
|
|
if (nodes_2_1 && !nodes_2_1.done && (_b = nodes_2.return)) _b.call(nodes_2);
|
|
}
|
|
finally { if (e_2) throw e_2.error; }
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
function transformAll(visitor, nodes) {
|
|
var e_3, _a;
|
|
var result = [];
|
|
var changed = false;
|
|
try {
|
|
for (var nodes_3 = __values(nodes), nodes_3_1 = nodes_3.next(); !nodes_3_1.done; nodes_3_1 = nodes_3.next()) {
|
|
var node = nodes_3_1.value;
|
|
var newNode = node.visit(visitor);
|
|
if (newNode) {
|
|
result.push(newNode);
|
|
}
|
|
changed = changed || newNode != node;
|
|
}
|
|
}
|
|
catch (e_3_1) { e_3 = { error: e_3_1 }; }
|
|
finally {
|
|
try {
|
|
if (nodes_3_1 && !nodes_3_1.done && (_a = nodes_3.return)) _a.call(nodes_3);
|
|
}
|
|
finally { if (e_3) throw e_3.error; }
|
|
}
|
|
return changed ? result : nodes;
|
|
}
|
|
|
|
/**
|
|
* @license
|
|
* Copyright Google LLC All Rights Reserved.
|
|
*
|
|
* Use of this source code is governed by an MIT-style license that can be
|
|
* found in the LICENSE file at https://angular.io/license
|
|
*/
|
|
var Message = /** @class */ (function () {
|
|
/**
|
|
* @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
|
|
*/
|
|
function Message(nodes, placeholders, placeholderToMessage, meaning, description, customId) {
|
|
this.nodes = nodes;
|
|
this.placeholders = placeholders;
|
|
this.placeholderToMessage = placeholderToMessage;
|
|
this.meaning = meaning;
|
|
this.description = description;
|
|
this.customId = customId;
|
|
this.id = this.customId;
|
|
/** The ids to use if there are no custom id and if `i18nLegacyMessageIdFormat` is not empty */
|
|
this.legacyIds = [];
|
|
if (nodes.length) {
|
|
this.sources = [{
|
|
filePath: nodes[0].sourceSpan.start.file.url,
|
|
startLine: nodes[0].sourceSpan.start.line + 1,
|
|
startCol: nodes[0].sourceSpan.start.col + 1,
|
|
endLine: nodes[nodes.length - 1].sourceSpan.end.line + 1,
|
|
endCol: nodes[0].sourceSpan.start.col + 1
|
|
}];
|
|
}
|
|
else {
|
|
this.sources = [];
|
|
}
|
|
}
|
|
return Message;
|
|
}());
|
|
var Text$1 = /** @class */ (function () {
|
|
function Text(value, sourceSpan) {
|
|
this.value = value;
|
|
this.sourceSpan = sourceSpan;
|
|
}
|
|
Text.prototype.visit = function (visitor, context) {
|
|
return visitor.visitText(this, context);
|
|
};
|
|
return Text;
|
|
}());
|
|
// TODO(vicb): do we really need this node (vs an array) ?
|
|
var Container = /** @class */ (function () {
|
|
function Container(children, sourceSpan) {
|
|
this.children = children;
|
|
this.sourceSpan = sourceSpan;
|
|
}
|
|
Container.prototype.visit = function (visitor, context) {
|
|
return visitor.visitContainer(this, context);
|
|
};
|
|
return Container;
|
|
}());
|
|
var Icu$1 = /** @class */ (function () {
|
|
function Icu(expression, type, cases, sourceSpan) {
|
|
this.expression = expression;
|
|
this.type = type;
|
|
this.cases = cases;
|
|
this.sourceSpan = sourceSpan;
|
|
}
|
|
Icu.prototype.visit = function (visitor, context) {
|
|
return visitor.visitIcu(this, context);
|
|
};
|
|
return Icu;
|
|
}());
|
|
var TagPlaceholder = /** @class */ (function () {
|
|
function TagPlaceholder(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;
|
|
}
|
|
TagPlaceholder.prototype.visit = function (visitor, context) {
|
|
return visitor.visitTagPlaceholder(this, context);
|
|
};
|
|
return TagPlaceholder;
|
|
}());
|
|
var Placeholder = /** @class */ (function () {
|
|
function Placeholder(value, name, sourceSpan) {
|
|
this.value = value;
|
|
this.name = name;
|
|
this.sourceSpan = sourceSpan;
|
|
}
|
|
Placeholder.prototype.visit = function (visitor, context) {
|
|
return visitor.visitPlaceholder(this, context);
|
|
};
|
|
return Placeholder;
|
|
}());
|
|
var IcuPlaceholder = /** @class */ (function () {
|
|
function IcuPlaceholder(value, name, sourceSpan) {
|
|
this.value = value;
|
|
this.name = name;
|
|
this.sourceSpan = sourceSpan;
|
|
}
|
|
IcuPlaceholder.prototype.visit = function (visitor, context) {
|
|
return visitor.visitIcuPlaceholder(this, context);
|
|
};
|
|
return IcuPlaceholder;
|
|
}());
|
|
// Clone the AST
|
|
var CloneVisitor = /** @class */ (function () {
|
|
function CloneVisitor() {
|
|
}
|
|
CloneVisitor.prototype.visitText = function (text, context) {
|
|
return new Text$1(text.value, text.sourceSpan);
|
|
};
|
|
CloneVisitor.prototype.visitContainer = function (container, context) {
|
|
var _this = this;
|
|
var children = container.children.map(function (n) { return n.visit(_this, context); });
|
|
return new Container(children, container.sourceSpan);
|
|
};
|
|
CloneVisitor.prototype.visitIcu = function (icu, context) {
|
|
var _this = this;
|
|
var cases = {};
|
|
Object.keys(icu.cases).forEach(function (key) { return cases[key] = icu.cases[key].visit(_this, context); });
|
|
var msg = new Icu$1(icu.expression, icu.type, cases, icu.sourceSpan);
|
|
msg.expressionPlaceholder = icu.expressionPlaceholder;
|
|
return msg;
|
|
};
|
|
CloneVisitor.prototype.visitTagPlaceholder = function (ph, context) {
|
|
var _this = this;
|
|
var children = ph.children.map(function (n) { return n.visit(_this, context); });
|
|
return new TagPlaceholder(ph.tag, ph.attrs, ph.startName, ph.closeName, children, ph.isVoid, ph.sourceSpan, ph.startSourceSpan, ph.endSourceSpan);
|
|
};
|
|
CloneVisitor.prototype.visitPlaceholder = function (ph, context) {
|
|
return new Placeholder(ph.value, ph.name, ph.sourceSpan);
|
|
};
|
|
CloneVisitor.prototype.visitIcuPlaceholder = function (ph, context) {
|
|
return new IcuPlaceholder(ph.value, ph.name, ph.sourceSpan);
|
|
};
|
|
return CloneVisitor;
|
|
}());
|
|
// Visit all the nodes recursively
|
|
var RecurseVisitor = /** @class */ (function () {
|
|
function RecurseVisitor() {
|
|
}
|
|
RecurseVisitor.prototype.visitText = function (text, context) { };
|
|
RecurseVisitor.prototype.visitContainer = function (container, context) {
|
|
var _this = this;
|
|
container.children.forEach(function (child) { return child.visit(_this); });
|
|
};
|
|
RecurseVisitor.prototype.visitIcu = function (icu, context) {
|
|
var _this = this;
|
|
Object.keys(icu.cases).forEach(function (k) {
|
|
icu.cases[k].visit(_this);
|
|
});
|
|
};
|
|
RecurseVisitor.prototype.visitTagPlaceholder = function (ph, context) {
|
|
var _this = this;
|
|
ph.children.forEach(function (child) { return child.visit(_this); });
|
|
};
|
|
RecurseVisitor.prototype.visitPlaceholder = function (ph, context) { };
|
|
RecurseVisitor.prototype.visitIcuPlaceholder = function (ph, context) { };
|
|
return RecurseVisitor;
|
|
}());
|
|
|
|
/**
|
|
* @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.
|
|
*/
|
|
var BigInteger = /** @class */ (function () {
|
|
/**
|
|
* Creates a big integer using its individual digits in little endian storage.
|
|
*/
|
|
function BigInteger(digits) {
|
|
this.digits = digits;
|
|
}
|
|
BigInteger.zero = function () {
|
|
return new BigInteger([0]);
|
|
};
|
|
BigInteger.one = function () {
|
|
return new BigInteger([1]);
|
|
};
|
|
/**
|
|
* Creates a clone of this instance.
|
|
*/
|
|
BigInteger.prototype.clone = function () {
|
|
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`.
|
|
*/
|
|
BigInteger.prototype.add = function (other) {
|
|
var result = this.clone();
|
|
result.addToSelf(other);
|
|
return result;
|
|
};
|
|
/**
|
|
* Adds `other` to the instance itself, thereby mutating its value.
|
|
*/
|
|
BigInteger.prototype.addToSelf = function (other) {
|
|
var maxNrOfDigits = Math.max(this.digits.length, other.digits.length);
|
|
var carry = 0;
|
|
for (var i = 0; i < maxNrOfDigits; i++) {
|
|
var 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.
|
|
*/
|
|
BigInteger.prototype.toString = function () {
|
|
var res = '';
|
|
for (var i = this.digits.length - 1; i >= 0; i--) {
|
|
res += this.digits[i];
|
|
}
|
|
return res;
|
|
};
|
|
return BigInteger;
|
|
}());
|
|
/**
|
|
* 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.
|
|
*/
|
|
var BigIntForMultiplication = /** @class */ (function () {
|
|
function BigIntForMultiplication(value) {
|
|
this.powerOfTwos = [value];
|
|
}
|
|
/**
|
|
* Returns the big integer itself.
|
|
*/
|
|
BigIntForMultiplication.prototype.getValue = function () {
|
|
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.
|
|
*/
|
|
BigIntForMultiplication.prototype.multiplyBy = function (num) {
|
|
var 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.
|
|
*/
|
|
BigIntForMultiplication.prototype.multiplyByAndAddTo = function (num, result) {
|
|
for (var exponent = 0; num !== 0; num = num >>> 1, exponent++) {
|
|
if (num & 1) {
|
|
var value = this.getMultipliedByPowerOfTwo(exponent);
|
|
result.addToSelf(value);
|
|
}
|
|
}
|
|
};
|
|
/**
|
|
* Computes and memoizes the big integer value for `this.number * 2^exponent`.
|
|
*/
|
|
BigIntForMultiplication.prototype.getMultipliedByPowerOfTwo = function (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 (var i = this.powerOfTwos.length; i <= exponent; i++) {
|
|
var previousPower = this.powerOfTwos[i - 1];
|
|
this.powerOfTwos[i] = previousPower.add(previousPower);
|
|
}
|
|
return this.powerOfTwos[exponent];
|
|
};
|
|
return BigIntForMultiplication;
|
|
}());
|
|
/**
|
|
* 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.
|
|
*/
|
|
var BigIntExponentiation = /** @class */ (function () {
|
|
function BigIntExponentiation(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.
|
|
*/
|
|
BigIntExponentiation.prototype.toThePowerOf = function (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 (var i = this.exponents.length; i <= exponent; i++) {
|
|
var value = this.exponents[i - 1].multiplyBy(this.base);
|
|
this.exponents[i] = new BigIntForMultiplication(value);
|
|
}
|
|
return this.exponents[exponent];
|
|
};
|
|
return BigIntExponentiation;
|
|
}());
|
|
|
|
/**
|
|
* Return the message id or compute it using the XLIFF1 digest.
|
|
*/
|
|
function digest(message) {
|
|
return message.id || computeDigest(message);
|
|
}
|
|
/**
|
|
* Compute the message id using the XLIFF1 digest.
|
|
*/
|
|
function computeDigest(message) {
|
|
return sha1(serializeNodes(message.nodes).join('') + ("[" + message.meaning + "]"));
|
|
}
|
|
/**
|
|
* Return the message id or compute it using the XLIFF2/XMB/$localize digest.
|
|
*/
|
|
function decimalDigest(message) {
|
|
return message.id || computeDecimalDigest(message);
|
|
}
|
|
/**
|
|
* Compute the message id using the XLIFF2/XMB/$localize digest.
|
|
*/
|
|
function computeDecimalDigest(message) {
|
|
var visitor = new _SerializerIgnoreIcuExpVisitor();
|
|
var parts = message.nodes.map(function (a) { return 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
|
|
*/
|
|
var _SerializerVisitor = /** @class */ (function () {
|
|
function _SerializerVisitor() {
|
|
}
|
|
_SerializerVisitor.prototype.visitText = function (text, context) {
|
|
return text.value;
|
|
};
|
|
_SerializerVisitor.prototype.visitContainer = function (container, context) {
|
|
var _this = this;
|
|
return "[" + container.children.map(function (child) { return child.visit(_this); }).join(', ') + "]";
|
|
};
|
|
_SerializerVisitor.prototype.visitIcu = function (icu, context) {
|
|
var _this = this;
|
|
var strCases = Object.keys(icu.cases).map(function (k) { return k + " {" + icu.cases[k].visit(_this) + "}"; });
|
|
return "{" + icu.expression + ", " + icu.type + ", " + strCases.join(', ') + "}";
|
|
};
|
|
_SerializerVisitor.prototype.visitTagPlaceholder = function (ph, context) {
|
|
var _this = this;
|
|
return ph.isVoid ?
|
|
"<ph tag name=\"" + ph.startName + "\"/>" :
|
|
"<ph tag name=\"" + ph.startName + "\">" + ph.children.map(function (child) { return child.visit(_this); }).join(', ') + "</ph name=\"" + ph.closeName + "\">";
|
|
};
|
|
_SerializerVisitor.prototype.visitPlaceholder = function (ph, context) {
|
|
return ph.value ? "<ph name=\"" + ph.name + "\">" + ph.value + "</ph>" : "<ph name=\"" + ph.name + "\"/>";
|
|
};
|
|
_SerializerVisitor.prototype.visitIcuPlaceholder = function (ph, context) {
|
|
return "<ph icu name=\"" + ph.name + "\">" + ph.value.visit(this) + "</ph>";
|
|
};
|
|
return _SerializerVisitor;
|
|
}());
|
|
var serializerVisitor = new _SerializerVisitor();
|
|
function serializeNodes(nodes) {
|
|
return nodes.map(function (a) { return a.visit(serializerVisitor, null); });
|
|
}
|
|
/**
|
|
* Serialize the i18n ast to something xml-like in order to generate an UID.
|
|
*
|
|
* Ignore the ICU expressions so that message IDs stays identical if only the expression changes.
|
|
*
|
|
* @internal
|
|
*/
|
|
var _SerializerIgnoreIcuExpVisitor = /** @class */ (function (_super) {
|
|
__extends(_SerializerIgnoreIcuExpVisitor, _super);
|
|
function _SerializerIgnoreIcuExpVisitor() {
|
|
return _super !== null && _super.apply(this, arguments) || this;
|
|
}
|
|
_SerializerIgnoreIcuExpVisitor.prototype.visitIcu = function (icu, context) {
|
|
var _this = this;
|
|
var strCases = Object.keys(icu.cases).map(function (k) { return k + " {" + icu.cases[k].visit(_this) + "}"; });
|
|
// Do not take the expression into account
|
|
return "{" + icu.type + ", " + strCases.join(', ') + "}";
|
|
};
|
|
return _SerializerIgnoreIcuExpVisitor;
|
|
}(_SerializerVisitor));
|
|
/**
|
|
* 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) {
|
|
var utf8 = utf8Encode(str);
|
|
var words32 = bytesToWords32(utf8, Endian.Big);
|
|
var len = utf8.length * 8;
|
|
var w = newArray(80);
|
|
var 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 (var i = 0; i < words32.length; i += 16) {
|
|
var h0 = a, h1 = b, h2 = c, h3 = d, h4 = e;
|
|
for (var 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);
|
|
}
|
|
var fkVal = fk(j, b, c, d);
|
|
var f = fkVal[0];
|
|
var k = fkVal[1];
|
|
var temp = [rol32(a, 5), f, e, k, w[j]].reduce(add32);
|
|
e = d;
|
|
d = c;
|
|
c = rol32(b, 30);
|
|
b = a;
|
|
a = temp;
|
|
}
|
|
a = add32(a, h0);
|
|
b = add32(b, h1);
|
|
c = add32(c, h2);
|
|
d = add32(d, h3);
|
|
e = add32(e, h4);
|
|
}
|
|
return bytesToHexString(words32ToByteString([a, b, c, d, e]));
|
|
}
|
|
function fk(index, b, c, d) {
|
|
if (index < 20) {
|
|
return [(b & c) | (~b & d), 0x5a827999];
|
|
}
|
|
if (index < 40) {
|
|
return [b ^ c ^ d, 0x6ed9eba1];
|
|
}
|
|
if (index < 60) {
|
|
return [(b & c) | (b & d) | (c & d), 0x8f1bbcdc];
|
|
}
|
|
return [b ^ c ^ d, 0xca62c1d6];
|
|
}
|
|
/**
|
|
* Compute the fingerprint of the given string
|
|
*
|
|
* The output is 64 bit number encoded as a decimal string
|
|
*
|
|
* based on:
|
|
* https://github.com/google/closure-compiler/blob/master/src/com/google/javascript/jscomp/GoogleJsMessageIdGenerator.java
|
|
*/
|
|
function fingerprint(str) {
|
|
var utf8 = utf8Encode(str);
|
|
var hi = hash32(utf8, 0);
|
|
var lo = hash32(utf8, 102072);
|
|
if (hi == 0 && (lo == 0 || lo == 1)) {
|
|
hi = hi ^ 0x130f9bef;
|
|
lo = lo ^ -0x6b5f56d8;
|
|
}
|
|
return [hi, lo];
|
|
}
|
|
function computeMsgId(msg, meaning) {
|
|
if (meaning === void 0) { meaning = ''; }
|
|
var msgFingerprint = fingerprint(msg);
|
|
if (meaning) {
|
|
var meaningFingerprint = fingerprint(meaning);
|
|
msgFingerprint = add64(rol64(msgFingerprint, 1), meaningFingerprint);
|
|
}
|
|
var hi = msgFingerprint[0];
|
|
var lo = msgFingerprint[1];
|
|
return wordsToDecimalString(hi & 0x7fffffff, lo);
|
|
}
|
|
function hash32(bytes, c) {
|
|
var a = 0x9e3779b9, b = 0x9e3779b9;
|
|
var i;
|
|
var len = bytes.length;
|
|
for (i = 0; i + 12 <= len; i += 12) {
|
|
a = add32(a, wordAt(bytes, i, Endian.Little));
|
|
b = add32(b, wordAt(bytes, i + 4, Endian.Little));
|
|
c = add32(c, wordAt(bytes, i + 8, Endian.Little));
|
|
var res = mix(a, b, c);
|
|
a = res[0], b = res[1], c = res[2];
|
|
}
|
|
a = add32(a, wordAt(bytes, i, Endian.Little));
|
|
b = add32(b, wordAt(bytes, i + 4, Endian.Little));
|
|
// the first byte of c is reserved for the length
|
|
c = add32(c, len);
|
|
c = add32(c, wordAt(bytes, i + 8, Endian.Little) << 8);
|
|
return mix(a, b, c)[2];
|
|
}
|
|
// clang-format off
|
|
function mix(a, b, c) {
|
|
a = sub32(a, b);
|
|
a = sub32(a, c);
|
|
a ^= c >>> 13;
|
|
b = sub32(b, c);
|
|
b = sub32(b, a);
|
|
b ^= a << 8;
|
|
c = sub32(c, a);
|
|
c = sub32(c, b);
|
|
c ^= b >>> 13;
|
|
a = sub32(a, b);
|
|
a = sub32(a, c);
|
|
a ^= c >>> 12;
|
|
b = sub32(b, c);
|
|
b = sub32(b, a);
|
|
b ^= a << 16;
|
|
c = sub32(c, a);
|
|
c = sub32(c, b);
|
|
c ^= b >>> 5;
|
|
a = sub32(a, b);
|
|
a = sub32(a, c);
|
|
a ^= c >>> 3;
|
|
b = sub32(b, c);
|
|
b = sub32(b, a);
|
|
b ^= a << 10;
|
|
c = sub32(c, a);
|
|
c = sub32(c, b);
|
|
c ^= b >>> 15;
|
|
return [a, b, c];
|
|
}
|
|
// clang-format on
|
|
// Utils
|
|
var Endian;
|
|
(function (Endian) {
|
|
Endian[Endian["Little"] = 0] = "Little";
|
|
Endian[Endian["Big"] = 1] = "Big";
|
|
})(Endian || (Endian = {}));
|
|
function add32(a, b) {
|
|
return add32to64(a, b)[1];
|
|
}
|
|
function add32to64(a, b) {
|
|
var low = (a & 0xffff) + (b & 0xffff);
|
|
var high = (a >>> 16) + (b >>> 16) + (low >>> 16);
|
|
return [high >>> 16, (high << 16) | (low & 0xffff)];
|
|
}
|
|
function add64(a, b) {
|
|
var ah = a[0], al = a[1];
|
|
var bh = b[0], bl = b[1];
|
|
var result = add32to64(al, bl);
|
|
var carry = result[0];
|
|
var l = result[1];
|
|
var h = add32(add32(ah, bh), carry);
|
|
return [h, l];
|
|
}
|
|
function sub32(a, b) {
|
|
var low = (a & 0xffff) - (b & 0xffff);
|
|
var high = (a >> 16) - (b >> 16) + (low >> 16);
|
|
return (high << 16) | (low & 0xffff);
|
|
}
|
|
// Rotate a 32b number left `count` position
|
|
function rol32(a, count) {
|
|
return (a << count) | (a >>> (32 - count));
|
|
}
|
|
// Rotate a 64b number left `count` position
|
|
function rol64(num, count) {
|
|
var hi = num[0], lo = num[1];
|
|
var h = (hi << count) | (lo >>> (32 - count));
|
|
var l = (lo << count) | (hi >>> (32 - count));
|
|
return [h, l];
|
|
}
|
|
function bytesToWords32(bytes, endian) {
|
|
var size = (bytes.length + 3) >>> 2;
|
|
var words32 = [];
|
|
for (var 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) {
|
|
var word = 0;
|
|
if (endian === Endian.Big) {
|
|
for (var i = 0; i < 4; i++) {
|
|
word += byteAt(bytes, index + i) << (24 - 8 * i);
|
|
}
|
|
}
|
|
else {
|
|
for (var i = 0; i < 4; i++) {
|
|
word += byteAt(bytes, index + i) << 8 * i;
|
|
}
|
|
}
|
|
return word;
|
|
}
|
|
function words32ToByteString(words32) {
|
|
return words32.reduce(function (bytes, word) { return bytes.concat(word32ToByteString(word)); }, []);
|
|
}
|
|
function word32ToByteString(word) {
|
|
var bytes = [];
|
|
for (var i = 0; i < 4; i++) {
|
|
bytes.push((word >>> 8 * (3 - i)) & 0xff);
|
|
}
|
|
return bytes;
|
|
}
|
|
function bytesToHexString(bytes) {
|
|
var hex = '';
|
|
for (var i = 0; i < bytes.length; i++) {
|
|
var b = byteAt(bytes, i);
|
|
hex += (b >>> 4).toString(16) + (b & 0x0f).toString(16);
|
|
}
|
|
return hex.toLowerCase();
|
|
}
|
|
/**
|
|
* Create a shared exponentiation pool for base-256 computations. This shared pool provides memoized
|
|
* power-of-256 results with memoized power-of-two computations for efficient multiplication.
|
|
*
|
|
* For our purposes, this can be safely stored as a global without memory concerns. The reason is
|
|
* that we encode two words, so only need the 0th (for the low word) and 4th (for the high word)
|
|
* exponent.
|
|
*/
|
|
var 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.
|
|
var 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();
|
|
}
|
|
|
|
var Serializer = /** @class */ (function () {
|
|
function Serializer() {
|
|
}
|
|
// Creates a name mapper, see `PlaceholderMapper`
|
|
// Returning `null` means that no name mapping is used.
|
|
Serializer.prototype.createNameMapper = function (message) {
|
|
return null;
|
|
};
|
|
return Serializer;
|
|
}());
|
|
/**
|
|
* A simple mapper that take a function to transform an internal name to a public name
|
|
*/
|
|
var SimplePlaceholderMapper = /** @class */ (function (_super) {
|
|
__extends(SimplePlaceholderMapper, _super);
|
|
// create a mapping from the message
|
|
function SimplePlaceholderMapper(message, mapName) {
|
|
var _this = _super.call(this) || this;
|
|
_this.mapName = mapName;
|
|
_this.internalToPublic = {};
|
|
_this.publicToNextId = {};
|
|
_this.publicToInternal = {};
|
|
message.nodes.forEach(function (node) { return node.visit(_this); });
|
|
return _this;
|
|
}
|
|
SimplePlaceholderMapper.prototype.toPublicName = function (internalName) {
|
|
return this.internalToPublic.hasOwnProperty(internalName) ?
|
|
this.internalToPublic[internalName] :
|
|
null;
|
|
};
|
|
SimplePlaceholderMapper.prototype.toInternalName = function (publicName) {
|
|
return this.publicToInternal.hasOwnProperty(publicName) ? this.publicToInternal[publicName] :
|
|
null;
|
|
};
|
|
SimplePlaceholderMapper.prototype.visitText = function (text, context) {
|
|
return null;
|
|
};
|
|
SimplePlaceholderMapper.prototype.visitTagPlaceholder = function (ph, context) {
|
|
this.visitPlaceholderName(ph.startName);
|
|
_super.prototype.visitTagPlaceholder.call(this, ph, context);
|
|
this.visitPlaceholderName(ph.closeName);
|
|
};
|
|
SimplePlaceholderMapper.prototype.visitPlaceholder = function (ph, context) {
|
|
this.visitPlaceholderName(ph.name);
|
|
};
|
|
SimplePlaceholderMapper.prototype.visitIcuPlaceholder = function (ph, context) {
|
|
this.visitPlaceholderName(ph.name);
|
|
};
|
|
// XMB placeholders could only contains A-Z, 0-9 and _
|
|
SimplePlaceholderMapper.prototype.visitPlaceholderName = function (internalName) {
|
|
if (!internalName || this.internalToPublic.hasOwnProperty(internalName)) {
|
|
return;
|
|
}
|
|
var publicName = this.mapName(internalName);
|
|
if (this.publicToInternal.hasOwnProperty(publicName)) {
|
|
// Create a new XMB when it has already been used
|
|
var nextId = this.publicToNextId[publicName];
|
|
this.publicToNextId[publicName] = nextId + 1;
|
|
publicName = publicName + "_" + nextId;
|
|
}
|
|
else {
|
|
this.publicToNextId[publicName] = 1;
|
|
}
|
|
this.internalToPublic[internalName] = publicName;
|
|
this.publicToInternal[publicName] = internalName;
|
|
};
|
|
return SimplePlaceholderMapper;
|
|
}(RecurseVisitor));
|
|
|
|
/**
|
|
* @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 _Visitor = /** @class */ (function () {
|
|
function _Visitor() {
|
|
}
|
|
_Visitor.prototype.visitTag = function (tag) {
|
|
var _this = this;
|
|
var strAttrs = this._serializeAttributes(tag.attrs);
|
|
if (tag.children.length == 0) {
|
|
return "<" + tag.name + strAttrs + "/>";
|
|
}
|
|
var strChildren = tag.children.map(function (node) { return node.visit(_this); });
|
|
return "<" + tag.name + strAttrs + ">" + strChildren.join('') + "</" + tag.name + ">";
|
|
};
|
|
_Visitor.prototype.visitText = function (text) {
|
|
return text.value;
|
|
};
|
|
_Visitor.prototype.visitDeclaration = function (decl) {
|
|
return "<?xml" + this._serializeAttributes(decl.attrs) + " ?>";
|
|
};
|
|
_Visitor.prototype._serializeAttributes = function (attrs) {
|
|
var strAttrs = Object.keys(attrs).map(function (name) { return name + "=\"" + attrs[name] + "\""; }).join(' ');
|
|
return strAttrs.length > 0 ? ' ' + strAttrs : '';
|
|
};
|
|
_Visitor.prototype.visitDoctype = function (doctype) {
|
|
return "<!DOCTYPE " + doctype.rootTag + " [\n" + doctype.dtd + "\n]>";
|
|
};
|
|
return _Visitor;
|
|
}());
|
|
var _visitor = new _Visitor();
|
|
function serialize(nodes) {
|
|
return nodes.map(function (node) { return node.visit(_visitor); }).join('');
|
|
}
|
|
var Declaration = /** @class */ (function () {
|
|
function Declaration(unescapedAttrs) {
|
|
var _this = this;
|
|
this.attrs = {};
|
|
Object.keys(unescapedAttrs).forEach(function (k) {
|
|
_this.attrs[k] = escapeXml(unescapedAttrs[k]);
|
|
});
|
|
}
|
|
Declaration.prototype.visit = function (visitor) {
|
|
return visitor.visitDeclaration(this);
|
|
};
|
|
return Declaration;
|
|
}());
|
|
var Doctype = /** @class */ (function () {
|
|
function Doctype(rootTag, dtd) {
|
|
this.rootTag = rootTag;
|
|
this.dtd = dtd;
|
|
}
|
|
Doctype.prototype.visit = function (visitor) {
|
|
return visitor.visitDoctype(this);
|
|
};
|
|
return Doctype;
|
|
}());
|
|
var Tag = /** @class */ (function () {
|
|
function Tag(name, unescapedAttrs, children) {
|
|
var _this = this;
|
|
if (unescapedAttrs === void 0) { unescapedAttrs = {}; }
|
|
if (children === void 0) { children = []; }
|
|
this.name = name;
|
|
this.children = children;
|
|
this.attrs = {};
|
|
Object.keys(unescapedAttrs).forEach(function (k) {
|
|
_this.attrs[k] = escapeXml(unescapedAttrs[k]);
|
|
});
|
|
}
|
|
Tag.prototype.visit = function (visitor) {
|
|
return visitor.visitTag(this);
|
|
};
|
|
return Tag;
|
|
}());
|
|
var Text$2 = /** @class */ (function () {
|
|
function Text(unescapedValue) {
|
|
this.value = escapeXml(unescapedValue);
|
|
}
|
|
Text.prototype.visit = function (visitor) {
|
|
return visitor.visitText(this);
|
|
};
|
|
return Text;
|
|
}());
|
|
var CR = /** @class */ (function (_super) {
|
|
__extends(CR, _super);
|
|
function CR(ws) {
|
|
if (ws === void 0) { ws = 0; }
|
|
return _super.call(this, "\n" + new Array(ws + 1).join(' ')) || this;
|
|
}
|
|
return CR;
|
|
}(Text$2));
|
|
var _ESCAPED_CHARS = [
|
|
[/&/g, '&'],
|
|
[/"/g, '"'],
|
|
[/'/g, '''],
|
|
[/</g, '<'],
|
|
[/>/g, '>'],
|
|
];
|
|
// Escape `_ESCAPED_CHARS` characters in the given text with encoded entities
|
|
function escapeXml(text) {
|
|
return _ESCAPED_CHARS.reduce(function (text, entry) { return text.replace(entry[0], entry[1]); }, text);
|
|
}
|
|
|
|
var _MESSAGES_TAG = 'messagebundle';
|
|
var _MESSAGE_TAG = 'msg';
|
|
var _PLACEHOLDER_TAG = 'ph';
|
|
var _EXAMPLE_TAG = 'ex';
|
|
var _SOURCE_TAG = 'source';
|
|
var _DOCTYPE = "<!ELEMENT messagebundle (msg)*>\n<!ATTLIST messagebundle class CDATA #IMPLIED>\n\n<!ELEMENT msg (#PCDATA|ph|source)*>\n<!ATTLIST msg id CDATA #IMPLIED>\n<!ATTLIST msg seq CDATA #IMPLIED>\n<!ATTLIST msg name CDATA #IMPLIED>\n<!ATTLIST msg desc CDATA #IMPLIED>\n<!ATTLIST msg meaning CDATA #IMPLIED>\n<!ATTLIST msg obsolete (obsolete) #IMPLIED>\n<!ATTLIST msg xml:space (default|preserve) \"default\">\n<!ATTLIST msg is_hidden CDATA #IMPLIED>\n\n<!ELEMENT source (#PCDATA)>\n\n<!ELEMENT ph (#PCDATA|ex)*>\n<!ATTLIST ph name CDATA #REQUIRED>\n\n<!ELEMENT ex (#PCDATA)>";
|
|
var Xmb = /** @class */ (function (_super) {
|
|
__extends(Xmb, _super);
|
|
function Xmb() {
|
|
return _super !== null && _super.apply(this, arguments) || this;
|
|
}
|
|
Xmb.prototype.write = function (messages, locale) {
|
|
var exampleVisitor = new ExampleVisitor();
|
|
var visitor = new _Visitor$1();
|
|
var rootNode = new Tag(_MESSAGES_TAG);
|
|
messages.forEach(function (message) {
|
|
var attrs = { id: message.id };
|
|
if (message.description) {
|
|
attrs['desc'] = message.description;
|
|
}
|
|
if (message.meaning) {
|
|
attrs['meaning'] = message.meaning;
|
|
}
|
|
var sourceTags = [];
|
|
message.sources.forEach(function (source) {
|
|
sourceTags.push(new Tag(_SOURCE_TAG, {}, [new Text$2(source.filePath + ":" + source.startLine + (source.endLine !== source.startLine ? ',' + source.endLine : ''))]));
|
|
});
|
|
rootNode.children.push(new CR(2), new Tag(_MESSAGE_TAG, attrs, __spreadArray(__spreadArray([], __read(sourceTags)), __read(visitor.serialize(message.nodes)))));
|
|
});
|
|
rootNode.children.push(new CR());
|
|
return serialize([
|
|
new Declaration({ version: '1.0', encoding: 'UTF-8' }),
|
|
new CR(),
|
|
new Doctype(_MESSAGES_TAG, _DOCTYPE),
|
|
new CR(),
|
|
exampleVisitor.addDefaultExamples(rootNode),
|
|
new CR(),
|
|
]);
|
|
};
|
|
Xmb.prototype.load = function (content, url) {
|
|
throw new Error('Unsupported');
|
|
};
|
|
Xmb.prototype.digest = function (message) {
|
|
return digest$1(message);
|
|
};
|
|
Xmb.prototype.createNameMapper = function (message) {
|
|
return new SimplePlaceholderMapper(message, toPublicName);
|
|
};
|
|
return Xmb;
|
|
}(Serializer));
|
|
var _Visitor$1 = /** @class */ (function () {
|
|
function _Visitor() {
|
|
}
|
|
_Visitor.prototype.visitText = function (text, context) {
|
|
return [new Text$2(text.value)];
|
|
};
|
|
_Visitor.prototype.visitContainer = function (container, context) {
|
|
var _this = this;
|
|
var nodes = [];
|
|
container.children.forEach(function (node) { return nodes.push.apply(nodes, __spreadArray([], __read(node.visit(_this)))); });
|
|
return nodes;
|
|
};
|
|
_Visitor.prototype.visitIcu = function (icu, context) {
|
|
var _this = this;
|
|
var nodes = [new Text$2("{" + icu.expressionPlaceholder + ", " + icu.type + ", ")];
|
|
Object.keys(icu.cases).forEach(function (c) {
|
|
nodes.push.apply(nodes, __spreadArray(__spreadArray([new Text$2(c + " {")], __read(icu.cases[c].visit(_this))), [new Text$2("} ")]));
|
|
});
|
|
nodes.push(new Text$2("}"));
|
|
return nodes;
|
|
};
|
|
_Visitor.prototype.visitTagPlaceholder = function (ph, context) {
|
|
var startTagAsText = new Text$2("<" + ph.tag + ">");
|
|
var startEx = new Tag(_EXAMPLE_TAG, {}, [startTagAsText]);
|
|
// TC requires PH to have a non empty EX, and uses the text node to show the "original" value.
|
|
var startTagPh = new Tag(_PLACEHOLDER_TAG, { name: ph.startName }, [startEx, startTagAsText]);
|
|
if (ph.isVoid) {
|
|
// void tags have no children nor closing tags
|
|
return [startTagPh];
|
|
}
|
|
var closeTagAsText = new Text$2("</" + ph.tag + ">");
|
|
var closeEx = new Tag(_EXAMPLE_TAG, {}, [closeTagAsText]);
|
|
// TC requires PH to have a non empty EX, and uses the text node to show the "original" value.
|
|
var closeTagPh = new Tag(_PLACEHOLDER_TAG, { name: ph.closeName }, [closeEx, closeTagAsText]);
|
|
return __spreadArray(__spreadArray([startTagPh], __read(this.serialize(ph.children))), [closeTagPh]);
|
|
};
|
|
_Visitor.prototype.visitPlaceholder = function (ph, context) {
|
|
var interpolationAsText = new Text$2("{{" + ph.value + "}}");
|
|
// Example tag needs to be not-empty for TC.
|
|
var exTag = new Tag(_EXAMPLE_TAG, {}, [interpolationAsText]);
|
|
return [
|
|
// TC requires PH to have a non empty EX, and uses the text node to show the "original" value.
|
|
new Tag(_PLACEHOLDER_TAG, { name: ph.name }, [exTag, interpolationAsText])
|
|
];
|
|
};
|
|
_Visitor.prototype.visitIcuPlaceholder = function (ph, context) {
|
|
var icuExpression = ph.value.expression;
|
|
var icuType = ph.value.type;
|
|
var icuCases = Object.keys(ph.value.cases).map(function (value) { return value + ' {...}'; }).join(' ');
|
|
var icuAsText = new Text$2("{" + icuExpression + ", " + icuType + ", " + icuCases + "}");
|
|
var exTag = new Tag(_EXAMPLE_TAG, {}, [icuAsText]);
|
|
return [
|
|
// TC requires PH to have a non empty EX, and uses the text node to show the "original" value.
|
|
new Tag(_PLACEHOLDER_TAG, { name: ph.name }, [exTag, icuAsText])
|
|
];
|
|
};
|
|
_Visitor.prototype.serialize = function (nodes) {
|
|
var _this = this;
|
|
return [].concat.apply([], __spreadArray([], __read(nodes.map(function (node) { return node.visit(_this); }))));
|
|
};
|
|
return _Visitor;
|
|
}());
|
|
function digest$1(message) {
|
|
return decimalDigest(message);
|
|
}
|
|
// TC requires at least one non-empty example on placeholders
|
|
var ExampleVisitor = /** @class */ (function () {
|
|
function ExampleVisitor() {
|
|
}
|
|
ExampleVisitor.prototype.addDefaultExamples = function (node) {
|
|
node.visit(this);
|
|
return node;
|
|
};
|
|
ExampleVisitor.prototype.visitTag = function (tag) {
|
|
var _this = this;
|
|
if (tag.name === _PLACEHOLDER_TAG) {
|
|
if (!tag.children || tag.children.length == 0) {
|
|
var exText = new Text$2(tag.attrs['name'] || '...');
|
|
tag.children = [new Tag(_EXAMPLE_TAG, {}, [exText])];
|
|
}
|
|
}
|
|
else if (tag.children) {
|
|
tag.children.forEach(function (node) { return node.visit(_this); });
|
|
}
|
|
};
|
|
ExampleVisitor.prototype.visitText = function (text) { };
|
|
ExampleVisitor.prototype.visitDeclaration = function (decl) { };
|
|
ExampleVisitor.prototype.visitDoctype = function (doctype) { };
|
|
return ExampleVisitor;
|
|
}());
|
|
// XMB/XTB placeholders can only contain A-Z, 0-9 and _
|
|
function toPublicName(internalName) {
|
|
return internalName.toUpperCase().replace(/[^A-Z0-9_]/g, '_');
|
|
}
|
|
|
|
/* Closure variables holding messages must be named `MSG_[A-Z0-9]+` */
|
|
var 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.
|
|
*/
|
|
var TRANSLATION_VAR_PREFIX = 'i18n_';
|
|
/** Name of the i18n attributes **/
|
|
var I18N_ATTR = 'i18n';
|
|
var I18N_ATTR_PREFIX = 'i18n-';
|
|
/** Prefix of var expressions used in ICUs */
|
|
var I18N_ICU_VAR_PREFIX = 'VAR_';
|
|
/** Prefix of ICU expressions for post processing */
|
|
var I18N_ICU_MAPPING_PREFIX = 'I18N_EXP_';
|
|
/** Placeholder wrapper for i18n expressions **/
|
|
var I18N_PLACEHOLDER_SYMBOL = '�';
|
|
function isI18nAttribute(name) {
|
|
return name === I18N_ATTR || name.startsWith(I18N_ATTR_PREFIX);
|
|
}
|
|
function isI18nRootNode(meta) {
|
|
return meta instanceof Message;
|
|
}
|
|
function isSingleI18nIcu(meta) {
|
|
return isI18nRootNode(meta) && meta.nodes.length === 1 && meta.nodes[0] instanceof Icu$1;
|
|
}
|
|
function hasI18nMeta(node) {
|
|
return !!node.i18n;
|
|
}
|
|
function hasI18nAttrs(element) {
|
|
return element.attrs.some(function (attr) { return isI18nAttribute(attr.name); });
|
|
}
|
|
function icuFromI18nMessage(message) {
|
|
return message.nodes[0];
|
|
}
|
|
function wrapI18nPlaceholder(content, contextId) {
|
|
if (contextId === void 0) { contextId = 0; }
|
|
var blockId = contextId > 0 ? ":" + contextId : '';
|
|
return "" + I18N_PLACEHOLDER_SYMBOL + content + blockId + I18N_PLACEHOLDER_SYMBOL;
|
|
}
|
|
function assembleI18nBoundString(strings, bindingStartIndex, contextId) {
|
|
if (bindingStartIndex === void 0) { bindingStartIndex = 0; }
|
|
if (contextId === void 0) { contextId = 0; }
|
|
if (!strings.length)
|
|
return '';
|
|
var acc = '';
|
|
var lastIdx = strings.length - 1;
|
|
for (var i = 0; i < lastIdx; i++) {
|
|
acc += "" + strings[i] + wrapI18nPlaceholder(bindingStartIndex + i, contextId);
|
|
}
|
|
acc += strings[lastIdx];
|
|
return acc;
|
|
}
|
|
function getSeqNumberGenerator(startsAt) {
|
|
if (startsAt === void 0) { startsAt = 0; }
|
|
var current = startsAt;
|
|
return function () { return current++; };
|
|
}
|
|
function placeholdersToParams(placeholders) {
|
|
var params = {};
|
|
placeholders.forEach(function (values, key) {
|
|
params[key] = literal(values.length > 1 ? "[" + values.join('|') + "]" : values[0]);
|
|
});
|
|
return params;
|
|
}
|
|
function updatePlaceholderMap(map, name) {
|
|
var values = [];
|
|
for (var _i = 2; _i < arguments.length; _i++) {
|
|
values[_i - 2] = arguments[_i];
|
|
}
|
|
var current = map.get(name) || [];
|
|
current.push.apply(current, __spreadArray([], __read(values)));
|
|
map.set(name, current);
|
|
}
|
|
function assembleBoundTextPlaceholders(meta, bindingStartIndex, contextId) {
|
|
if (bindingStartIndex === void 0) { bindingStartIndex = 0; }
|
|
if (contextId === void 0) { contextId = 0; }
|
|
var startIdx = bindingStartIndex;
|
|
var placeholders = new Map();
|
|
var node = meta instanceof Message ? meta.nodes.find(function (node) { return node instanceof Container; }) : meta;
|
|
if (node) {
|
|
node
|
|
.children
|
|
.filter(function (child) { return child instanceof Placeholder; })
|
|
.forEach(function (child, idx) {
|
|
var content = wrapI18nPlaceholder(startIdx + idx, contextId);
|
|
updatePlaceholderMap(placeholders, child.name, content);
|
|
});
|
|
}
|
|
return placeholders;
|
|
}
|
|
/**
|
|
* Format the placeholder names in a map of placeholders to expressions.
|
|
*
|
|
* The placeholder names are converted from "internal" format (e.g. `START_TAG_DIV_1`) to "external"
|
|
* format (e.g. `startTagDiv_1`).
|
|
*
|
|
* @param params A map of placeholder names to expressions.
|
|
* @param useCamelCase whether to camelCase the placeholder name when formatting.
|
|
* @returns A new map of formatted placeholder names to expressions.
|
|
*/
|
|
function i18nFormatPlaceholderNames(params, useCamelCase) {
|
|
if (params === void 0) { params = {}; }
|
|
var _params = {};
|
|
if (params && Object.keys(params).length) {
|
|
Object.keys(params).forEach(function (key) { return _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) {
|
|
if (useCamelCase === void 0) { useCamelCase = true; }
|
|
var publicName = toPublicName(name);
|
|
if (!useCamelCase) {
|
|
return publicName;
|
|
}
|
|
var chunks = publicName.split('_');
|
|
if (chunks.length === 1) {
|
|
// if no "_" found - just lowercase the value
|
|
return name.toLowerCase();
|
|
}
|
|
var postfix;
|
|
// eject last element if it's a number
|
|
if (/^\d+$/.test(chunks[chunks.length - 1])) {
|
|
postfix = chunks.pop();
|
|
}
|
|
var raw = chunks.shift().toLowerCase();
|
|
if (chunks.length) {
|
|
raw += chunks.map(function (c) { return 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);
|
|
}
|
|
|
|
/**
|
|
* 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.
|
|
*/
|
|
var UNSAFE_OBJECT_KEY_NAME_REGEXP = /[-.]/;
|
|
/** Name of the temporary to use during data binding */
|
|
var TEMPORARY_NAME = '_t';
|
|
/** Name of the context parameter passed into a template function */
|
|
var CONTEXT_NAME = 'ctx';
|
|
/** Name of the RenderFlag passed into a template function */
|
|
var RENDER_FLAGS = 'rf';
|
|
/** The prefix reference variables */
|
|
var REFERENCE_PREFIX = '_r';
|
|
/** The name of the implicit context reference */
|
|
var IMPLICIT_REFERENCE = '$implicit';
|
|
/** Non bindable attribute name **/
|
|
var NON_BINDABLE_ATTR = 'ngNonBindable';
|
|
/** Name for the variable keeping track of the context returned by `ɵɵrestoreView`. */
|
|
var RESTORED_VIEW_CONTEXT_NAME = 'restoredCtx';
|
|
/**
|
|
* Creates an allocator for a temporary variable.
|
|
*
|
|
* A variable declaration is added to the statements the first time the allocator is invoked.
|
|
*/
|
|
function temporaryAllocator(statements, name) {
|
|
var temp = null;
|
|
return function () {
|
|
if (!temp) {
|
|
statements.push(new DeclareVarStmt(TEMPORARY_NAME, undefined, DYNAMIC_TYPE));
|
|
temp = variable(name);
|
|
}
|
|
return temp;
|
|
};
|
|
}
|
|
function unsupported(feature) {
|
|
if (this) {
|
|
throw new Error("Builder " + this.constructor.name + " doesn't support " + feature + " yet");
|
|
}
|
|
throw new Error("Feature " + feature + " is not supported yet");
|
|
}
|
|
function invalid$1(arg) {
|
|
throw new Error("Invalid state: Visitor " + this.constructor.name + " doesn't handle " + arg.constructor.name);
|
|
}
|
|
function asLiteral(value) {
|
|
if (Array.isArray(value)) {
|
|
return literalArr(value.map(asLiteral));
|
|
}
|
|
return literal(value, INFERRED_TYPE);
|
|
}
|
|
function conditionallyCreateMapObjectLiteral(keys, keepDeclared) {
|
|
if (Object.getOwnPropertyNames(keys).length > 0) {
|
|
return mapToExpression(keys, keepDeclared);
|
|
}
|
|
return null;
|
|
}
|
|
function mapToExpression(map, keepDeclared) {
|
|
return literalMap(Object.getOwnPropertyNames(map).map(function (key) {
|
|
var _a, _b;
|
|
// canonical syntax: `dirProp: publicProp`
|
|
// if there is no `:`, use dirProp = elProp
|
|
var value = map[key];
|
|
var declaredName;
|
|
var publicName;
|
|
var minifiedName;
|
|
var needsDeclaredName;
|
|
if (Array.isArray(value)) {
|
|
_a = __read(value, 2), publicName = _a[0], declaredName = _a[1];
|
|
minifiedName = key;
|
|
needsDeclaredName = publicName !== declaredName;
|
|
}
|
|
else {
|
|
_b = __read(splitAtColon(key, [key, value]), 2), declaredName = _b[0], publicName = _b[1];
|
|
minifiedName = declaredName;
|
|
// Only include the declared name if extracted from the key, i.e. the key contains a colon.
|
|
// Otherwise the declared name should be omitted even if it is different from the public name,
|
|
// as it may have already been minified.
|
|
needsDeclaredName = publicName !== declaredName && key.includes(':');
|
|
}
|
|
return {
|
|
key: minifiedName,
|
|
// put quotes around keys that contain potentially unsafe characters
|
|
quoted: UNSAFE_OBJECT_KEY_NAME_REGEXP.test(minifiedName),
|
|
value: (keepDeclared && needsDeclaredName) ?
|
|
literalArr([asLiteral(publicName), asLiteral(declaredName)]) :
|
|
asLiteral(publicName)
|
|
};
|
|
}));
|
|
}
|
|
/**
|
|
* Remove trailing null nodes as they are implied.
|
|
*/
|
|
function trimTrailingNulls(parameters) {
|
|
while (isNull(parameters[parameters.length - 1])) {
|
|
parameters.pop();
|
|
}
|
|
return parameters;
|
|
}
|
|
function getQueryPredicate(query, constantPool) {
|
|
if (Array.isArray(query.predicate)) {
|
|
var predicate_1 = [];
|
|
query.predicate.forEach(function (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
|
|
var selectors = selector.split(',').map(function (token) { return literal(token.trim()); });
|
|
predicate_1.push.apply(predicate_1, __spreadArray([], __read(selectors)));
|
|
});
|
|
return constantPool.getConstLiteral(literalArr(predicate_1), true);
|
|
}
|
|
else {
|
|
// The original predicate may have been wrapped in a `forwardRef()` call.
|
|
switch (query.predicate.forwardRef) {
|
|
case 0 /* None */:
|
|
case 2 /* Unwrapped */:
|
|
return query.predicate.expression;
|
|
case 1 /* Wrapped */:
|
|
return importExpr(Identifiers.resolveForwardRef).callFn([query.predicate.expression]);
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* A representation for an object literal used during codegen of definition objects. The generic
|
|
* type `T` allows to reference a documented type of the generated structure, such that the
|
|
* property names that are set can be resolved to their documented declaration.
|
|
*/
|
|
var DefinitionMap = /** @class */ (function () {
|
|
function DefinitionMap() {
|
|
this.values = [];
|
|
}
|
|
DefinitionMap.prototype.set = function (key, value) {
|
|
if (value) {
|
|
this.values.push({ key: key, value: value, quoted: false });
|
|
}
|
|
};
|
|
DefinitionMap.prototype.toLiteralMap = function () {
|
|
return literalMap(this.values);
|
|
};
|
|
return DefinitionMap;
|
|
}());
|
|
/**
|
|
* 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) {
|
|
var attributesMap = {};
|
|
if (elOrTpl instanceof Template && elOrTpl.tagName !== 'ng-template') {
|
|
elOrTpl.templateAttrs.forEach(function (a) { return attributesMap[a.name] = ''; });
|
|
}
|
|
else {
|
|
elOrTpl.attributes.forEach(function (a) {
|
|
if (!isI18nAttribute(a.name)) {
|
|
attributesMap[a.name] = a.value;
|
|
}
|
|
});
|
|
elOrTpl.inputs.forEach(function (i) {
|
|
attributesMap[i.name] = '';
|
|
});
|
|
elOrTpl.outputs.forEach(function (o) {
|
|
attributesMap[o.name] = '';
|
|
});
|
|
}
|
|
return attributesMap;
|
|
}
|
|
/** Returns a call expression to a chained instruction, e.g. `property(params[0])(params[1])`. */
|
|
function chainedInstruction(reference, calls, span) {
|
|
var expression = importExpr(reference, null, span);
|
|
if (calls.length > 0) {
|
|
for (var i = 0; i < calls.length; i++) {
|
|
expression = expression.callFn(calls[i], span);
|
|
}
|
|
}
|
|
else {
|
|
// Add a blank invocation, in case the `calls` array is empty.
|
|
expression = expression.callFn([], span);
|
|
}
|
|
return expression;
|
|
}
|
|
/**
|
|
* Gets the number of arguments expected to be passed to a generated instruction in the case of
|
|
* interpolation instructions.
|
|
* @param interpolation An interpolation ast
|
|
*/
|
|
function getInterpolationArgsLength(interpolation) {
|
|
var expressions = interpolation.expressions, strings = interpolation.strings;
|
|
if (expressions.length === 1 && strings.length === 2 && strings[0] === '' && strings[1] === '') {
|
|
// If the interpolation has one interpolated value, but the prefix and suffix are both empty
|
|
// strings, we only pass one argument, to a special instruction like `propertyInterpolate` or
|
|
// `textInterpolate`.
|
|
return 1;
|
|
}
|
|
else {
|
|
return expressions.length + strings.length;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @license
|
|
* Copyright Google LLC All Rights Reserved.
|
|
*
|
|
* Use of this source code is governed by an MIT-style license that can be
|
|
* found in the LICENSE file at https://angular.io/license
|
|
*/
|
|
function compileInjectable(meta, resolveForwardRefs) {
|
|
var result = null;
|
|
var factoryMeta = {
|
|
name: meta.name,
|
|
type: meta.type,
|
|
internalType: meta.internalType,
|
|
typeArgumentCount: meta.typeArgumentCount,
|
|
deps: [],
|
|
target: exports.FactoryTarget.Injectable,
|
|
};
|
|
if (meta.useClass !== undefined) {
|
|
// meta.useClass has two modes of operation. Either deps are specified, in which case `new` is
|
|
// used to instantiate the class with dependencies injected, or deps are not specified and
|
|
// the factory of the class is used to instantiate it.
|
|
//
|
|
// A special case exists for useClass: Type where Type is the injectable type itself and no
|
|
// deps are specified, in which case 'useClass' is effectively ignored.
|
|
var useClassOnSelf = meta.useClass.expression.isEquivalent(meta.internalType);
|
|
var deps = undefined;
|
|
if (meta.deps !== undefined) {
|
|
deps = meta.deps;
|
|
}
|
|
if (deps !== undefined) {
|
|
// factory: () => new meta.useClass(...deps)
|
|
result = compileFactoryFunction(Object.assign(Object.assign({}, factoryMeta), { delegate: meta.useClass.expression, delegateDeps: deps, delegateType: R3FactoryDelegateType.Class }));
|
|
}
|
|
else if (useClassOnSelf) {
|
|
result = compileFactoryFunction(factoryMeta);
|
|
}
|
|
else {
|
|
result = {
|
|
statements: [],
|
|
expression: delegateToFactory(meta.type.value, meta.useClass.expression, resolveForwardRefs)
|
|
};
|
|
}
|
|
}
|
|
else if (meta.useFactory !== undefined) {
|
|
if (meta.deps !== undefined) {
|
|
result = compileFactoryFunction(Object.assign(Object.assign({}, factoryMeta), { delegate: meta.useFactory, delegateDeps: meta.deps || [], delegateType: R3FactoryDelegateType.Function }));
|
|
}
|
|
else {
|
|
result = {
|
|
statements: [],
|
|
expression: fn([], [new ReturnStatement(meta.useFactory.callFn([]))])
|
|
};
|
|
}
|
|
}
|
|
else if (meta.useValue !== undefined) {
|
|
// Note: it's safe to use `meta.useValue` instead of the `USE_VALUE in meta` check used for
|
|
// client code because meta.useValue is an Expression which will be defined even if the actual
|
|
// value is undefined.
|
|
result = compileFactoryFunction(Object.assign(Object.assign({}, factoryMeta), { expression: meta.useValue.expression }));
|
|
}
|
|
else if (meta.useExisting !== undefined) {
|
|
// useExisting is an `inject` call on the existing token.
|
|
result = compileFactoryFunction(Object.assign(Object.assign({}, factoryMeta), { expression: importExpr(Identifiers.inject).callFn([meta.useExisting.expression]) }));
|
|
}
|
|
else {
|
|
result = {
|
|
statements: [],
|
|
expression: delegateToFactory(meta.type.value, meta.internalType, resolveForwardRefs)
|
|
};
|
|
}
|
|
var token = meta.internalType;
|
|
var 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));
|
|
}
|
|
var expression = importExpr(Identifiers.ɵɵdefineInjectable)
|
|
.callFn([injectableProps.toLiteralMap()], undefined, true);
|
|
return {
|
|
expression: expression,
|
|
type: createInjectableType(meta),
|
|
statements: result.statements,
|
|
};
|
|
}
|
|
function createInjectableType(meta) {
|
|
return new ExpressionType(importExpr(Identifiers.InjectableDeclaration, [typeWithParameters(meta.type.type, meta.typeArgumentCount)]));
|
|
}
|
|
function delegateToFactory(type, internalType, unwrapForwardRefs) {
|
|
if (type.node === internalType.node) {
|
|
// The types are the same, so we can simply delegate directly to the type's factory.
|
|
// ```
|
|
// factory: type.ɵfac
|
|
// ```
|
|
return internalType.prop('ɵfac');
|
|
}
|
|
if (!unwrapForwardRefs) {
|
|
// The type is not wrapped in a `forwardRef()`, so we create a simple factory function that
|
|
// accepts a sub-type as an argument.
|
|
// ```
|
|
// factory: function(t) { return internalType.ɵfac(t); }
|
|
// ```
|
|
return createFactoryFunction(internalType);
|
|
}
|
|
// The internalType is actually wrapped in a `forwardRef()` so we need to resolve that before
|
|
// calling its factory.
|
|
// ```
|
|
// factory: function(t) { return core.resolveForwardRef(type).ɵfac(t); }
|
|
// ```
|
|
var unwrappedType = importExpr(Identifiers.resolveForwardRef).callFn([internalType]);
|
|
return createFactoryFunction(unwrappedType);
|
|
}
|
|
function createFactoryFunction(type) {
|
|
return fn([new FnParam('t', DYNAMIC_TYPE)], [new ReturnStatement(type.callMethod('ɵfac', [variable('t')]))]);
|
|
}
|
|
|
|
/**
|
|
* @license
|
|
* Copyright Google LLC All Rights Reserved.
|
|
*
|
|
* Use of this source code is governed by an MIT-style license that can be
|
|
* found in the LICENSE file at https://angular.io/license
|
|
*/
|
|
function assertArrayOfStrings(identifier, value) {
|
|
if (value == null) {
|
|
return;
|
|
}
|
|
if (!Array.isArray(value)) {
|
|
throw new Error("Expected '" + identifier + "' to be an array of strings.");
|
|
}
|
|
for (var i = 0; i < value.length; i += 1) {
|
|
if (typeof value[i] !== 'string') {
|
|
throw new Error("Expected '" + identifier + "' to be an array of strings.");
|
|
}
|
|
}
|
|
}
|
|
var 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) {
|
|
var start_1 = value[0];
|
|
var end_1 = value[1];
|
|
// Check for unusable interpolation symbols
|
|
UNUSABLE_INTERPOLATION_REGEXPS.forEach(function (regexp) {
|
|
if (regexp.test(start_1) || regexp.test(end_1)) {
|
|
throw new Error("['" + start_1 + "', '" + end_1 + "'] 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
|
|
*/
|
|
var InterpolationConfig = /** @class */ (function () {
|
|
function InterpolationConfig(start, end) {
|
|
this.start = start;
|
|
this.end = end;
|
|
}
|
|
InterpolationConfig.fromArray = function (markers) {
|
|
if (!markers) {
|
|
return DEFAULT_INTERPOLATION_CONFIG;
|
|
}
|
|
assertInterpolationSymbols('interpolation', markers);
|
|
return new InterpolationConfig(markers[0], markers[1]);
|
|
};
|
|
return InterpolationConfig;
|
|
}());
|
|
var DEFAULT_INTERPOLATION_CONFIG = new InterpolationConfig('{{', '}}');
|
|
|
|
/**
|
|
* @license
|
|
* Copyright Google LLC All Rights Reserved.
|
|
*
|
|
* Use of this source code is governed by an MIT-style license that can be
|
|
* found in the LICENSE file at https://angular.io/license
|
|
*/
|
|
/**
|
|
* A token representing the a reference to a static type.
|
|
*
|
|
* This token is unique for a filePath and name and can be used as a hash table key.
|
|
*/
|
|
var StaticSymbol = /** @class */ (function () {
|
|
function StaticSymbol(filePath, name, members) {
|
|
this.filePath = filePath;
|
|
this.name = name;
|
|
this.members = members;
|
|
}
|
|
StaticSymbol.prototype.assertNoMembers = function () {
|
|
if (this.members.length) {
|
|
throw new Error("Illegal state: symbol without members expected, but got " + JSON.stringify(this) + ".");
|
|
}
|
|
};
|
|
return StaticSymbol;
|
|
}());
|
|
/**
|
|
* A cache of static symbol used by the StaticReflector to return the same symbol for the
|
|
* same symbol values.
|
|
*/
|
|
var StaticSymbolCache = /** @class */ (function () {
|
|
function StaticSymbolCache() {
|
|
this.cache = new Map();
|
|
}
|
|
StaticSymbolCache.prototype.get = function (declarationFile, name, members) {
|
|
members = members || [];
|
|
var memberSuffix = members.length ? "." + members.join('.') : '';
|
|
var key = "\"" + declarationFile + "\"." + name + memberSuffix;
|
|
var result = this.cache.get(key);
|
|
if (!result) {
|
|
result = new StaticSymbol(declarationFile, name, members);
|
|
this.cache.set(key, result);
|
|
}
|
|
return result;
|
|
};
|
|
return StaticSymbolCache;
|
|
}());
|
|
|
|
/**
|
|
* @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 $EOF = 0;
|
|
var $BSPACE = 8;
|
|
var $TAB = 9;
|
|
var $LF = 10;
|
|
var $VTAB = 11;
|
|
var $FF = 12;
|
|
var $CR = 13;
|
|
var $SPACE = 32;
|
|
var $BANG = 33;
|
|
var $DQ = 34;
|
|
var $HASH = 35;
|
|
var $$ = 36;
|
|
var $PERCENT = 37;
|
|
var $AMPERSAND = 38;
|
|
var $SQ = 39;
|
|
var $LPAREN = 40;
|
|
var $RPAREN = 41;
|
|
var $STAR = 42;
|
|
var $PLUS = 43;
|
|
var $COMMA = 44;
|
|
var $MINUS = 45;
|
|
var $PERIOD = 46;
|
|
var $SLASH = 47;
|
|
var $COLON = 58;
|
|
var $SEMICOLON = 59;
|
|
var $LT = 60;
|
|
var $EQ = 61;
|
|
var $GT = 62;
|
|
var $QUESTION = 63;
|
|
var $0 = 48;
|
|
var $7 = 55;
|
|
var $9 = 57;
|
|
var $A = 65;
|
|
var $E = 69;
|
|
var $F = 70;
|
|
var $X = 88;
|
|
var $Z = 90;
|
|
var $LBRACKET = 91;
|
|
var $BACKSLASH = 92;
|
|
var $RBRACKET = 93;
|
|
var $CARET = 94;
|
|
var $_ = 95;
|
|
var $a = 97;
|
|
var $b = 98;
|
|
var $e = 101;
|
|
var $f = 102;
|
|
var $n = 110;
|
|
var $r = 114;
|
|
var $t = 116;
|
|
var $u = 117;
|
|
var $v = 118;
|
|
var $x = 120;
|
|
var $z = 122;
|
|
var $LBRACE = 123;
|
|
var $BAR = 124;
|
|
var $RBRACE = 125;
|
|
var $NBSP = 160;
|
|
var $PIPE = 124;
|
|
var $TILDA = 126;
|
|
var $AT = 64;
|
|
var $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
|
|
*/
|
|
var ParseLocation = /** @class */ (function () {
|
|
function ParseLocation(file, offset, line, col) {
|
|
this.file = file;
|
|
this.offset = offset;
|
|
this.line = line;
|
|
this.col = col;
|
|
}
|
|
ParseLocation.prototype.toString = function () {
|
|
return this.offset != null ? this.file.url + "@" + this.line + ":" + this.col : this.file.url;
|
|
};
|
|
ParseLocation.prototype.moveBy = function (delta) {
|
|
var source = this.file.content;
|
|
var len = source.length;
|
|
var offset = this.offset;
|
|
var line = this.line;
|
|
var col = this.col;
|
|
while (offset > 0 && delta < 0) {
|
|
offset--;
|
|
delta++;
|
|
var ch = source.charCodeAt(offset);
|
|
if (ch == $LF) {
|
|
line--;
|
|
var priorLine = source.substr(0, offset - 1).lastIndexOf(String.fromCharCode($LF));
|
|
col = priorLine > 0 ? offset - priorLine : offset;
|
|
}
|
|
else {
|
|
col--;
|
|
}
|
|
}
|
|
while (offset < len && delta > 0) {
|
|
var 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
|
|
ParseLocation.prototype.getContext = function (maxChars, maxLines) {
|
|
var content = this.file.content;
|
|
var startOffset = this.offset;
|
|
if (startOffset != null) {
|
|
if (startOffset > content.length - 1) {
|
|
startOffset = content.length - 1;
|
|
}
|
|
var endOffset = startOffset;
|
|
var ctxChars = 0;
|
|
var 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;
|
|
};
|
|
return ParseLocation;
|
|
}());
|
|
var ParseSourceFile = /** @class */ (function () {
|
|
function ParseSourceFile(content, url) {
|
|
this.content = content;
|
|
this.url = url;
|
|
}
|
|
return ParseSourceFile;
|
|
}());
|
|
var ParseSourceSpan = /** @class */ (function () {
|
|
/**
|
|
* 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.
|
|
*/
|
|
function ParseSourceSpan(start, end, fullStart, details) {
|
|
if (fullStart === void 0) { fullStart = start; }
|
|
if (details === void 0) { details = null; }
|
|
this.start = start;
|
|
this.end = end;
|
|
this.fullStart = fullStart;
|
|
this.details = details;
|
|
}
|
|
ParseSourceSpan.prototype.toString = function () {
|
|
return this.start.file.content.substring(this.start.offset, this.end.offset);
|
|
};
|
|
return ParseSourceSpan;
|
|
}());
|
|
(function (ParseErrorLevel) {
|
|
ParseErrorLevel[ParseErrorLevel["WARNING"] = 0] = "WARNING";
|
|
ParseErrorLevel[ParseErrorLevel["ERROR"] = 1] = "ERROR";
|
|
})(exports.ParseErrorLevel || (exports.ParseErrorLevel = {}));
|
|
var ParseError = /** @class */ (function () {
|
|
function ParseError(span, msg, level) {
|
|
if (level === void 0) { level = exports.ParseErrorLevel.ERROR; }
|
|
this.span = span;
|
|
this.msg = msg;
|
|
this.level = level;
|
|
}
|
|
ParseError.prototype.contextualMessage = function () {
|
|
var ctx = this.span.start.getContext(100, 3);
|
|
return ctx ? this.msg + " (\"" + ctx.before + "[" + exports.ParseErrorLevel[this.level] + " ->]" + ctx.after + "\")" :
|
|
this.msg;
|
|
};
|
|
ParseError.prototype.toString = function () {
|
|
var details = this.span.details ? ", " + this.span.details : '';
|
|
return this.contextualMessage() + ": " + this.span.start + details;
|
|
};
|
|
return ParseError;
|
|
}());
|
|
function typeSourceSpan(kind, type) {
|
|
var moduleUrl = identifierModuleUrl(type);
|
|
var sourceFileName = moduleUrl != null ? "in " + kind + " " + identifierName(type) + " in " + moduleUrl :
|
|
"in " + kind + " " + identifierName(type);
|
|
var sourceFile = new ParseSourceFile('', sourceFileName);
|
|
return new ParseSourceSpan(new ParseLocation(sourceFile, -1, -1, -1), new ParseLocation(sourceFile, -1, -1, -1));
|
|
}
|
|
/**
|
|
* Generates Source Span object for a given R3 Type for JIT mode.
|
|
*
|
|
* @param kind Component or Directive.
|
|
* @param typeName name of the Component or Directive.
|
|
* @param sourceUrl reference to Component or Directive source.
|
|
* @returns instance of ParseSourceSpan that represent a given Component or Directive.
|
|
*/
|
|
function r3JitTypeSourceSpan(kind, typeName, sourceUrl) {
|
|
var sourceFileName = "in " + kind + " " + typeName + " in " + sourceUrl;
|
|
var sourceFile = new ParseSourceFile('', sourceFileName);
|
|
return new ParseSourceSpan(new ParseLocation(sourceFile, -1, -1, -1), new ParseLocation(sourceFile, -1, -1, -1));
|
|
}
|
|
function syntaxError(msg, parseErrors) {
|
|
var error = Error(msg);
|
|
error[ERROR_SYNTAX_ERROR] = true;
|
|
if (parseErrors)
|
|
error[ERROR_PARSE_ERRORS] = parseErrors;
|
|
return error;
|
|
}
|
|
var ERROR_SYNTAX_ERROR = 'ngSyntaxError';
|
|
var ERROR_PARSE_ERRORS = 'ngParseErrors';
|
|
function isSyntaxError(error) {
|
|
return error[ERROR_SYNTAX_ERROR];
|
|
}
|
|
function getParseErrors(error) {
|
|
return error[ERROR_PARSE_ERRORS] || [];
|
|
}
|
|
var _anonymousTypeIndex = 0;
|
|
function identifierName(compileIdentifier) {
|
|
if (!compileIdentifier || !compileIdentifier.reference) {
|
|
return null;
|
|
}
|
|
var ref = compileIdentifier.reference;
|
|
if (ref instanceof StaticSymbol) {
|
|
return ref.name;
|
|
}
|
|
if (ref['__anonymousType']) {
|
|
return ref['__anonymousType'];
|
|
}
|
|
if (ref['__forward_ref__']) {
|
|
// We do not want to try to stringify a `forwardRef()` function because that would cause the
|
|
// inner function to be evaluated too early, defeating the whole point of the `forwardRef`.
|
|
return '__forward_ref__';
|
|
}
|
|
var identifier = stringify(ref);
|
|
if (identifier.indexOf('(') >= 0) {
|
|
// case: anonymous functions!
|
|
identifier = "anonymous_" + _anonymousTypeIndex++;
|
|
ref['__anonymousType'] = identifier;
|
|
}
|
|
else {
|
|
identifier = sanitizeIdentifier(identifier);
|
|
}
|
|
return identifier;
|
|
}
|
|
function identifierModuleUrl(compileIdentifier) {
|
|
var ref = compileIdentifier.reference;
|
|
if (ref instanceof StaticSymbol) {
|
|
return ref.filePath;
|
|
}
|
|
// Runtime type
|
|
return "./" + stringify(ref);
|
|
}
|
|
function sanitizeIdentifier(name) {
|
|
return name.replace(/\W/g, '_');
|
|
}
|
|
|
|
/**
|
|
* 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.
|
|
*/
|
|
var makeTemplateObjectPolyfill = '(this&&this.__makeTemplateObject||function(e,t){return Object.defineProperty?Object.defineProperty(e,"raw",{value:t}):e.raw=t,e})';
|
|
var AbstractJsEmitterVisitor = /** @class */ (function (_super) {
|
|
__extends(AbstractJsEmitterVisitor, _super);
|
|
function AbstractJsEmitterVisitor() {
|
|
return _super.call(this, false) || this;
|
|
}
|
|
AbstractJsEmitterVisitor.prototype.visitDeclareClassStmt = function (stmt, ctx) {
|
|
var _this = this;
|
|
ctx.pushClass(stmt);
|
|
this._visitClassConstructor(stmt, ctx);
|
|
if (stmt.parent != null) {
|
|
ctx.print(stmt, stmt.name + ".prototype = Object.create(");
|
|
stmt.parent.visitExpression(this, ctx);
|
|
ctx.println(stmt, ".prototype);");
|
|
}
|
|
stmt.getters.forEach(function (getter) { return _this._visitClassGetter(stmt, getter, ctx); });
|
|
stmt.methods.forEach(function (method) { return _this._visitClassMethod(stmt, method, ctx); });
|
|
ctx.popClass();
|
|
return null;
|
|
};
|
|
AbstractJsEmitterVisitor.prototype._visitClassConstructor = function (stmt, ctx) {
|
|
ctx.print(stmt, "function " + stmt.name + "(");
|
|
if (stmt.constructorMethod != null) {
|
|
this._visitParams(stmt.constructorMethod.params, ctx);
|
|
}
|
|
ctx.println(stmt, ") {");
|
|
ctx.incIndent();
|
|
if (stmt.constructorMethod != null) {
|
|
if (stmt.constructorMethod.body.length > 0) {
|
|
ctx.println(stmt, "var self = this;");
|
|
this.visitAllStatements(stmt.constructorMethod.body, ctx);
|
|
}
|
|
}
|
|
ctx.decIndent();
|
|
ctx.println(stmt, "}");
|
|
};
|
|
AbstractJsEmitterVisitor.prototype._visitClassGetter = function (stmt, getter, ctx) {
|
|
ctx.println(stmt, "Object.defineProperty(" + stmt.name + ".prototype, '" + getter.name + "', { get: function() {");
|
|
ctx.incIndent();
|
|
if (getter.body.length > 0) {
|
|
ctx.println(stmt, "var self = this;");
|
|
this.visitAllStatements(getter.body, ctx);
|
|
}
|
|
ctx.decIndent();
|
|
ctx.println(stmt, "}});");
|
|
};
|
|
AbstractJsEmitterVisitor.prototype._visitClassMethod = function (stmt, method, ctx) {
|
|
ctx.print(stmt, stmt.name + ".prototype." + method.name + " = function(");
|
|
this._visitParams(method.params, ctx);
|
|
ctx.println(stmt, ") {");
|
|
ctx.incIndent();
|
|
if (method.body.length > 0) {
|
|
ctx.println(stmt, "var self = this;");
|
|
this.visitAllStatements(method.body, ctx);
|
|
}
|
|
ctx.decIndent();
|
|
ctx.println(stmt, "};");
|
|
};
|
|
AbstractJsEmitterVisitor.prototype.visitWrappedNodeExpr = function (ast, ctx) {
|
|
throw new Error('Cannot emit a WrappedNodeExpr in Javascript.');
|
|
};
|
|
AbstractJsEmitterVisitor.prototype.visitReadVarExpr = function (ast, ctx) {
|
|
if (ast.builtin === exports.BuiltinVar.This) {
|
|
ctx.print(ast, 'self');
|
|
}
|
|
else if (ast.builtin === exports.BuiltinVar.Super) {
|
|
throw new Error("'super' needs to be handled at a parent ast node, not at the variable level!");
|
|
}
|
|
else {
|
|
_super.prototype.visitReadVarExpr.call(this, ast, ctx);
|
|
}
|
|
return null;
|
|
};
|
|
AbstractJsEmitterVisitor.prototype.visitDeclareVarStmt = function (stmt, ctx) {
|
|
ctx.print(stmt, "var " + stmt.name);
|
|
if (stmt.value) {
|
|
ctx.print(stmt, ' = ');
|
|
stmt.value.visitExpression(this, ctx);
|
|
}
|
|
ctx.println(stmt, ";");
|
|
return null;
|
|
};
|
|
AbstractJsEmitterVisitor.prototype.visitCastExpr = function (ast, ctx) {
|
|
ast.value.visitExpression(this, ctx);
|
|
return null;
|
|
};
|
|
AbstractJsEmitterVisitor.prototype.visitInvokeFunctionExpr = function (expr, ctx) {
|
|
var fnExpr = expr.fn;
|
|
if (fnExpr instanceof ReadVarExpr && fnExpr.builtin === exports.BuiltinVar.Super) {
|
|
ctx.currentClass.parent.visitExpression(this, ctx);
|
|
ctx.print(expr, ".call(this");
|
|
if (expr.args.length > 0) {
|
|
ctx.print(expr, ", ");
|
|
this.visitAllExpressions(expr.args, ctx, ',');
|
|
}
|
|
ctx.print(expr, ")");
|
|
}
|
|
else {
|
|
_super.prototype.visitInvokeFunctionExpr.call(this, expr, ctx);
|
|
}
|
|
return null;
|
|
};
|
|
AbstractJsEmitterVisitor.prototype.visitTaggedTemplateExpr = function (ast, ctx) {
|
|
var _this = this;
|
|
// The following convoluted piece of code is effectively the downlevelled equivalent of
|
|
// ```
|
|
// tag`...`
|
|
// ```
|
|
// which is effectively like:
|
|
// ```
|
|
// tag(__makeTemplateObject(cooked, raw), expression1, expression2, ...);
|
|
// ```
|
|
var elements = ast.template.elements;
|
|
ast.tag.visitExpression(this, ctx);
|
|
ctx.print(ast, "(" + makeTemplateObjectPolyfill + "(");
|
|
ctx.print(ast, "[" + elements.map(function (part) { return escapeIdentifier(part.text, false); }).join(', ') + "], ");
|
|
ctx.print(ast, "[" + elements.map(function (part) { return escapeIdentifier(part.rawText, false); }).join(', ') + "])");
|
|
ast.template.expressions.forEach(function (expression) {
|
|
ctx.print(ast, ', ');
|
|
expression.visitExpression(_this, ctx);
|
|
});
|
|
ctx.print(ast, ')');
|
|
return null;
|
|
};
|
|
AbstractJsEmitterVisitor.prototype.visitFunctionExpr = function (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;
|
|
};
|
|
AbstractJsEmitterVisitor.prototype.visitDeclareFunctionStmt = function (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;
|
|
};
|
|
AbstractJsEmitterVisitor.prototype.visitTryCatchStmt = function (stmt, ctx) {
|
|
ctx.println(stmt, "try {");
|
|
ctx.incIndent();
|
|
this.visitAllStatements(stmt.bodyStmts, ctx);
|
|
ctx.decIndent();
|
|
ctx.println(stmt, "} catch (" + CATCH_ERROR_VAR$1.name + ") {");
|
|
ctx.incIndent();
|
|
var catchStmts = [CATCH_STACK_VAR$1.set(CATCH_ERROR_VAR$1.prop('stack')).toDeclStmt(null, [
|
|
exports.StmtModifier.Final
|
|
])].concat(stmt.catchStmts);
|
|
this.visitAllStatements(catchStmts, ctx);
|
|
ctx.decIndent();
|
|
ctx.println(stmt, "}");
|
|
return null;
|
|
};
|
|
AbstractJsEmitterVisitor.prototype.visitLocalizedString = function (ast, ctx) {
|
|
var _this = this;
|
|
// 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 + "(");
|
|
var parts = [ast.serializeI18nHead()];
|
|
for (var i = 1; i < ast.messageParts.length; i++) {
|
|
parts.push(ast.serializeI18nTemplatePart(i));
|
|
}
|
|
ctx.print(ast, "[" + parts.map(function (part) { return escapeIdentifier(part.cooked, false); }).join(', ') + "], ");
|
|
ctx.print(ast, "[" + parts.map(function (part) { return escapeIdentifier(part.raw, false); }).join(', ') + "])");
|
|
ast.expressions.forEach(function (expression) {
|
|
ctx.print(ast, ', ');
|
|
expression.visitExpression(_this, ctx);
|
|
});
|
|
ctx.print(ast, ')');
|
|
return null;
|
|
};
|
|
AbstractJsEmitterVisitor.prototype._visitParams = function (params, ctx) {
|
|
this.visitAllObjects(function (param) { return ctx.print(null, param.name); }, params, ctx, ',');
|
|
};
|
|
AbstractJsEmitterVisitor.prototype.getBuiltinMethodName = function (method) {
|
|
var name;
|
|
switch (method) {
|
|
case exports.BuiltinMethod.ConcatArray:
|
|
name = 'concat';
|
|
break;
|
|
case exports.BuiltinMethod.SubscribeObservable:
|
|
name = 'subscribe';
|
|
break;
|
|
case exports.BuiltinMethod.Bind:
|
|
name = 'bind';
|
|
break;
|
|
default:
|
|
throw new Error("Unknown builtin method: " + method);
|
|
}
|
|
return name;
|
|
};
|
|
return AbstractJsEmitterVisitor;
|
|
}(AbstractEmitterVisitor));
|
|
|
|
/**
|
|
* The Trusted Types policy, or null if Trusted Types are not
|
|
* enabled/supported, or undefined if the policy has not been created yet.
|
|
*/
|
|
var 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: function (s) { return s; },
|
|
});
|
|
}
|
|
catch (_a) {
|
|
// trustedTypes.createPolicy throws if called with a name that is
|
|
// already registered, even in report-only mode. Until the API changes,
|
|
// catch the error not to break the applications functionally. In such
|
|
// cases, the code will fall back to using strings.
|
|
}
|
|
}
|
|
}
|
|
return policy;
|
|
}
|
|
/**
|
|
* Unsafely promote a string to a TrustedScript, falling back to strings when
|
|
* Trusted Types are not available.
|
|
* @security In particular, it must be assured that the provided string will
|
|
* never cause an XSS vulnerability if used in a context that will be
|
|
* interpreted and executed as a script by a browser, e.g. when calling eval.
|
|
*/
|
|
function trustedScriptFromString(script) {
|
|
var _a;
|
|
return ((_a = getPolicy()) === null || _a === void 0 ? void 0 : _a.createScript(script)) || script;
|
|
}
|
|
/**
|
|
* Unsafely call the Function constructor with the given string arguments.
|
|
* @security This is a security-sensitive function; any use of this function
|
|
* must go through security review. In particular, it must be assured that it
|
|
* is only called from the JIT compiler, as use in other code can lead to XSS
|
|
* vulnerabilities.
|
|
*/
|
|
function newTrustedFunctionForJIT() {
|
|
var args = [];
|
|
for (var _i = 0; _i < arguments.length; _i++) {
|
|
args[_i] = arguments[_i];
|
|
}
|
|
if (!_global.trustedTypes) {
|
|
// In environments that don't support Trusted Types, fall back to the most
|
|
// straightforward implementation:
|
|
return new (Function.bind.apply(Function, __spreadArray([void 0], __read(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
|
|
var fnArgs = args.slice(0, -1).join(',');
|
|
var fnBody = args[args.length - 1];
|
|
var body = "(function anonymous(" + fnArgs + "\n) { " + fnBody + "\n})";
|
|
// 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.
|
|
var 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.bind.apply(Function, __spreadArray([void 0], __read(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 = function () { return 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)));
|
|
}
|
|
|
|
/**
|
|
* A helper class to manage the evaluation of JIT generated code.
|
|
*/
|
|
var JitEvaluator = /** @class */ (function () {
|
|
function JitEvaluator() {
|
|
}
|
|
/**
|
|
*
|
|
* @param sourceUrl The URL of the generated code.
|
|
* @param statements An array of Angular statement AST nodes to be evaluated.
|
|
* @param reflector A helper used when converting the statements to executable code.
|
|
* @param createSourceMaps If true then create a source-map for the generated code and include it
|
|
* inline as a source-map comment.
|
|
* @returns A map of all the variables in the generated code.
|
|
*/
|
|
JitEvaluator.prototype.evaluateStatements = function (sourceUrl, statements, reflector, createSourceMaps) {
|
|
var converter = new JitEmitterVisitor(reflector);
|
|
var ctx = EmitterVisitorContext.createRoot();
|
|
// Ensure generated code is in strict mode
|
|
if (statements.length > 0 && !isUseStrictStatement(statements[0])) {
|
|
statements = __spreadArray([
|
|
literal('use strict').toStmt()
|
|
], __read(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.
|
|
*/
|
|
JitEvaluator.prototype.evaluateCode = function (sourceUrl, ctx, vars, createSourceMap) {
|
|
var fnBody = "\"use strict\";" + ctx.toSource() + "\n//# sourceURL=" + sourceUrl;
|
|
var fnArgNames = [];
|
|
var fnArgValues = [];
|
|
for (var 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.
|
|
var emptyFn = newTrustedFunctionForJIT.apply(void 0, __spreadArray([], __read(fnArgNames.concat('return null;')))).toString();
|
|
var headerLines = emptyFn.slice(0, emptyFn.indexOf('return null;')).split('\n').length - 1;
|
|
fnBody += "\n" + ctx.toSourceMapGenerator(sourceUrl, headerLines).toJsComment();
|
|
}
|
|
var fn = newTrustedFunctionForJIT.apply(void 0, __spreadArray([], __read(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.
|
|
*/
|
|
JitEvaluator.prototype.executeFunction = function (fn, args) {
|
|
return fn.apply(void 0, __spreadArray([], __read(args)));
|
|
};
|
|
return JitEvaluator;
|
|
}());
|
|
/**
|
|
* An Angular AST visitor that converts AST nodes into executable JavaScript code.
|
|
*/
|
|
var JitEmitterVisitor = /** @class */ (function (_super) {
|
|
__extends(JitEmitterVisitor, _super);
|
|
function JitEmitterVisitor(reflector) {
|
|
var _this = _super.call(this) || this;
|
|
_this.reflector = reflector;
|
|
_this._evalArgNames = [];
|
|
_this._evalArgValues = [];
|
|
_this._evalExportedVars = [];
|
|
return _this;
|
|
}
|
|
JitEmitterVisitor.prototype.createReturnStmt = function (ctx) {
|
|
var stmt = new ReturnStatement(new LiteralMapExpr(this._evalExportedVars.map(function (resultVar) { return new LiteralMapEntry(resultVar, variable(resultVar), false); })));
|
|
stmt.visitStatement(this, ctx);
|
|
};
|
|
JitEmitterVisitor.prototype.getArgs = function () {
|
|
var result = {};
|
|
for (var i = 0; i < this._evalArgNames.length; i++) {
|
|
result[this._evalArgNames[i]] = this._evalArgValues[i];
|
|
}
|
|
return result;
|
|
};
|
|
JitEmitterVisitor.prototype.visitExternalExpr = function (ast, ctx) {
|
|
this._emitReferenceToExternal(ast, this.reflector.resolveExternalReference(ast.value), ctx);
|
|
return null;
|
|
};
|
|
JitEmitterVisitor.prototype.visitWrappedNodeExpr = function (ast, ctx) {
|
|
this._emitReferenceToExternal(ast, ast.node, ctx);
|
|
return null;
|
|
};
|
|
JitEmitterVisitor.prototype.visitDeclareVarStmt = function (stmt, ctx) {
|
|
if (stmt.hasModifier(exports.StmtModifier.Exported)) {
|
|
this._evalExportedVars.push(stmt.name);
|
|
}
|
|
return _super.prototype.visitDeclareVarStmt.call(this, stmt, ctx);
|
|
};
|
|
JitEmitterVisitor.prototype.visitDeclareFunctionStmt = function (stmt, ctx) {
|
|
if (stmt.hasModifier(exports.StmtModifier.Exported)) {
|
|
this._evalExportedVars.push(stmt.name);
|
|
}
|
|
return _super.prototype.visitDeclareFunctionStmt.call(this, stmt, ctx);
|
|
};
|
|
JitEmitterVisitor.prototype.visitDeclareClassStmt = function (stmt, ctx) {
|
|
if (stmt.hasModifier(exports.StmtModifier.Exported)) {
|
|
this._evalExportedVars.push(stmt.name);
|
|
}
|
|
return _super.prototype.visitDeclareClassStmt.call(this, stmt, ctx);
|
|
};
|
|
JitEmitterVisitor.prototype._emitReferenceToExternal = function (ast, value, ctx) {
|
|
var id = this._evalArgValues.indexOf(value);
|
|
if (id === -1) {
|
|
id = this._evalArgValues.length;
|
|
this._evalArgValues.push(value);
|
|
var name = identifierName({ reference: value }) || 'val';
|
|
this._evalArgNames.push("jit_" + name + "_" + id);
|
|
}
|
|
ctx.print(ast, this._evalArgNames[id]);
|
|
};
|
|
return JitEmitterVisitor;
|
|
}(AbstractJsEmitterVisitor));
|
|
function isUseStrictStatement(statement) {
|
|
return statement.isEquivalent(literal('use strict').toStmt());
|
|
}
|
|
|
|
/**
|
|
* @license
|
|
* Copyright Google LLC All Rights Reserved.
|
|
*
|
|
* Use of this source code is governed by an MIT-style license that can be
|
|
* found in the LICENSE file at https://angular.io/license
|
|
*/
|
|
function compileInjector(meta) {
|
|
var definitionMap = new DefinitionMap();
|
|
if (meta.providers !== null) {
|
|
definitionMap.set('providers', meta.providers);
|
|
}
|
|
if (meta.imports.length > 0) {
|
|
definitionMap.set('imports', literalArr(meta.imports));
|
|
}
|
|
var expression = importExpr(Identifiers.defineInjector).callFn([definitionMap.toLiteralMap()], undefined, true);
|
|
var type = createInjectorType(meta);
|
|
return { expression: expression, type: 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.
|
|
*/
|
|
var R3JitReflector = /** @class */ (function () {
|
|
function R3JitReflector(context) {
|
|
this.context = context;
|
|
}
|
|
R3JitReflector.prototype.resolveExternalReference = function (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];
|
|
};
|
|
R3JitReflector.prototype.parameters = function (typeOrFunc) {
|
|
throw new Error('Not implemented.');
|
|
};
|
|
R3JitReflector.prototype.annotations = function (typeOrFunc) {
|
|
throw new Error('Not implemented.');
|
|
};
|
|
R3JitReflector.prototype.shallowAnnotations = function (typeOrFunc) {
|
|
throw new Error('Not implemented.');
|
|
};
|
|
R3JitReflector.prototype.tryAnnotations = function (typeOrFunc) {
|
|
throw new Error('Not implemented.');
|
|
};
|
|
R3JitReflector.prototype.propMetadata = function (typeOrFunc) {
|
|
throw new Error('Not implemented.');
|
|
};
|
|
R3JitReflector.prototype.hasLifecycleHook = function (type, lcProperty) {
|
|
throw new Error('Not implemented.');
|
|
};
|
|
R3JitReflector.prototype.guards = function (typeOrFunc) {
|
|
throw new Error('Not implemented.');
|
|
};
|
|
R3JitReflector.prototype.componentModuleUrl = function (type, cmpMetadata) {
|
|
throw new Error('Not implemented.');
|
|
};
|
|
return R3JitReflector;
|
|
}());
|
|
|
|
/**
|
|
* @license
|
|
* Copyright Google LLC All Rights Reserved.
|
|
*
|
|
* Use of this source code is governed by an MIT-style license that can be
|
|
* found in the LICENSE file at https://angular.io/license
|
|
*/
|
|
/**
|
|
* Construct an `R3NgModuleDef` for the given `R3NgModuleMetadata`.
|
|
*/
|
|
function compileNgModule(meta) {
|
|
var internalType = meta.internalType, bootstrap = meta.bootstrap, declarations = meta.declarations, imports = meta.imports, exports = meta.exports, schemas = meta.schemas, containsForwardDecls = meta.containsForwardDecls, emitInline = meta.emitInline, id = meta.id;
|
|
var statements = [];
|
|
var definitionMap = new DefinitionMap();
|
|
definitionMap.set('type', internalType);
|
|
if (bootstrap.length > 0) {
|
|
definitionMap.set('bootstrap', refsToArray(bootstrap, containsForwardDecls));
|
|
}
|
|
// If requested to emit scope information inline, pass the `declarations`, `imports` and `exports`
|
|
// to the `ɵɵdefineNgModule()` call. The JIT compilation uses this.
|
|
if (emitInline) {
|
|
if (declarations.length > 0) {
|
|
definitionMap.set('declarations', refsToArray(declarations, containsForwardDecls));
|
|
}
|
|
if (imports.length > 0) {
|
|
definitionMap.set('imports', refsToArray(imports, containsForwardDecls));
|
|
}
|
|
if (exports.length > 0) {
|
|
definitionMap.set('exports', refsToArray(exports, containsForwardDecls));
|
|
}
|
|
}
|
|
// If not emitting inline, the scope information is not passed into `ɵɵdefineNgModule` as it would
|
|
// prevent tree-shaking of the declarations, imports and exports references.
|
|
else {
|
|
var setNgModuleScopeCall = generateSetNgModuleScopeCall(meta);
|
|
if (setNgModuleScopeCall !== null) {
|
|
statements.push(setNgModuleScopeCall);
|
|
}
|
|
}
|
|
if (schemas !== null && schemas.length > 0) {
|
|
definitionMap.set('schemas', literalArr(schemas.map(function (ref) { return ref.value; })));
|
|
}
|
|
if (id !== null) {
|
|
definitionMap.set('id', id);
|
|
}
|
|
var expression = importExpr(Identifiers.defineNgModule).callFn([definitionMap.toLiteralMap()], undefined, true);
|
|
var type = createNgModuleType(meta);
|
|
return { expression: expression, type: type, statements: statements };
|
|
}
|
|
/**
|
|
* This function is used in JIT mode to generate the call to `ɵɵdefineNgModule()` from a call to
|
|
* `ɵɵngDeclareNgModule()`.
|
|
*/
|
|
function compileNgModuleDeclarationExpression(meta) {
|
|
var 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(_a) {
|
|
var moduleType = _a.type, declarations = _a.declarations, imports = _a.imports, exports = _a.exports;
|
|
return new ExpressionType(importExpr(Identifiers.NgModuleDeclaration, [
|
|
new ExpressionType(moduleType.type), tupleTypeOf(declarations), tupleTypeOf(imports),
|
|
tupleTypeOf(exports)
|
|
]));
|
|
}
|
|
/**
|
|
* Generates a function call to `ɵɵsetNgModuleScope` with all necessary information so that the
|
|
* transitive module scope can be computed during runtime in JIT mode. This call is marked pure
|
|
* such that the references to declarations, imports and exports may be elided causing these
|
|
* symbols to become tree-shakeable.
|
|
*/
|
|
function generateSetNgModuleScopeCall(meta) {
|
|
var moduleType = meta.adjacentType, declarations = meta.declarations, imports = meta.imports, exports = meta.exports, containsForwardDecls = meta.containsForwardDecls;
|
|
var 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(...)
|
|
var fnCall = new InvokeFunctionExpr(
|
|
/* fn */ importExpr(Identifiers.setNgModuleScope),
|
|
/* args */ [moduleType, scopeMap.toLiteralMap()]);
|
|
// (ngJitMode guard) && setNgModuleScope(...)
|
|
var guardedCall = jitOnlyGuardedExpression(fnCall);
|
|
// function() { (ngJitMode guard) && setNgModuleScope(...); }
|
|
var iife = new FunctionExpr(
|
|
/* params */ [],
|
|
/* statements */ [guardedCall.toStmt()]);
|
|
// (function() { (ngJitMode guard) && setNgModuleScope(...); })()
|
|
var iifeCall = new InvokeFunctionExpr(
|
|
/* fn */ iife,
|
|
/* args */ []);
|
|
return iifeCall.toStmt();
|
|
}
|
|
function tupleTypeOf(exp) {
|
|
var types = exp.map(function (ref) { return typeofExpr(ref.type); });
|
|
return exp.length > 0 ? expressionType(literalArr(types)) : NONE_TYPE;
|
|
}
|
|
|
|
/**
|
|
* @license
|
|
* Copyright Google LLC All Rights Reserved.
|
|
*
|
|
* Use of this source code is governed by an MIT-style license that can be
|
|
* found in the LICENSE file at https://angular.io/license
|
|
*/
|
|
function compilePipeFromMetadata(metadata) {
|
|
var definitionMapValues = [];
|
|
// e.g. `name: 'myPipe'`
|
|
definitionMapValues.push({ key: 'name', value: literal(metadata.pipeName), quoted: false });
|
|
// e.g. `type: MyPipe`
|
|
definitionMapValues.push({ key: 'type', value: metadata.type.value, quoted: false });
|
|
// e.g. `pure: true`
|
|
definitionMapValues.push({ key: 'pure', value: literal(metadata.pure), quoted: false });
|
|
var expression = importExpr(Identifiers.definePipe).callFn([literalMap(definitionMapValues)], undefined, true);
|
|
var type = createPipeType(metadata);
|
|
return { expression: expression, type: type, statements: [] };
|
|
}
|
|
function createPipeType(metadata) {
|
|
return new ExpressionType(importExpr(Identifiers.PipeDeclaration, [
|
|
typeWithParameters(metadata.type.type, metadata.typeArgumentCount),
|
|
new ExpressionType(new LiteralExpr(metadata.pipeName)),
|
|
]));
|
|
}
|
|
|
|
/**
|
|
* @license
|
|
* Copyright Google LLC All Rights Reserved.
|
|
*
|
|
* Use of this source code is governed by an MIT-style license that can be
|
|
* found in the LICENSE file at https://angular.io/license
|
|
*/
|
|
var ParserError = /** @class */ (function () {
|
|
function ParserError(message, input, errLocation, ctxLocation) {
|
|
this.input = input;
|
|
this.errLocation = errLocation;
|
|
this.ctxLocation = ctxLocation;
|
|
this.message = "Parser Error: " + message + " " + errLocation + " [" + input + "] in " + ctxLocation;
|
|
}
|
|
return ParserError;
|
|
}());
|
|
var ParseSpan = /** @class */ (function () {
|
|
function ParseSpan(start, end) {
|
|
this.start = start;
|
|
this.end = end;
|
|
}
|
|
ParseSpan.prototype.toAbsolute = function (absoluteOffset) {
|
|
return new AbsoluteSourceSpan(absoluteOffset + this.start, absoluteOffset + this.end);
|
|
};
|
|
return ParseSpan;
|
|
}());
|
|
var AST = /** @class */ (function () {
|
|
function AST(span,
|
|
/**
|
|
* Absolute location of the expression AST in a source code file.
|
|
*/
|
|
sourceSpan) {
|
|
this.span = span;
|
|
this.sourceSpan = sourceSpan;
|
|
}
|
|
AST.prototype.toString = function () {
|
|
return 'AST';
|
|
};
|
|
return AST;
|
|
}());
|
|
var ASTWithName = /** @class */ (function (_super) {
|
|
__extends(ASTWithName, _super);
|
|
function ASTWithName(span, sourceSpan, nameSpan) {
|
|
var _this = _super.call(this, span, sourceSpan) || this;
|
|
_this.nameSpan = nameSpan;
|
|
return _this;
|
|
}
|
|
return ASTWithName;
|
|
}(AST));
|
|
/**
|
|
* Represents a quoted expression of the form:
|
|
*
|
|
* quote = prefix `:` uninterpretedExpression
|
|
* prefix = identifier
|
|
* uninterpretedExpression = arbitrary string
|
|
*
|
|
* A quoted expression is meant to be pre-processed by an AST transformer that
|
|
* converts it into another AST that no longer contains quoted expressions.
|
|
* It is meant to allow third-party developers to extend Angular template
|
|
* expression language. The `uninterpretedExpression` part of the quote is
|
|
* therefore not interpreted by the Angular's own expression parser.
|
|
*/
|
|
var Quote = /** @class */ (function (_super) {
|
|
__extends(Quote, _super);
|
|
function Quote(span, sourceSpan, prefix, uninterpretedExpression, location) {
|
|
var _this = _super.call(this, span, sourceSpan) || this;
|
|
_this.prefix = prefix;
|
|
_this.uninterpretedExpression = uninterpretedExpression;
|
|
_this.location = location;
|
|
return _this;
|
|
}
|
|
Quote.prototype.visit = function (visitor, context) {
|
|
if (context === void 0) { context = null; }
|
|
return visitor.visitQuote(this, context);
|
|
};
|
|
Quote.prototype.toString = function () {
|
|
return 'Quote';
|
|
};
|
|
return Quote;
|
|
}(AST));
|
|
var EmptyExpr = /** @class */ (function (_super) {
|
|
__extends(EmptyExpr, _super);
|
|
function EmptyExpr() {
|
|
return _super !== null && _super.apply(this, arguments) || this;
|
|
}
|
|
EmptyExpr.prototype.visit = function (visitor, context) {
|
|
if (context === void 0) { context = null; }
|
|
// do nothing
|
|
};
|
|
return EmptyExpr;
|
|
}(AST));
|
|
var ImplicitReceiver = /** @class */ (function (_super) {
|
|
__extends(ImplicitReceiver, _super);
|
|
function ImplicitReceiver() {
|
|
return _super !== null && _super.apply(this, arguments) || this;
|
|
}
|
|
ImplicitReceiver.prototype.visit = function (visitor, context) {
|
|
if (context === void 0) { context = null; }
|
|
return visitor.visitImplicitReceiver(this, context);
|
|
};
|
|
return ImplicitReceiver;
|
|
}(AST));
|
|
/**
|
|
* 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.
|
|
*/
|
|
var ThisReceiver = /** @class */ (function (_super) {
|
|
__extends(ThisReceiver, _super);
|
|
function ThisReceiver() {
|
|
return _super !== null && _super.apply(this, arguments) || this;
|
|
}
|
|
ThisReceiver.prototype.visit = function (visitor, context) {
|
|
if (context === void 0) { context = null; }
|
|
var _a;
|
|
return (_a = visitor.visitThisReceiver) === null || _a === void 0 ? void 0 : _a.call(visitor, this, context);
|
|
};
|
|
return ThisReceiver;
|
|
}(ImplicitReceiver));
|
|
/**
|
|
* Multiple expressions separated by a semicolon.
|
|
*/
|
|
var Chain = /** @class */ (function (_super) {
|
|
__extends(Chain, _super);
|
|
function Chain(span, sourceSpan, expressions) {
|
|
var _this = _super.call(this, span, sourceSpan) || this;
|
|
_this.expressions = expressions;
|
|
return _this;
|
|
}
|
|
Chain.prototype.visit = function (visitor, context) {
|
|
if (context === void 0) { context = null; }
|
|
return visitor.visitChain(this, context);
|
|
};
|
|
return Chain;
|
|
}(AST));
|
|
var Conditional = /** @class */ (function (_super) {
|
|
__extends(Conditional, _super);
|
|
function Conditional(span, sourceSpan, condition, trueExp, falseExp) {
|
|
var _this = _super.call(this, span, sourceSpan) || this;
|
|
_this.condition = condition;
|
|
_this.trueExp = trueExp;
|
|
_this.falseExp = falseExp;
|
|
return _this;
|
|
}
|
|
Conditional.prototype.visit = function (visitor, context) {
|
|
if (context === void 0) { context = null; }
|
|
return visitor.visitConditional(this, context);
|
|
};
|
|
return Conditional;
|
|
}(AST));
|
|
var PropertyRead = /** @class */ (function (_super) {
|
|
__extends(PropertyRead, _super);
|
|
function PropertyRead(span, sourceSpan, nameSpan, receiver, name) {
|
|
var _this = _super.call(this, span, sourceSpan, nameSpan) || this;
|
|
_this.receiver = receiver;
|
|
_this.name = name;
|
|
return _this;
|
|
}
|
|
PropertyRead.prototype.visit = function (visitor, context) {
|
|
if (context === void 0) { context = null; }
|
|
return visitor.visitPropertyRead(this, context);
|
|
};
|
|
return PropertyRead;
|
|
}(ASTWithName));
|
|
var PropertyWrite = /** @class */ (function (_super) {
|
|
__extends(PropertyWrite, _super);
|
|
function PropertyWrite(span, sourceSpan, nameSpan, receiver, name, value) {
|
|
var _this = _super.call(this, span, sourceSpan, nameSpan) || this;
|
|
_this.receiver = receiver;
|
|
_this.name = name;
|
|
_this.value = value;
|
|
return _this;
|
|
}
|
|
PropertyWrite.prototype.visit = function (visitor, context) {
|
|
if (context === void 0) { context = null; }
|
|
return visitor.visitPropertyWrite(this, context);
|
|
};
|
|
return PropertyWrite;
|
|
}(ASTWithName));
|
|
var SafePropertyRead = /** @class */ (function (_super) {
|
|
__extends(SafePropertyRead, _super);
|
|
function SafePropertyRead(span, sourceSpan, nameSpan, receiver, name) {
|
|
var _this = _super.call(this, span, sourceSpan, nameSpan) || this;
|
|
_this.receiver = receiver;
|
|
_this.name = name;
|
|
return _this;
|
|
}
|
|
SafePropertyRead.prototype.visit = function (visitor, context) {
|
|
if (context === void 0) { context = null; }
|
|
return visitor.visitSafePropertyRead(this, context);
|
|
};
|
|
return SafePropertyRead;
|
|
}(ASTWithName));
|
|
var KeyedRead = /** @class */ (function (_super) {
|
|
__extends(KeyedRead, _super);
|
|
function KeyedRead(span, sourceSpan, receiver, key) {
|
|
var _this = _super.call(this, span, sourceSpan) || this;
|
|
_this.receiver = receiver;
|
|
_this.key = key;
|
|
return _this;
|
|
}
|
|
KeyedRead.prototype.visit = function (visitor, context) {
|
|
if (context === void 0) { context = null; }
|
|
return visitor.visitKeyedRead(this, context);
|
|
};
|
|
return KeyedRead;
|
|
}(AST));
|
|
var SafeKeyedRead = /** @class */ (function (_super) {
|
|
__extends(SafeKeyedRead, _super);
|
|
function SafeKeyedRead(span, sourceSpan, receiver, key) {
|
|
var _this = _super.call(this, span, sourceSpan) || this;
|
|
_this.receiver = receiver;
|
|
_this.key = key;
|
|
return _this;
|
|
}
|
|
SafeKeyedRead.prototype.visit = function (visitor, context) {
|
|
if (context === void 0) { context = null; }
|
|
return visitor.visitSafeKeyedRead(this, context);
|
|
};
|
|
return SafeKeyedRead;
|
|
}(AST));
|
|
var KeyedWrite = /** @class */ (function (_super) {
|
|
__extends(KeyedWrite, _super);
|
|
function KeyedWrite(span, sourceSpan, receiver, key, value) {
|
|
var _this = _super.call(this, span, sourceSpan) || this;
|
|
_this.receiver = receiver;
|
|
_this.key = key;
|
|
_this.value = value;
|
|
return _this;
|
|
}
|
|
KeyedWrite.prototype.visit = function (visitor, context) {
|
|
if (context === void 0) { context = null; }
|
|
return visitor.visitKeyedWrite(this, context);
|
|
};
|
|
return KeyedWrite;
|
|
}(AST));
|
|
var BindingPipe = /** @class */ (function (_super) {
|
|
__extends(BindingPipe, _super);
|
|
function BindingPipe(span, sourceSpan, exp, name, args, nameSpan) {
|
|
var _this = _super.call(this, span, sourceSpan, nameSpan) || this;
|
|
_this.exp = exp;
|
|
_this.name = name;
|
|
_this.args = args;
|
|
return _this;
|
|
}
|
|
BindingPipe.prototype.visit = function (visitor, context) {
|
|
if (context === void 0) { context = null; }
|
|
return visitor.visitPipe(this, context);
|
|
};
|
|
return BindingPipe;
|
|
}(ASTWithName));
|
|
var LiteralPrimitive = /** @class */ (function (_super) {
|
|
__extends(LiteralPrimitive, _super);
|
|
function LiteralPrimitive(span, sourceSpan, value) {
|
|
var _this = _super.call(this, span, sourceSpan) || this;
|
|
_this.value = value;
|
|
return _this;
|
|
}
|
|
LiteralPrimitive.prototype.visit = function (visitor, context) {
|
|
if (context === void 0) { context = null; }
|
|
return visitor.visitLiteralPrimitive(this, context);
|
|
};
|
|
return LiteralPrimitive;
|
|
}(AST));
|
|
var LiteralArray = /** @class */ (function (_super) {
|
|
__extends(LiteralArray, _super);
|
|
function LiteralArray(span, sourceSpan, expressions) {
|
|
var _this = _super.call(this, span, sourceSpan) || this;
|
|
_this.expressions = expressions;
|
|
return _this;
|
|
}
|
|
LiteralArray.prototype.visit = function (visitor, context) {
|
|
if (context === void 0) { context = null; }
|
|
return visitor.visitLiteralArray(this, context);
|
|
};
|
|
return LiteralArray;
|
|
}(AST));
|
|
var LiteralMap = /** @class */ (function (_super) {
|
|
__extends(LiteralMap, _super);
|
|
function LiteralMap(span, sourceSpan, keys, values) {
|
|
var _this = _super.call(this, span, sourceSpan) || this;
|
|
_this.keys = keys;
|
|
_this.values = values;
|
|
return _this;
|
|
}
|
|
LiteralMap.prototype.visit = function (visitor, context) {
|
|
if (context === void 0) { context = null; }
|
|
return visitor.visitLiteralMap(this, context);
|
|
};
|
|
return LiteralMap;
|
|
}(AST));
|
|
var Interpolation = /** @class */ (function (_super) {
|
|
__extends(Interpolation, _super);
|
|
function Interpolation(span, sourceSpan, strings, expressions) {
|
|
var _this = _super.call(this, span, sourceSpan) || this;
|
|
_this.strings = strings;
|
|
_this.expressions = expressions;
|
|
return _this;
|
|
}
|
|
Interpolation.prototype.visit = function (visitor, context) {
|
|
if (context === void 0) { context = null; }
|
|
return visitor.visitInterpolation(this, context);
|
|
};
|
|
return Interpolation;
|
|
}(AST));
|
|
var Binary = /** @class */ (function (_super) {
|
|
__extends(Binary, _super);
|
|
function Binary(span, sourceSpan, operation, left, right) {
|
|
var _this = _super.call(this, span, sourceSpan) || this;
|
|
_this.operation = operation;
|
|
_this.left = left;
|
|
_this.right = right;
|
|
return _this;
|
|
}
|
|
Binary.prototype.visit = function (visitor, context) {
|
|
if (context === void 0) { context = null; }
|
|
return visitor.visitBinary(this, context);
|
|
};
|
|
return Binary;
|
|
}(AST));
|
|
/**
|
|
* 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.
|
|
*/
|
|
var Unary = /** @class */ (function (_super) {
|
|
__extends(Unary, _super);
|
|
/**
|
|
* During the deprecation period this constructor is private, to avoid consumers from creating
|
|
* a `Unary` with the fallback properties for `Binary`.
|
|
*/
|
|
function Unary(span, sourceSpan, operator, expr, binaryOp, binaryLeft, binaryRight) {
|
|
var _this = _super.call(this, span, sourceSpan, binaryOp, binaryLeft, binaryRight) || this;
|
|
_this.operator = operator;
|
|
_this.expr = expr;
|
|
return _this;
|
|
}
|
|
/**
|
|
* Creates a unary minus expression "-x", represented as `Binary` using "0 - x".
|
|
*/
|
|
Unary.createMinus = function (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".
|
|
*/
|
|
Unary.createPlus = function (span, sourceSpan, expr) {
|
|
return new Unary(span, sourceSpan, '+', expr, '-', expr, new LiteralPrimitive(span, sourceSpan, 0));
|
|
};
|
|
Unary.prototype.visit = function (visitor, context) {
|
|
if (context === void 0) { context = null; }
|
|
if (visitor.visitUnary !== undefined) {
|
|
return visitor.visitUnary(this, context);
|
|
}
|
|
return visitor.visitBinary(this, context);
|
|
};
|
|
return Unary;
|
|
}(Binary));
|
|
var PrefixNot = /** @class */ (function (_super) {
|
|
__extends(PrefixNot, _super);
|
|
function PrefixNot(span, sourceSpan, expression) {
|
|
var _this = _super.call(this, span, sourceSpan) || this;
|
|
_this.expression = expression;
|
|
return _this;
|
|
}
|
|
PrefixNot.prototype.visit = function (visitor, context) {
|
|
if (context === void 0) { context = null; }
|
|
return visitor.visitPrefixNot(this, context);
|
|
};
|
|
return PrefixNot;
|
|
}(AST));
|
|
var NonNullAssert = /** @class */ (function (_super) {
|
|
__extends(NonNullAssert, _super);
|
|
function NonNullAssert(span, sourceSpan, expression) {
|
|
var _this = _super.call(this, span, sourceSpan) || this;
|
|
_this.expression = expression;
|
|
return _this;
|
|
}
|
|
NonNullAssert.prototype.visit = function (visitor, context) {
|
|
if (context === void 0) { context = null; }
|
|
return visitor.visitNonNullAssert(this, context);
|
|
};
|
|
return NonNullAssert;
|
|
}(AST));
|
|
var MethodCall = /** @class */ (function (_super) {
|
|
__extends(MethodCall, _super);
|
|
function MethodCall(span, sourceSpan, nameSpan, receiver, name, args, argumentSpan) {
|
|
var _this = _super.call(this, span, sourceSpan, nameSpan) || this;
|
|
_this.receiver = receiver;
|
|
_this.name = name;
|
|
_this.args = args;
|
|
_this.argumentSpan = argumentSpan;
|
|
return _this;
|
|
}
|
|
MethodCall.prototype.visit = function (visitor, context) {
|
|
if (context === void 0) { context = null; }
|
|
return visitor.visitMethodCall(this, context);
|
|
};
|
|
return MethodCall;
|
|
}(ASTWithName));
|
|
var SafeMethodCall = /** @class */ (function (_super) {
|
|
__extends(SafeMethodCall, _super);
|
|
function SafeMethodCall(span, sourceSpan, nameSpan, receiver, name, args, argumentSpan) {
|
|
var _this = _super.call(this, span, sourceSpan, nameSpan) || this;
|
|
_this.receiver = receiver;
|
|
_this.name = name;
|
|
_this.args = args;
|
|
_this.argumentSpan = argumentSpan;
|
|
return _this;
|
|
}
|
|
SafeMethodCall.prototype.visit = function (visitor, context) {
|
|
if (context === void 0) { context = null; }
|
|
return visitor.visitSafeMethodCall(this, context);
|
|
};
|
|
return SafeMethodCall;
|
|
}(ASTWithName));
|
|
var FunctionCall = /** @class */ (function (_super) {
|
|
__extends(FunctionCall, _super);
|
|
function FunctionCall(span, sourceSpan, target, args) {
|
|
var _this = _super.call(this, span, sourceSpan) || this;
|
|
_this.target = target;
|
|
_this.args = args;
|
|
return _this;
|
|
}
|
|
FunctionCall.prototype.visit = function (visitor, context) {
|
|
if (context === void 0) { context = null; }
|
|
return visitor.visitFunctionCall(this, context);
|
|
};
|
|
return FunctionCall;
|
|
}(AST));
|
|
/**
|
|
* 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.
|
|
*/
|
|
var AbsoluteSourceSpan = /** @class */ (function () {
|
|
function AbsoluteSourceSpan(start, end) {
|
|
this.start = start;
|
|
this.end = end;
|
|
}
|
|
return AbsoluteSourceSpan;
|
|
}());
|
|
var ASTWithSource = /** @class */ (function (_super) {
|
|
__extends(ASTWithSource, _super);
|
|
function ASTWithSource(ast, source, location, absoluteOffset, errors) {
|
|
var _this = _super.call(this, new ParseSpan(0, source === null ? 0 : source.length), new AbsoluteSourceSpan(absoluteOffset, source === null ? absoluteOffset : absoluteOffset + source.length)) || this;
|
|
_this.ast = ast;
|
|
_this.source = source;
|
|
_this.location = location;
|
|
_this.errors = errors;
|
|
return _this;
|
|
}
|
|
ASTWithSource.prototype.visit = function (visitor, context) {
|
|
if (context === void 0) { context = null; }
|
|
if (visitor.visitASTWithSource) {
|
|
return visitor.visitASTWithSource(this, context);
|
|
}
|
|
return this.ast.visit(visitor, context);
|
|
};
|
|
ASTWithSource.prototype.toString = function () {
|
|
return this.source + " in " + this.location;
|
|
};
|
|
return ASTWithSource;
|
|
}(AST));
|
|
var VariableBinding = /** @class */ (function () {
|
|
/**
|
|
* @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.
|
|
*/
|
|
function VariableBinding(sourceSpan, key, value) {
|
|
this.sourceSpan = sourceSpan;
|
|
this.key = key;
|
|
this.value = value;
|
|
}
|
|
return VariableBinding;
|
|
}());
|
|
var ExpressionBinding = /** @class */ (function () {
|
|
/**
|
|
* @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.
|
|
*/
|
|
function ExpressionBinding(sourceSpan, key, value) {
|
|
this.sourceSpan = sourceSpan;
|
|
this.key = key;
|
|
this.value = value;
|
|
}
|
|
return ExpressionBinding;
|
|
}());
|
|
var RecursiveAstVisitor$1 = /** @class */ (function () {
|
|
function RecursiveAstVisitor() {
|
|
}
|
|
RecursiveAstVisitor.prototype.visit = function (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);
|
|
};
|
|
RecursiveAstVisitor.prototype.visitUnary = function (ast, context) {
|
|
this.visit(ast.expr, context);
|
|
};
|
|
RecursiveAstVisitor.prototype.visitBinary = function (ast, context) {
|
|
this.visit(ast.left, context);
|
|
this.visit(ast.right, context);
|
|
};
|
|
RecursiveAstVisitor.prototype.visitChain = function (ast, context) {
|
|
this.visitAll(ast.expressions, context);
|
|
};
|
|
RecursiveAstVisitor.prototype.visitConditional = function (ast, context) {
|
|
this.visit(ast.condition, context);
|
|
this.visit(ast.trueExp, context);
|
|
this.visit(ast.falseExp, context);
|
|
};
|
|
RecursiveAstVisitor.prototype.visitPipe = function (ast, context) {
|
|
this.visit(ast.exp, context);
|
|
this.visitAll(ast.args, context);
|
|
};
|
|
RecursiveAstVisitor.prototype.visitFunctionCall = function (ast, context) {
|
|
if (ast.target) {
|
|
this.visit(ast.target, context);
|
|
}
|
|
this.visitAll(ast.args, context);
|
|
};
|
|
RecursiveAstVisitor.prototype.visitImplicitReceiver = function (ast, context) { };
|
|
RecursiveAstVisitor.prototype.visitThisReceiver = function (ast, context) { };
|
|
RecursiveAstVisitor.prototype.visitInterpolation = function (ast, context) {
|
|
this.visitAll(ast.expressions, context);
|
|
};
|
|
RecursiveAstVisitor.prototype.visitKeyedRead = function (ast, context) {
|
|
this.visit(ast.receiver, context);
|
|
this.visit(ast.key, context);
|
|
};
|
|
RecursiveAstVisitor.prototype.visitKeyedWrite = function (ast, context) {
|
|
this.visit(ast.receiver, context);
|
|
this.visit(ast.key, context);
|
|
this.visit(ast.value, context);
|
|
};
|
|
RecursiveAstVisitor.prototype.visitLiteralArray = function (ast, context) {
|
|
this.visitAll(ast.expressions, context);
|
|
};
|
|
RecursiveAstVisitor.prototype.visitLiteralMap = function (ast, context) {
|
|
this.visitAll(ast.values, context);
|
|
};
|
|
RecursiveAstVisitor.prototype.visitLiteralPrimitive = function (ast, context) { };
|
|
RecursiveAstVisitor.prototype.visitMethodCall = function (ast, context) {
|
|
this.visit(ast.receiver, context);
|
|
this.visitAll(ast.args, context);
|
|
};
|
|
RecursiveAstVisitor.prototype.visitPrefixNot = function (ast, context) {
|
|
this.visit(ast.expression, context);
|
|
};
|
|
RecursiveAstVisitor.prototype.visitNonNullAssert = function (ast, context) {
|
|
this.visit(ast.expression, context);
|
|
};
|
|
RecursiveAstVisitor.prototype.visitPropertyRead = function (ast, context) {
|
|
this.visit(ast.receiver, context);
|
|
};
|
|
RecursiveAstVisitor.prototype.visitPropertyWrite = function (ast, context) {
|
|
this.visit(ast.receiver, context);
|
|
this.visit(ast.value, context);
|
|
};
|
|
RecursiveAstVisitor.prototype.visitSafePropertyRead = function (ast, context) {
|
|
this.visit(ast.receiver, context);
|
|
};
|
|
RecursiveAstVisitor.prototype.visitSafeMethodCall = function (ast, context) {
|
|
this.visit(ast.receiver, context);
|
|
this.visitAll(ast.args, context);
|
|
};
|
|
RecursiveAstVisitor.prototype.visitSafeKeyedRead = function (ast, context) {
|
|
this.visit(ast.receiver, context);
|
|
this.visit(ast.key, context);
|
|
};
|
|
RecursiveAstVisitor.prototype.visitQuote = function (ast, context) { };
|
|
// This is not part of the AstVisitor interface, just a helper method
|
|
RecursiveAstVisitor.prototype.visitAll = function (asts, context) {
|
|
var e_1, _b;
|
|
try {
|
|
for (var asts_1 = __values(asts), asts_1_1 = asts_1.next(); !asts_1_1.done; asts_1_1 = asts_1.next()) {
|
|
var ast = asts_1_1.value;
|
|
this.visit(ast, context);
|
|
}
|
|
}
|
|
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
finally {
|
|
try {
|
|
if (asts_1_1 && !asts_1_1.done && (_b = asts_1.return)) _b.call(asts_1);
|
|
}
|
|
finally { if (e_1) throw e_1.error; }
|
|
}
|
|
};
|
|
return RecursiveAstVisitor;
|
|
}());
|
|
var AstTransformer$1 = /** @class */ (function () {
|
|
function AstTransformer() {
|
|
}
|
|
AstTransformer.prototype.visitImplicitReceiver = function (ast, context) {
|
|
return ast;
|
|
};
|
|
AstTransformer.prototype.visitThisReceiver = function (ast, context) {
|
|
return ast;
|
|
};
|
|
AstTransformer.prototype.visitInterpolation = function (ast, context) {
|
|
return new Interpolation(ast.span, ast.sourceSpan, ast.strings, this.visitAll(ast.expressions));
|
|
};
|
|
AstTransformer.prototype.visitLiteralPrimitive = function (ast, context) {
|
|
return new LiteralPrimitive(ast.span, ast.sourceSpan, ast.value);
|
|
};
|
|
AstTransformer.prototype.visitPropertyRead = function (ast, context) {
|
|
return new PropertyRead(ast.span, ast.sourceSpan, ast.nameSpan, ast.receiver.visit(this), ast.name);
|
|
};
|
|
AstTransformer.prototype.visitPropertyWrite = function (ast, context) {
|
|
return new PropertyWrite(ast.span, ast.sourceSpan, ast.nameSpan, ast.receiver.visit(this), ast.name, ast.value.visit(this));
|
|
};
|
|
AstTransformer.prototype.visitSafePropertyRead = function (ast, context) {
|
|
return new SafePropertyRead(ast.span, ast.sourceSpan, ast.nameSpan, ast.receiver.visit(this), ast.name);
|
|
};
|
|
AstTransformer.prototype.visitMethodCall = function (ast, context) {
|
|
return new MethodCall(ast.span, ast.sourceSpan, ast.nameSpan, ast.receiver.visit(this), ast.name, this.visitAll(ast.args), ast.argumentSpan);
|
|
};
|
|
AstTransformer.prototype.visitSafeMethodCall = function (ast, context) {
|
|
return new SafeMethodCall(ast.span, ast.sourceSpan, ast.nameSpan, ast.receiver.visit(this), ast.name, this.visitAll(ast.args), ast.argumentSpan);
|
|
};
|
|
AstTransformer.prototype.visitFunctionCall = function (ast, context) {
|
|
return new FunctionCall(ast.span, ast.sourceSpan, ast.target.visit(this), this.visitAll(ast.args));
|
|
};
|
|
AstTransformer.prototype.visitLiteralArray = function (ast, context) {
|
|
return new LiteralArray(ast.span, ast.sourceSpan, this.visitAll(ast.expressions));
|
|
};
|
|
AstTransformer.prototype.visitLiteralMap = function (ast, context) {
|
|
return new LiteralMap(ast.span, ast.sourceSpan, ast.keys, this.visitAll(ast.values));
|
|
};
|
|
AstTransformer.prototype.visitUnary = function (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);
|
|
}
|
|
};
|
|
AstTransformer.prototype.visitBinary = function (ast, context) {
|
|
return new Binary(ast.span, ast.sourceSpan, ast.operation, ast.left.visit(this), ast.right.visit(this));
|
|
};
|
|
AstTransformer.prototype.visitPrefixNot = function (ast, context) {
|
|
return new PrefixNot(ast.span, ast.sourceSpan, ast.expression.visit(this));
|
|
};
|
|
AstTransformer.prototype.visitNonNullAssert = function (ast, context) {
|
|
return new NonNullAssert(ast.span, ast.sourceSpan, ast.expression.visit(this));
|
|
};
|
|
AstTransformer.prototype.visitConditional = function (ast, context) {
|
|
return new Conditional(ast.span, ast.sourceSpan, ast.condition.visit(this), ast.trueExp.visit(this), ast.falseExp.visit(this));
|
|
};
|
|
AstTransformer.prototype.visitPipe = function (ast, context) {
|
|
return new BindingPipe(ast.span, ast.sourceSpan, ast.exp.visit(this), ast.name, this.visitAll(ast.args), ast.nameSpan);
|
|
};
|
|
AstTransformer.prototype.visitKeyedRead = function (ast, context) {
|
|
return new KeyedRead(ast.span, ast.sourceSpan, ast.receiver.visit(this), ast.key.visit(this));
|
|
};
|
|
AstTransformer.prototype.visitKeyedWrite = function (ast, context) {
|
|
return new KeyedWrite(ast.span, ast.sourceSpan, ast.receiver.visit(this), ast.key.visit(this), ast.value.visit(this));
|
|
};
|
|
AstTransformer.prototype.visitAll = function (asts) {
|
|
var res = [];
|
|
for (var i = 0; i < asts.length; ++i) {
|
|
res[i] = asts[i].visit(this);
|
|
}
|
|
return res;
|
|
};
|
|
AstTransformer.prototype.visitChain = function (ast, context) {
|
|
return new Chain(ast.span, ast.sourceSpan, this.visitAll(ast.expressions));
|
|
};
|
|
AstTransformer.prototype.visitQuote = function (ast, context) {
|
|
return new Quote(ast.span, ast.sourceSpan, ast.prefix, ast.uninterpretedExpression, ast.location);
|
|
};
|
|
AstTransformer.prototype.visitSafeKeyedRead = function (ast, context) {
|
|
return new SafeKeyedRead(ast.span, ast.sourceSpan, ast.receiver.visit(this), ast.key.visit(this));
|
|
};
|
|
return AstTransformer;
|
|
}());
|
|
// A transformer that only creates new nodes if the transformer makes a change or
|
|
// a change is made a child node.
|
|
var AstMemoryEfficientTransformer = /** @class */ (function () {
|
|
function AstMemoryEfficientTransformer() {
|
|
}
|
|
AstMemoryEfficientTransformer.prototype.visitImplicitReceiver = function (ast, context) {
|
|
return ast;
|
|
};
|
|
AstMemoryEfficientTransformer.prototype.visitThisReceiver = function (ast, context) {
|
|
return ast;
|
|
};
|
|
AstMemoryEfficientTransformer.prototype.visitInterpolation = function (ast, context) {
|
|
var expressions = this.visitAll(ast.expressions);
|
|
if (expressions !== ast.expressions)
|
|
return new Interpolation(ast.span, ast.sourceSpan, ast.strings, expressions);
|
|
return ast;
|
|
};
|
|
AstMemoryEfficientTransformer.prototype.visitLiteralPrimitive = function (ast, context) {
|
|
return ast;
|
|
};
|
|
AstMemoryEfficientTransformer.prototype.visitPropertyRead = function (ast, context) {
|
|
var receiver = ast.receiver.visit(this);
|
|
if (receiver !== ast.receiver) {
|
|
return new PropertyRead(ast.span, ast.sourceSpan, ast.nameSpan, receiver, ast.name);
|
|
}
|
|
return ast;
|
|
};
|
|
AstMemoryEfficientTransformer.prototype.visitPropertyWrite = function (ast, context) {
|
|
var receiver = ast.receiver.visit(this);
|
|
var 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;
|
|
};
|
|
AstMemoryEfficientTransformer.prototype.visitSafePropertyRead = function (ast, context) {
|
|
var receiver = ast.receiver.visit(this);
|
|
if (receiver !== ast.receiver) {
|
|
return new SafePropertyRead(ast.span, ast.sourceSpan, ast.nameSpan, receiver, ast.name);
|
|
}
|
|
return ast;
|
|
};
|
|
AstMemoryEfficientTransformer.prototype.visitMethodCall = function (ast, context) {
|
|
var receiver = ast.receiver.visit(this);
|
|
var args = this.visitAll(ast.args);
|
|
if (receiver !== ast.receiver || args !== ast.args) {
|
|
return new MethodCall(ast.span, ast.sourceSpan, ast.nameSpan, receiver, ast.name, args, ast.argumentSpan);
|
|
}
|
|
return ast;
|
|
};
|
|
AstMemoryEfficientTransformer.prototype.visitSafeMethodCall = function (ast, context) {
|
|
var receiver = ast.receiver.visit(this);
|
|
var args = this.visitAll(ast.args);
|
|
if (receiver !== ast.receiver || args !== ast.args) {
|
|
return new SafeMethodCall(ast.span, ast.sourceSpan, ast.nameSpan, receiver, ast.name, args, ast.argumentSpan);
|
|
}
|
|
return ast;
|
|
};
|
|
AstMemoryEfficientTransformer.prototype.visitFunctionCall = function (ast, context) {
|
|
var target = ast.target && ast.target.visit(this);
|
|
var args = this.visitAll(ast.args);
|
|
if (target !== ast.target || args !== ast.args) {
|
|
return new FunctionCall(ast.span, ast.sourceSpan, target, args);
|
|
}
|
|
return ast;
|
|
};
|
|
AstMemoryEfficientTransformer.prototype.visitLiteralArray = function (ast, context) {
|
|
var expressions = this.visitAll(ast.expressions);
|
|
if (expressions !== ast.expressions) {
|
|
return new LiteralArray(ast.span, ast.sourceSpan, expressions);
|
|
}
|
|
return ast;
|
|
};
|
|
AstMemoryEfficientTransformer.prototype.visitLiteralMap = function (ast, context) {
|
|
var values = this.visitAll(ast.values);
|
|
if (values !== ast.values) {
|
|
return new LiteralMap(ast.span, ast.sourceSpan, ast.keys, values);
|
|
}
|
|
return ast;
|
|
};
|
|
AstMemoryEfficientTransformer.prototype.visitUnary = function (ast, context) {
|
|
var 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;
|
|
};
|
|
AstMemoryEfficientTransformer.prototype.visitBinary = function (ast, context) {
|
|
var left = ast.left.visit(this);
|
|
var 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;
|
|
};
|
|
AstMemoryEfficientTransformer.prototype.visitPrefixNot = function (ast, context) {
|
|
var expression = ast.expression.visit(this);
|
|
if (expression !== ast.expression) {
|
|
return new PrefixNot(ast.span, ast.sourceSpan, expression);
|
|
}
|
|
return ast;
|
|
};
|
|
AstMemoryEfficientTransformer.prototype.visitNonNullAssert = function (ast, context) {
|
|
var expression = ast.expression.visit(this);
|
|
if (expression !== ast.expression) {
|
|
return new NonNullAssert(ast.span, ast.sourceSpan, expression);
|
|
}
|
|
return ast;
|
|
};
|
|
AstMemoryEfficientTransformer.prototype.visitConditional = function (ast, context) {
|
|
var condition = ast.condition.visit(this);
|
|
var trueExp = ast.trueExp.visit(this);
|
|
var 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;
|
|
};
|
|
AstMemoryEfficientTransformer.prototype.visitPipe = function (ast, context) {
|
|
var exp = ast.exp.visit(this);
|
|
var 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;
|
|
};
|
|
AstMemoryEfficientTransformer.prototype.visitKeyedRead = function (ast, context) {
|
|
var obj = ast.receiver.visit(this);
|
|
var key = ast.key.visit(this);
|
|
if (obj !== ast.receiver || key !== ast.key) {
|
|
return new KeyedRead(ast.span, ast.sourceSpan, obj, key);
|
|
}
|
|
return ast;
|
|
};
|
|
AstMemoryEfficientTransformer.prototype.visitKeyedWrite = function (ast, context) {
|
|
var obj = ast.receiver.visit(this);
|
|
var key = ast.key.visit(this);
|
|
var 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;
|
|
};
|
|
AstMemoryEfficientTransformer.prototype.visitAll = function (asts) {
|
|
var res = [];
|
|
var modified = false;
|
|
for (var i = 0; i < asts.length; ++i) {
|
|
var original = asts[i];
|
|
var value = original.visit(this);
|
|
res[i] = value;
|
|
modified = modified || value !== original;
|
|
}
|
|
return modified ? res : asts;
|
|
};
|
|
AstMemoryEfficientTransformer.prototype.visitChain = function (ast, context) {
|
|
var expressions = this.visitAll(ast.expressions);
|
|
if (expressions !== ast.expressions) {
|
|
return new Chain(ast.span, ast.sourceSpan, expressions);
|
|
}
|
|
return ast;
|
|
};
|
|
AstMemoryEfficientTransformer.prototype.visitQuote = function (ast, context) {
|
|
return ast;
|
|
};
|
|
AstMemoryEfficientTransformer.prototype.visitSafeKeyedRead = function (ast, context) {
|
|
var obj = ast.receiver.visit(this);
|
|
var key = ast.key.visit(this);
|
|
if (obj !== ast.receiver || key !== ast.key) {
|
|
return new SafeKeyedRead(ast.span, ast.sourceSpan, obj, key);
|
|
}
|
|
return ast;
|
|
};
|
|
return AstMemoryEfficientTransformer;
|
|
}());
|
|
// Bindings
|
|
var ParsedProperty = /** @class */ (function () {
|
|
function ParsedProperty(name, expression, type,
|
|
// TODO(FW-2095): `keySpan` should really be required but allows `undefined` so VE does
|
|
// not need to be updated. Make `keySpan` required when VE is removed.
|
|
sourceSpan, keySpan, valueSpan) {
|
|
this.name = name;
|
|
this.expression = expression;
|
|
this.type = type;
|
|
this.sourceSpan = sourceSpan;
|
|
this.keySpan = keySpan;
|
|
this.valueSpan = valueSpan;
|
|
this.isLiteral = this.type === exports.ParsedPropertyType.LITERAL_ATTR;
|
|
this.isAnimation = this.type === exports.ParsedPropertyType.ANIMATION;
|
|
}
|
|
return ParsedProperty;
|
|
}());
|
|
(function (ParsedPropertyType) {
|
|
ParsedPropertyType[ParsedPropertyType["DEFAULT"] = 0] = "DEFAULT";
|
|
ParsedPropertyType[ParsedPropertyType["LITERAL_ATTR"] = 1] = "LITERAL_ATTR";
|
|
ParsedPropertyType[ParsedPropertyType["ANIMATION"] = 2] = "ANIMATION";
|
|
})(exports.ParsedPropertyType || (exports.ParsedPropertyType = {}));
|
|
var ParsedEvent = /** @class */ (function () {
|
|
// Regular events have a target
|
|
// Animation events have a phase
|
|
function ParsedEvent(name, targetOrPhase, type, handler, sourceSpan,
|
|
// TODO(FW-2095): keySpan should be required but was made optional to avoid changing VE
|
|
handlerSpan, keySpan) {
|
|
this.name = name;
|
|
this.targetOrPhase = targetOrPhase;
|
|
this.type = type;
|
|
this.handler = handler;
|
|
this.sourceSpan = sourceSpan;
|
|
this.handlerSpan = handlerSpan;
|
|
this.keySpan = keySpan;
|
|
}
|
|
return ParsedEvent;
|
|
}());
|
|
/**
|
|
* ParsedVariable represents a variable declaration in a microsyntax expression.
|
|
*/
|
|
var ParsedVariable = /** @class */ (function () {
|
|
function ParsedVariable(name, value, sourceSpan, keySpan, valueSpan) {
|
|
this.name = name;
|
|
this.value = value;
|
|
this.sourceSpan = sourceSpan;
|
|
this.keySpan = keySpan;
|
|
this.valueSpan = valueSpan;
|
|
}
|
|
return ParsedVariable;
|
|
}());
|
|
var BoundElementProperty = /** @class */ (function () {
|
|
function BoundElementProperty(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;
|
|
}
|
|
return BoundElementProperty;
|
|
}());
|
|
|
|
/**
|
|
* @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 CORE$1 = '@angular/core';
|
|
var Identifiers$1 = /** @class */ (function () {
|
|
function Identifiers() {
|
|
}
|
|
return Identifiers;
|
|
}());
|
|
Identifiers$1.ANALYZE_FOR_ENTRY_COMPONENTS = {
|
|
name: 'ANALYZE_FOR_ENTRY_COMPONENTS',
|
|
moduleName: CORE$1,
|
|
};
|
|
Identifiers$1.ElementRef = { name: 'ElementRef', moduleName: CORE$1 };
|
|
Identifiers$1.NgModuleRef = { name: 'NgModuleRef', moduleName: CORE$1 };
|
|
Identifiers$1.ViewContainerRef = { name: 'ViewContainerRef', moduleName: CORE$1 };
|
|
Identifiers$1.ChangeDetectorRef = {
|
|
name: 'ChangeDetectorRef',
|
|
moduleName: CORE$1,
|
|
};
|
|
Identifiers$1.QueryList = { name: 'QueryList', moduleName: CORE$1 };
|
|
Identifiers$1.TemplateRef = { name: 'TemplateRef', moduleName: CORE$1 };
|
|
Identifiers$1.Renderer2 = { name: 'Renderer2', moduleName: CORE$1 };
|
|
Identifiers$1.CodegenComponentFactoryResolver = {
|
|
name: 'ɵCodegenComponentFactoryResolver',
|
|
moduleName: CORE$1,
|
|
};
|
|
Identifiers$1.ComponentFactoryResolver = {
|
|
name: 'ComponentFactoryResolver',
|
|
moduleName: CORE$1,
|
|
};
|
|
Identifiers$1.ComponentFactory = { name: 'ComponentFactory', moduleName: CORE$1 };
|
|
Identifiers$1.ComponentRef = { name: 'ComponentRef', moduleName: CORE$1 };
|
|
Identifiers$1.NgModuleFactory = { name: 'NgModuleFactory', moduleName: CORE$1 };
|
|
Identifiers$1.createModuleFactory = {
|
|
name: 'ɵcmf',
|
|
moduleName: CORE$1,
|
|
};
|
|
Identifiers$1.moduleDef = {
|
|
name: 'ɵmod',
|
|
moduleName: CORE$1,
|
|
};
|
|
Identifiers$1.moduleProviderDef = {
|
|
name: 'ɵmpd',
|
|
moduleName: CORE$1,
|
|
};
|
|
Identifiers$1.RegisterModuleFactoryFn = {
|
|
name: 'ɵregisterModuleFactory',
|
|
moduleName: CORE$1,
|
|
};
|
|
Identifiers$1.inject = { name: 'ɵɵinject', moduleName: CORE$1 };
|
|
Identifiers$1.directiveInject = { name: 'ɵɵdirectiveInject', moduleName: CORE$1 };
|
|
Identifiers$1.INJECTOR = { name: 'INJECTOR', moduleName: CORE$1 };
|
|
Identifiers$1.Injector = { name: 'Injector', moduleName: CORE$1 };
|
|
Identifiers$1.ViewEncapsulation = {
|
|
name: 'ViewEncapsulation',
|
|
moduleName: CORE$1,
|
|
};
|
|
Identifiers$1.ChangeDetectionStrategy = {
|
|
name: 'ChangeDetectionStrategy',
|
|
moduleName: CORE$1,
|
|
};
|
|
Identifiers$1.SecurityContext = {
|
|
name: 'SecurityContext',
|
|
moduleName: CORE$1,
|
|
};
|
|
Identifiers$1.LOCALE_ID = { name: 'LOCALE_ID', moduleName: CORE$1 };
|
|
Identifiers$1.TRANSLATIONS_FORMAT = {
|
|
name: 'TRANSLATIONS_FORMAT',
|
|
moduleName: CORE$1,
|
|
};
|
|
Identifiers$1.inlineInterpolate = {
|
|
name: 'ɵinlineInterpolate',
|
|
moduleName: CORE$1,
|
|
};
|
|
Identifiers$1.interpolate = { name: 'ɵinterpolate', moduleName: CORE$1 };
|
|
Identifiers$1.EMPTY_ARRAY = { name: 'ɵEMPTY_ARRAY', moduleName: CORE$1 };
|
|
Identifiers$1.EMPTY_MAP = { name: 'ɵEMPTY_MAP', moduleName: CORE$1 };
|
|
Identifiers$1.Renderer = { name: 'Renderer', moduleName: CORE$1 };
|
|
Identifiers$1.viewDef = { name: 'ɵvid', moduleName: CORE$1 };
|
|
Identifiers$1.elementDef = { name: 'ɵeld', moduleName: CORE$1 };
|
|
Identifiers$1.anchorDef = { name: 'ɵand', moduleName: CORE$1 };
|
|
Identifiers$1.textDef = { name: 'ɵted', moduleName: CORE$1 };
|
|
Identifiers$1.directiveDef = { name: 'ɵdid', moduleName: CORE$1 };
|
|
Identifiers$1.providerDef = { name: 'ɵprd', moduleName: CORE$1 };
|
|
Identifiers$1.queryDef = { name: 'ɵqud', moduleName: CORE$1 };
|
|
Identifiers$1.pureArrayDef = { name: 'ɵpad', moduleName: CORE$1 };
|
|
Identifiers$1.pureObjectDef = { name: 'ɵpod', moduleName: CORE$1 };
|
|
Identifiers$1.purePipeDef = { name: 'ɵppd', moduleName: CORE$1 };
|
|
Identifiers$1.pipeDef = { name: 'ɵpid', moduleName: CORE$1 };
|
|
Identifiers$1.nodeValue = { name: 'ɵnov', moduleName: CORE$1 };
|
|
Identifiers$1.ngContentDef = { name: 'ɵncd', moduleName: CORE$1 };
|
|
Identifiers$1.unwrapValue = { name: 'ɵunv', moduleName: CORE$1 };
|
|
Identifiers$1.createRendererType2 = { name: 'ɵcrt', moduleName: CORE$1 };
|
|
// type only
|
|
Identifiers$1.RendererType2 = {
|
|
name: 'RendererType2',
|
|
moduleName: CORE$1,
|
|
};
|
|
// type only
|
|
Identifiers$1.ViewDefinition = {
|
|
name: 'ɵViewDefinition',
|
|
moduleName: CORE$1,
|
|
};
|
|
Identifiers$1.createComponentFactory = { name: 'ɵccf', moduleName: CORE$1 };
|
|
function createTokenForReference(reference) {
|
|
return { identifier: { reference: reference } };
|
|
}
|
|
function createTokenForExternalReference(reflector, reference) {
|
|
return createTokenForReference(reflector.resolveExternalReference(reference));
|
|
}
|
|
|
|
var EventHandlerVars = /** @class */ (function () {
|
|
function EventHandlerVars() {
|
|
}
|
|
return EventHandlerVars;
|
|
}());
|
|
EventHandlerVars.event = variable('$event');
|
|
var ConvertActionBindingResult = /** @class */ (function () {
|
|
function ConvertActionBindingResult(
|
|
/**
|
|
* Render2 compatible statements,
|
|
*/
|
|
stmts,
|
|
/**
|
|
* Variable name used with render2 compatible statements.
|
|
*/
|
|
allowDefault) {
|
|
this.stmts = stmts;
|
|
this.allowDefault = allowDefault;
|
|
/**
|
|
* This is bit of a hack. It converts statements which render2 expects to statements which are
|
|
* expected by render3.
|
|
*
|
|
* Example: `<div click="doSomething($event)">` will generate:
|
|
*
|
|
* Render3:
|
|
* ```
|
|
* const pd_b:any = ((<any>ctx.doSomething($event)) !== false);
|
|
* return pd_b;
|
|
* ```
|
|
*
|
|
* but render2 expects:
|
|
* ```
|
|
* return ctx.doSomething($event);
|
|
* ```
|
|
*/
|
|
// TODO(misko): remove this hack once we no longer support ViewEngine.
|
|
this.render3Stmts = stmts.map(function (statement) {
|
|
if (statement instanceof DeclareVarStmt && statement.name == allowDefault.name &&
|
|
statement.value instanceof BinaryOperatorExpr) {
|
|
var lhs = statement.value.lhs;
|
|
return new ReturnStatement(lhs.value);
|
|
}
|
|
return statement;
|
|
});
|
|
}
|
|
return ConvertActionBindingResult;
|
|
}());
|
|
/**
|
|
* Converts the given expression AST into an executable output AST, assuming the expression is
|
|
* used in an action binding (e.g. an event handler).
|
|
*/
|
|
function convertActionBinding(localResolver, implicitReceiver, action, bindingId, interpolationFunction, baseSourceSpan, implicitReceiverAccesses, globals) {
|
|
if (!localResolver) {
|
|
localResolver = new DefaultLocalResolver(globals);
|
|
}
|
|
var actionWithoutBuiltins = convertPropertyBindingBuiltins({
|
|
createLiteralArrayConverter: function (argCount) {
|
|
// Note: no caching for literal arrays in actions.
|
|
return function (args) { return literalArr(args); };
|
|
},
|
|
createLiteralMapConverter: function (keys) {
|
|
// Note: no caching for literal maps in actions.
|
|
return function (values) {
|
|
var entries = keys.map(function (k, i) { return ({
|
|
key: k.key,
|
|
value: values[i],
|
|
quoted: k.quoted,
|
|
}); });
|
|
return literalMap(entries);
|
|
};
|
|
},
|
|
createPipeConverter: function (name) {
|
|
throw new Error("Illegal State: Actions are not allowed to contain pipes. Pipe: " + name);
|
|
}
|
|
}, action);
|
|
var visitor = new _AstToIrVisitor(localResolver, implicitReceiver, bindingId, interpolationFunction, baseSourceSpan, implicitReceiverAccesses);
|
|
var actionStmts = [];
|
|
flattenStatements(actionWithoutBuiltins.visit(visitor, _Mode.Statement), actionStmts);
|
|
prependTemporaryDecls(visitor.temporaryCount, bindingId, actionStmts);
|
|
if (visitor.usesImplicitReceiver) {
|
|
localResolver.notifyImplicitReceiverUse();
|
|
}
|
|
var lastIndex = actionStmts.length - 1;
|
|
var preventDefaultVar = null;
|
|
if (lastIndex >= 0) {
|
|
var lastStatement = actionStmts[lastIndex];
|
|
var returnExpr = convertStmtIntoExpression(lastStatement);
|
|
if (returnExpr) {
|
|
// Note: We need to cast the result of the method call to dynamic,
|
|
// as it might be a void method!
|
|
preventDefaultVar = createPreventDefaultVar(bindingId);
|
|
actionStmts[lastIndex] =
|
|
preventDefaultVar.set(returnExpr.cast(DYNAMIC_TYPE).notIdentical(literal(false)))
|
|
.toDeclStmt(null, [exports.StmtModifier.Final]);
|
|
}
|
|
}
|
|
return new ConvertActionBindingResult(actionStmts, preventDefaultVar);
|
|
}
|
|
function convertPropertyBindingBuiltins(converterFactory, ast) {
|
|
return convertBuiltins(converterFactory, ast);
|
|
}
|
|
var ConvertPropertyBindingResult = /** @class */ (function () {
|
|
function ConvertPropertyBindingResult(stmts, currValExpr) {
|
|
this.stmts = stmts;
|
|
this.currValExpr = currValExpr;
|
|
}
|
|
return ConvertPropertyBindingResult;
|
|
}());
|
|
var BindingForm;
|
|
(function (BindingForm) {
|
|
// The general form of binding expression, supports all expressions.
|
|
BindingForm[BindingForm["General"] = 0] = "General";
|
|
// Try to generate a simple binding (no temporaries or statements)
|
|
// otherwise generate a general binding
|
|
BindingForm[BindingForm["TrySimple"] = 1] = "TrySimple";
|
|
// Inlines assignment of temporaries into the generated expression. The result may still
|
|
// have statements attached for declarations of temporary variables.
|
|
// This is the only relevant form for Ivy, the other forms are only used in ViewEngine.
|
|
BindingForm[BindingForm["Expression"] = 2] = "Expression";
|
|
})(BindingForm || (BindingForm = {}));
|
|
/**
|
|
* Converts the given expression AST into an executable output AST, assuming the expression
|
|
* is used in property binding. The expression has to be preprocessed via
|
|
* `convertPropertyBindingBuiltins`.
|
|
*/
|
|
function convertPropertyBinding(localResolver, implicitReceiver, expressionWithoutBuiltins, bindingId, form, interpolationFunction) {
|
|
if (!localResolver) {
|
|
localResolver = new DefaultLocalResolver();
|
|
}
|
|
var visitor = new _AstToIrVisitor(localResolver, implicitReceiver, bindingId, interpolationFunction);
|
|
var outputExpr = expressionWithoutBuiltins.visit(visitor, _Mode.Expression);
|
|
var stmts = getStatementsFromVisitor(visitor, bindingId);
|
|
if (visitor.usesImplicitReceiver) {
|
|
localResolver.notifyImplicitReceiverUse();
|
|
}
|
|
if (visitor.temporaryCount === 0 && form == BindingForm.TrySimple) {
|
|
return new ConvertPropertyBindingResult([], outputExpr);
|
|
}
|
|
else if (form === BindingForm.Expression) {
|
|
return new ConvertPropertyBindingResult(stmts, outputExpr);
|
|
}
|
|
var currValExpr = createCurrValueExpr(bindingId);
|
|
stmts.push(currValExpr.set(outputExpr).toDeclStmt(DYNAMIC_TYPE, [exports.StmtModifier.Final]));
|
|
return new ConvertPropertyBindingResult(stmts, currValExpr);
|
|
}
|
|
/**
|
|
* Given some expression, such as a binding or interpolation expression, and a context expression to
|
|
* look values up on, visit each facet of the given expression resolving values from the context
|
|
* expression such that a list of arguments can be derived from the found values that can be used as
|
|
* arguments to an external update instruction.
|
|
*
|
|
* @param localResolver The resolver to use to look up expressions by name appropriately
|
|
* @param contextVariableExpression The expression representing the context variable used to create
|
|
* the final argument expressions
|
|
* @param expressionWithArgumentsToExtract The expression to visit to figure out what values need to
|
|
* be resolved and what arguments list to build.
|
|
* @param bindingId A name prefix used to create temporary variable names if they're needed for the
|
|
* arguments generated
|
|
* @returns An array of expressions that can be passed as arguments to instruction expressions like
|
|
* `o.importExpr(R3.propertyInterpolate).callFn(result)`
|
|
*/
|
|
function convertUpdateArguments(localResolver, contextVariableExpression, expressionWithArgumentsToExtract, bindingId) {
|
|
var visitor = new _AstToIrVisitor(localResolver, contextVariableExpression, bindingId, undefined);
|
|
var outputExpr = expressionWithArgumentsToExtract.visit(visitor, _Mode.Expression);
|
|
if (visitor.usesImplicitReceiver) {
|
|
localResolver.notifyImplicitReceiverUse();
|
|
}
|
|
var stmts = getStatementsFromVisitor(visitor, bindingId);
|
|
// Removing the first argument, because it was a length for ViewEngine, not Ivy.
|
|
var args = outputExpr.args.slice(1);
|
|
if (expressionWithArgumentsToExtract instanceof Interpolation) {
|
|
// If we're dealing with an interpolation of 1 value with an empty prefix and suffix, reduce the
|
|
// args returned to just the value, because we're going to pass it to a special instruction.
|
|
var strings = expressionWithArgumentsToExtract.strings;
|
|
if (args.length === 3 && strings[0] === '' && strings[1] === '') {
|
|
// Single argument interpolate instructions.
|
|
args = [args[1]];
|
|
}
|
|
else if (args.length >= 19) {
|
|
// 19 or more arguments must be passed to the `interpolateV`-style instructions, which accept
|
|
// an array of arguments
|
|
args = [literalArr(args)];
|
|
}
|
|
}
|
|
return { stmts: stmts, args: args };
|
|
}
|
|
function getStatementsFromVisitor(visitor, bindingId) {
|
|
var stmts = [];
|
|
for (var i = 0; i < visitor.temporaryCount; i++) {
|
|
stmts.push(temporaryDeclaration(bindingId, i));
|
|
}
|
|
return stmts;
|
|
}
|
|
function convertBuiltins(converterFactory, ast) {
|
|
var 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 (var 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;
|
|
}
|
|
}
|
|
var _BuiltinAstConverter = /** @class */ (function (_super) {
|
|
__extends(_BuiltinAstConverter, _super);
|
|
function _BuiltinAstConverter(_converterFactory) {
|
|
var _this = _super.call(this) || this;
|
|
_this._converterFactory = _converterFactory;
|
|
return _this;
|
|
}
|
|
_BuiltinAstConverter.prototype.visitPipe = function (ast, context) {
|
|
var _this = this;
|
|
var args = __spreadArray([ast.exp], __read(ast.args)).map(function (ast) { return ast.visit(_this, context); });
|
|
return new BuiltinFunctionCall(ast.span, ast.sourceSpan, args, this._converterFactory.createPipeConverter(ast.name, args.length));
|
|
};
|
|
_BuiltinAstConverter.prototype.visitLiteralArray = function (ast, context) {
|
|
var _this = this;
|
|
var args = ast.expressions.map(function (ast) { return ast.visit(_this, context); });
|
|
return new BuiltinFunctionCall(ast.span, ast.sourceSpan, args, this._converterFactory.createLiteralArrayConverter(ast.expressions.length));
|
|
};
|
|
_BuiltinAstConverter.prototype.visitLiteralMap = function (ast, context) {
|
|
var _this = this;
|
|
var args = ast.values.map(function (ast) { return ast.visit(_this, context); });
|
|
return new BuiltinFunctionCall(ast.span, ast.sourceSpan, args, this._converterFactory.createLiteralMapConverter(ast.keys));
|
|
};
|
|
return _BuiltinAstConverter;
|
|
}(AstTransformer$1));
|
|
var _AstToIrVisitor = /** @class */ (function () {
|
|
function _AstToIrVisitor(_localResolver, _implicitReceiver, bindingId, interpolationFunction, baseSourceSpan, implicitReceiverAccesses) {
|
|
this._localResolver = _localResolver;
|
|
this._implicitReceiver = _implicitReceiver;
|
|
this.bindingId = bindingId;
|
|
this.interpolationFunction = interpolationFunction;
|
|
this.baseSourceSpan = baseSourceSpan;
|
|
this.implicitReceiverAccesses = implicitReceiverAccesses;
|
|
this._nodeMap = new Map();
|
|
this._resultMap = new Map();
|
|
this._currentTemporary = 0;
|
|
this.temporaryCount = 0;
|
|
this.usesImplicitReceiver = false;
|
|
}
|
|
_AstToIrVisitor.prototype.visitUnary = function (ast, mode) {
|
|
var op;
|
|
switch (ast.operator) {
|
|
case '+':
|
|
op = exports.UnaryOperator.Plus;
|
|
break;
|
|
case '-':
|
|
op = exports.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)));
|
|
};
|
|
_AstToIrVisitor.prototype.visitBinary = function (ast, mode) {
|
|
var op;
|
|
switch (ast.operation) {
|
|
case '+':
|
|
op = exports.BinaryOperator.Plus;
|
|
break;
|
|
case '-':
|
|
op = exports.BinaryOperator.Minus;
|
|
break;
|
|
case '*':
|
|
op = exports.BinaryOperator.Multiply;
|
|
break;
|
|
case '/':
|
|
op = exports.BinaryOperator.Divide;
|
|
break;
|
|
case '%':
|
|
op = exports.BinaryOperator.Modulo;
|
|
break;
|
|
case '&&':
|
|
op = exports.BinaryOperator.And;
|
|
break;
|
|
case '||':
|
|
op = exports.BinaryOperator.Or;
|
|
break;
|
|
case '==':
|
|
op = exports.BinaryOperator.Equals;
|
|
break;
|
|
case '!=':
|
|
op = exports.BinaryOperator.NotEquals;
|
|
break;
|
|
case '===':
|
|
op = exports.BinaryOperator.Identical;
|
|
break;
|
|
case '!==':
|
|
op = exports.BinaryOperator.NotIdentical;
|
|
break;
|
|
case '<':
|
|
op = exports.BinaryOperator.Lower;
|
|
break;
|
|
case '>':
|
|
op = exports.BinaryOperator.Bigger;
|
|
break;
|
|
case '<=':
|
|
op = exports.BinaryOperator.LowerEquals;
|
|
break;
|
|
case '>=':
|
|
op = exports.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)));
|
|
};
|
|
_AstToIrVisitor.prototype.visitChain = function (ast, mode) {
|
|
ensureStatementMode(mode, ast);
|
|
return this.visitAll(ast.expressions, mode);
|
|
};
|
|
_AstToIrVisitor.prototype.visitConditional = function (ast, mode) {
|
|
var 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)));
|
|
};
|
|
_AstToIrVisitor.prototype.visitPipe = function (ast, mode) {
|
|
throw new Error("Illegal state: Pipes should have been converted into functions. Pipe: " + ast.name);
|
|
};
|
|
_AstToIrVisitor.prototype.visitFunctionCall = function (ast, mode) {
|
|
var convertedArgs = this.visitAll(ast.args, _Mode.Expression);
|
|
var fnResult;
|
|
if (ast instanceof BuiltinFunctionCall) {
|
|
fnResult = ast.converter(convertedArgs);
|
|
}
|
|
else {
|
|
fnResult = this._visit(ast.target, _Mode.Expression)
|
|
.callFn(convertedArgs, this.convertSourceSpan(ast.span));
|
|
}
|
|
return convertToStatementIfNeeded(mode, fnResult);
|
|
};
|
|
_AstToIrVisitor.prototype.visitImplicitReceiver = function (ast, mode) {
|
|
ensureExpressionMode(mode, ast);
|
|
this.usesImplicitReceiver = true;
|
|
return this._implicitReceiver;
|
|
};
|
|
_AstToIrVisitor.prototype.visitThisReceiver = function (ast, mode) {
|
|
return this.visitImplicitReceiver(ast, mode);
|
|
};
|
|
_AstToIrVisitor.prototype.visitInterpolation = function (ast, mode) {
|
|
ensureExpressionMode(mode, ast);
|
|
var args = [literal(ast.expressions.length)];
|
|
for (var i = 0; i < ast.strings.length - 1; i++) {
|
|
args.push(literal(ast.strings[i]));
|
|
args.push(this._visit(ast.expressions[i], _Mode.Expression));
|
|
}
|
|
args.push(literal(ast.strings[ast.strings.length - 1]));
|
|
if (this.interpolationFunction) {
|
|
return this.interpolationFunction(args);
|
|
}
|
|
return ast.expressions.length <= 9 ?
|
|
importExpr(Identifiers$1.inlineInterpolate).callFn(args) :
|
|
importExpr(Identifiers$1.interpolate).callFn([
|
|
args[0], literalArr(args.slice(1), undefined, this.convertSourceSpan(ast.span))
|
|
]);
|
|
};
|
|
_AstToIrVisitor.prototype.visitKeyedRead = function (ast, mode) {
|
|
var 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)));
|
|
}
|
|
};
|
|
_AstToIrVisitor.prototype.visitKeyedWrite = function (ast, mode) {
|
|
var obj = this._visit(ast.receiver, _Mode.Expression);
|
|
var key = this._visit(ast.key, _Mode.Expression);
|
|
var value = this._visit(ast.value, _Mode.Expression);
|
|
if (obj === this._implicitReceiver) {
|
|
this._localResolver.maybeRestoreView();
|
|
}
|
|
return convertToStatementIfNeeded(mode, obj.key(key).set(value));
|
|
};
|
|
_AstToIrVisitor.prototype.visitLiteralArray = function (ast, mode) {
|
|
throw new Error("Illegal State: literal arrays should have been converted into functions");
|
|
};
|
|
_AstToIrVisitor.prototype.visitLiteralMap = function (ast, mode) {
|
|
throw new Error("Illegal State: literal maps should have been converted into functions");
|
|
};
|
|
_AstToIrVisitor.prototype.visitLiteralPrimitive = function (ast, mode) {
|
|
// For literal values of null, undefined, true, or false allow type interference
|
|
// to infer the type.
|
|
var type = ast.value === null || ast.value === undefined || ast.value === true || ast.value === true ?
|
|
INFERRED_TYPE :
|
|
undefined;
|
|
return convertToStatementIfNeeded(mode, literal(ast.value, type, this.convertSourceSpan(ast.span)));
|
|
};
|
|
_AstToIrVisitor.prototype._getLocal = function (name, receiver) {
|
|
var _a;
|
|
if (((_a = this._localResolver.globals) === null || _a === void 0 ? void 0 : _a.has(name)) && receiver instanceof ThisReceiver) {
|
|
return null;
|
|
}
|
|
return this._localResolver.getLocal(name);
|
|
};
|
|
_AstToIrVisitor.prototype.visitMethodCall = function (ast, mode) {
|
|
if (ast.receiver instanceof ImplicitReceiver &&
|
|
!(ast.receiver instanceof ThisReceiver) && ast.name === '$any') {
|
|
var args = this.visitAll(ast.args, _Mode.Expression);
|
|
if (args.length != 1) {
|
|
throw new Error("Invalid call to $any, expected 1 argument but received " + (args.length || 'none'));
|
|
}
|
|
return args[0].cast(DYNAMIC_TYPE, this.convertSourceSpan(ast.span));
|
|
}
|
|
var leftMostSafe = this.leftMostSafeNode(ast);
|
|
if (leftMostSafe) {
|
|
return this.convertSafeAccess(ast, leftMostSafe, mode);
|
|
}
|
|
else {
|
|
var args = this.visitAll(ast.args, _Mode.Expression);
|
|
var prevUsesImplicitReceiver = this.usesImplicitReceiver;
|
|
var result = null;
|
|
var receiver = this._visit(ast.receiver, _Mode.Expression);
|
|
if (receiver === this._implicitReceiver) {
|
|
var varExpr = this._getLocal(ast.name, ast.receiver);
|
|
if (varExpr) {
|
|
// Restore the previous "usesImplicitReceiver" state since the implicit
|
|
// receiver has been replaced with a resolved local expression.
|
|
this.usesImplicitReceiver = prevUsesImplicitReceiver;
|
|
result = varExpr.callFn(args);
|
|
this.addImplicitReceiverAccess(ast.name);
|
|
}
|
|
}
|
|
if (result == null) {
|
|
result = receiver.callMethod(ast.name, args, this.convertSourceSpan(ast.span));
|
|
}
|
|
return convertToStatementIfNeeded(mode, result);
|
|
}
|
|
};
|
|
_AstToIrVisitor.prototype.visitPrefixNot = function (ast, mode) {
|
|
return convertToStatementIfNeeded(mode, not(this._visit(ast.expression, _Mode.Expression)));
|
|
};
|
|
_AstToIrVisitor.prototype.visitNonNullAssert = function (ast, mode) {
|
|
return convertToStatementIfNeeded(mode, assertNotNull(this._visit(ast.expression, _Mode.Expression)));
|
|
};
|
|
_AstToIrVisitor.prototype.visitPropertyRead = function (ast, mode) {
|
|
var leftMostSafe = this.leftMostSafeNode(ast);
|
|
if (leftMostSafe) {
|
|
return this.convertSafeAccess(ast, leftMostSafe, mode);
|
|
}
|
|
else {
|
|
var result = null;
|
|
var prevUsesImplicitReceiver = this.usesImplicitReceiver;
|
|
var receiver = this._visit(ast.receiver, _Mode.Expression);
|
|
if (receiver === this._implicitReceiver) {
|
|
result = this._getLocal(ast.name, ast.receiver);
|
|
if (result) {
|
|
// Restore the previous "usesImplicitReceiver" state since the implicit
|
|
// receiver has been replaced with a resolved local expression.
|
|
this.usesImplicitReceiver = prevUsesImplicitReceiver;
|
|
this.addImplicitReceiverAccess(ast.name);
|
|
}
|
|
}
|
|
if (result == null) {
|
|
result = receiver.prop(ast.name);
|
|
}
|
|
return convertToStatementIfNeeded(mode, result);
|
|
}
|
|
};
|
|
_AstToIrVisitor.prototype.visitPropertyWrite = function (ast, mode) {
|
|
var receiver = this._visit(ast.receiver, _Mode.Expression);
|
|
var prevUsesImplicitReceiver = this.usesImplicitReceiver;
|
|
var varExpr = null;
|
|
if (receiver === this._implicitReceiver) {
|
|
var 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.
|
|
var receiver_1 = ast.name;
|
|
var value = (ast.value instanceof PropertyRead) ? ast.value.name : undefined;
|
|
throw new Error("Cannot assign value \"" + value + "\" to template variable \"" + receiver_1 + "\". Template variables are read-only.");
|
|
}
|
|
}
|
|
}
|
|
// If no local expression could be produced, use the original receiver's
|
|
// property as the target.
|
|
if (varExpr === null) {
|
|
varExpr = receiver.prop(ast.name);
|
|
}
|
|
return convertToStatementIfNeeded(mode, varExpr.set(this._visit(ast.value, _Mode.Expression)));
|
|
};
|
|
_AstToIrVisitor.prototype.visitSafePropertyRead = function (ast, mode) {
|
|
return this.convertSafeAccess(ast, this.leftMostSafeNode(ast), mode);
|
|
};
|
|
_AstToIrVisitor.prototype.visitSafeMethodCall = function (ast, mode) {
|
|
return this.convertSafeAccess(ast, this.leftMostSafeNode(ast), mode);
|
|
};
|
|
_AstToIrVisitor.prototype.visitSafeKeyedRead = function (ast, mode) {
|
|
return this.convertSafeAccess(ast, this.leftMostSafeNode(ast), mode);
|
|
};
|
|
_AstToIrVisitor.prototype.visitAll = function (asts, mode) {
|
|
var _this = this;
|
|
return asts.map(function (ast) { return _this._visit(ast, mode); });
|
|
};
|
|
_AstToIrVisitor.prototype.visitQuote = function (ast, mode) {
|
|
throw new Error("Quotes are not supported for evaluation!\n Statement: " + ast.uninterpretedExpression + " located at " + ast.location);
|
|
};
|
|
_AstToIrVisitor.prototype._visit = function (ast, mode) {
|
|
var result = this._resultMap.get(ast);
|
|
if (result)
|
|
return result;
|
|
return (this._nodeMap.get(ast) || ast).visit(this, mode);
|
|
};
|
|
_AstToIrVisitor.prototype.convertSafeAccess = function (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.
|
|
var guardedExpression = this._visit(leftMostSafe.receiver, _Mode.Expression);
|
|
var 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);
|
|
}
|
|
var condition = guardedExpression.isBlank();
|
|
// Convert the ast to an unguarded access to the receiver's member. The map will substitute
|
|
// leftMostNode with its unguarded version in the call to `this.visit()`.
|
|
if (leftMostSafe instanceof SafeMethodCall) {
|
|
this._nodeMap.set(leftMostSafe, new MethodCall(leftMostSafe.span, leftMostSafe.sourceSpan, leftMostSafe.nameSpan, leftMostSafe.receiver, leftMostSafe.name, leftMostSafe.args, leftMostSafe.argumentSpan));
|
|
}
|
|
else if (leftMostSafe instanceof SafeKeyedRead) {
|
|
this._nodeMap.set(leftMostSafe, new KeyedRead(leftMostSafe.span, leftMostSafe.sourceSpan, leftMostSafe.receiver, leftMostSafe.key));
|
|
}
|
|
else {
|
|
this._nodeMap.set(leftMostSafe, new PropertyRead(leftMostSafe.span, leftMostSafe.sourceSpan, leftMostSafe.nameSpan, leftMostSafe.receiver, leftMostSafe.name));
|
|
}
|
|
// Recursively convert the node now without the guarded member access.
|
|
var 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));
|
|
};
|
|
_AstToIrVisitor.prototype.convertNullishCoalesce = function (ast, mode) {
|
|
var left = this._visit(ast.left, _Mode.Expression);
|
|
var right = this._visit(ast.right, _Mode.Expression);
|
|
var temporary = this.allocateTemporary();
|
|
this.releaseTemporary(temporary);
|
|
// Generate the following expression. It is identical to how TS
|
|
// transpiles binary expressions with a nullish coalescing operator.
|
|
// let temp;
|
|
// (temp = a) !== null && temp !== undefined ? temp : b;
|
|
return convertToStatementIfNeeded(mode, temporary.set(left)
|
|
.notIdentical(NULL_EXPR)
|
|
.and(temporary.notIdentical(literal(undefined)))
|
|
.conditional(temporary, right));
|
|
};
|
|
// Given an expression of the form a?.b.c?.d.e then the left most safe node is
|
|
// the (a?.b). The . and ?. are left associative thus can be rewritten as:
|
|
// ((((a?.c).b).c)?.d).e. This returns the most deeply nested safe read or
|
|
// safe method call as this needs to be transformed initially to:
|
|
// a == null ? null : a.c.b.c?.d.e
|
|
// then to:
|
|
// a == null ? null : a.b.c == null ? null : a.b.c.d.e
|
|
_AstToIrVisitor.prototype.leftMostSafeNode = function (ast) {
|
|
var _this = this;
|
|
var visit = function (visitor, ast) {
|
|
return (_this._nodeMap.get(ast) || ast).visit(visitor);
|
|
};
|
|
return ast.visit({
|
|
visitUnary: function (ast) {
|
|
return null;
|
|
},
|
|
visitBinary: function (ast) {
|
|
return null;
|
|
},
|
|
visitChain: function (ast) {
|
|
return null;
|
|
},
|
|
visitConditional: function (ast) {
|
|
return null;
|
|
},
|
|
visitFunctionCall: function (ast) {
|
|
return null;
|
|
},
|
|
visitImplicitReceiver: function (ast) {
|
|
return null;
|
|
},
|
|
visitThisReceiver: function (ast) {
|
|
return null;
|
|
},
|
|
visitInterpolation: function (ast) {
|
|
return null;
|
|
},
|
|
visitKeyedRead: function (ast) {
|
|
return visit(this, ast.receiver);
|
|
},
|
|
visitKeyedWrite: function (ast) {
|
|
return null;
|
|
},
|
|
visitLiteralArray: function (ast) {
|
|
return null;
|
|
},
|
|
visitLiteralMap: function (ast) {
|
|
return null;
|
|
},
|
|
visitLiteralPrimitive: function (ast) {
|
|
return null;
|
|
},
|
|
visitMethodCall: function (ast) {
|
|
return visit(this, ast.receiver);
|
|
},
|
|
visitPipe: function (ast) {
|
|
return null;
|
|
},
|
|
visitPrefixNot: function (ast) {
|
|
return null;
|
|
},
|
|
visitNonNullAssert: function (ast) {
|
|
return null;
|
|
},
|
|
visitPropertyRead: function (ast) {
|
|
return visit(this, ast.receiver);
|
|
},
|
|
visitPropertyWrite: function (ast) {
|
|
return null;
|
|
},
|
|
visitQuote: function (ast) {
|
|
return null;
|
|
},
|
|
visitSafeMethodCall: function (ast) {
|
|
return visit(this, ast.receiver) || ast;
|
|
},
|
|
visitSafePropertyRead: function (ast) {
|
|
return visit(this, ast.receiver) || ast;
|
|
},
|
|
visitSafeKeyedRead: function (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.
|
|
_AstToIrVisitor.prototype.needsTemporaryInSafeAccess = function (ast) {
|
|
var _this = this;
|
|
var visit = function (visitor, ast) {
|
|
return ast && (_this._nodeMap.get(ast) || ast).visit(visitor);
|
|
};
|
|
var visitSome = function (visitor, ast) {
|
|
return ast.some(function (ast) { return visit(visitor, ast); });
|
|
};
|
|
return ast.visit({
|
|
visitUnary: function (ast) {
|
|
return visit(this, ast.expr);
|
|
},
|
|
visitBinary: function (ast) {
|
|
return visit(this, ast.left) || visit(this, ast.right);
|
|
},
|
|
visitChain: function (ast) {
|
|
return false;
|
|
},
|
|
visitConditional: function (ast) {
|
|
return visit(this, ast.condition) || visit(this, ast.trueExp) || visit(this, ast.falseExp);
|
|
},
|
|
visitFunctionCall: function (ast) {
|
|
return true;
|
|
},
|
|
visitImplicitReceiver: function (ast) {
|
|
return false;
|
|
},
|
|
visitThisReceiver: function (ast) {
|
|
return false;
|
|
},
|
|
visitInterpolation: function (ast) {
|
|
return visitSome(this, ast.expressions);
|
|
},
|
|
visitKeyedRead: function (ast) {
|
|
return false;
|
|
},
|
|
visitKeyedWrite: function (ast) {
|
|
return false;
|
|
},
|
|
visitLiteralArray: function (ast) {
|
|
return true;
|
|
},
|
|
visitLiteralMap: function (ast) {
|
|
return true;
|
|
},
|
|
visitLiteralPrimitive: function (ast) {
|
|
return false;
|
|
},
|
|
visitMethodCall: function (ast) {
|
|
return true;
|
|
},
|
|
visitPipe: function (ast) {
|
|
return true;
|
|
},
|
|
visitPrefixNot: function (ast) {
|
|
return visit(this, ast.expression);
|
|
},
|
|
visitNonNullAssert: function (ast) {
|
|
return visit(this, ast.expression);
|
|
},
|
|
visitPropertyRead: function (ast) {
|
|
return false;
|
|
},
|
|
visitPropertyWrite: function (ast) {
|
|
return false;
|
|
},
|
|
visitQuote: function (ast) {
|
|
return false;
|
|
},
|
|
visitSafeMethodCall: function (ast) {
|
|
return true;
|
|
},
|
|
visitSafePropertyRead: function (ast) {
|
|
return false;
|
|
},
|
|
visitSafeKeyedRead: function (ast) {
|
|
return false;
|
|
}
|
|
});
|
|
};
|
|
_AstToIrVisitor.prototype.allocateTemporary = function () {
|
|
var tempNumber = this._currentTemporary++;
|
|
this.temporaryCount = Math.max(this._currentTemporary, this.temporaryCount);
|
|
return new ReadVarExpr(temporaryName(this.bindingId, tempNumber));
|
|
};
|
|
_AstToIrVisitor.prototype.releaseTemporary = function (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.
|
|
*/
|
|
_AstToIrVisitor.prototype.convertSourceSpan = function (span) {
|
|
if (this.baseSourceSpan) {
|
|
var start = this.baseSourceSpan.start.moveBy(span.start);
|
|
var end = this.baseSourceSpan.start.moveBy(span.end);
|
|
var 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. */
|
|
_AstToIrVisitor.prototype.addImplicitReceiverAccess = function (name) {
|
|
if (this.implicitReceiverAccesses) {
|
|
this.implicitReceiverAccesses.add(name);
|
|
}
|
|
};
|
|
return _AstToIrVisitor;
|
|
}());
|
|
function flattenStatements(arg, output) {
|
|
if (Array.isArray(arg)) {
|
|
arg.forEach(function (entry) { return flattenStatements(entry, output); });
|
|
}
|
|
else {
|
|
output.push(arg);
|
|
}
|
|
}
|
|
var DefaultLocalResolver = /** @class */ (function () {
|
|
function DefaultLocalResolver(globals) {
|
|
this.globals = globals;
|
|
}
|
|
DefaultLocalResolver.prototype.notifyImplicitReceiverUse = function () { };
|
|
DefaultLocalResolver.prototype.maybeRestoreView = function () { };
|
|
DefaultLocalResolver.prototype.getLocal = function (name) {
|
|
if (name === EventHandlerVars.event.name) {
|
|
return EventHandlerVars.event;
|
|
}
|
|
return null;
|
|
};
|
|
return DefaultLocalResolver;
|
|
}());
|
|
function createCurrValueExpr(bindingId) {
|
|
return variable("currVal_" + bindingId); // fix syntax highlighting: `
|
|
}
|
|
function createPreventDefaultVar(bindingId) {
|
|
return variable("pd_" + bindingId);
|
|
}
|
|
function convertStmtIntoExpression(stmt) {
|
|
if (stmt instanceof ExpressionStatement) {
|
|
return stmt.expr;
|
|
}
|
|
else if (stmt instanceof ReturnStatement) {
|
|
return stmt.value;
|
|
}
|
|
return null;
|
|
}
|
|
var BuiltinFunctionCall = /** @class */ (function (_super) {
|
|
__extends(BuiltinFunctionCall, _super);
|
|
function BuiltinFunctionCall(span, sourceSpan, args, converter) {
|
|
var _this = _super.call(this, span, sourceSpan, null, args) || this;
|
|
_this.converter = converter;
|
|
return _this;
|
|
}
|
|
return BuiltinFunctionCall;
|
|
}(FunctionCall));
|
|
|
|
/**
|
|
* @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 file is a port of shadowCSS from webcomponents.js to TypeScript.
|
|
*
|
|
* Please make sure to keep to edits in sync with the source file.
|
|
*
|
|
* Source:
|
|
* https://github.com/webcomponents/webcomponentsjs/blob/4efecd7e0e/src/ShadowCSS/ShadowCSS.js
|
|
*
|
|
* The original file level comment is reproduced below
|
|
*/
|
|
/*
|
|
This is a limited shim for ShadowDOM css styling.
|
|
https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html#styles
|
|
|
|
The intention here is to support only the styling features which can be
|
|
relatively simply implemented. The goal is to allow users to avoid the
|
|
most obvious pitfalls and do so without compromising performance significantly.
|
|
For ShadowDOM styling that's not covered here, a set of best practices
|
|
can be provided that should allow users to accomplish more complex styling.
|
|
|
|
The following is a list of specific ShadowDOM styling features and a brief
|
|
discussion of the approach used to shim.
|
|
|
|
Shimmed features:
|
|
|
|
* :host, :host-context: ShadowDOM allows styling of the shadowRoot's host
|
|
element using the :host rule. To shim this feature, the :host styles are
|
|
reformatted and prefixed with a given scope name and promoted to a
|
|
document level stylesheet.
|
|
For example, given a scope name of .foo, a rule like this:
|
|
|
|
:host {
|
|
background: red;
|
|
}
|
|
}
|
|
|
|
becomes:
|
|
|
|
.foo {
|
|
background: red;
|
|
}
|
|
|
|
* encapsulation: Styles defined within ShadowDOM, apply only to
|
|
dom inside the ShadowDOM. Polymer uses one of two techniques to implement
|
|
this feature.
|
|
|
|
By default, rules are prefixed with the host element tag name
|
|
as a descendant selector. This ensures styling does not leak out of the 'top'
|
|
of the element's ShadowDOM. For example,
|
|
|
|
div {
|
|
font-weight: bold;
|
|
}
|
|
|
|
becomes:
|
|
|
|
x-foo div {
|
|
font-weight: bold;
|
|
}
|
|
|
|
becomes:
|
|
|
|
|
|
Alternatively, if WebComponents.ShadowCSS.strictStyling is set to true then
|
|
selectors are scoped by adding an attribute selector suffix to each
|
|
simple selector that contains the host element tag name. Each element
|
|
in the element's ShadowDOM template is also given the scope attribute.
|
|
Thus, these rules match only elements that have the scope attribute.
|
|
For example, given a scope name of x-foo, a rule like this:
|
|
|
|
div {
|
|
font-weight: bold;
|
|
}
|
|
|
|
becomes:
|
|
|
|
div[x-foo] {
|
|
font-weight: bold;
|
|
}
|
|
|
|
Note that elements that are dynamically added to a scope must have the scope
|
|
selector added to them manually.
|
|
|
|
* upper/lower bound encapsulation: Styles which are defined outside a
|
|
shadowRoot should not cross the ShadowDOM boundary and should not apply
|
|
inside a shadowRoot.
|
|
|
|
This styling behavior is not emulated. Some possible ways to do this that
|
|
were rejected due to complexity and/or performance concerns include: (1) reset
|
|
every possible property for every possible selector for a given scope name;
|
|
(2) re-implement css in javascript.
|
|
|
|
As an alternative, users should make sure to use selectors
|
|
specific to the scope in which they are working.
|
|
|
|
* ::distributed: This behavior is not emulated. It's often not necessary
|
|
to style the contents of a specific insertion point and instead, descendants
|
|
of the host element can be styled selectively. Users can also create an
|
|
extra node around an insertion point and style that node's contents
|
|
via descendent selectors. For example, with a shadowRoot like this:
|
|
|
|
<style>
|
|
::content(div) {
|
|
background: red;
|
|
}
|
|
</style>
|
|
<content></content>
|
|
|
|
could become:
|
|
|
|
<style>
|
|
/ *@polyfill .content-container div * /
|
|
::content(div) {
|
|
background: red;
|
|
}
|
|
</style>
|
|
<div class="content-container">
|
|
<content></content>
|
|
</div>
|
|
|
|
Note the use of @polyfill in the comment above a ShadowDOM specific style
|
|
declaration. This is a directive to the styling shim to use the selector
|
|
in comments in lieu of the next selector when running under polyfill.
|
|
*/
|
|
var ShadowCss = /** @class */ (function () {
|
|
function ShadowCss() {
|
|
this.strictStyling = true;
|
|
}
|
|
/*
|
|
* Shim some cssText with the given selector. Returns cssText that can
|
|
* be included in the document via WebComponents.ShadowCSS.addCssToDocument(css).
|
|
*
|
|
* When strictStyling is true:
|
|
* - selector is the attribute added to all elements inside the host,
|
|
* - hostSelector is the attribute added to the host itself.
|
|
*/
|
|
ShadowCss.prototype.shimCssText = function (cssText, selector, hostSelector) {
|
|
if (hostSelector === void 0) { hostSelector = ''; }
|
|
var commentsWithHash = extractCommentsWithHash(cssText);
|
|
cssText = stripComments(cssText);
|
|
cssText = this._insertDirectives(cssText);
|
|
var scopedCssText = this._scopeCssText(cssText, selector, hostSelector);
|
|
return __spreadArray([scopedCssText], __read(commentsWithHash)).join('\n');
|
|
};
|
|
ShadowCss.prototype._insertDirectives = function (cssText) {
|
|
cssText = this._insertPolyfillDirectivesInCssText(cssText);
|
|
return this._insertPolyfillRulesInCssText(cssText);
|
|
};
|
|
/*
|
|
* Process styles to convert native ShadowDOM rules that will trip
|
|
* up the css parser; we rely on decorating the stylesheet with inert rules.
|
|
*
|
|
* For example, we convert this rule:
|
|
*
|
|
* polyfill-next-selector { content: ':host menu-item'; }
|
|
* ::content menu-item {
|
|
*
|
|
* to this:
|
|
*
|
|
* scopeName menu-item {
|
|
*
|
|
**/
|
|
ShadowCss.prototype._insertPolyfillDirectivesInCssText = function (cssText) {
|
|
// Difference with webcomponents.js: does not handle comments
|
|
return cssText.replace(_cssContentNextSelectorRe, function () {
|
|
var m = [];
|
|
for (var _i = 0; _i < arguments.length; _i++) {
|
|
m[_i] = arguments[_i];
|
|
}
|
|
return m[2] + '{';
|
|
});
|
|
};
|
|
/*
|
|
* Process styles to add rules which will only apply under the polyfill
|
|
*
|
|
* For example, we convert this rule:
|
|
*
|
|
* polyfill-rule {
|
|
* content: ':host menu-item';
|
|
* ...
|
|
* }
|
|
*
|
|
* to this:
|
|
*
|
|
* scopeName menu-item {...}
|
|
*
|
|
**/
|
|
ShadowCss.prototype._insertPolyfillRulesInCssText = function (cssText) {
|
|
// Difference with webcomponents.js: does not handle comments
|
|
return cssText.replace(_cssContentRuleRe, function () {
|
|
var m = [];
|
|
for (var _i = 0; _i < arguments.length; _i++) {
|
|
m[_i] = arguments[_i];
|
|
}
|
|
var rule = m[0].replace(m[1], '').replace(m[2], '');
|
|
return m[4] + rule;
|
|
});
|
|
};
|
|
/* Ensure styles are scoped. Pseudo-scoping takes a rule like:
|
|
*
|
|
* .foo {... }
|
|
*
|
|
* and converts this to
|
|
*
|
|
* scopeName .foo { ... }
|
|
*/
|
|
ShadowCss.prototype._scopeCssText = function (cssText, scopeSelector, hostSelector) {
|
|
var unscopedRules = this._extractUnscopedRulesFromCssText(cssText);
|
|
// replace :host and :host-context -shadowcsshost and -shadowcsshost respectively
|
|
cssText = this._insertPolyfillHostInCssText(cssText);
|
|
cssText = this._convertColonHost(cssText);
|
|
cssText = this._convertColonHostContext(cssText);
|
|
cssText = this._convertShadowDOMSelectors(cssText);
|
|
if (scopeSelector) {
|
|
cssText = this._scopeSelectors(cssText, scopeSelector, hostSelector);
|
|
}
|
|
cssText = cssText + '\n' + unscopedRules;
|
|
return cssText.trim();
|
|
};
|
|
/*
|
|
* Process styles to add rules which will only apply under the polyfill
|
|
* and do not process via CSSOM. (CSSOM is destructive to rules on rare
|
|
* occasions, e.g. -webkit-calc on Safari.)
|
|
* For example, we convert this rule:
|
|
*
|
|
* @polyfill-unscoped-rule {
|
|
* content: 'menu-item';
|
|
* ... }
|
|
*
|
|
* to this:
|
|
*
|
|
* menu-item {...}
|
|
*
|
|
**/
|
|
ShadowCss.prototype._extractUnscopedRulesFromCssText = function (cssText) {
|
|
// Difference with webcomponents.js: does not handle comments
|
|
var r = '';
|
|
var m;
|
|
_cssContentUnscopedRuleRe.lastIndex = 0;
|
|
while ((m = _cssContentUnscopedRuleRe.exec(cssText)) !== null) {
|
|
var rule = m[0].replace(m[2], '').replace(m[1], m[4]);
|
|
r += rule + '\n\n';
|
|
}
|
|
return r;
|
|
};
|
|
/*
|
|
* convert a rule like :host(.foo) > .bar { }
|
|
*
|
|
* to
|
|
*
|
|
* .foo<scopeName> > .bar
|
|
*/
|
|
ShadowCss.prototype._convertColonHost = function (cssText) {
|
|
return cssText.replace(_cssColonHostRe, function (_, hostSelectors, otherSelectors) {
|
|
var e_1, _b;
|
|
if (hostSelectors) {
|
|
var convertedSelectors = [];
|
|
var hostSelectorArray = hostSelectors.split(',').map(function (p) { return p.trim(); });
|
|
try {
|
|
for (var hostSelectorArray_1 = __values(hostSelectorArray), hostSelectorArray_1_1 = hostSelectorArray_1.next(); !hostSelectorArray_1_1.done; hostSelectorArray_1_1 = hostSelectorArray_1.next()) {
|
|
var hostSelector = hostSelectorArray_1_1.value;
|
|
if (!hostSelector)
|
|
break;
|
|
var convertedSelector = _polyfillHostNoCombinator + hostSelector.replace(_polyfillHost, '') + otherSelectors;
|
|
convertedSelectors.push(convertedSelector);
|
|
}
|
|
}
|
|
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
finally {
|
|
try {
|
|
if (hostSelectorArray_1_1 && !hostSelectorArray_1_1.done && (_b = hostSelectorArray_1.return)) _b.call(hostSelectorArray_1);
|
|
}
|
|
finally { if (e_1) throw e_1.error; }
|
|
}
|
|
return convertedSelectors.join(',');
|
|
}
|
|
else {
|
|
return _polyfillHostNoCombinator + otherSelectors;
|
|
}
|
|
});
|
|
};
|
|
/*
|
|
* convert a rule like :host-context(.foo) > .bar { }
|
|
*
|
|
* to
|
|
*
|
|
* .foo<scopeName> > .bar, .foo <scopeName> > .bar { }
|
|
*
|
|
* and
|
|
*
|
|
* :host-context(.foo:host) .bar { ... }
|
|
*
|
|
* to
|
|
*
|
|
* .foo<scopeName> .bar { ... }
|
|
*/
|
|
ShadowCss.prototype._convertColonHostContext = function (cssText) {
|
|
return cssText.replace(_cssColonHostContextReGlobal, function (selectorText) {
|
|
// We have captured a selector that contains a `:host-context` rule.
|
|
var _a;
|
|
// For backward compatibility `:host-context` may contain a comma separated list of selectors.
|
|
// Each context selector group will contain a list of host-context selectors that must match
|
|
// an ancestor of the host.
|
|
// (Normally `contextSelectorGroups` will only contain a single array of context selectors.)
|
|
var contextSelectorGroups = [[]];
|
|
// There may be more than `:host-context` in this selector so `selectorText` could look like:
|
|
// `:host-context(.one):host-context(.two)`.
|
|
// Execute `_cssColonHostContextRe` over and over until we have extracted all the
|
|
// `:host-context` selectors from this selector.
|
|
var match;
|
|
while (match = _cssColonHostContextRe.exec(selectorText)) {
|
|
// `match` = [':host-context(<selectors>)<rest>', <selectors>, <rest>]
|
|
// The `<selectors>` could actually be a comma separated list: `:host-context(.one, .two)`.
|
|
var newContextSelectors = ((_a = match[1]) !== null && _a !== void 0 ? _a : '').trim().split(',').map(function (m) { return m.trim(); }).filter(function (m) { return m !== ''; });
|
|
// We must duplicate the current selector group for each of these new selectors.
|
|
// For example if the current groups are:
|
|
// ```
|
|
// [
|
|
// ['a', 'b', 'c'],
|
|
// ['x', 'y', 'z'],
|
|
// ]
|
|
// ```
|
|
// And we have a new set of comma separated selectors: `:host-context(m,n)` then the new
|
|
// groups are:
|
|
// ```
|
|
// [
|
|
// ['a', 'b', 'c', 'm'],
|
|
// ['x', 'y', 'z', 'm'],
|
|
// ['a', 'b', 'c', 'n'],
|
|
// ['x', 'y', 'z', 'n'],
|
|
// ]
|
|
// ```
|
|
var contextSelectorGroupsLength = contextSelectorGroups.length;
|
|
repeatGroups(contextSelectorGroups, newContextSelectors.length);
|
|
for (var i = 0; i < newContextSelectors.length; i++) {
|
|
for (var j = 0; j < contextSelectorGroupsLength; j++) {
|
|
contextSelectorGroups[j + (i * contextSelectorGroupsLength)].push(newContextSelectors[i]);
|
|
}
|
|
}
|
|
// Update the `selectorText` and see repeat to see if there are more `:host-context`s.
|
|
selectorText = match[2];
|
|
}
|
|
// The context selectors now must be combined with each other to capture all the possible
|
|
// selectors that `:host-context` can match. See `combineHostContextSelectors()` for more
|
|
// info about how this is done.
|
|
return contextSelectorGroups
|
|
.map(function (contextSelectors) { return combineHostContextSelectors(contextSelectors, selectorText); })
|
|
.join(', ');
|
|
});
|
|
};
|
|
/*
|
|
* Convert combinators like ::shadow and pseudo-elements like ::content
|
|
* by replacing with space.
|
|
*/
|
|
ShadowCss.prototype._convertShadowDOMSelectors = function (cssText) {
|
|
return _shadowDOMSelectorsRe.reduce(function (result, pattern) { return result.replace(pattern, ' '); }, cssText);
|
|
};
|
|
// change a selector like 'div' to 'name div'
|
|
ShadowCss.prototype._scopeSelectors = function (cssText, scopeSelector, hostSelector) {
|
|
var _this = this;
|
|
return processRules(cssText, function (rule) {
|
|
var selector = rule.selector;
|
|
var content = rule.content;
|
|
if (rule.selector[0] !== '@') {
|
|
selector =
|
|
_this._scopeSelector(rule.selector, scopeSelector, hostSelector, _this.strictStyling);
|
|
}
|
|
else if (rule.selector.startsWith('@media') || rule.selector.startsWith('@supports') ||
|
|
rule.selector.startsWith('@document')) {
|
|
content = _this._scopeSelectors(rule.content, scopeSelector, hostSelector);
|
|
}
|
|
else if (rule.selector.startsWith('@font-face') || rule.selector.startsWith('@page')) {
|
|
content = _this._stripScopingSelectors(rule.content);
|
|
}
|
|
return new CssRule(selector, content);
|
|
});
|
|
};
|
|
/**
|
|
* Handle a css text that is within a rule that should not contain scope selectors by simply
|
|
* removing them! An example of such a rule is `@font-face`.
|
|
*
|
|
* `@font-face` rules cannot contain nested selectors. Nor can they be nested under a selector.
|
|
* Normally this would be a syntax error by the author of the styles. But in some rare cases, such
|
|
* as importing styles from a library, and applying `:host ::ng-deep` to the imported styles, we
|
|
* can end up with broken css if the imported styles happen to contain @font-face rules.
|
|
*
|
|
* For example:
|
|
*
|
|
* ```
|
|
* :host ::ng-deep {
|
|
* import 'some/lib/containing/font-face';
|
|
* }
|
|
*
|
|
* Similar logic applies to `@page` rules which can contain a particular set of properties,
|
|
* as well as some specific at-rules. Since they can't be encapsulated, we have to strip
|
|
* any scoping selectors from them. For more information: https://www.w3.org/TR/css-page-3
|
|
* ```
|
|
*/
|
|
ShadowCss.prototype._stripScopingSelectors = function (cssText) {
|
|
return processRules(cssText, function (rule) {
|
|
var selector = rule.selector.replace(_shadowDeepSelectors, ' ')
|
|
.replace(_polyfillHostNoCombinatorRe, ' ');
|
|
return new CssRule(selector, rule.content);
|
|
});
|
|
};
|
|
ShadowCss.prototype._scopeSelector = function (selector, scopeSelector, hostSelector, strict) {
|
|
var _this = this;
|
|
return selector.split(',')
|
|
.map(function (part) { return part.trim().split(_shadowDeepSelectors); })
|
|
.map(function (deepParts) {
|
|
var _b = __read(deepParts), shallowPart = _b[0], otherParts = _b.slice(1);
|
|
var applyScope = function (shallowPart) {
|
|
if (_this._selectorNeedsScoping(shallowPart, scopeSelector)) {
|
|
return strict ?
|
|
_this._applyStrictSelectorScope(shallowPart, scopeSelector, hostSelector) :
|
|
_this._applySelectorScope(shallowPart, scopeSelector, hostSelector);
|
|
}
|
|
else {
|
|
return shallowPart;
|
|
}
|
|
};
|
|
return __spreadArray([applyScope(shallowPart)], __read(otherParts)).join(' ');
|
|
})
|
|
.join(', ');
|
|
};
|
|
ShadowCss.prototype._selectorNeedsScoping = function (selector, scopeSelector) {
|
|
var re = this._makeScopeMatcher(scopeSelector);
|
|
return !re.test(selector);
|
|
};
|
|
ShadowCss.prototype._makeScopeMatcher = function (scopeSelector) {
|
|
var lre = /\[/g;
|
|
var rre = /\]/g;
|
|
scopeSelector = scopeSelector.replace(lre, '\\[').replace(rre, '\\]');
|
|
return new RegExp('^(' + scopeSelector + ')' + _selectorReSuffix, 'm');
|
|
};
|
|
ShadowCss.prototype._applySelectorScope = function (selector, scopeSelector, hostSelector) {
|
|
// Difference from webcomponents.js: scopeSelector could not be an array
|
|
return this._applySimpleSelectorScope(selector, scopeSelector, hostSelector);
|
|
};
|
|
// scope via name and [is=name]
|
|
ShadowCss.prototype._applySimpleSelectorScope = function (selector, scopeSelector, hostSelector) {
|
|
// In Android browser, the lastIndex is not reset when the regex is used in String.replace()
|
|
_polyfillHostRe.lastIndex = 0;
|
|
if (_polyfillHostRe.test(selector)) {
|
|
var replaceBy_1 = this.strictStyling ? "[" + hostSelector + "]" : scopeSelector;
|
|
return selector
|
|
.replace(_polyfillHostNoCombinatorRe, function (hnc, selector) {
|
|
return selector.replace(/([^:]*)(:*)(.*)/, function (_, before, colon, after) {
|
|
return before + replaceBy_1 + colon + after;
|
|
});
|
|
})
|
|
.replace(_polyfillHostRe, replaceBy_1 + ' ');
|
|
}
|
|
return scopeSelector + ' ' + selector;
|
|
};
|
|
// return a selector with [name] suffix on each simple selector
|
|
// e.g. .foo.bar > .zot becomes .foo[name].bar[name] > .zot[name] /** @internal */
|
|
ShadowCss.prototype._applyStrictSelectorScope = function (selector, scopeSelector, hostSelector) {
|
|
var _this = this;
|
|
var isRe = /\[is=([^\]]*)\]/g;
|
|
scopeSelector = scopeSelector.replace(isRe, function (_) {
|
|
var parts = [];
|
|
for (var _i = 1; _i < arguments.length; _i++) {
|
|
parts[_i - 1] = arguments[_i];
|
|
}
|
|
return parts[0];
|
|
});
|
|
var attrName = '[' + scopeSelector + ']';
|
|
var _scopeSelectorPart = function (p) {
|
|
var scopedP = p.trim();
|
|
if (!scopedP) {
|
|
return '';
|
|
}
|
|
if (p.indexOf(_polyfillHostNoCombinator) > -1) {
|
|
scopedP = _this._applySimpleSelectorScope(p, scopeSelector, hostSelector);
|
|
}
|
|
else {
|
|
// remove :host since it should be unnecessary
|
|
var t = p.replace(_polyfillHostRe, '');
|
|
if (t.length > 0) {
|
|
var matches = t.match(/([^:]*)(:*)(.*)/);
|
|
if (matches) {
|
|
scopedP = matches[1] + attrName + matches[2] + matches[3];
|
|
}
|
|
}
|
|
}
|
|
return scopedP;
|
|
};
|
|
var safeContent = new SafeSelector(selector);
|
|
selector = safeContent.content();
|
|
var scopedSelector = '';
|
|
var startIndex = 0;
|
|
var res;
|
|
var sep = /( |>|\+|~(?!=))\s*/g;
|
|
// If a selector appears before :host it should not be shimmed as it
|
|
// matches on ancestor elements and not on elements in the host's shadow
|
|
// `:host-context(div)` is transformed to
|
|
// `-shadowcsshost-no-combinatordiv, div -shadowcsshost-no-combinator`
|
|
// the `div` is not part of the component in the 2nd selectors and should not be scoped.
|
|
// Historically `component-tag:host` was matching the component so we also want to preserve
|
|
// this behavior to avoid breaking legacy apps (it should not match).
|
|
// The behavior should be:
|
|
// - `tag:host` -> `tag[h]` (this is to avoid breaking legacy apps, should not match anything)
|
|
// - `tag :host` -> `tag [h]` (`tag` is not scoped because it's considered part of a
|
|
// `:host-context(tag)`)
|
|
var hasHost = selector.indexOf(_polyfillHostNoCombinator) > -1;
|
|
// Only scope parts after the first `-shadowcsshost-no-combinator` when it is present
|
|
var shouldScope = !hasHost;
|
|
while ((res = sep.exec(selector)) !== null) {
|
|
var separator = res[1];
|
|
var part_1 = selector.slice(startIndex, res.index).trim();
|
|
shouldScope = shouldScope || part_1.indexOf(_polyfillHostNoCombinator) > -1;
|
|
var scopedPart = shouldScope ? _scopeSelectorPart(part_1) : part_1;
|
|
scopedSelector += scopedPart + " " + separator + " ";
|
|
startIndex = sep.lastIndex;
|
|
}
|
|
var part = selector.substring(startIndex);
|
|
shouldScope = shouldScope || part.indexOf(_polyfillHostNoCombinator) > -1;
|
|
scopedSelector += shouldScope ? _scopeSelectorPart(part) : part;
|
|
// replace the placeholders with their original values
|
|
return safeContent.restore(scopedSelector);
|
|
};
|
|
ShadowCss.prototype._insertPolyfillHostInCssText = function (selector) {
|
|
return selector.replace(_colonHostContextRe, _polyfillHostContext)
|
|
.replace(_colonHostRe, _polyfillHost);
|
|
};
|
|
return ShadowCss;
|
|
}());
|
|
var SafeSelector = /** @class */ (function () {
|
|
function SafeSelector(selector) {
|
|
var _this = this;
|
|
this.placeholders = [];
|
|
this.index = 0;
|
|
// Replaces attribute selectors with placeholders.
|
|
// The WS in [attr="va lue"] would otherwise be interpreted as a selector separator.
|
|
selector = this._escapeRegexMatches(selector, /(\[[^\]]*\])/g);
|
|
// CSS allows for certain special characters to be used in selectors if they're escaped.
|
|
// E.g. `.foo:blue` won't match a class called `foo:blue`, because the colon denotes a
|
|
// pseudo-class, but writing `.foo\:blue` will match, because the colon was escaped.
|
|
// Replace all escape sequences (`\` followed by a character) with a placeholder so
|
|
// that our handling of pseudo-selectors doesn't mess with them.
|
|
selector = this._escapeRegexMatches(selector, /(\\.)/g);
|
|
// Replaces the expression in `:nth-child(2n + 1)` with a placeholder.
|
|
// WS and "+" would otherwise be interpreted as selector separators.
|
|
this._content = selector.replace(/(:nth-[-\w]+)(\([^)]+\))/g, function (_, pseudo, exp) {
|
|
var replaceBy = "__ph-" + _this.index + "__";
|
|
_this.placeholders.push(exp);
|
|
_this.index++;
|
|
return pseudo + replaceBy;
|
|
});
|
|
}
|
|
SafeSelector.prototype.restore = function (content) {
|
|
var _this = this;
|
|
return content.replace(/__ph-(\d+)__/g, function (_ph, index) { return _this.placeholders[+index]; });
|
|
};
|
|
SafeSelector.prototype.content = function () {
|
|
return this._content;
|
|
};
|
|
/**
|
|
* Replaces all of the substrings that match a regex within a
|
|
* special string (e.g. `__ph-0__`, `__ph-1__`, etc).
|
|
*/
|
|
SafeSelector.prototype._escapeRegexMatches = function (content, pattern) {
|
|
var _this = this;
|
|
return content.replace(pattern, function (_, keep) {
|
|
var replaceBy = "__ph-" + _this.index + "__";
|
|
_this.placeholders.push(keep);
|
|
_this.index++;
|
|
return replaceBy;
|
|
});
|
|
};
|
|
return SafeSelector;
|
|
}());
|
|
var _cssContentNextSelectorRe = /polyfill-next-selector[^}]*content:[\s]*?(['"])(.*?)\1[;\s]*}([^{]*?){/gim;
|
|
var _cssContentRuleRe = /(polyfill-rule)[^}]*(content:[\s]*(['"])(.*?)\3)[;\s]*[^}]*}/gim;
|
|
var _cssContentUnscopedRuleRe = /(polyfill-unscoped-rule)[^}]*(content:[\s]*(['"])(.*?)\3)[;\s]*[^}]*}/gim;
|
|
var _polyfillHost = '-shadowcsshost';
|
|
// note: :host-context pre-processed to -shadowcsshostcontext.
|
|
var _polyfillHostContext = '-shadowcsscontext';
|
|
var _parenSuffix = '(?:\\((' +
|
|
'(?:\\([^)(]*\\)|[^)(]*)+?' +
|
|
')\\))?([^,{]*)';
|
|
var _cssColonHostRe = new RegExp(_polyfillHost + _parenSuffix, 'gim');
|
|
var _cssColonHostContextReGlobal = new RegExp(_polyfillHostContext + _parenSuffix, 'gim');
|
|
var _cssColonHostContextRe = new RegExp(_polyfillHostContext + _parenSuffix, 'im');
|
|
var _polyfillHostNoCombinator = _polyfillHost + '-no-combinator';
|
|
var _polyfillHostNoCombinatorRe = /-shadowcsshost-no-combinator([^\s]*)/;
|
|
var _shadowDOMSelectorsRe = [
|
|
/::shadow/g,
|
|
/::content/g,
|
|
// Deprecated selectors
|
|
/\/shadow-deep\//g,
|
|
/\/shadow\//g,
|
|
];
|
|
// The deep combinator is deprecated in the CSS spec
|
|
// Support for `>>>`, `deep`, `::ng-deep` is then also deprecated and will be removed in the future.
|
|
// see https://github.com/angular/angular/pull/17677
|
|
var _shadowDeepSelectors = /(?:>>>)|(?:\/deep\/)|(?:::ng-deep)/g;
|
|
var _selectorReSuffix = '([>\\s~+[.,{:][\\s\\S]*)?$';
|
|
var _polyfillHostRe = /-shadowcsshost/gim;
|
|
var _colonHostRe = /:host/gim;
|
|
var _colonHostContextRe = /:host-context/gim;
|
|
var _commentRe = /\/\*[\s\S]*?\*\//g;
|
|
function stripComments(input) {
|
|
return input.replace(_commentRe, '');
|
|
}
|
|
var _commentWithHashRe = /\/\*\s*#\s*source(Mapping)?URL=[\s\S]+?\*\//g;
|
|
function extractCommentsWithHash(input) {
|
|
return input.match(_commentWithHashRe) || [];
|
|
}
|
|
var BLOCK_PLACEHOLDER = '%BLOCK%';
|
|
var QUOTE_PLACEHOLDER = '%QUOTED%';
|
|
var _ruleRe = /(\s*)([^;\{\}]+?)(\s*)((?:{%BLOCK%}?\s*;?)|(?:\s*;))/g;
|
|
var _quotedRe = /%QUOTED%/g;
|
|
var CONTENT_PAIRS = new Map([['{', '}']]);
|
|
var QUOTE_PAIRS = new Map([["\"", "\""], ["'", "'"]]);
|
|
var CssRule = /** @class */ (function () {
|
|
function CssRule(selector, content) {
|
|
this.selector = selector;
|
|
this.content = content;
|
|
}
|
|
return CssRule;
|
|
}());
|
|
function processRules(input, ruleCallback) {
|
|
var inputWithEscapedQuotes = escapeBlocks(input, QUOTE_PAIRS, QUOTE_PLACEHOLDER);
|
|
var inputWithEscapedBlocks = escapeBlocks(inputWithEscapedQuotes.escapedString, CONTENT_PAIRS, BLOCK_PLACEHOLDER);
|
|
var nextBlockIndex = 0;
|
|
var nextQuoteIndex = 0;
|
|
return inputWithEscapedBlocks.escapedString
|
|
.replace(_ruleRe, function () {
|
|
var m = [];
|
|
for (var _i = 0; _i < arguments.length; _i++) {
|
|
m[_i] = arguments[_i];
|
|
}
|
|
var selector = m[2];
|
|
var content = '';
|
|
var suffix = m[4];
|
|
var contentPrefix = '';
|
|
if (suffix && suffix.startsWith('{' + BLOCK_PLACEHOLDER)) {
|
|
content = inputWithEscapedBlocks.blocks[nextBlockIndex++];
|
|
suffix = suffix.substring(BLOCK_PLACEHOLDER.length + 1);
|
|
contentPrefix = '{';
|
|
}
|
|
var rule = ruleCallback(new CssRule(selector, content));
|
|
return "" + m[1] + rule.selector + m[3] + contentPrefix + rule.content + suffix;
|
|
})
|
|
.replace(_quotedRe, function () { return inputWithEscapedQuotes.blocks[nextQuoteIndex++]; });
|
|
}
|
|
var StringWithEscapedBlocks = /** @class */ (function () {
|
|
function StringWithEscapedBlocks(escapedString, blocks) {
|
|
this.escapedString = escapedString;
|
|
this.blocks = blocks;
|
|
}
|
|
return StringWithEscapedBlocks;
|
|
}());
|
|
function escapeBlocks(input, charPairs, placeholder) {
|
|
var resultParts = [];
|
|
var escapedBlocks = [];
|
|
var openCharCount = 0;
|
|
var nonBlockStartIndex = 0;
|
|
var blockStartIndex = -1;
|
|
var openChar;
|
|
var closeChar;
|
|
for (var i = 0; i < input.length; i++) {
|
|
var char = input[i];
|
|
if (char === '\\') {
|
|
i++;
|
|
}
|
|
else if (char === closeChar) {
|
|
openCharCount--;
|
|
if (openCharCount === 0) {
|
|
escapedBlocks.push(input.substring(blockStartIndex, i));
|
|
resultParts.push(placeholder);
|
|
nonBlockStartIndex = i;
|
|
blockStartIndex = -1;
|
|
openChar = closeChar = undefined;
|
|
}
|
|
}
|
|
else if (char === openChar) {
|
|
openCharCount++;
|
|
}
|
|
else if (openCharCount === 0 && charPairs.has(char)) {
|
|
openChar = char;
|
|
closeChar = charPairs.get(char);
|
|
openCharCount = 1;
|
|
blockStartIndex = i + 1;
|
|
resultParts.push(input.substring(nonBlockStartIndex, blockStartIndex));
|
|
}
|
|
}
|
|
if (blockStartIndex !== -1) {
|
|
escapedBlocks.push(input.substring(blockStartIndex));
|
|
resultParts.push(placeholder);
|
|
}
|
|
else {
|
|
resultParts.push(input.substring(nonBlockStartIndex));
|
|
}
|
|
return new StringWithEscapedBlocks(resultParts.join(''), escapedBlocks);
|
|
}
|
|
/**
|
|
* Combine the `contextSelectors` with the `hostMarker` and the `otherSelectors`
|
|
* to create a selector that matches the same as `:host-context()`.
|
|
*
|
|
* Given a single context selector `A` we need to output selectors that match on the host and as an
|
|
* ancestor of the host:
|
|
*
|
|
* ```
|
|
* A <hostMarker>, A<hostMarker> {}
|
|
* ```
|
|
*
|
|
* When there is more than one context selector we also have to create combinations of those
|
|
* selectors with each other. For example if there are `A` and `B` selectors the output is:
|
|
*
|
|
* ```
|
|
* AB<hostMarker>, AB <hostMarker>, A B<hostMarker>,
|
|
* B A<hostMarker>, A B <hostMarker>, B A <hostMarker> {}
|
|
* ```
|
|
*
|
|
* And so on...
|
|
*
|
|
* @param hostMarker the string that selects the host element.
|
|
* @param contextSelectors an array of context selectors that will be combined.
|
|
* @param otherSelectors the rest of the selectors that are not context selectors.
|
|
*/
|
|
function combineHostContextSelectors(contextSelectors, otherSelectors) {
|
|
var hostMarker = _polyfillHostNoCombinator;
|
|
_polyfillHostRe.lastIndex = 0; // reset the regex to ensure we get an accurate test
|
|
var otherSelectorsHasHost = _polyfillHostRe.test(otherSelectors);
|
|
// If there are no context selectors then just output a host marker
|
|
if (contextSelectors.length === 0) {
|
|
return hostMarker + otherSelectors;
|
|
}
|
|
var combined = [contextSelectors.pop() || ''];
|
|
while (contextSelectors.length > 0) {
|
|
var length = combined.length;
|
|
var contextSelector = contextSelectors.pop();
|
|
for (var i = 0; i < length; i++) {
|
|
var previousSelectors = combined[i];
|
|
// Add the new selector as a descendant of the previous selectors
|
|
combined[length * 2 + i] = previousSelectors + ' ' + contextSelector;
|
|
// Add the new selector as an ancestor of the previous selectors
|
|
combined[length + i] = contextSelector + ' ' + previousSelectors;
|
|
// Add the new selector to act on the same element as the previous selectors
|
|
combined[i] = contextSelector + previousSelectors;
|
|
}
|
|
}
|
|
// Finally connect the selector to the `hostMarker`s: either acting directly on the host
|
|
// (A<hostMarker>) or as an ancestor (A <hostMarker>).
|
|
return combined
|
|
.map(function (s) { return otherSelectorsHasHost ?
|
|
"" + s + otherSelectors :
|
|
"" + s + hostMarker + otherSelectors + ", " + s + " " + hostMarker + otherSelectors; })
|
|
.join(',');
|
|
}
|
|
/**
|
|
* Mutate the given `groups` array so that there are `multiples` clones of the original array
|
|
* stored.
|
|
*
|
|
* For example `repeatGroups([a, b], 3)` will result in `[a, b, a, b, a, b]` - but importantly the
|
|
* newly added groups will be clones of the original.
|
|
*
|
|
* @param groups An array of groups of strings that will be repeated. This array is mutated
|
|
* in-place.
|
|
* @param multiples The number of times the current groups should appear.
|
|
*/
|
|
function repeatGroups(groups, multiples) {
|
|
var length = groups.length;
|
|
for (var i = 1; i < multiples; i++) {
|
|
for (var j = 0; j < length; j++) {
|
|
groups[j + (i * length)] = groups[j].slice(0);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @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
|
|
*/
|
|
// group 0: "[prop] or (event) or @trigger"
|
|
// group 1: "prop" from "[prop]"
|
|
// group 2: "event" from "(event)"
|
|
// group 3: "@trigger" from "@trigger"
|
|
var HOST_REG_EXP = /^(?:(?:\[([^\]]+)\])|(?:\(([^\)]+)\)))|(\@[-\w]+)$/;
|
|
function viewClassName(compType, embeddedTemplateIndex) {
|
|
return "View_" + identifierName({ reference: compType }) + "_" + embeddedTemplateIndex;
|
|
}
|
|
function rendererTypeName(compType) {
|
|
return "RenderType_" + identifierName({ reference: compType });
|
|
}
|
|
function hostViewClassName(compType) {
|
|
return "HostView_" + identifierName({ reference: compType });
|
|
}
|
|
function componentFactoryName(compType) {
|
|
return identifierName({ reference: compType }) + "NgFactory";
|
|
}
|
|
(function (CompileSummaryKind) {
|
|
CompileSummaryKind[CompileSummaryKind["Pipe"] = 0] = "Pipe";
|
|
CompileSummaryKind[CompileSummaryKind["Directive"] = 1] = "Directive";
|
|
CompileSummaryKind[CompileSummaryKind["NgModule"] = 2] = "NgModule";
|
|
CompileSummaryKind[CompileSummaryKind["Injectable"] = 3] = "Injectable";
|
|
})(exports.CompileSummaryKind || (exports.CompileSummaryKind = {}));
|
|
function tokenName(token) {
|
|
return token.value != null ? sanitizeIdentifier(token.value) : identifierName(token.identifier);
|
|
}
|
|
function tokenReference(token) {
|
|
if (token.identifier != null) {
|
|
return token.identifier.reference;
|
|
}
|
|
else {
|
|
return token.value;
|
|
}
|
|
}
|
|
/**
|
|
* Metadata about a stylesheet
|
|
*/
|
|
var CompileStylesheetMetadata = /** @class */ (function () {
|
|
function CompileStylesheetMetadata(_a) {
|
|
var _b = _a === void 0 ? {} : _a, moduleUrl = _b.moduleUrl, styles = _b.styles, styleUrls = _b.styleUrls;
|
|
this.moduleUrl = moduleUrl || null;
|
|
this.styles = _normalizeArray(styles);
|
|
this.styleUrls = _normalizeArray(styleUrls);
|
|
}
|
|
return CompileStylesheetMetadata;
|
|
}());
|
|
/**
|
|
* Metadata regarding compilation of a template.
|
|
*/
|
|
var CompileTemplateMetadata = /** @class */ (function () {
|
|
function CompileTemplateMetadata(_a) {
|
|
var encapsulation = _a.encapsulation, template = _a.template, templateUrl = _a.templateUrl, htmlAst = _a.htmlAst, styles = _a.styles, styleUrls = _a.styleUrls, externalStylesheets = _a.externalStylesheets, animations = _a.animations, ngContentSelectors = _a.ngContentSelectors, interpolation = _a.interpolation, isInline = _a.isInline, preserveWhitespaces = _a.preserveWhitespaces;
|
|
this.encapsulation = encapsulation;
|
|
this.template = template;
|
|
this.templateUrl = templateUrl;
|
|
this.htmlAst = htmlAst;
|
|
this.styles = _normalizeArray(styles);
|
|
this.styleUrls = _normalizeArray(styleUrls);
|
|
this.externalStylesheets = _normalizeArray(externalStylesheets);
|
|
this.animations = animations ? flatten(animations) : [];
|
|
this.ngContentSelectors = ngContentSelectors || [];
|
|
if (interpolation && interpolation.length != 2) {
|
|
throw new Error("'interpolation' should have a start and an end symbol.");
|
|
}
|
|
this.interpolation = interpolation;
|
|
this.isInline = isInline;
|
|
this.preserveWhitespaces = preserveWhitespaces;
|
|
}
|
|
CompileTemplateMetadata.prototype.toSummary = function () {
|
|
return {
|
|
ngContentSelectors: this.ngContentSelectors,
|
|
encapsulation: this.encapsulation,
|
|
styles: this.styles,
|
|
animations: this.animations
|
|
};
|
|
};
|
|
return CompileTemplateMetadata;
|
|
}());
|
|
/**
|
|
* Metadata regarding compilation of a directive.
|
|
*/
|
|
var CompileDirectiveMetadata = /** @class */ (function () {
|
|
function CompileDirectiveMetadata(_a) {
|
|
var isHost = _a.isHost, type = _a.type, isComponent = _a.isComponent, selector = _a.selector, exportAs = _a.exportAs, changeDetection = _a.changeDetection, inputs = _a.inputs, outputs = _a.outputs, hostListeners = _a.hostListeners, hostProperties = _a.hostProperties, hostAttributes = _a.hostAttributes, providers = _a.providers, viewProviders = _a.viewProviders, queries = _a.queries, guards = _a.guards, viewQueries = _a.viewQueries, entryComponents = _a.entryComponents, template = _a.template, componentViewType = _a.componentViewType, rendererType = _a.rendererType, componentFactory = _a.componentFactory;
|
|
this.isHost = !!isHost;
|
|
this.type = type;
|
|
this.isComponent = isComponent;
|
|
this.selector = selector;
|
|
this.exportAs = exportAs;
|
|
this.changeDetection = changeDetection;
|
|
this.inputs = inputs;
|
|
this.outputs = outputs;
|
|
this.hostListeners = hostListeners;
|
|
this.hostProperties = hostProperties;
|
|
this.hostAttributes = hostAttributes;
|
|
this.providers = _normalizeArray(providers);
|
|
this.viewProviders = _normalizeArray(viewProviders);
|
|
this.queries = _normalizeArray(queries);
|
|
this.guards = guards;
|
|
this.viewQueries = _normalizeArray(viewQueries);
|
|
this.entryComponents = _normalizeArray(entryComponents);
|
|
this.template = template;
|
|
this.componentViewType = componentViewType;
|
|
this.rendererType = rendererType;
|
|
this.componentFactory = componentFactory;
|
|
}
|
|
CompileDirectiveMetadata.create = function (_a) {
|
|
var isHost = _a.isHost, type = _a.type, isComponent = _a.isComponent, selector = _a.selector, exportAs = _a.exportAs, changeDetection = _a.changeDetection, inputs = _a.inputs, outputs = _a.outputs, host = _a.host, providers = _a.providers, viewProviders = _a.viewProviders, queries = _a.queries, guards = _a.guards, viewQueries = _a.viewQueries, entryComponents = _a.entryComponents, template = _a.template, componentViewType = _a.componentViewType, rendererType = _a.rendererType, componentFactory = _a.componentFactory;
|
|
var hostListeners = {};
|
|
var hostProperties = {};
|
|
var hostAttributes = {};
|
|
if (host != null) {
|
|
Object.keys(host).forEach(function (key) {
|
|
var value = host[key];
|
|
var matches = key.match(HOST_REG_EXP);
|
|
if (matches === null) {
|
|
hostAttributes[key] = value;
|
|
}
|
|
else if (matches[1] != null) {
|
|
hostProperties[matches[1]] = value;
|
|
}
|
|
else if (matches[2] != null) {
|
|
hostListeners[matches[2]] = value;
|
|
}
|
|
});
|
|
}
|
|
var inputsMap = {};
|
|
if (inputs != null) {
|
|
inputs.forEach(function (bindConfig) {
|
|
// canonical syntax: `dirProp: elProp`
|
|
// if there is no `:`, use dirProp = elProp
|
|
var parts = splitAtColon(bindConfig, [bindConfig, bindConfig]);
|
|
inputsMap[parts[0]] = parts[1];
|
|
});
|
|
}
|
|
var outputsMap = {};
|
|
if (outputs != null) {
|
|
outputs.forEach(function (bindConfig) {
|
|
// canonical syntax: `dirProp: elProp`
|
|
// if there is no `:`, use dirProp = elProp
|
|
var parts = splitAtColon(bindConfig, [bindConfig, bindConfig]);
|
|
outputsMap[parts[0]] = parts[1];
|
|
});
|
|
}
|
|
return new CompileDirectiveMetadata({
|
|
isHost: isHost,
|
|
type: type,
|
|
isComponent: !!isComponent,
|
|
selector: selector,
|
|
exportAs: exportAs,
|
|
changeDetection: changeDetection,
|
|
inputs: inputsMap,
|
|
outputs: outputsMap,
|
|
hostListeners: hostListeners,
|
|
hostProperties: hostProperties,
|
|
hostAttributes: hostAttributes,
|
|
providers: providers,
|
|
viewProviders: viewProviders,
|
|
queries: queries,
|
|
guards: guards,
|
|
viewQueries: viewQueries,
|
|
entryComponents: entryComponents,
|
|
template: template,
|
|
componentViewType: componentViewType,
|
|
rendererType: rendererType,
|
|
componentFactory: componentFactory,
|
|
});
|
|
};
|
|
CompileDirectiveMetadata.prototype.toSummary = function () {
|
|
return {
|
|
summaryKind: exports.CompileSummaryKind.Directive,
|
|
type: this.type,
|
|
isComponent: this.isComponent,
|
|
selector: this.selector,
|
|
exportAs: this.exportAs,
|
|
inputs: this.inputs,
|
|
outputs: this.outputs,
|
|
hostListeners: this.hostListeners,
|
|
hostProperties: this.hostProperties,
|
|
hostAttributes: this.hostAttributes,
|
|
providers: this.providers,
|
|
viewProviders: this.viewProviders,
|
|
queries: this.queries,
|
|
guards: this.guards,
|
|
viewQueries: this.viewQueries,
|
|
entryComponents: this.entryComponents,
|
|
changeDetection: this.changeDetection,
|
|
template: this.template && this.template.toSummary(),
|
|
componentViewType: this.componentViewType,
|
|
rendererType: this.rendererType,
|
|
componentFactory: this.componentFactory
|
|
};
|
|
};
|
|
return CompileDirectiveMetadata;
|
|
}());
|
|
var CompilePipeMetadata = /** @class */ (function () {
|
|
function CompilePipeMetadata(_a) {
|
|
var type = _a.type, name = _a.name, pure = _a.pure;
|
|
this.type = type;
|
|
this.name = name;
|
|
this.pure = !!pure;
|
|
}
|
|
CompilePipeMetadata.prototype.toSummary = function () {
|
|
return {
|
|
summaryKind: exports.CompileSummaryKind.Pipe,
|
|
type: this.type,
|
|
name: this.name,
|
|
pure: this.pure
|
|
};
|
|
};
|
|
return CompilePipeMetadata;
|
|
}());
|
|
var CompileShallowModuleMetadata = /** @class */ (function () {
|
|
function CompileShallowModuleMetadata() {
|
|
}
|
|
return CompileShallowModuleMetadata;
|
|
}());
|
|
/**
|
|
* Metadata regarding compilation of a module.
|
|
*/
|
|
var CompileNgModuleMetadata = /** @class */ (function () {
|
|
function CompileNgModuleMetadata(_a) {
|
|
var type = _a.type, providers = _a.providers, declaredDirectives = _a.declaredDirectives, exportedDirectives = _a.exportedDirectives, declaredPipes = _a.declaredPipes, exportedPipes = _a.exportedPipes, entryComponents = _a.entryComponents, bootstrapComponents = _a.bootstrapComponents, importedModules = _a.importedModules, exportedModules = _a.exportedModules, schemas = _a.schemas, transitiveModule = _a.transitiveModule, id = _a.id;
|
|
this.type = type || null;
|
|
this.declaredDirectives = _normalizeArray(declaredDirectives);
|
|
this.exportedDirectives = _normalizeArray(exportedDirectives);
|
|
this.declaredPipes = _normalizeArray(declaredPipes);
|
|
this.exportedPipes = _normalizeArray(exportedPipes);
|
|
this.providers = _normalizeArray(providers);
|
|
this.entryComponents = _normalizeArray(entryComponents);
|
|
this.bootstrapComponents = _normalizeArray(bootstrapComponents);
|
|
this.importedModules = _normalizeArray(importedModules);
|
|
this.exportedModules = _normalizeArray(exportedModules);
|
|
this.schemas = _normalizeArray(schemas);
|
|
this.id = id || null;
|
|
this.transitiveModule = transitiveModule || null;
|
|
}
|
|
CompileNgModuleMetadata.prototype.toSummary = function () {
|
|
var module = this.transitiveModule;
|
|
return {
|
|
summaryKind: exports.CompileSummaryKind.NgModule,
|
|
type: this.type,
|
|
entryComponents: module.entryComponents,
|
|
providers: module.providers,
|
|
modules: module.modules,
|
|
exportedDirectives: module.exportedDirectives,
|
|
exportedPipes: module.exportedPipes
|
|
};
|
|
};
|
|
return CompileNgModuleMetadata;
|
|
}());
|
|
var TransitiveCompileNgModuleMetadata = /** @class */ (function () {
|
|
function TransitiveCompileNgModuleMetadata() {
|
|
this.directivesSet = new Set();
|
|
this.directives = [];
|
|
this.exportedDirectivesSet = new Set();
|
|
this.exportedDirectives = [];
|
|
this.pipesSet = new Set();
|
|
this.pipes = [];
|
|
this.exportedPipesSet = new Set();
|
|
this.exportedPipes = [];
|
|
this.modulesSet = new Set();
|
|
this.modules = [];
|
|
this.entryComponentsSet = new Set();
|
|
this.entryComponents = [];
|
|
this.providers = [];
|
|
}
|
|
TransitiveCompileNgModuleMetadata.prototype.addProvider = function (provider, module) {
|
|
this.providers.push({ provider: provider, module: module });
|
|
};
|
|
TransitiveCompileNgModuleMetadata.prototype.addDirective = function (id) {
|
|
if (!this.directivesSet.has(id.reference)) {
|
|
this.directivesSet.add(id.reference);
|
|
this.directives.push(id);
|
|
}
|
|
};
|
|
TransitiveCompileNgModuleMetadata.prototype.addExportedDirective = function (id) {
|
|
if (!this.exportedDirectivesSet.has(id.reference)) {
|
|
this.exportedDirectivesSet.add(id.reference);
|
|
this.exportedDirectives.push(id);
|
|
}
|
|
};
|
|
TransitiveCompileNgModuleMetadata.prototype.addPipe = function (id) {
|
|
if (!this.pipesSet.has(id.reference)) {
|
|
this.pipesSet.add(id.reference);
|
|
this.pipes.push(id);
|
|
}
|
|
};
|
|
TransitiveCompileNgModuleMetadata.prototype.addExportedPipe = function (id) {
|
|
if (!this.exportedPipesSet.has(id.reference)) {
|
|
this.exportedPipesSet.add(id.reference);
|
|
this.exportedPipes.push(id);
|
|
}
|
|
};
|
|
TransitiveCompileNgModuleMetadata.prototype.addModule = function (id) {
|
|
if (!this.modulesSet.has(id.reference)) {
|
|
this.modulesSet.add(id.reference);
|
|
this.modules.push(id);
|
|
}
|
|
};
|
|
TransitiveCompileNgModuleMetadata.prototype.addEntryComponent = function (ec) {
|
|
if (!this.entryComponentsSet.has(ec.componentType)) {
|
|
this.entryComponentsSet.add(ec.componentType);
|
|
this.entryComponents.push(ec);
|
|
}
|
|
};
|
|
return TransitiveCompileNgModuleMetadata;
|
|
}());
|
|
function _normalizeArray(obj) {
|
|
return obj || [];
|
|
}
|
|
var ProviderMeta = /** @class */ (function () {
|
|
function ProviderMeta(token, _a) {
|
|
var useClass = _a.useClass, useValue = _a.useValue, useExisting = _a.useExisting, useFactory = _a.useFactory, deps = _a.deps, multi = _a.multi;
|
|
this.token = token;
|
|
this.useClass = useClass || null;
|
|
this.useValue = useValue;
|
|
this.useExisting = useExisting;
|
|
this.useFactory = useFactory || null;
|
|
this.dependencies = deps || null;
|
|
this.multi = !!multi;
|
|
}
|
|
return ProviderMeta;
|
|
}());
|
|
function flatten(list) {
|
|
return list.reduce(function (flat, item) {
|
|
var flatItem = Array.isArray(item) ? flatten(item) : item;
|
|
return flat.concat(flatItem);
|
|
}, []);
|
|
}
|
|
function jitSourceUrl(url) {
|
|
// Note: We need 3 "/" so that ng shows up as a separate domain
|
|
// in the chrome dev tools.
|
|
return url.replace(/(\w+:\/\/[\w:-]+)?(\/+)?/, 'ng:///');
|
|
}
|
|
function templateSourceUrl(ngModuleType, compMeta, templateMeta) {
|
|
var url;
|
|
if (templateMeta.isInline) {
|
|
if (compMeta.type.reference instanceof StaticSymbol) {
|
|
// Note: a .ts file might contain multiple components with inline templates,
|
|
// so we need to give them unique urls, as these will be used for sourcemaps.
|
|
url = compMeta.type.reference.filePath + "." + compMeta.type.reference.name + ".html";
|
|
}
|
|
else {
|
|
url = identifierName(ngModuleType) + "/" + identifierName(compMeta.type) + ".html";
|
|
}
|
|
}
|
|
else {
|
|
url = templateMeta.templateUrl;
|
|
}
|
|
return compMeta.type.reference instanceof StaticSymbol ? url : jitSourceUrl(url);
|
|
}
|
|
function sharedStylesheetJitUrl(meta, id) {
|
|
var pathParts = meta.moduleUrl.split(/\/\\/g);
|
|
var baseName = pathParts[pathParts.length - 1];
|
|
return jitSourceUrl("css/" + id + baseName + ".ngstyle.js");
|
|
}
|
|
function ngModuleJitUrl(moduleMeta) {
|
|
return jitSourceUrl(identifierName(moduleMeta.type) + "/module.ngfactory.js");
|
|
}
|
|
function templateJitUrl(ngModuleType, compMeta) {
|
|
return jitSourceUrl(identifierName(ngModuleType) + "/" + identifierName(compMeta.type) + ".ngfactory.js");
|
|
}
|
|
|
|
/**
|
|
* @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 COMPONENT_VARIABLE = '%COMP%';
|
|
var HOST_ATTR = "_nghost-" + COMPONENT_VARIABLE;
|
|
var CONTENT_ATTR = "_ngcontent-" + COMPONENT_VARIABLE;
|
|
var StylesCompileDependency = /** @class */ (function () {
|
|
function StylesCompileDependency(name, moduleUrl, setValue) {
|
|
this.name = name;
|
|
this.moduleUrl = moduleUrl;
|
|
this.setValue = setValue;
|
|
}
|
|
return StylesCompileDependency;
|
|
}());
|
|
var CompiledStylesheet = /** @class */ (function () {
|
|
function CompiledStylesheet(outputCtx, stylesVar, dependencies, isShimmed, meta) {
|
|
this.outputCtx = outputCtx;
|
|
this.stylesVar = stylesVar;
|
|
this.dependencies = dependencies;
|
|
this.isShimmed = isShimmed;
|
|
this.meta = meta;
|
|
}
|
|
return CompiledStylesheet;
|
|
}());
|
|
var StyleCompiler = /** @class */ (function () {
|
|
function StyleCompiler(_urlResolver) {
|
|
this._urlResolver = _urlResolver;
|
|
this._shadowCss = new ShadowCss();
|
|
}
|
|
StyleCompiler.prototype.compileComponent = function (outputCtx, comp) {
|
|
var template = comp.template;
|
|
return this._compileStyles(outputCtx, comp, new CompileStylesheetMetadata({
|
|
styles: template.styles,
|
|
styleUrls: template.styleUrls,
|
|
moduleUrl: identifierModuleUrl(comp.type)
|
|
}), this.needsStyleShim(comp), true);
|
|
};
|
|
StyleCompiler.prototype.compileStyles = function (outputCtx, comp, stylesheet, shim) {
|
|
if (shim === void 0) { shim = this.needsStyleShim(comp); }
|
|
return this._compileStyles(outputCtx, comp, stylesheet, shim, false);
|
|
};
|
|
StyleCompiler.prototype.needsStyleShim = function (comp) {
|
|
return comp.template.encapsulation === ViewEncapsulation.Emulated;
|
|
};
|
|
StyleCompiler.prototype._compileStyles = function (outputCtx, comp, stylesheet, shim, isComponentStylesheet) {
|
|
var _this = this;
|
|
var styleExpressions = stylesheet.styles.map(function (plainStyle) { return literal(_this._shimIfNeeded(plainStyle, shim)); });
|
|
var dependencies = [];
|
|
stylesheet.styleUrls.forEach(function (styleUrl) {
|
|
var exprIndex = styleExpressions.length;
|
|
// Note: This placeholder will be filled later.
|
|
styleExpressions.push(null);
|
|
dependencies.push(new StylesCompileDependency(getStylesVarName(null), styleUrl, function (value) { return styleExpressions[exprIndex] = outputCtx.importExpr(value); }));
|
|
});
|
|
// styles variable contains plain strings and arrays of other styles arrays (recursive),
|
|
// so we set its type to dynamic.
|
|
var stylesVar = getStylesVarName(isComponentStylesheet ? comp : null);
|
|
var stmt = variable(stylesVar)
|
|
.set(literalArr(styleExpressions, new ArrayType(DYNAMIC_TYPE, [TypeModifier.Const])))
|
|
.toDeclStmt(null, isComponentStylesheet ? [exports.StmtModifier.Final] : [
|
|
exports.StmtModifier.Final, exports.StmtModifier.Exported
|
|
]);
|
|
outputCtx.statements.push(stmt);
|
|
return new CompiledStylesheet(outputCtx, stylesVar, dependencies, shim, stylesheet);
|
|
};
|
|
StyleCompiler.prototype._shimIfNeeded = function (style, shim) {
|
|
return shim ? this._shadowCss.shimCssText(style, CONTENT_ATTR, HOST_ATTR) : style;
|
|
};
|
|
return StyleCompiler;
|
|
}());
|
|
function getStylesVarName(component) {
|
|
var result = "styles";
|
|
if (component) {
|
|
result += "_" + identifierName(component.type);
|
|
}
|
|
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
|
|
*/
|
|
/**
|
|
* A path is an ordered set of elements. Typically a path is to a
|
|
* particular offset in a source file. The head of the list is the top
|
|
* most node. The tail is the node that contains the offset directly.
|
|
*
|
|
* For example, the expression `a + b + c` might have an ast that looks
|
|
* like:
|
|
* +
|
|
* / \
|
|
* a +
|
|
* / \
|
|
* b c
|
|
*
|
|
* The path to the node at offset 9 would be `['+' at 1-10, '+' at 7-10,
|
|
* 'c' at 9-10]` and the path the node at offset 1 would be
|
|
* `['+' at 1-10, 'a' at 1-2]`.
|
|
*/
|
|
var AstPath = /** @class */ (function () {
|
|
function AstPath(path, position) {
|
|
if (position === void 0) { position = -1; }
|
|
this.path = path;
|
|
this.position = position;
|
|
}
|
|
Object.defineProperty(AstPath.prototype, "empty", {
|
|
get: function () {
|
|
return !this.path || !this.path.length;
|
|
},
|
|
enumerable: false,
|
|
configurable: true
|
|
});
|
|
Object.defineProperty(AstPath.prototype, "head", {
|
|
get: function () {
|
|
return this.path[0];
|
|
},
|
|
enumerable: false,
|
|
configurable: true
|
|
});
|
|
Object.defineProperty(AstPath.prototype, "tail", {
|
|
get: function () {
|
|
return this.path[this.path.length - 1];
|
|
},
|
|
enumerable: false,
|
|
configurable: true
|
|
});
|
|
AstPath.prototype.parentOf = function (node) {
|
|
return node && this.path[this.path.indexOf(node) - 1];
|
|
};
|
|
AstPath.prototype.childOf = function (node) {
|
|
return this.path[this.path.indexOf(node) + 1];
|
|
};
|
|
AstPath.prototype.first = function (ctor) {
|
|
for (var i = this.path.length - 1; i >= 0; i--) {
|
|
var item = this.path[i];
|
|
if (item instanceof ctor)
|
|
return item;
|
|
}
|
|
};
|
|
AstPath.prototype.push = function (node) {
|
|
this.path.push(node);
|
|
};
|
|
AstPath.prototype.pop = function () {
|
|
return this.path.pop();
|
|
};
|
|
return AstPath;
|
|
}());
|
|
|
|
var NodeWithI18n = /** @class */ (function () {
|
|
function NodeWithI18n(sourceSpan, i18n) {
|
|
this.sourceSpan = sourceSpan;
|
|
this.i18n = i18n;
|
|
}
|
|
return NodeWithI18n;
|
|
}());
|
|
var Text$3 = /** @class */ (function (_super) {
|
|
__extends(Text, _super);
|
|
function Text(value, sourceSpan, tokens, i18n) {
|
|
var _this = _super.call(this, sourceSpan, i18n) || this;
|
|
_this.value = value;
|
|
_this.tokens = tokens;
|
|
return _this;
|
|
}
|
|
Text.prototype.visit = function (visitor, context) {
|
|
return visitor.visitText(this, context);
|
|
};
|
|
return Text;
|
|
}(NodeWithI18n));
|
|
var Expansion = /** @class */ (function (_super) {
|
|
__extends(Expansion, _super);
|
|
function Expansion(switchValue, type, cases, sourceSpan, switchValueSourceSpan, i18n) {
|
|
var _this = _super.call(this, sourceSpan, i18n) || this;
|
|
_this.switchValue = switchValue;
|
|
_this.type = type;
|
|
_this.cases = cases;
|
|
_this.switchValueSourceSpan = switchValueSourceSpan;
|
|
return _this;
|
|
}
|
|
Expansion.prototype.visit = function (visitor, context) {
|
|
return visitor.visitExpansion(this, context);
|
|
};
|
|
return Expansion;
|
|
}(NodeWithI18n));
|
|
var ExpansionCase = /** @class */ (function () {
|
|
function ExpansionCase(value, expression, sourceSpan, valueSourceSpan, expSourceSpan) {
|
|
this.value = value;
|
|
this.expression = expression;
|
|
this.sourceSpan = sourceSpan;
|
|
this.valueSourceSpan = valueSourceSpan;
|
|
this.expSourceSpan = expSourceSpan;
|
|
}
|
|
ExpansionCase.prototype.visit = function (visitor, context) {
|
|
return visitor.visitExpansionCase(this, context);
|
|
};
|
|
return ExpansionCase;
|
|
}());
|
|
var Attribute = /** @class */ (function (_super) {
|
|
__extends(Attribute, _super);
|
|
function Attribute(name, value, sourceSpan, keySpan, valueSpan, valueTokens, i18n) {
|
|
var _this = _super.call(this, sourceSpan, i18n) || this;
|
|
_this.name = name;
|
|
_this.value = value;
|
|
_this.keySpan = keySpan;
|
|
_this.valueSpan = valueSpan;
|
|
_this.valueTokens = valueTokens;
|
|
return _this;
|
|
}
|
|
Attribute.prototype.visit = function (visitor, context) {
|
|
return visitor.visitAttribute(this, context);
|
|
};
|
|
return Attribute;
|
|
}(NodeWithI18n));
|
|
var Element$1 = /** @class */ (function (_super) {
|
|
__extends(Element, _super);
|
|
function Element(name, attrs, children, sourceSpan, startSourceSpan, endSourceSpan, i18n) {
|
|
if (endSourceSpan === void 0) { endSourceSpan = null; }
|
|
var _this = _super.call(this, sourceSpan, i18n) || this;
|
|
_this.name = name;
|
|
_this.attrs = attrs;
|
|
_this.children = children;
|
|
_this.startSourceSpan = startSourceSpan;
|
|
_this.endSourceSpan = endSourceSpan;
|
|
return _this;
|
|
}
|
|
Element.prototype.visit = function (visitor, context) {
|
|
return visitor.visitElement(this, context);
|
|
};
|
|
return Element;
|
|
}(NodeWithI18n));
|
|
var Comment$1 = /** @class */ (function () {
|
|
function Comment(value, sourceSpan) {
|
|
this.value = value;
|
|
this.sourceSpan = sourceSpan;
|
|
}
|
|
Comment.prototype.visit = function (visitor, context) {
|
|
return visitor.visitComment(this, context);
|
|
};
|
|
return Comment;
|
|
}());
|
|
function visitAll$1(visitor, nodes, context) {
|
|
if (context === void 0) { context = null; }
|
|
var result = [];
|
|
var visit = visitor.visit ?
|
|
function (ast) { return visitor.visit(ast, context) || ast.visit(visitor, context); } :
|
|
function (ast) { return ast.visit(visitor, context); };
|
|
nodes.forEach(function (ast) {
|
|
var astResult = visit(ast);
|
|
if (astResult) {
|
|
result.push(astResult);
|
|
}
|
|
});
|
|
return result;
|
|
}
|
|
var RecursiveVisitor$1 = /** @class */ (function () {
|
|
function RecursiveVisitor() {
|
|
}
|
|
RecursiveVisitor.prototype.visitElement = function (ast, context) {
|
|
this.visitChildren(context, function (visit) {
|
|
visit(ast.attrs);
|
|
visit(ast.children);
|
|
});
|
|
};
|
|
RecursiveVisitor.prototype.visitAttribute = function (ast, context) { };
|
|
RecursiveVisitor.prototype.visitText = function (ast, context) { };
|
|
RecursiveVisitor.prototype.visitComment = function (ast, context) { };
|
|
RecursiveVisitor.prototype.visitExpansion = function (ast, context) {
|
|
return this.visitChildren(context, function (visit) {
|
|
visit(ast.cases);
|
|
});
|
|
};
|
|
RecursiveVisitor.prototype.visitExpansionCase = function (ast, context) { };
|
|
RecursiveVisitor.prototype.visitChildren = function (context, cb) {
|
|
var results = [];
|
|
var t = this;
|
|
function visit(children) {
|
|
if (children)
|
|
results.push(visitAll$1(t, children, context));
|
|
}
|
|
cb(visit);
|
|
return Array.prototype.concat.apply([], results);
|
|
};
|
|
return RecursiveVisitor;
|
|
}());
|
|
function spanOf(ast) {
|
|
var start = ast.sourceSpan.start.offset;
|
|
var end = ast.sourceSpan.end.offset;
|
|
if (ast instanceof Element$1) {
|
|
if (ast.endSourceSpan) {
|
|
end = ast.endSourceSpan.end.offset;
|
|
}
|
|
else if (ast.children && ast.children.length) {
|
|
end = spanOf(ast.children[ast.children.length - 1]).end;
|
|
}
|
|
}
|
|
return { start: start, end: end };
|
|
}
|
|
function findNode(nodes, position) {
|
|
var path = [];
|
|
var visitor = new /** @class */ (function (_super) {
|
|
__extends(class_1, _super);
|
|
function class_1() {
|
|
return _super !== null && _super.apply(this, arguments) || this;
|
|
}
|
|
class_1.prototype.visit = function (ast, context) {
|
|
var span = spanOf(ast);
|
|
if (span.start <= position && position < span.end) {
|
|
path.push(ast);
|
|
}
|
|
else {
|
|
// Returning a value here will result in the children being skipped.
|
|
return true;
|
|
}
|
|
};
|
|
return class_1;
|
|
}(RecursiveVisitor$1));
|
|
visitAll$1(visitor, nodes);
|
|
return new AstPath(path, position);
|
|
}
|
|
|
|
/**
|
|
* @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
|
|
*/
|
|
// Mapping between all HTML entity names and their unicode representation.
|
|
// Generated from https://html.spec.whatwg.org/multipage/entities.json by stripping
|
|
// the `&` and `;` from the keys and removing the duplicates.
|
|
// see https://www.w3.org/TR/html51/syntax.html#named-character-references
|
|
var NAMED_ENTITIES = {
|
|
'AElig': '\u00C6',
|
|
'AMP': '\u0026',
|
|
'amp': '\u0026',
|
|
'Aacute': '\u00C1',
|
|
'Abreve': '\u0102',
|
|
'Acirc': '\u00C2',
|
|
'Acy': '\u0410',
|
|
'Afr': '\uD835\uDD04',
|
|
'Agrave': '\u00C0',
|
|
'Alpha': '\u0391',
|
|
'Amacr': '\u0100',
|
|
'And': '\u2A53',
|
|
'Aogon': '\u0104',
|
|
'Aopf': '\uD835\uDD38',
|
|
'ApplyFunction': '\u2061',
|
|
'af': '\u2061',
|
|
'Aring': '\u00C5',
|
|
'angst': '\u00C5',
|
|
'Ascr': '\uD835\uDC9C',
|
|
'Assign': '\u2254',
|
|
'colone': '\u2254',
|
|
'coloneq': '\u2254',
|
|
'Atilde': '\u00C3',
|
|
'Auml': '\u00C4',
|
|
'Backslash': '\u2216',
|
|
'setminus': '\u2216',
|
|
'setmn': '\u2216',
|
|
'smallsetminus': '\u2216',
|
|
'ssetmn': '\u2216',
|
|
'Barv': '\u2AE7',
|
|
'Barwed': '\u2306',
|
|
'doublebarwedge': '\u2306',
|
|
'Bcy': '\u0411',
|
|
'Because': '\u2235',
|
|
'becaus': '\u2235',
|
|
'because': '\u2235',
|
|
'Bernoullis': '\u212C',
|
|
'Bscr': '\u212C',
|
|
'bernou': '\u212C',
|
|
'Beta': '\u0392',
|
|
'Bfr': '\uD835\uDD05',
|
|
'Bopf': '\uD835\uDD39',
|
|
'Breve': '\u02D8',
|
|
'breve': '\u02D8',
|
|
'Bumpeq': '\u224E',
|
|
'HumpDownHump': '\u224E',
|
|
'bump': '\u224E',
|
|
'CHcy': '\u0427',
|
|
'COPY': '\u00A9',
|
|
'copy': '\u00A9',
|
|
'Cacute': '\u0106',
|
|
'Cap': '\u22D2',
|
|
'CapitalDifferentialD': '\u2145',
|
|
'DD': '\u2145',
|
|
'Cayleys': '\u212D',
|
|
'Cfr': '\u212D',
|
|
'Ccaron': '\u010C',
|
|
'Ccedil': '\u00C7',
|
|
'Ccirc': '\u0108',
|
|
'Cconint': '\u2230',
|
|
'Cdot': '\u010A',
|
|
'Cedilla': '\u00B8',
|
|
'cedil': '\u00B8',
|
|
'CenterDot': '\u00B7',
|
|
'centerdot': '\u00B7',
|
|
'middot': '\u00B7',
|
|
'Chi': '\u03A7',
|
|
'CircleDot': '\u2299',
|
|
'odot': '\u2299',
|
|
'CircleMinus': '\u2296',
|
|
'ominus': '\u2296',
|
|
'CirclePlus': '\u2295',
|
|
'oplus': '\u2295',
|
|
'CircleTimes': '\u2297',
|
|
'otimes': '\u2297',
|
|
'ClockwiseContourIntegral': '\u2232',
|
|
'cwconint': '\u2232',
|
|
'CloseCurlyDoubleQuote': '\u201D',
|
|
'rdquo': '\u201D',
|
|
'rdquor': '\u201D',
|
|
'CloseCurlyQuote': '\u2019',
|
|
'rsquo': '\u2019',
|
|
'rsquor': '\u2019',
|
|
'Colon': '\u2237',
|
|
'Proportion': '\u2237',
|
|
'Colone': '\u2A74',
|
|
'Congruent': '\u2261',
|
|
'equiv': '\u2261',
|
|
'Conint': '\u222F',
|
|
'DoubleContourIntegral': '\u222F',
|
|
'ContourIntegral': '\u222E',
|
|
'conint': '\u222E',
|
|
'oint': '\u222E',
|
|
'Copf': '\u2102',
|
|
'complexes': '\u2102',
|
|
'Coproduct': '\u2210',
|
|
'coprod': '\u2210',
|
|
'CounterClockwiseContourIntegral': '\u2233',
|
|
'awconint': '\u2233',
|
|
'Cross': '\u2A2F',
|
|
'Cscr': '\uD835\uDC9E',
|
|
'Cup': '\u22D3',
|
|
'CupCap': '\u224D',
|
|
'asympeq': '\u224D',
|
|
'DDotrahd': '\u2911',
|
|
'DJcy': '\u0402',
|
|
'DScy': '\u0405',
|
|
'DZcy': '\u040F',
|
|
'Dagger': '\u2021',
|
|
'ddagger': '\u2021',
|
|
'Darr': '\u21A1',
|
|
'Dashv': '\u2AE4',
|
|
'DoubleLeftTee': '\u2AE4',
|
|
'Dcaron': '\u010E',
|
|
'Dcy': '\u0414',
|
|
'Del': '\u2207',
|
|
'nabla': '\u2207',
|
|
'Delta': '\u0394',
|
|
'Dfr': '\uD835\uDD07',
|
|
'DiacriticalAcute': '\u00B4',
|
|
'acute': '\u00B4',
|
|
'DiacriticalDot': '\u02D9',
|
|
'dot': '\u02D9',
|
|
'DiacriticalDoubleAcute': '\u02DD',
|
|
'dblac': '\u02DD',
|
|
'DiacriticalGrave': '\u0060',
|
|
'grave': '\u0060',
|
|
'DiacriticalTilde': '\u02DC',
|
|
'tilde': '\u02DC',
|
|
'Diamond': '\u22C4',
|
|
'diam': '\u22C4',
|
|
'diamond': '\u22C4',
|
|
'DifferentialD': '\u2146',
|
|
'dd': '\u2146',
|
|
'Dopf': '\uD835\uDD3B',
|
|
'Dot': '\u00A8',
|
|
'DoubleDot': '\u00A8',
|
|
'die': '\u00A8',
|
|
'uml': '\u00A8',
|
|
'DotDot': '\u20DC',
|
|
'DotEqual': '\u2250',
|
|
'doteq': '\u2250',
|
|
'esdot': '\u2250',
|
|
'DoubleDownArrow': '\u21D3',
|
|
'Downarrow': '\u21D3',
|
|
'dArr': '\u21D3',
|
|
'DoubleLeftArrow': '\u21D0',
|
|
'Leftarrow': '\u21D0',
|
|
'lArr': '\u21D0',
|
|
'DoubleLeftRightArrow': '\u21D4',
|
|
'Leftrightarrow': '\u21D4',
|
|
'hArr': '\u21D4',
|
|
'iff': '\u21D4',
|
|
'DoubleLongLeftArrow': '\u27F8',
|
|
'Longleftarrow': '\u27F8',
|
|
'xlArr': '\u27F8',
|
|
'DoubleLongLeftRightArrow': '\u27FA',
|
|
'Longleftrightarrow': '\u27FA',
|
|
'xhArr': '\u27FA',
|
|
'DoubleLongRightArrow': '\u27F9',
|
|
'Longrightarrow': '\u27F9',
|
|
'xrArr': '\u27F9',
|
|
'DoubleRightArrow': '\u21D2',
|
|
'Implies': '\u21D2',
|
|
'Rightarrow': '\u21D2',
|
|
'rArr': '\u21D2',
|
|
'DoubleRightTee': '\u22A8',
|
|
'vDash': '\u22A8',
|
|
'DoubleUpArrow': '\u21D1',
|
|
'Uparrow': '\u21D1',
|
|
'uArr': '\u21D1',
|
|
'DoubleUpDownArrow': '\u21D5',
|
|
'Updownarrow': '\u21D5',
|
|
'vArr': '\u21D5',
|
|
'DoubleVerticalBar': '\u2225',
|
|
'par': '\u2225',
|
|
'parallel': '\u2225',
|
|
'shortparallel': '\u2225',
|
|
'spar': '\u2225',
|
|
'DownArrow': '\u2193',
|
|
'ShortDownArrow': '\u2193',
|
|
'darr': '\u2193',
|
|
'downarrow': '\u2193',
|
|
'DownArrowBar': '\u2913',
|
|
'DownArrowUpArrow': '\u21F5',
|
|
'duarr': '\u21F5',
|
|
'DownBreve': '\u0311',
|
|
'DownLeftRightVector': '\u2950',
|
|
'DownLeftTeeVector': '\u295E',
|
|
'DownLeftVector': '\u21BD',
|
|
'leftharpoondown': '\u21BD',
|
|
'lhard': '\u21BD',
|
|
'DownLeftVectorBar': '\u2956',
|
|
'DownRightTeeVector': '\u295F',
|
|
'DownRightVector': '\u21C1',
|
|
'rhard': '\u21C1',
|
|
'rightharpoondown': '\u21C1',
|
|
'DownRightVectorBar': '\u2957',
|
|
'DownTee': '\u22A4',
|
|
'top': '\u22A4',
|
|
'DownTeeArrow': '\u21A7',
|
|
'mapstodown': '\u21A7',
|
|
'Dscr': '\uD835\uDC9F',
|
|
'Dstrok': '\u0110',
|
|
'ENG': '\u014A',
|
|
'ETH': '\u00D0',
|
|
'Eacute': '\u00C9',
|
|
'Ecaron': '\u011A',
|
|
'Ecirc': '\u00CA',
|
|
'Ecy': '\u042D',
|
|
'Edot': '\u0116',
|
|
'Efr': '\uD835\uDD08',
|
|
'Egrave': '\u00C8',
|
|
'Element': '\u2208',
|
|
'in': '\u2208',
|
|
'isin': '\u2208',
|
|
'isinv': '\u2208',
|
|
'Emacr': '\u0112',
|
|
'EmptySmallSquare': '\u25FB',
|
|
'EmptyVerySmallSquare': '\u25AB',
|
|
'Eogon': '\u0118',
|
|
'Eopf': '\uD835\uDD3C',
|
|
'Epsilon': '\u0395',
|
|
'Equal': '\u2A75',
|
|
'EqualTilde': '\u2242',
|
|
'eqsim': '\u2242',
|
|
'esim': '\u2242',
|
|
'Equilibrium': '\u21CC',
|
|
'rightleftharpoons': '\u21CC',
|
|
'rlhar': '\u21CC',
|
|
'Escr': '\u2130',
|
|
'expectation': '\u2130',
|
|
'Esim': '\u2A73',
|
|
'Eta': '\u0397',
|
|
'Euml': '\u00CB',
|
|
'Exists': '\u2203',
|
|
'exist': '\u2203',
|
|
'ExponentialE': '\u2147',
|
|
'ee': '\u2147',
|
|
'exponentiale': '\u2147',
|
|
'Fcy': '\u0424',
|
|
'Ffr': '\uD835\uDD09',
|
|
'FilledSmallSquare': '\u25FC',
|
|
'FilledVerySmallSquare': '\u25AA',
|
|
'blacksquare': '\u25AA',
|
|
'squarf': '\u25AA',
|
|
'squf': '\u25AA',
|
|
'Fopf': '\uD835\uDD3D',
|
|
'ForAll': '\u2200',
|
|
'forall': '\u2200',
|
|
'Fouriertrf': '\u2131',
|
|
'Fscr': '\u2131',
|
|
'GJcy': '\u0403',
|
|
'GT': '\u003E',
|
|
'gt': '\u003E',
|
|
'Gamma': '\u0393',
|
|
'Gammad': '\u03DC',
|
|
'Gbreve': '\u011E',
|
|
'Gcedil': '\u0122',
|
|
'Gcirc': '\u011C',
|
|
'Gcy': '\u0413',
|
|
'Gdot': '\u0120',
|
|
'Gfr': '\uD835\uDD0A',
|
|
'Gg': '\u22D9',
|
|
'ggg': '\u22D9',
|
|
'Gopf': '\uD835\uDD3E',
|
|
'GreaterEqual': '\u2265',
|
|
'ge': '\u2265',
|
|
'geq': '\u2265',
|
|
'GreaterEqualLess': '\u22DB',
|
|
'gel': '\u22DB',
|
|
'gtreqless': '\u22DB',
|
|
'GreaterFullEqual': '\u2267',
|
|
'gE': '\u2267',
|
|
'geqq': '\u2267',
|
|
'GreaterGreater': '\u2AA2',
|
|
'GreaterLess': '\u2277',
|
|
'gl': '\u2277',
|
|
'gtrless': '\u2277',
|
|
'GreaterSlantEqual': '\u2A7E',
|
|
'geqslant': '\u2A7E',
|
|
'ges': '\u2A7E',
|
|
'GreaterTilde': '\u2273',
|
|
'gsim': '\u2273',
|
|
'gtrsim': '\u2273',
|
|
'Gscr': '\uD835\uDCA2',
|
|
'Gt': '\u226B',
|
|
'NestedGreaterGreater': '\u226B',
|
|
'gg': '\u226B',
|
|
'HARDcy': '\u042A',
|
|
'Hacek': '\u02C7',
|
|
'caron': '\u02C7',
|
|
'Hat': '\u005E',
|
|
'Hcirc': '\u0124',
|
|
'Hfr': '\u210C',
|
|
'Poincareplane': '\u210C',
|
|
'HilbertSpace': '\u210B',
|
|
'Hscr': '\u210B',
|
|
'hamilt': '\u210B',
|
|
'Hopf': '\u210D',
|
|
'quaternions': '\u210D',
|
|
'HorizontalLine': '\u2500',
|
|
'boxh': '\u2500',
|
|
'Hstrok': '\u0126',
|
|
'HumpEqual': '\u224F',
|
|
'bumpe': '\u224F',
|
|
'bumpeq': '\u224F',
|
|
'IEcy': '\u0415',
|
|
'IJlig': '\u0132',
|
|
'IOcy': '\u0401',
|
|
'Iacute': '\u00CD',
|
|
'Icirc': '\u00CE',
|
|
'Icy': '\u0418',
|
|
'Idot': '\u0130',
|
|
'Ifr': '\u2111',
|
|
'Im': '\u2111',
|
|
'image': '\u2111',
|
|
'imagpart': '\u2111',
|
|
'Igrave': '\u00CC',
|
|
'Imacr': '\u012A',
|
|
'ImaginaryI': '\u2148',
|
|
'ii': '\u2148',
|
|
'Int': '\u222C',
|
|
'Integral': '\u222B',
|
|
'int': '\u222B',
|
|
'Intersection': '\u22C2',
|
|
'bigcap': '\u22C2',
|
|
'xcap': '\u22C2',
|
|
'InvisibleComma': '\u2063',
|
|
'ic': '\u2063',
|
|
'InvisibleTimes': '\u2062',
|
|
'it': '\u2062',
|
|
'Iogon': '\u012E',
|
|
'Iopf': '\uD835\uDD40',
|
|
'Iota': '\u0399',
|
|
'Iscr': '\u2110',
|
|
'imagline': '\u2110',
|
|
'Itilde': '\u0128',
|
|
'Iukcy': '\u0406',
|
|
'Iuml': '\u00CF',
|
|
'Jcirc': '\u0134',
|
|
'Jcy': '\u0419',
|
|
'Jfr': '\uD835\uDD0D',
|
|
'Jopf': '\uD835\uDD41',
|
|
'Jscr': '\uD835\uDCA5',
|
|
'Jsercy': '\u0408',
|
|
'Jukcy': '\u0404',
|
|
'KHcy': '\u0425',
|
|
'KJcy': '\u040C',
|
|
'Kappa': '\u039A',
|
|
'Kcedil': '\u0136',
|
|
'Kcy': '\u041A',
|
|
'Kfr': '\uD835\uDD0E',
|
|
'Kopf': '\uD835\uDD42',
|
|
'Kscr': '\uD835\uDCA6',
|
|
'LJcy': '\u0409',
|
|
'LT': '\u003C',
|
|
'lt': '\u003C',
|
|
'Lacute': '\u0139',
|
|
'Lambda': '\u039B',
|
|
'Lang': '\u27EA',
|
|
'Laplacetrf': '\u2112',
|
|
'Lscr': '\u2112',
|
|
'lagran': '\u2112',
|
|
'Larr': '\u219E',
|
|
'twoheadleftarrow': '\u219E',
|
|
'Lcaron': '\u013D',
|
|
'Lcedil': '\u013B',
|
|
'Lcy': '\u041B',
|
|
'LeftAngleBracket': '\u27E8',
|
|
'lang': '\u27E8',
|
|
'langle': '\u27E8',
|
|
'LeftArrow': '\u2190',
|
|
'ShortLeftArrow': '\u2190',
|
|
'larr': '\u2190',
|
|
'leftarrow': '\u2190',
|
|
'slarr': '\u2190',
|
|
'LeftArrowBar': '\u21E4',
|
|
'larrb': '\u21E4',
|
|
'LeftArrowRightArrow': '\u21C6',
|
|
'leftrightarrows': '\u21C6',
|
|
'lrarr': '\u21C6',
|
|
'LeftCeiling': '\u2308',
|
|
'lceil': '\u2308',
|
|
'LeftDoubleBracket': '\u27E6',
|
|
'lobrk': '\u27E6',
|
|
'LeftDownTeeVector': '\u2961',
|
|
'LeftDownVector': '\u21C3',
|
|
'dharl': '\u21C3',
|
|
'downharpoonleft': '\u21C3',
|
|
'LeftDownVectorBar': '\u2959',
|
|
'LeftFloor': '\u230A',
|
|
'lfloor': '\u230A',
|
|
'LeftRightArrow': '\u2194',
|
|
'harr': '\u2194',
|
|
'leftrightarrow': '\u2194',
|
|
'LeftRightVector': '\u294E',
|
|
'LeftTee': '\u22A3',
|
|
'dashv': '\u22A3',
|
|
'LeftTeeArrow': '\u21A4',
|
|
'mapstoleft': '\u21A4',
|
|
'LeftTeeVector': '\u295A',
|
|
'LeftTriangle': '\u22B2',
|
|
'vartriangleleft': '\u22B2',
|
|
'vltri': '\u22B2',
|
|
'LeftTriangleBar': '\u29CF',
|
|
'LeftTriangleEqual': '\u22B4',
|
|
'ltrie': '\u22B4',
|
|
'trianglelefteq': '\u22B4',
|
|
'LeftUpDownVector': '\u2951',
|
|
'LeftUpTeeVector': '\u2960',
|
|
'LeftUpVector': '\u21BF',
|
|
'uharl': '\u21BF',
|
|
'upharpoonleft': '\u21BF',
|
|
'LeftUpVectorBar': '\u2958',
|
|
'LeftVector': '\u21BC',
|
|
'leftharpoonup': '\u21BC',
|
|
'lharu': '\u21BC',
|
|
'LeftVectorBar': '\u2952',
|
|
'LessEqualGreater': '\u22DA',
|
|
'leg': '\u22DA',
|
|
'lesseqgtr': '\u22DA',
|
|
'LessFullEqual': '\u2266',
|
|
'lE': '\u2266',
|
|
'leqq': '\u2266',
|
|
'LessGreater': '\u2276',
|
|
'lessgtr': '\u2276',
|
|
'lg': '\u2276',
|
|
'LessLess': '\u2AA1',
|
|
'LessSlantEqual': '\u2A7D',
|
|
'leqslant': '\u2A7D',
|
|
'les': '\u2A7D',
|
|
'LessTilde': '\u2272',
|
|
'lesssim': '\u2272',
|
|
'lsim': '\u2272',
|
|
'Lfr': '\uD835\uDD0F',
|
|
'Ll': '\u22D8',
|
|
'Lleftarrow': '\u21DA',
|
|
'lAarr': '\u21DA',
|
|
'Lmidot': '\u013F',
|
|
'LongLeftArrow': '\u27F5',
|
|
'longleftarrow': '\u27F5',
|
|
'xlarr': '\u27F5',
|
|
'LongLeftRightArrow': '\u27F7',
|
|
'longleftrightarrow': '\u27F7',
|
|
'xharr': '\u27F7',
|
|
'LongRightArrow': '\u27F6',
|
|
'longrightarrow': '\u27F6',
|
|
'xrarr': '\u27F6',
|
|
'Lopf': '\uD835\uDD43',
|
|
'LowerLeftArrow': '\u2199',
|
|
'swarr': '\u2199',
|
|
'swarrow': '\u2199',
|
|
'LowerRightArrow': '\u2198',
|
|
'searr': '\u2198',
|
|
'searrow': '\u2198',
|
|
'Lsh': '\u21B0',
|
|
'lsh': '\u21B0',
|
|
'Lstrok': '\u0141',
|
|
'Lt': '\u226A',
|
|
'NestedLessLess': '\u226A',
|
|
'll': '\u226A',
|
|
'Map': '\u2905',
|
|
'Mcy': '\u041C',
|
|
'MediumSpace': '\u205F',
|
|
'Mellintrf': '\u2133',
|
|
'Mscr': '\u2133',
|
|
'phmmat': '\u2133',
|
|
'Mfr': '\uD835\uDD10',
|
|
'MinusPlus': '\u2213',
|
|
'mnplus': '\u2213',
|
|
'mp': '\u2213',
|
|
'Mopf': '\uD835\uDD44',
|
|
'Mu': '\u039C',
|
|
'NJcy': '\u040A',
|
|
'Nacute': '\u0143',
|
|
'Ncaron': '\u0147',
|
|
'Ncedil': '\u0145',
|
|
'Ncy': '\u041D',
|
|
'NegativeMediumSpace': '\u200B',
|
|
'NegativeThickSpace': '\u200B',
|
|
'NegativeThinSpace': '\u200B',
|
|
'NegativeVeryThinSpace': '\u200B',
|
|
'ZeroWidthSpace': '\u200B',
|
|
'NewLine': '\u000A',
|
|
'Nfr': '\uD835\uDD11',
|
|
'NoBreak': '\u2060',
|
|
'NonBreakingSpace': '\u00A0',
|
|
'nbsp': '\u00A0',
|
|
'Nopf': '\u2115',
|
|
'naturals': '\u2115',
|
|
'Not': '\u2AEC',
|
|
'NotCongruent': '\u2262',
|
|
'nequiv': '\u2262',
|
|
'NotCupCap': '\u226D',
|
|
'NotDoubleVerticalBar': '\u2226',
|
|
'npar': '\u2226',
|
|
'nparallel': '\u2226',
|
|
'nshortparallel': '\u2226',
|
|
'nspar': '\u2226',
|
|
'NotElement': '\u2209',
|
|
'notin': '\u2209',
|
|
'notinva': '\u2209',
|
|
'NotEqual': '\u2260',
|
|
'ne': '\u2260',
|
|
'NotEqualTilde': '\u2242\u0338',
|
|
'nesim': '\u2242\u0338',
|
|
'NotExists': '\u2204',
|
|
'nexist': '\u2204',
|
|
'nexists': '\u2204',
|
|
'NotGreater': '\u226F',
|
|
'ngt': '\u226F',
|
|
'ngtr': '\u226F',
|
|
'NotGreaterEqual': '\u2271',
|
|
'nge': '\u2271',
|
|
'ngeq': '\u2271',
|
|
'NotGreaterFullEqual': '\u2267\u0338',
|
|
'ngE': '\u2267\u0338',
|
|
'ngeqq': '\u2267\u0338',
|
|
'NotGreaterGreater': '\u226B\u0338',
|
|
'nGtv': '\u226B\u0338',
|
|
'NotGreaterLess': '\u2279',
|
|
'ntgl': '\u2279',
|
|
'NotGreaterSlantEqual': '\u2A7E\u0338',
|
|
'ngeqslant': '\u2A7E\u0338',
|
|
'nges': '\u2A7E\u0338',
|
|
'NotGreaterTilde': '\u2275',
|
|
'ngsim': '\u2275',
|
|
'NotHumpDownHump': '\u224E\u0338',
|
|
'nbump': '\u224E\u0338',
|
|
'NotHumpEqual': '\u224F\u0338',
|
|
'nbumpe': '\u224F\u0338',
|
|
'NotLeftTriangle': '\u22EA',
|
|
'nltri': '\u22EA',
|
|
'ntriangleleft': '\u22EA',
|
|
'NotLeftTriangleBar': '\u29CF\u0338',
|
|
'NotLeftTriangleEqual': '\u22EC',
|
|
'nltrie': '\u22EC',
|
|
'ntrianglelefteq': '\u22EC',
|
|
'NotLess': '\u226E',
|
|
'nless': '\u226E',
|
|
'nlt': '\u226E',
|
|
'NotLessEqual': '\u2270',
|
|
'nle': '\u2270',
|
|
'nleq': '\u2270',
|
|
'NotLessGreater': '\u2278',
|
|
'ntlg': '\u2278',
|
|
'NotLessLess': '\u226A\u0338',
|
|
'nLtv': '\u226A\u0338',
|
|
'NotLessSlantEqual': '\u2A7D\u0338',
|
|
'nleqslant': '\u2A7D\u0338',
|
|
'nles': '\u2A7D\u0338',
|
|
'NotLessTilde': '\u2274',
|
|
'nlsim': '\u2274',
|
|
'NotNestedGreaterGreater': '\u2AA2\u0338',
|
|
'NotNestedLessLess': '\u2AA1\u0338',
|
|
'NotPrecedes': '\u2280',
|
|
'npr': '\u2280',
|
|
'nprec': '\u2280',
|
|
'NotPrecedesEqual': '\u2AAF\u0338',
|
|
'npre': '\u2AAF\u0338',
|
|
'npreceq': '\u2AAF\u0338',
|
|
'NotPrecedesSlantEqual': '\u22E0',
|
|
'nprcue': '\u22E0',
|
|
'NotReverseElement': '\u220C',
|
|
'notni': '\u220C',
|
|
'notniva': '\u220C',
|
|
'NotRightTriangle': '\u22EB',
|
|
'nrtri': '\u22EB',
|
|
'ntriangleright': '\u22EB',
|
|
'NotRightTriangleBar': '\u29D0\u0338',
|
|
'NotRightTriangleEqual': '\u22ED',
|
|
'nrtrie': '\u22ED',
|
|
'ntrianglerighteq': '\u22ED',
|
|
'NotSquareSubset': '\u228F\u0338',
|
|
'NotSquareSubsetEqual': '\u22E2',
|
|
'nsqsube': '\u22E2',
|
|
'NotSquareSuperset': '\u2290\u0338',
|
|
'NotSquareSupersetEqual': '\u22E3',
|
|
'nsqsupe': '\u22E3',
|
|
'NotSubset': '\u2282\u20D2',
|
|
'nsubset': '\u2282\u20D2',
|
|
'vnsub': '\u2282\u20D2',
|
|
'NotSubsetEqual': '\u2288',
|
|
'nsube': '\u2288',
|
|
'nsubseteq': '\u2288',
|
|
'NotSucceeds': '\u2281',
|
|
'nsc': '\u2281',
|
|
'nsucc': '\u2281',
|
|
'NotSucceedsEqual': '\u2AB0\u0338',
|
|
'nsce': '\u2AB0\u0338',
|
|
'nsucceq': '\u2AB0\u0338',
|
|
'NotSucceedsSlantEqual': '\u22E1',
|
|
'nsccue': '\u22E1',
|
|
'NotSucceedsTilde': '\u227F\u0338',
|
|
'NotSuperset': '\u2283\u20D2',
|
|
'nsupset': '\u2283\u20D2',
|
|
'vnsup': '\u2283\u20D2',
|
|
'NotSupersetEqual': '\u2289',
|
|
'nsupe': '\u2289',
|
|
'nsupseteq': '\u2289',
|
|
'NotTilde': '\u2241',
|
|
'nsim': '\u2241',
|
|
'NotTildeEqual': '\u2244',
|
|
'nsime': '\u2244',
|
|
'nsimeq': '\u2244',
|
|
'NotTildeFullEqual': '\u2247',
|
|
'ncong': '\u2247',
|
|
'NotTildeTilde': '\u2249',
|
|
'nap': '\u2249',
|
|
'napprox': '\u2249',
|
|
'NotVerticalBar': '\u2224',
|
|
'nmid': '\u2224',
|
|
'nshortmid': '\u2224',
|
|
'nsmid': '\u2224',
|
|
'Nscr': '\uD835\uDCA9',
|
|
'Ntilde': '\u00D1',
|
|
'Nu': '\u039D',
|
|
'OElig': '\u0152',
|
|
'Oacute': '\u00D3',
|
|
'Ocirc': '\u00D4',
|
|
'Ocy': '\u041E',
|
|
'Odblac': '\u0150',
|
|
'Ofr': '\uD835\uDD12',
|
|
'Ograve': '\u00D2',
|
|
'Omacr': '\u014C',
|
|
'Omega': '\u03A9',
|
|
'ohm': '\u03A9',
|
|
'Omicron': '\u039F',
|
|
'Oopf': '\uD835\uDD46',
|
|
'OpenCurlyDoubleQuote': '\u201C',
|
|
'ldquo': '\u201C',
|
|
'OpenCurlyQuote': '\u2018',
|
|
'lsquo': '\u2018',
|
|
'Or': '\u2A54',
|
|
'Oscr': '\uD835\uDCAA',
|
|
'Oslash': '\u00D8',
|
|
'Otilde': '\u00D5',
|
|
'Otimes': '\u2A37',
|
|
'Ouml': '\u00D6',
|
|
'OverBar': '\u203E',
|
|
'oline': '\u203E',
|
|
'OverBrace': '\u23DE',
|
|
'OverBracket': '\u23B4',
|
|
'tbrk': '\u23B4',
|
|
'OverParenthesis': '\u23DC',
|
|
'PartialD': '\u2202',
|
|
'part': '\u2202',
|
|
'Pcy': '\u041F',
|
|
'Pfr': '\uD835\uDD13',
|
|
'Phi': '\u03A6',
|
|
'Pi': '\u03A0',
|
|
'PlusMinus': '\u00B1',
|
|
'plusmn': '\u00B1',
|
|
'pm': '\u00B1',
|
|
'Popf': '\u2119',
|
|
'primes': '\u2119',
|
|
'Pr': '\u2ABB',
|
|
'Precedes': '\u227A',
|
|
'pr': '\u227A',
|
|
'prec': '\u227A',
|
|
'PrecedesEqual': '\u2AAF',
|
|
'pre': '\u2AAF',
|
|
'preceq': '\u2AAF',
|
|
'PrecedesSlantEqual': '\u227C',
|
|
'prcue': '\u227C',
|
|
'preccurlyeq': '\u227C',
|
|
'PrecedesTilde': '\u227E',
|
|
'precsim': '\u227E',
|
|
'prsim': '\u227E',
|
|
'Prime': '\u2033',
|
|
'Product': '\u220F',
|
|
'prod': '\u220F',
|
|
'Proportional': '\u221D',
|
|
'prop': '\u221D',
|
|
'propto': '\u221D',
|
|
'varpropto': '\u221D',
|
|
'vprop': '\u221D',
|
|
'Pscr': '\uD835\uDCAB',
|
|
'Psi': '\u03A8',
|
|
'QUOT': '\u0022',
|
|
'quot': '\u0022',
|
|
'Qfr': '\uD835\uDD14',
|
|
'Qopf': '\u211A',
|
|
'rationals': '\u211A',
|
|
'Qscr': '\uD835\uDCAC',
|
|
'RBarr': '\u2910',
|
|
'drbkarow': '\u2910',
|
|
'REG': '\u00AE',
|
|
'circledR': '\u00AE',
|
|
'reg': '\u00AE',
|
|
'Racute': '\u0154',
|
|
'Rang': '\u27EB',
|
|
'Rarr': '\u21A0',
|
|
'twoheadrightarrow': '\u21A0',
|
|
'Rarrtl': '\u2916',
|
|
'Rcaron': '\u0158',
|
|
'Rcedil': '\u0156',
|
|
'Rcy': '\u0420',
|
|
'Re': '\u211C',
|
|
'Rfr': '\u211C',
|
|
'real': '\u211C',
|
|
'realpart': '\u211C',
|
|
'ReverseElement': '\u220B',
|
|
'SuchThat': '\u220B',
|
|
'ni': '\u220B',
|
|
'niv': '\u220B',
|
|
'ReverseEquilibrium': '\u21CB',
|
|
'leftrightharpoons': '\u21CB',
|
|
'lrhar': '\u21CB',
|
|
'ReverseUpEquilibrium': '\u296F',
|
|
'duhar': '\u296F',
|
|
'Rho': '\u03A1',
|
|
'RightAngleBracket': '\u27E9',
|
|
'rang': '\u27E9',
|
|
'rangle': '\u27E9',
|
|
'RightArrow': '\u2192',
|
|
'ShortRightArrow': '\u2192',
|
|
'rarr': '\u2192',
|
|
'rightarrow': '\u2192',
|
|
'srarr': '\u2192',
|
|
'RightArrowBar': '\u21E5',
|
|
'rarrb': '\u21E5',
|
|
'RightArrowLeftArrow': '\u21C4',
|
|
'rightleftarrows': '\u21C4',
|
|
'rlarr': '\u21C4',
|
|
'RightCeiling': '\u2309',
|
|
'rceil': '\u2309',
|
|
'RightDoubleBracket': '\u27E7',
|
|
'robrk': '\u27E7',
|
|
'RightDownTeeVector': '\u295D',
|
|
'RightDownVector': '\u21C2',
|
|
'dharr': '\u21C2',
|
|
'downharpoonright': '\u21C2',
|
|
'RightDownVectorBar': '\u2955',
|
|
'RightFloor': '\u230B',
|
|
'rfloor': '\u230B',
|
|
'RightTee': '\u22A2',
|
|
'vdash': '\u22A2',
|
|
'RightTeeArrow': '\u21A6',
|
|
'map': '\u21A6',
|
|
'mapsto': '\u21A6',
|
|
'RightTeeVector': '\u295B',
|
|
'RightTriangle': '\u22B3',
|
|
'vartriangleright': '\u22B3',
|
|
'vrtri': '\u22B3',
|
|
'RightTriangleBar': '\u29D0',
|
|
'RightTriangleEqual': '\u22B5',
|
|
'rtrie': '\u22B5',
|
|
'trianglerighteq': '\u22B5',
|
|
'RightUpDownVector': '\u294F',
|
|
'RightUpTeeVector': '\u295C',
|
|
'RightUpVector': '\u21BE',
|
|
'uharr': '\u21BE',
|
|
'upharpoonright': '\u21BE',
|
|
'RightUpVectorBar': '\u2954',
|
|
'RightVector': '\u21C0',
|
|
'rharu': '\u21C0',
|
|
'rightharpoonup': '\u21C0',
|
|
'RightVectorBar': '\u2953',
|
|
'Ropf': '\u211D',
|
|
'reals': '\u211D',
|
|
'RoundImplies': '\u2970',
|
|
'Rrightarrow': '\u21DB',
|
|
'rAarr': '\u21DB',
|
|
'Rscr': '\u211B',
|
|
'realine': '\u211B',
|
|
'Rsh': '\u21B1',
|
|
'rsh': '\u21B1',
|
|
'RuleDelayed': '\u29F4',
|
|
'SHCHcy': '\u0429',
|
|
'SHcy': '\u0428',
|
|
'SOFTcy': '\u042C',
|
|
'Sacute': '\u015A',
|
|
'Sc': '\u2ABC',
|
|
'Scaron': '\u0160',
|
|
'Scedil': '\u015E',
|
|
'Scirc': '\u015C',
|
|
'Scy': '\u0421',
|
|
'Sfr': '\uD835\uDD16',
|
|
'ShortUpArrow': '\u2191',
|
|
'UpArrow': '\u2191',
|
|
'uarr': '\u2191',
|
|
'uparrow': '\u2191',
|
|
'Sigma': '\u03A3',
|
|
'SmallCircle': '\u2218',
|
|
'compfn': '\u2218',
|
|
'Sopf': '\uD835\uDD4A',
|
|
'Sqrt': '\u221A',
|
|
'radic': '\u221A',
|
|
'Square': '\u25A1',
|
|
'squ': '\u25A1',
|
|
'square': '\u25A1',
|
|
'SquareIntersection': '\u2293',
|
|
'sqcap': '\u2293',
|
|
'SquareSubset': '\u228F',
|
|
'sqsub': '\u228F',
|
|
'sqsubset': '\u228F',
|
|
'SquareSubsetEqual': '\u2291',
|
|
'sqsube': '\u2291',
|
|
'sqsubseteq': '\u2291',
|
|
'SquareSuperset': '\u2290',
|
|
'sqsup': '\u2290',
|
|
'sqsupset': '\u2290',
|
|
'SquareSupersetEqual': '\u2292',
|
|
'sqsupe': '\u2292',
|
|
'sqsupseteq': '\u2292',
|
|
'SquareUnion': '\u2294',
|
|
'sqcup': '\u2294',
|
|
'Sscr': '\uD835\uDCAE',
|
|
'Star': '\u22C6',
|
|
'sstarf': '\u22C6',
|
|
'Sub': '\u22D0',
|
|
'Subset': '\u22D0',
|
|
'SubsetEqual': '\u2286',
|
|
'sube': '\u2286',
|
|
'subseteq': '\u2286',
|
|
'Succeeds': '\u227B',
|
|
'sc': '\u227B',
|
|
'succ': '\u227B',
|
|
'SucceedsEqual': '\u2AB0',
|
|
'sce': '\u2AB0',
|
|
'succeq': '\u2AB0',
|
|
'SucceedsSlantEqual': '\u227D',
|
|
'sccue': '\u227D',
|
|
'succcurlyeq': '\u227D',
|
|
'SucceedsTilde': '\u227F',
|
|
'scsim': '\u227F',
|
|
'succsim': '\u227F',
|
|
'Sum': '\u2211',
|
|
'sum': '\u2211',
|
|
'Sup': '\u22D1',
|
|
'Supset': '\u22D1',
|
|
'Superset': '\u2283',
|
|
'sup': '\u2283',
|
|
'supset': '\u2283',
|
|
'SupersetEqual': '\u2287',
|
|
'supe': '\u2287',
|
|
'supseteq': '\u2287',
|
|
'THORN': '\u00DE',
|
|
'TRADE': '\u2122',
|
|
'trade': '\u2122',
|
|
'TSHcy': '\u040B',
|
|
'TScy': '\u0426',
|
|
'Tab': '\u0009',
|
|
'Tau': '\u03A4',
|
|
'Tcaron': '\u0164',
|
|
'Tcedil': '\u0162',
|
|
'Tcy': '\u0422',
|
|
'Tfr': '\uD835\uDD17',
|
|
'Therefore': '\u2234',
|
|
'there4': '\u2234',
|
|
'therefore': '\u2234',
|
|
'Theta': '\u0398',
|
|
'ThickSpace': '\u205F\u200A',
|
|
'ThinSpace': '\u2009',
|
|
'thinsp': '\u2009',
|
|
'Tilde': '\u223C',
|
|
'sim': '\u223C',
|
|
'thicksim': '\u223C',
|
|
'thksim': '\u223C',
|
|
'TildeEqual': '\u2243',
|
|
'sime': '\u2243',
|
|
'simeq': '\u2243',
|
|
'TildeFullEqual': '\u2245',
|
|
'cong': '\u2245',
|
|
'TildeTilde': '\u2248',
|
|
'ap': '\u2248',
|
|
'approx': '\u2248',
|
|
'asymp': '\u2248',
|
|
'thickapprox': '\u2248',
|
|
'thkap': '\u2248',
|
|
'Topf': '\uD835\uDD4B',
|
|
'TripleDot': '\u20DB',
|
|
'tdot': '\u20DB',
|
|
'Tscr': '\uD835\uDCAF',
|
|
'Tstrok': '\u0166',
|
|
'Uacute': '\u00DA',
|
|
'Uarr': '\u219F',
|
|
'Uarrocir': '\u2949',
|
|
'Ubrcy': '\u040E',
|
|
'Ubreve': '\u016C',
|
|
'Ucirc': '\u00DB',
|
|
'Ucy': '\u0423',
|
|
'Udblac': '\u0170',
|
|
'Ufr': '\uD835\uDD18',
|
|
'Ugrave': '\u00D9',
|
|
'Umacr': '\u016A',
|
|
'UnderBar': '\u005F',
|
|
'lowbar': '\u005F',
|
|
'UnderBrace': '\u23DF',
|
|
'UnderBracket': '\u23B5',
|
|
'bbrk': '\u23B5',
|
|
'UnderParenthesis': '\u23DD',
|
|
'Union': '\u22C3',
|
|
'bigcup': '\u22C3',
|
|
'xcup': '\u22C3',
|
|
'UnionPlus': '\u228E',
|
|
'uplus': '\u228E',
|
|
'Uogon': '\u0172',
|
|
'Uopf': '\uD835\uDD4C',
|
|
'UpArrowBar': '\u2912',
|
|
'UpArrowDownArrow': '\u21C5',
|
|
'udarr': '\u21C5',
|
|
'UpDownArrow': '\u2195',
|
|
'updownarrow': '\u2195',
|
|
'varr': '\u2195',
|
|
'UpEquilibrium': '\u296E',
|
|
'udhar': '\u296E',
|
|
'UpTee': '\u22A5',
|
|
'bot': '\u22A5',
|
|
'bottom': '\u22A5',
|
|
'perp': '\u22A5',
|
|
'UpTeeArrow': '\u21A5',
|
|
'mapstoup': '\u21A5',
|
|
'UpperLeftArrow': '\u2196',
|
|
'nwarr': '\u2196',
|
|
'nwarrow': '\u2196',
|
|
'UpperRightArrow': '\u2197',
|
|
'nearr': '\u2197',
|
|
'nearrow': '\u2197',
|
|
'Upsi': '\u03D2',
|
|
'upsih': '\u03D2',
|
|
'Upsilon': '\u03A5',
|
|
'Uring': '\u016E',
|
|
'Uscr': '\uD835\uDCB0',
|
|
'Utilde': '\u0168',
|
|
'Uuml': '\u00DC',
|
|
'VDash': '\u22AB',
|
|
'Vbar': '\u2AEB',
|
|
'Vcy': '\u0412',
|
|
'Vdash': '\u22A9',
|
|
'Vdashl': '\u2AE6',
|
|
'Vee': '\u22C1',
|
|
'bigvee': '\u22C1',
|
|
'xvee': '\u22C1',
|
|
'Verbar': '\u2016',
|
|
'Vert': '\u2016',
|
|
'VerticalBar': '\u2223',
|
|
'mid': '\u2223',
|
|
'shortmid': '\u2223',
|
|
'smid': '\u2223',
|
|
'VerticalLine': '\u007C',
|
|
'verbar': '\u007C',
|
|
'vert': '\u007C',
|
|
'VerticalSeparator': '\u2758',
|
|
'VerticalTilde': '\u2240',
|
|
'wr': '\u2240',
|
|
'wreath': '\u2240',
|
|
'VeryThinSpace': '\u200A',
|
|
'hairsp': '\u200A',
|
|
'Vfr': '\uD835\uDD19',
|
|
'Vopf': '\uD835\uDD4D',
|
|
'Vscr': '\uD835\uDCB1',
|
|
'Vvdash': '\u22AA',
|
|
'Wcirc': '\u0174',
|
|
'Wedge': '\u22C0',
|
|
'bigwedge': '\u22C0',
|
|
'xwedge': '\u22C0',
|
|
'Wfr': '\uD835\uDD1A',
|
|
'Wopf': '\uD835\uDD4E',
|
|
'Wscr': '\uD835\uDCB2',
|
|
'Xfr': '\uD835\uDD1B',
|
|
'Xi': '\u039E',
|
|
'Xopf': '\uD835\uDD4F',
|
|
'Xscr': '\uD835\uDCB3',
|
|
'YAcy': '\u042F',
|
|
'YIcy': '\u0407',
|
|
'YUcy': '\u042E',
|
|
'Yacute': '\u00DD',
|
|
'Ycirc': '\u0176',
|
|
'Ycy': '\u042B',
|
|
'Yfr': '\uD835\uDD1C',
|
|
'Yopf': '\uD835\uDD50',
|
|
'Yscr': '\uD835\uDCB4',
|
|
'Yuml': '\u0178',
|
|
'ZHcy': '\u0416',
|
|
'Zacute': '\u0179',
|
|
'Zcaron': '\u017D',
|
|
'Zcy': '\u0417',
|
|
'Zdot': '\u017B',
|
|
'Zeta': '\u0396',
|
|
'Zfr': '\u2128',
|
|
'zeetrf': '\u2128',
|
|
'Zopf': '\u2124',
|
|
'integers': '\u2124',
|
|
'Zscr': '\uD835\uDCB5',
|
|
'aacute': '\u00E1',
|
|
'abreve': '\u0103',
|
|
'ac': '\u223E',
|
|
'mstpos': '\u223E',
|
|
'acE': '\u223E\u0333',
|
|
'acd': '\u223F',
|
|
'acirc': '\u00E2',
|
|
'acy': '\u0430',
|
|
'aelig': '\u00E6',
|
|
'afr': '\uD835\uDD1E',
|
|
'agrave': '\u00E0',
|
|
'alefsym': '\u2135',
|
|
'aleph': '\u2135',
|
|
'alpha': '\u03B1',
|
|
'amacr': '\u0101',
|
|
'amalg': '\u2A3F',
|
|
'and': '\u2227',
|
|
'wedge': '\u2227',
|
|
'andand': '\u2A55',
|
|
'andd': '\u2A5C',
|
|
'andslope': '\u2A58',
|
|
'andv': '\u2A5A',
|
|
'ang': '\u2220',
|
|
'angle': '\u2220',
|
|
'ange': '\u29A4',
|
|
'angmsd': '\u2221',
|
|
'measuredangle': '\u2221',
|
|
'angmsdaa': '\u29A8',
|
|
'angmsdab': '\u29A9',
|
|
'angmsdac': '\u29AA',
|
|
'angmsdad': '\u29AB',
|
|
'angmsdae': '\u29AC',
|
|
'angmsdaf': '\u29AD',
|
|
'angmsdag': '\u29AE',
|
|
'angmsdah': '\u29AF',
|
|
'angrt': '\u221F',
|
|
'angrtvb': '\u22BE',
|
|
'angrtvbd': '\u299D',
|
|
'angsph': '\u2222',
|
|
'angzarr': '\u237C',
|
|
'aogon': '\u0105',
|
|
'aopf': '\uD835\uDD52',
|
|
'apE': '\u2A70',
|
|
'apacir': '\u2A6F',
|
|
'ape': '\u224A',
|
|
'approxeq': '\u224A',
|
|
'apid': '\u224B',
|
|
'apos': '\u0027',
|
|
'aring': '\u00E5',
|
|
'ascr': '\uD835\uDCB6',
|
|
'ast': '\u002A',
|
|
'midast': '\u002A',
|
|
'atilde': '\u00E3',
|
|
'auml': '\u00E4',
|
|
'awint': '\u2A11',
|
|
'bNot': '\u2AED',
|
|
'backcong': '\u224C',
|
|
'bcong': '\u224C',
|
|
'backepsilon': '\u03F6',
|
|
'bepsi': '\u03F6',
|
|
'backprime': '\u2035',
|
|
'bprime': '\u2035',
|
|
'backsim': '\u223D',
|
|
'bsim': '\u223D',
|
|
'backsimeq': '\u22CD',
|
|
'bsime': '\u22CD',
|
|
'barvee': '\u22BD',
|
|
'barwed': '\u2305',
|
|
'barwedge': '\u2305',
|
|
'bbrktbrk': '\u23B6',
|
|
'bcy': '\u0431',
|
|
'bdquo': '\u201E',
|
|
'ldquor': '\u201E',
|
|
'bemptyv': '\u29B0',
|
|
'beta': '\u03B2',
|
|
'beth': '\u2136',
|
|
'between': '\u226C',
|
|
'twixt': '\u226C',
|
|
'bfr': '\uD835\uDD1F',
|
|
'bigcirc': '\u25EF',
|
|
'xcirc': '\u25EF',
|
|
'bigodot': '\u2A00',
|
|
'xodot': '\u2A00',
|
|
'bigoplus': '\u2A01',
|
|
'xoplus': '\u2A01',
|
|
'bigotimes': '\u2A02',
|
|
'xotime': '\u2A02',
|
|
'bigsqcup': '\u2A06',
|
|
'xsqcup': '\u2A06',
|
|
'bigstar': '\u2605',
|
|
'starf': '\u2605',
|
|
'bigtriangledown': '\u25BD',
|
|
'xdtri': '\u25BD',
|
|
'bigtriangleup': '\u25B3',
|
|
'xutri': '\u25B3',
|
|
'biguplus': '\u2A04',
|
|
'xuplus': '\u2A04',
|
|
'bkarow': '\u290D',
|
|
'rbarr': '\u290D',
|
|
'blacklozenge': '\u29EB',
|
|
'lozf': '\u29EB',
|
|
'blacktriangle': '\u25B4',
|
|
'utrif': '\u25B4',
|
|
'blacktriangledown': '\u25BE',
|
|
'dtrif': '\u25BE',
|
|
'blacktriangleleft': '\u25C2',
|
|
'ltrif': '\u25C2',
|
|
'blacktriangleright': '\u25B8',
|
|
'rtrif': '\u25B8',
|
|
'blank': '\u2423',
|
|
'blk12': '\u2592',
|
|
'blk14': '\u2591',
|
|
'blk34': '\u2593',
|
|
'block': '\u2588',
|
|
'bne': '\u003D\u20E5',
|
|
'bnequiv': '\u2261\u20E5',
|
|
'bnot': '\u2310',
|
|
'bopf': '\uD835\uDD53',
|
|
'bowtie': '\u22C8',
|
|
'boxDL': '\u2557',
|
|
'boxDR': '\u2554',
|
|
'boxDl': '\u2556',
|
|
'boxDr': '\u2553',
|
|
'boxH': '\u2550',
|
|
'boxHD': '\u2566',
|
|
'boxHU': '\u2569',
|
|
'boxHd': '\u2564',
|
|
'boxHu': '\u2567',
|
|
'boxUL': '\u255D',
|
|
'boxUR': '\u255A',
|
|
'boxUl': '\u255C',
|
|
'boxUr': '\u2559',
|
|
'boxV': '\u2551',
|
|
'boxVH': '\u256C',
|
|
'boxVL': '\u2563',
|
|
'boxVR': '\u2560',
|
|
'boxVh': '\u256B',
|
|
'boxVl': '\u2562',
|
|
'boxVr': '\u255F',
|
|
'boxbox': '\u29C9',
|
|
'boxdL': '\u2555',
|
|
'boxdR': '\u2552',
|
|
'boxdl': '\u2510',
|
|
'boxdr': '\u250C',
|
|
'boxhD': '\u2565',
|
|
'boxhU': '\u2568',
|
|
'boxhd': '\u252C',
|
|
'boxhu': '\u2534',
|
|
'boxminus': '\u229F',
|
|
'minusb': '\u229F',
|
|
'boxplus': '\u229E',
|
|
'plusb': '\u229E',
|
|
'boxtimes': '\u22A0',
|
|
'timesb': '\u22A0',
|
|
'boxuL': '\u255B',
|
|
'boxuR': '\u2558',
|
|
'boxul': '\u2518',
|
|
'boxur': '\u2514',
|
|
'boxv': '\u2502',
|
|
'boxvH': '\u256A',
|
|
'boxvL': '\u2561',
|
|
'boxvR': '\u255E',
|
|
'boxvh': '\u253C',
|
|
'boxvl': '\u2524',
|
|
'boxvr': '\u251C',
|
|
'brvbar': '\u00A6',
|
|
'bscr': '\uD835\uDCB7',
|
|
'bsemi': '\u204F',
|
|
'bsol': '\u005C',
|
|
'bsolb': '\u29C5',
|
|
'bsolhsub': '\u27C8',
|
|
'bull': '\u2022',
|
|
'bullet': '\u2022',
|
|
'bumpE': '\u2AAE',
|
|
'cacute': '\u0107',
|
|
'cap': '\u2229',
|
|
'capand': '\u2A44',
|
|
'capbrcup': '\u2A49',
|
|
'capcap': '\u2A4B',
|
|
'capcup': '\u2A47',
|
|
'capdot': '\u2A40',
|
|
'caps': '\u2229\uFE00',
|
|
'caret': '\u2041',
|
|
'ccaps': '\u2A4D',
|
|
'ccaron': '\u010D',
|
|
'ccedil': '\u00E7',
|
|
'ccirc': '\u0109',
|
|
'ccups': '\u2A4C',
|
|
'ccupssm': '\u2A50',
|
|
'cdot': '\u010B',
|
|
'cemptyv': '\u29B2',
|
|
'cent': '\u00A2',
|
|
'cfr': '\uD835\uDD20',
|
|
'chcy': '\u0447',
|
|
'check': '\u2713',
|
|
'checkmark': '\u2713',
|
|
'chi': '\u03C7',
|
|
'cir': '\u25CB',
|
|
'cirE': '\u29C3',
|
|
'circ': '\u02C6',
|
|
'circeq': '\u2257',
|
|
'cire': '\u2257',
|
|
'circlearrowleft': '\u21BA',
|
|
'olarr': '\u21BA',
|
|
'circlearrowright': '\u21BB',
|
|
'orarr': '\u21BB',
|
|
'circledS': '\u24C8',
|
|
'oS': '\u24C8',
|
|
'circledast': '\u229B',
|
|
'oast': '\u229B',
|
|
'circledcirc': '\u229A',
|
|
'ocir': '\u229A',
|
|
'circleddash': '\u229D',
|
|
'odash': '\u229D',
|
|
'cirfnint': '\u2A10',
|
|
'cirmid': '\u2AEF',
|
|
'cirscir': '\u29C2',
|
|
'clubs': '\u2663',
|
|
'clubsuit': '\u2663',
|
|
'colon': '\u003A',
|
|
'comma': '\u002C',
|
|
'commat': '\u0040',
|
|
'comp': '\u2201',
|
|
'complement': '\u2201',
|
|
'congdot': '\u2A6D',
|
|
'copf': '\uD835\uDD54',
|
|
'copysr': '\u2117',
|
|
'crarr': '\u21B5',
|
|
'cross': '\u2717',
|
|
'cscr': '\uD835\uDCB8',
|
|
'csub': '\u2ACF',
|
|
'csube': '\u2AD1',
|
|
'csup': '\u2AD0',
|
|
'csupe': '\u2AD2',
|
|
'ctdot': '\u22EF',
|
|
'cudarrl': '\u2938',
|
|
'cudarrr': '\u2935',
|
|
'cuepr': '\u22DE',
|
|
'curlyeqprec': '\u22DE',
|
|
'cuesc': '\u22DF',
|
|
'curlyeqsucc': '\u22DF',
|
|
'cularr': '\u21B6',
|
|
'curvearrowleft': '\u21B6',
|
|
'cularrp': '\u293D',
|
|
'cup': '\u222A',
|
|
'cupbrcap': '\u2A48',
|
|
'cupcap': '\u2A46',
|
|
'cupcup': '\u2A4A',
|
|
'cupdot': '\u228D',
|
|
'cupor': '\u2A45',
|
|
'cups': '\u222A\uFE00',
|
|
'curarr': '\u21B7',
|
|
'curvearrowright': '\u21B7',
|
|
'curarrm': '\u293C',
|
|
'curlyvee': '\u22CE',
|
|
'cuvee': '\u22CE',
|
|
'curlywedge': '\u22CF',
|
|
'cuwed': '\u22CF',
|
|
'curren': '\u00A4',
|
|
'cwint': '\u2231',
|
|
'cylcty': '\u232D',
|
|
'dHar': '\u2965',
|
|
'dagger': '\u2020',
|
|
'daleth': '\u2138',
|
|
'dash': '\u2010',
|
|
'hyphen': '\u2010',
|
|
'dbkarow': '\u290F',
|
|
'rBarr': '\u290F',
|
|
'dcaron': '\u010F',
|
|
'dcy': '\u0434',
|
|
'ddarr': '\u21CA',
|
|
'downdownarrows': '\u21CA',
|
|
'ddotseq': '\u2A77',
|
|
'eDDot': '\u2A77',
|
|
'deg': '\u00B0',
|
|
'delta': '\u03B4',
|
|
'demptyv': '\u29B1',
|
|
'dfisht': '\u297F',
|
|
'dfr': '\uD835\uDD21',
|
|
'diamondsuit': '\u2666',
|
|
'diams': '\u2666',
|
|
'digamma': '\u03DD',
|
|
'gammad': '\u03DD',
|
|
'disin': '\u22F2',
|
|
'div': '\u00F7',
|
|
'divide': '\u00F7',
|
|
'divideontimes': '\u22C7',
|
|
'divonx': '\u22C7',
|
|
'djcy': '\u0452',
|
|
'dlcorn': '\u231E',
|
|
'llcorner': '\u231E',
|
|
'dlcrop': '\u230D',
|
|
'dollar': '\u0024',
|
|
'dopf': '\uD835\uDD55',
|
|
'doteqdot': '\u2251',
|
|
'eDot': '\u2251',
|
|
'dotminus': '\u2238',
|
|
'minusd': '\u2238',
|
|
'dotplus': '\u2214',
|
|
'plusdo': '\u2214',
|
|
'dotsquare': '\u22A1',
|
|
'sdotb': '\u22A1',
|
|
'drcorn': '\u231F',
|
|
'lrcorner': '\u231F',
|
|
'drcrop': '\u230C',
|
|
'dscr': '\uD835\uDCB9',
|
|
'dscy': '\u0455',
|
|
'dsol': '\u29F6',
|
|
'dstrok': '\u0111',
|
|
'dtdot': '\u22F1',
|
|
'dtri': '\u25BF',
|
|
'triangledown': '\u25BF',
|
|
'dwangle': '\u29A6',
|
|
'dzcy': '\u045F',
|
|
'dzigrarr': '\u27FF',
|
|
'eacute': '\u00E9',
|
|
'easter': '\u2A6E',
|
|
'ecaron': '\u011B',
|
|
'ecir': '\u2256',
|
|
'eqcirc': '\u2256',
|
|
'ecirc': '\u00EA',
|
|
'ecolon': '\u2255',
|
|
'eqcolon': '\u2255',
|
|
'ecy': '\u044D',
|
|
'edot': '\u0117',
|
|
'efDot': '\u2252',
|
|
'fallingdotseq': '\u2252',
|
|
'efr': '\uD835\uDD22',
|
|
'eg': '\u2A9A',
|
|
'egrave': '\u00E8',
|
|
'egs': '\u2A96',
|
|
'eqslantgtr': '\u2A96',
|
|
'egsdot': '\u2A98',
|
|
'el': '\u2A99',
|
|
'elinters': '\u23E7',
|
|
'ell': '\u2113',
|
|
'els': '\u2A95',
|
|
'eqslantless': '\u2A95',
|
|
'elsdot': '\u2A97',
|
|
'emacr': '\u0113',
|
|
'empty': '\u2205',
|
|
'emptyset': '\u2205',
|
|
'emptyv': '\u2205',
|
|
'varnothing': '\u2205',
|
|
'emsp13': '\u2004',
|
|
'emsp14': '\u2005',
|
|
'emsp': '\u2003',
|
|
'eng': '\u014B',
|
|
'ensp': '\u2002',
|
|
'eogon': '\u0119',
|
|
'eopf': '\uD835\uDD56',
|
|
'epar': '\u22D5',
|
|
'eparsl': '\u29E3',
|
|
'eplus': '\u2A71',
|
|
'epsi': '\u03B5',
|
|
'epsilon': '\u03B5',
|
|
'epsiv': '\u03F5',
|
|
'straightepsilon': '\u03F5',
|
|
'varepsilon': '\u03F5',
|
|
'equals': '\u003D',
|
|
'equest': '\u225F',
|
|
'questeq': '\u225F',
|
|
'equivDD': '\u2A78',
|
|
'eqvparsl': '\u29E5',
|
|
'erDot': '\u2253',
|
|
'risingdotseq': '\u2253',
|
|
'erarr': '\u2971',
|
|
'escr': '\u212F',
|
|
'eta': '\u03B7',
|
|
'eth': '\u00F0',
|
|
'euml': '\u00EB',
|
|
'euro': '\u20AC',
|
|
'excl': '\u0021',
|
|
'fcy': '\u0444',
|
|
'female': '\u2640',
|
|
'ffilig': '\uFB03',
|
|
'fflig': '\uFB00',
|
|
'ffllig': '\uFB04',
|
|
'ffr': '\uD835\uDD23',
|
|
'filig': '\uFB01',
|
|
'fjlig': '\u0066\u006A',
|
|
'flat': '\u266D',
|
|
'fllig': '\uFB02',
|
|
'fltns': '\u25B1',
|
|
'fnof': '\u0192',
|
|
'fopf': '\uD835\uDD57',
|
|
'fork': '\u22D4',
|
|
'pitchfork': '\u22D4',
|
|
'forkv': '\u2AD9',
|
|
'fpartint': '\u2A0D',
|
|
'frac12': '\u00BD',
|
|
'half': '\u00BD',
|
|
'frac13': '\u2153',
|
|
'frac14': '\u00BC',
|
|
'frac15': '\u2155',
|
|
'frac16': '\u2159',
|
|
'frac18': '\u215B',
|
|
'frac23': '\u2154',
|
|
'frac25': '\u2156',
|
|
'frac34': '\u00BE',
|
|
'frac35': '\u2157',
|
|
'frac38': '\u215C',
|
|
'frac45': '\u2158',
|
|
'frac56': '\u215A',
|
|
'frac58': '\u215D',
|
|
'frac78': '\u215E',
|
|
'frasl': '\u2044',
|
|
'frown': '\u2322',
|
|
'sfrown': '\u2322',
|
|
'fscr': '\uD835\uDCBB',
|
|
'gEl': '\u2A8C',
|
|
'gtreqqless': '\u2A8C',
|
|
'gacute': '\u01F5',
|
|
'gamma': '\u03B3',
|
|
'gap': '\u2A86',
|
|
'gtrapprox': '\u2A86',
|
|
'gbreve': '\u011F',
|
|
'gcirc': '\u011D',
|
|
'gcy': '\u0433',
|
|
'gdot': '\u0121',
|
|
'gescc': '\u2AA9',
|
|
'gesdot': '\u2A80',
|
|
'gesdoto': '\u2A82',
|
|
'gesdotol': '\u2A84',
|
|
'gesl': '\u22DB\uFE00',
|
|
'gesles': '\u2A94',
|
|
'gfr': '\uD835\uDD24',
|
|
'gimel': '\u2137',
|
|
'gjcy': '\u0453',
|
|
'glE': '\u2A92',
|
|
'gla': '\u2AA5',
|
|
'glj': '\u2AA4',
|
|
'gnE': '\u2269',
|
|
'gneqq': '\u2269',
|
|
'gnap': '\u2A8A',
|
|
'gnapprox': '\u2A8A',
|
|
'gne': '\u2A88',
|
|
'gneq': '\u2A88',
|
|
'gnsim': '\u22E7',
|
|
'gopf': '\uD835\uDD58',
|
|
'gscr': '\u210A',
|
|
'gsime': '\u2A8E',
|
|
'gsiml': '\u2A90',
|
|
'gtcc': '\u2AA7',
|
|
'gtcir': '\u2A7A',
|
|
'gtdot': '\u22D7',
|
|
'gtrdot': '\u22D7',
|
|
'gtlPar': '\u2995',
|
|
'gtquest': '\u2A7C',
|
|
'gtrarr': '\u2978',
|
|
'gvertneqq': '\u2269\uFE00',
|
|
'gvnE': '\u2269\uFE00',
|
|
'hardcy': '\u044A',
|
|
'harrcir': '\u2948',
|
|
'harrw': '\u21AD',
|
|
'leftrightsquigarrow': '\u21AD',
|
|
'hbar': '\u210F',
|
|
'hslash': '\u210F',
|
|
'planck': '\u210F',
|
|
'plankv': '\u210F',
|
|
'hcirc': '\u0125',
|
|
'hearts': '\u2665',
|
|
'heartsuit': '\u2665',
|
|
'hellip': '\u2026',
|
|
'mldr': '\u2026',
|
|
'hercon': '\u22B9',
|
|
'hfr': '\uD835\uDD25',
|
|
'hksearow': '\u2925',
|
|
'searhk': '\u2925',
|
|
'hkswarow': '\u2926',
|
|
'swarhk': '\u2926',
|
|
'hoarr': '\u21FF',
|
|
'homtht': '\u223B',
|
|
'hookleftarrow': '\u21A9',
|
|
'larrhk': '\u21A9',
|
|
'hookrightarrow': '\u21AA',
|
|
'rarrhk': '\u21AA',
|
|
'hopf': '\uD835\uDD59',
|
|
'horbar': '\u2015',
|
|
'hscr': '\uD835\uDCBD',
|
|
'hstrok': '\u0127',
|
|
'hybull': '\u2043',
|
|
'iacute': '\u00ED',
|
|
'icirc': '\u00EE',
|
|
'icy': '\u0438',
|
|
'iecy': '\u0435',
|
|
'iexcl': '\u00A1',
|
|
'ifr': '\uD835\uDD26',
|
|
'igrave': '\u00EC',
|
|
'iiiint': '\u2A0C',
|
|
'qint': '\u2A0C',
|
|
'iiint': '\u222D',
|
|
'tint': '\u222D',
|
|
'iinfin': '\u29DC',
|
|
'iiota': '\u2129',
|
|
'ijlig': '\u0133',
|
|
'imacr': '\u012B',
|
|
'imath': '\u0131',
|
|
'inodot': '\u0131',
|
|
'imof': '\u22B7',
|
|
'imped': '\u01B5',
|
|
'incare': '\u2105',
|
|
'infin': '\u221E',
|
|
'infintie': '\u29DD',
|
|
'intcal': '\u22BA',
|
|
'intercal': '\u22BA',
|
|
'intlarhk': '\u2A17',
|
|
'intprod': '\u2A3C',
|
|
'iprod': '\u2A3C',
|
|
'iocy': '\u0451',
|
|
'iogon': '\u012F',
|
|
'iopf': '\uD835\uDD5A',
|
|
'iota': '\u03B9',
|
|
'iquest': '\u00BF',
|
|
'iscr': '\uD835\uDCBE',
|
|
'isinE': '\u22F9',
|
|
'isindot': '\u22F5',
|
|
'isins': '\u22F4',
|
|
'isinsv': '\u22F3',
|
|
'itilde': '\u0129',
|
|
'iukcy': '\u0456',
|
|
'iuml': '\u00EF',
|
|
'jcirc': '\u0135',
|
|
'jcy': '\u0439',
|
|
'jfr': '\uD835\uDD27',
|
|
'jmath': '\u0237',
|
|
'jopf': '\uD835\uDD5B',
|
|
'jscr': '\uD835\uDCBF',
|
|
'jsercy': '\u0458',
|
|
'jukcy': '\u0454',
|
|
'kappa': '\u03BA',
|
|
'kappav': '\u03F0',
|
|
'varkappa': '\u03F0',
|
|
'kcedil': '\u0137',
|
|
'kcy': '\u043A',
|
|
'kfr': '\uD835\uDD28',
|
|
'kgreen': '\u0138',
|
|
'khcy': '\u0445',
|
|
'kjcy': '\u045C',
|
|
'kopf': '\uD835\uDD5C',
|
|
'kscr': '\uD835\uDCC0',
|
|
'lAtail': '\u291B',
|
|
'lBarr': '\u290E',
|
|
'lEg': '\u2A8B',
|
|
'lesseqqgtr': '\u2A8B',
|
|
'lHar': '\u2962',
|
|
'lacute': '\u013A',
|
|
'laemptyv': '\u29B4',
|
|
'lambda': '\u03BB',
|
|
'langd': '\u2991',
|
|
'lap': '\u2A85',
|
|
'lessapprox': '\u2A85',
|
|
'laquo': '\u00AB',
|
|
'larrbfs': '\u291F',
|
|
'larrfs': '\u291D',
|
|
'larrlp': '\u21AB',
|
|
'looparrowleft': '\u21AB',
|
|
'larrpl': '\u2939',
|
|
'larrsim': '\u2973',
|
|
'larrtl': '\u21A2',
|
|
'leftarrowtail': '\u21A2',
|
|
'lat': '\u2AAB',
|
|
'latail': '\u2919',
|
|
'late': '\u2AAD',
|
|
'lates': '\u2AAD\uFE00',
|
|
'lbarr': '\u290C',
|
|
'lbbrk': '\u2772',
|
|
'lbrace': '\u007B',
|
|
'lcub': '\u007B',
|
|
'lbrack': '\u005B',
|
|
'lsqb': '\u005B',
|
|
'lbrke': '\u298B',
|
|
'lbrksld': '\u298F',
|
|
'lbrkslu': '\u298D',
|
|
'lcaron': '\u013E',
|
|
'lcedil': '\u013C',
|
|
'lcy': '\u043B',
|
|
'ldca': '\u2936',
|
|
'ldrdhar': '\u2967',
|
|
'ldrushar': '\u294B',
|
|
'ldsh': '\u21B2',
|
|
'le': '\u2264',
|
|
'leq': '\u2264',
|
|
'leftleftarrows': '\u21C7',
|
|
'llarr': '\u21C7',
|
|
'leftthreetimes': '\u22CB',
|
|
'lthree': '\u22CB',
|
|
'lescc': '\u2AA8',
|
|
'lesdot': '\u2A7F',
|
|
'lesdoto': '\u2A81',
|
|
'lesdotor': '\u2A83',
|
|
'lesg': '\u22DA\uFE00',
|
|
'lesges': '\u2A93',
|
|
'lessdot': '\u22D6',
|
|
'ltdot': '\u22D6',
|
|
'lfisht': '\u297C',
|
|
'lfr': '\uD835\uDD29',
|
|
'lgE': '\u2A91',
|
|
'lharul': '\u296A',
|
|
'lhblk': '\u2584',
|
|
'ljcy': '\u0459',
|
|
'llhard': '\u296B',
|
|
'lltri': '\u25FA',
|
|
'lmidot': '\u0140',
|
|
'lmoust': '\u23B0',
|
|
'lmoustache': '\u23B0',
|
|
'lnE': '\u2268',
|
|
'lneqq': '\u2268',
|
|
'lnap': '\u2A89',
|
|
'lnapprox': '\u2A89',
|
|
'lne': '\u2A87',
|
|
'lneq': '\u2A87',
|
|
'lnsim': '\u22E6',
|
|
'loang': '\u27EC',
|
|
'loarr': '\u21FD',
|
|
'longmapsto': '\u27FC',
|
|
'xmap': '\u27FC',
|
|
'looparrowright': '\u21AC',
|
|
'rarrlp': '\u21AC',
|
|
'lopar': '\u2985',
|
|
'lopf': '\uD835\uDD5D',
|
|
'loplus': '\u2A2D',
|
|
'lotimes': '\u2A34',
|
|
'lowast': '\u2217',
|
|
'loz': '\u25CA',
|
|
'lozenge': '\u25CA',
|
|
'lpar': '\u0028',
|
|
'lparlt': '\u2993',
|
|
'lrhard': '\u296D',
|
|
'lrm': '\u200E',
|
|
'lrtri': '\u22BF',
|
|
'lsaquo': '\u2039',
|
|
'lscr': '\uD835\uDCC1',
|
|
'lsime': '\u2A8D',
|
|
'lsimg': '\u2A8F',
|
|
'lsquor': '\u201A',
|
|
'sbquo': '\u201A',
|
|
'lstrok': '\u0142',
|
|
'ltcc': '\u2AA6',
|
|
'ltcir': '\u2A79',
|
|
'ltimes': '\u22C9',
|
|
'ltlarr': '\u2976',
|
|
'ltquest': '\u2A7B',
|
|
'ltrPar': '\u2996',
|
|
'ltri': '\u25C3',
|
|
'triangleleft': '\u25C3',
|
|
'lurdshar': '\u294A',
|
|
'luruhar': '\u2966',
|
|
'lvertneqq': '\u2268\uFE00',
|
|
'lvnE': '\u2268\uFE00',
|
|
'mDDot': '\u223A',
|
|
'macr': '\u00AF',
|
|
'strns': '\u00AF',
|
|
'male': '\u2642',
|
|
'malt': '\u2720',
|
|
'maltese': '\u2720',
|
|
'marker': '\u25AE',
|
|
'mcomma': '\u2A29',
|
|
'mcy': '\u043C',
|
|
'mdash': '\u2014',
|
|
'mfr': '\uD835\uDD2A',
|
|
'mho': '\u2127',
|
|
'micro': '\u00B5',
|
|
'midcir': '\u2AF0',
|
|
'minus': '\u2212',
|
|
'minusdu': '\u2A2A',
|
|
'mlcp': '\u2ADB',
|
|
'models': '\u22A7',
|
|
'mopf': '\uD835\uDD5E',
|
|
'mscr': '\uD835\uDCC2',
|
|
'mu': '\u03BC',
|
|
'multimap': '\u22B8',
|
|
'mumap': '\u22B8',
|
|
'nGg': '\u22D9\u0338',
|
|
'nGt': '\u226B\u20D2',
|
|
'nLeftarrow': '\u21CD',
|
|
'nlArr': '\u21CD',
|
|
'nLeftrightarrow': '\u21CE',
|
|
'nhArr': '\u21CE',
|
|
'nLl': '\u22D8\u0338',
|
|
'nLt': '\u226A\u20D2',
|
|
'nRightarrow': '\u21CF',
|
|
'nrArr': '\u21CF',
|
|
'nVDash': '\u22AF',
|
|
'nVdash': '\u22AE',
|
|
'nacute': '\u0144',
|
|
'nang': '\u2220\u20D2',
|
|
'napE': '\u2A70\u0338',
|
|
'napid': '\u224B\u0338',
|
|
'napos': '\u0149',
|
|
'natur': '\u266E',
|
|
'natural': '\u266E',
|
|
'ncap': '\u2A43',
|
|
'ncaron': '\u0148',
|
|
'ncedil': '\u0146',
|
|
'ncongdot': '\u2A6D\u0338',
|
|
'ncup': '\u2A42',
|
|
'ncy': '\u043D',
|
|
'ndash': '\u2013',
|
|
'neArr': '\u21D7',
|
|
'nearhk': '\u2924',
|
|
'nedot': '\u2250\u0338',
|
|
'nesear': '\u2928',
|
|
'toea': '\u2928',
|
|
'nfr': '\uD835\uDD2B',
|
|
'nharr': '\u21AE',
|
|
'nleftrightarrow': '\u21AE',
|
|
'nhpar': '\u2AF2',
|
|
'nis': '\u22FC',
|
|
'nisd': '\u22FA',
|
|
'njcy': '\u045A',
|
|
'nlE': '\u2266\u0338',
|
|
'nleqq': '\u2266\u0338',
|
|
'nlarr': '\u219A',
|
|
'nleftarrow': '\u219A',
|
|
'nldr': '\u2025',
|
|
'nopf': '\uD835\uDD5F',
|
|
'not': '\u00AC',
|
|
'notinE': '\u22F9\u0338',
|
|
'notindot': '\u22F5\u0338',
|
|
'notinvb': '\u22F7',
|
|
'notinvc': '\u22F6',
|
|
'notnivb': '\u22FE',
|
|
'notnivc': '\u22FD',
|
|
'nparsl': '\u2AFD\u20E5',
|
|
'npart': '\u2202\u0338',
|
|
'npolint': '\u2A14',
|
|
'nrarr': '\u219B',
|
|
'nrightarrow': '\u219B',
|
|
'nrarrc': '\u2933\u0338',
|
|
'nrarrw': '\u219D\u0338',
|
|
'nscr': '\uD835\uDCC3',
|
|
'nsub': '\u2284',
|
|
'nsubE': '\u2AC5\u0338',
|
|
'nsubseteqq': '\u2AC5\u0338',
|
|
'nsup': '\u2285',
|
|
'nsupE': '\u2AC6\u0338',
|
|
'nsupseteqq': '\u2AC6\u0338',
|
|
'ntilde': '\u00F1',
|
|
'nu': '\u03BD',
|
|
'num': '\u0023',
|
|
'numero': '\u2116',
|
|
'numsp': '\u2007',
|
|
'nvDash': '\u22AD',
|
|
'nvHarr': '\u2904',
|
|
'nvap': '\u224D\u20D2',
|
|
'nvdash': '\u22AC',
|
|
'nvge': '\u2265\u20D2',
|
|
'nvgt': '\u003E\u20D2',
|
|
'nvinfin': '\u29DE',
|
|
'nvlArr': '\u2902',
|
|
'nvle': '\u2264\u20D2',
|
|
'nvlt': '\u003C\u20D2',
|
|
'nvltrie': '\u22B4\u20D2',
|
|
'nvrArr': '\u2903',
|
|
'nvrtrie': '\u22B5\u20D2',
|
|
'nvsim': '\u223C\u20D2',
|
|
'nwArr': '\u21D6',
|
|
'nwarhk': '\u2923',
|
|
'nwnear': '\u2927',
|
|
'oacute': '\u00F3',
|
|
'ocirc': '\u00F4',
|
|
'ocy': '\u043E',
|
|
'odblac': '\u0151',
|
|
'odiv': '\u2A38',
|
|
'odsold': '\u29BC',
|
|
'oelig': '\u0153',
|
|
'ofcir': '\u29BF',
|
|
'ofr': '\uD835\uDD2C',
|
|
'ogon': '\u02DB',
|
|
'ograve': '\u00F2',
|
|
'ogt': '\u29C1',
|
|
'ohbar': '\u29B5',
|
|
'olcir': '\u29BE',
|
|
'olcross': '\u29BB',
|
|
'olt': '\u29C0',
|
|
'omacr': '\u014D',
|
|
'omega': '\u03C9',
|
|
'omicron': '\u03BF',
|
|
'omid': '\u29B6',
|
|
'oopf': '\uD835\uDD60',
|
|
'opar': '\u29B7',
|
|
'operp': '\u29B9',
|
|
'or': '\u2228',
|
|
'vee': '\u2228',
|
|
'ord': '\u2A5D',
|
|
'order': '\u2134',
|
|
'orderof': '\u2134',
|
|
'oscr': '\u2134',
|
|
'ordf': '\u00AA',
|
|
'ordm': '\u00BA',
|
|
'origof': '\u22B6',
|
|
'oror': '\u2A56',
|
|
'orslope': '\u2A57',
|
|
'orv': '\u2A5B',
|
|
'oslash': '\u00F8',
|
|
'osol': '\u2298',
|
|
'otilde': '\u00F5',
|
|
'otimesas': '\u2A36',
|
|
'ouml': '\u00F6',
|
|
'ovbar': '\u233D',
|
|
'para': '\u00B6',
|
|
'parsim': '\u2AF3',
|
|
'parsl': '\u2AFD',
|
|
'pcy': '\u043F',
|
|
'percnt': '\u0025',
|
|
'period': '\u002E',
|
|
'permil': '\u2030',
|
|
'pertenk': '\u2031',
|
|
'pfr': '\uD835\uDD2D',
|
|
'phi': '\u03C6',
|
|
'phiv': '\u03D5',
|
|
'straightphi': '\u03D5',
|
|
'varphi': '\u03D5',
|
|
'phone': '\u260E',
|
|
'pi': '\u03C0',
|
|
'piv': '\u03D6',
|
|
'varpi': '\u03D6',
|
|
'planckh': '\u210E',
|
|
'plus': '\u002B',
|
|
'plusacir': '\u2A23',
|
|
'pluscir': '\u2A22',
|
|
'plusdu': '\u2A25',
|
|
'pluse': '\u2A72',
|
|
'plussim': '\u2A26',
|
|
'plustwo': '\u2A27',
|
|
'pointint': '\u2A15',
|
|
'popf': '\uD835\uDD61',
|
|
'pound': '\u00A3',
|
|
'prE': '\u2AB3',
|
|
'prap': '\u2AB7',
|
|
'precapprox': '\u2AB7',
|
|
'precnapprox': '\u2AB9',
|
|
'prnap': '\u2AB9',
|
|
'precneqq': '\u2AB5',
|
|
'prnE': '\u2AB5',
|
|
'precnsim': '\u22E8',
|
|
'prnsim': '\u22E8',
|
|
'prime': '\u2032',
|
|
'profalar': '\u232E',
|
|
'profline': '\u2312',
|
|
'profsurf': '\u2313',
|
|
'prurel': '\u22B0',
|
|
'pscr': '\uD835\uDCC5',
|
|
'psi': '\u03C8',
|
|
'puncsp': '\u2008',
|
|
'qfr': '\uD835\uDD2E',
|
|
'qopf': '\uD835\uDD62',
|
|
'qprime': '\u2057',
|
|
'qscr': '\uD835\uDCC6',
|
|
'quatint': '\u2A16',
|
|
'quest': '\u003F',
|
|
'rAtail': '\u291C',
|
|
'rHar': '\u2964',
|
|
'race': '\u223D\u0331',
|
|
'racute': '\u0155',
|
|
'raemptyv': '\u29B3',
|
|
'rangd': '\u2992',
|
|
'range': '\u29A5',
|
|
'raquo': '\u00BB',
|
|
'rarrap': '\u2975',
|
|
'rarrbfs': '\u2920',
|
|
'rarrc': '\u2933',
|
|
'rarrfs': '\u291E',
|
|
'rarrpl': '\u2945',
|
|
'rarrsim': '\u2974',
|
|
'rarrtl': '\u21A3',
|
|
'rightarrowtail': '\u21A3',
|
|
'rarrw': '\u219D',
|
|
'rightsquigarrow': '\u219D',
|
|
'ratail': '\u291A',
|
|
'ratio': '\u2236',
|
|
'rbbrk': '\u2773',
|
|
'rbrace': '\u007D',
|
|
'rcub': '\u007D',
|
|
'rbrack': '\u005D',
|
|
'rsqb': '\u005D',
|
|
'rbrke': '\u298C',
|
|
'rbrksld': '\u298E',
|
|
'rbrkslu': '\u2990',
|
|
'rcaron': '\u0159',
|
|
'rcedil': '\u0157',
|
|
'rcy': '\u0440',
|
|
'rdca': '\u2937',
|
|
'rdldhar': '\u2969',
|
|
'rdsh': '\u21B3',
|
|
'rect': '\u25AD',
|
|
'rfisht': '\u297D',
|
|
'rfr': '\uD835\uDD2F',
|
|
'rharul': '\u296C',
|
|
'rho': '\u03C1',
|
|
'rhov': '\u03F1',
|
|
'varrho': '\u03F1',
|
|
'rightrightarrows': '\u21C9',
|
|
'rrarr': '\u21C9',
|
|
'rightthreetimes': '\u22CC',
|
|
'rthree': '\u22CC',
|
|
'ring': '\u02DA',
|
|
'rlm': '\u200F',
|
|
'rmoust': '\u23B1',
|
|
'rmoustache': '\u23B1',
|
|
'rnmid': '\u2AEE',
|
|
'roang': '\u27ED',
|
|
'roarr': '\u21FE',
|
|
'ropar': '\u2986',
|
|
'ropf': '\uD835\uDD63',
|
|
'roplus': '\u2A2E',
|
|
'rotimes': '\u2A35',
|
|
'rpar': '\u0029',
|
|
'rpargt': '\u2994',
|
|
'rppolint': '\u2A12',
|
|
'rsaquo': '\u203A',
|
|
'rscr': '\uD835\uDCC7',
|
|
'rtimes': '\u22CA',
|
|
'rtri': '\u25B9',
|
|
'triangleright': '\u25B9',
|
|
'rtriltri': '\u29CE',
|
|
'ruluhar': '\u2968',
|
|
'rx': '\u211E',
|
|
'sacute': '\u015B',
|
|
'scE': '\u2AB4',
|
|
'scap': '\u2AB8',
|
|
'succapprox': '\u2AB8',
|
|
'scaron': '\u0161',
|
|
'scedil': '\u015F',
|
|
'scirc': '\u015D',
|
|
'scnE': '\u2AB6',
|
|
'succneqq': '\u2AB6',
|
|
'scnap': '\u2ABA',
|
|
'succnapprox': '\u2ABA',
|
|
'scnsim': '\u22E9',
|
|
'succnsim': '\u22E9',
|
|
'scpolint': '\u2A13',
|
|
'scy': '\u0441',
|
|
'sdot': '\u22C5',
|
|
'sdote': '\u2A66',
|
|
'seArr': '\u21D8',
|
|
'sect': '\u00A7',
|
|
'semi': '\u003B',
|
|
'seswar': '\u2929',
|
|
'tosa': '\u2929',
|
|
'sext': '\u2736',
|
|
'sfr': '\uD835\uDD30',
|
|
'sharp': '\u266F',
|
|
'shchcy': '\u0449',
|
|
'shcy': '\u0448',
|
|
'shy': '\u00AD',
|
|
'sigma': '\u03C3',
|
|
'sigmaf': '\u03C2',
|
|
'sigmav': '\u03C2',
|
|
'varsigma': '\u03C2',
|
|
'simdot': '\u2A6A',
|
|
'simg': '\u2A9E',
|
|
'simgE': '\u2AA0',
|
|
'siml': '\u2A9D',
|
|
'simlE': '\u2A9F',
|
|
'simne': '\u2246',
|
|
'simplus': '\u2A24',
|
|
'simrarr': '\u2972',
|
|
'smashp': '\u2A33',
|
|
'smeparsl': '\u29E4',
|
|
'smile': '\u2323',
|
|
'ssmile': '\u2323',
|
|
'smt': '\u2AAA',
|
|
'smte': '\u2AAC',
|
|
'smtes': '\u2AAC\uFE00',
|
|
'softcy': '\u044C',
|
|
'sol': '\u002F',
|
|
'solb': '\u29C4',
|
|
'solbar': '\u233F',
|
|
'sopf': '\uD835\uDD64',
|
|
'spades': '\u2660',
|
|
'spadesuit': '\u2660',
|
|
'sqcaps': '\u2293\uFE00',
|
|
'sqcups': '\u2294\uFE00',
|
|
'sscr': '\uD835\uDCC8',
|
|
'star': '\u2606',
|
|
'sub': '\u2282',
|
|
'subset': '\u2282',
|
|
'subE': '\u2AC5',
|
|
'subseteqq': '\u2AC5',
|
|
'subdot': '\u2ABD',
|
|
'subedot': '\u2AC3',
|
|
'submult': '\u2AC1',
|
|
'subnE': '\u2ACB',
|
|
'subsetneqq': '\u2ACB',
|
|
'subne': '\u228A',
|
|
'subsetneq': '\u228A',
|
|
'subplus': '\u2ABF',
|
|
'subrarr': '\u2979',
|
|
'subsim': '\u2AC7',
|
|
'subsub': '\u2AD5',
|
|
'subsup': '\u2AD3',
|
|
'sung': '\u266A',
|
|
'sup1': '\u00B9',
|
|
'sup2': '\u00B2',
|
|
'sup3': '\u00B3',
|
|
'supE': '\u2AC6',
|
|
'supseteqq': '\u2AC6',
|
|
'supdot': '\u2ABE',
|
|
'supdsub': '\u2AD8',
|
|
'supedot': '\u2AC4',
|
|
'suphsol': '\u27C9',
|
|
'suphsub': '\u2AD7',
|
|
'suplarr': '\u297B',
|
|
'supmult': '\u2AC2',
|
|
'supnE': '\u2ACC',
|
|
'supsetneqq': '\u2ACC',
|
|
'supne': '\u228B',
|
|
'supsetneq': '\u228B',
|
|
'supplus': '\u2AC0',
|
|
'supsim': '\u2AC8',
|
|
'supsub': '\u2AD4',
|
|
'supsup': '\u2AD6',
|
|
'swArr': '\u21D9',
|
|
'swnwar': '\u292A',
|
|
'szlig': '\u00DF',
|
|
'target': '\u2316',
|
|
'tau': '\u03C4',
|
|
'tcaron': '\u0165',
|
|
'tcedil': '\u0163',
|
|
'tcy': '\u0442',
|
|
'telrec': '\u2315',
|
|
'tfr': '\uD835\uDD31',
|
|
'theta': '\u03B8',
|
|
'thetasym': '\u03D1',
|
|
'thetav': '\u03D1',
|
|
'vartheta': '\u03D1',
|
|
'thorn': '\u00FE',
|
|
'times': '\u00D7',
|
|
'timesbar': '\u2A31',
|
|
'timesd': '\u2A30',
|
|
'topbot': '\u2336',
|
|
'topcir': '\u2AF1',
|
|
'topf': '\uD835\uDD65',
|
|
'topfork': '\u2ADA',
|
|
'tprime': '\u2034',
|
|
'triangle': '\u25B5',
|
|
'utri': '\u25B5',
|
|
'triangleq': '\u225C',
|
|
'trie': '\u225C',
|
|
'tridot': '\u25EC',
|
|
'triminus': '\u2A3A',
|
|
'triplus': '\u2A39',
|
|
'trisb': '\u29CD',
|
|
'tritime': '\u2A3B',
|
|
'trpezium': '\u23E2',
|
|
'tscr': '\uD835\uDCC9',
|
|
'tscy': '\u0446',
|
|
'tshcy': '\u045B',
|
|
'tstrok': '\u0167',
|
|
'uHar': '\u2963',
|
|
'uacute': '\u00FA',
|
|
'ubrcy': '\u045E',
|
|
'ubreve': '\u016D',
|
|
'ucirc': '\u00FB',
|
|
'ucy': '\u0443',
|
|
'udblac': '\u0171',
|
|
'ufisht': '\u297E',
|
|
'ufr': '\uD835\uDD32',
|
|
'ugrave': '\u00F9',
|
|
'uhblk': '\u2580',
|
|
'ulcorn': '\u231C',
|
|
'ulcorner': '\u231C',
|
|
'ulcrop': '\u230F',
|
|
'ultri': '\u25F8',
|
|
'umacr': '\u016B',
|
|
'uogon': '\u0173',
|
|
'uopf': '\uD835\uDD66',
|
|
'upsi': '\u03C5',
|
|
'upsilon': '\u03C5',
|
|
'upuparrows': '\u21C8',
|
|
'uuarr': '\u21C8',
|
|
'urcorn': '\u231D',
|
|
'urcorner': '\u231D',
|
|
'urcrop': '\u230E',
|
|
'uring': '\u016F',
|
|
'urtri': '\u25F9',
|
|
'uscr': '\uD835\uDCCA',
|
|
'utdot': '\u22F0',
|
|
'utilde': '\u0169',
|
|
'uuml': '\u00FC',
|
|
'uwangle': '\u29A7',
|
|
'vBar': '\u2AE8',
|
|
'vBarv': '\u2AE9',
|
|
'vangrt': '\u299C',
|
|
'varsubsetneq': '\u228A\uFE00',
|
|
'vsubne': '\u228A\uFE00',
|
|
'varsubsetneqq': '\u2ACB\uFE00',
|
|
'vsubnE': '\u2ACB\uFE00',
|
|
'varsupsetneq': '\u228B\uFE00',
|
|
'vsupne': '\u228B\uFE00',
|
|
'varsupsetneqq': '\u2ACC\uFE00',
|
|
'vsupnE': '\u2ACC\uFE00',
|
|
'vcy': '\u0432',
|
|
'veebar': '\u22BB',
|
|
'veeeq': '\u225A',
|
|
'vellip': '\u22EE',
|
|
'vfr': '\uD835\uDD33',
|
|
'vopf': '\uD835\uDD67',
|
|
'vscr': '\uD835\uDCCB',
|
|
'vzigzag': '\u299A',
|
|
'wcirc': '\u0175',
|
|
'wedbar': '\u2A5F',
|
|
'wedgeq': '\u2259',
|
|
'weierp': '\u2118',
|
|
'wp': '\u2118',
|
|
'wfr': '\uD835\uDD34',
|
|
'wopf': '\uD835\uDD68',
|
|
'wscr': '\uD835\uDCCC',
|
|
'xfr': '\uD835\uDD35',
|
|
'xi': '\u03BE',
|
|
'xnis': '\u22FB',
|
|
'xopf': '\uD835\uDD69',
|
|
'xscr': '\uD835\uDCCD',
|
|
'yacute': '\u00FD',
|
|
'yacy': '\u044F',
|
|
'ycirc': '\u0177',
|
|
'ycy': '\u044B',
|
|
'yen': '\u00A5',
|
|
'yfr': '\uD835\uDD36',
|
|
'yicy': '\u0457',
|
|
'yopf': '\uD835\uDD6A',
|
|
'yscr': '\uD835\uDCCE',
|
|
'yucy': '\u044E',
|
|
'yuml': '\u00FF',
|
|
'zacute': '\u017A',
|
|
'zcaron': '\u017E',
|
|
'zcy': '\u0437',
|
|
'zdot': '\u017C',
|
|
'zeta': '\u03B6',
|
|
'zfr': '\uD835\uDD37',
|
|
'zhcy': '\u0436',
|
|
'zigrarr': '\u21DD',
|
|
'zopf': '\uD835\uDD6B',
|
|
'zscr': '\uD835\uDCCF',
|
|
'zwj': '\u200D',
|
|
'zwnj': '\u200C'
|
|
};
|
|
// The &ngsp; pseudo-entity is denoting a space. see:
|
|
// https://github.com/dart-lang/angular/blob/0bb611387d29d65b5af7f9d2515ab571fd3fbee4/_tests/test/compiler/preserve_whitespace_test.dart
|
|
var NGSP_UNICODE = '\uE500';
|
|
NAMED_ENTITIES['ngsp'] = NGSP_UNICODE;
|
|
|
|
var TokenError = /** @class */ (function (_super) {
|
|
__extends(TokenError, _super);
|
|
function TokenError(errorMsg, tokenType, span) {
|
|
var _this = _super.call(this, span, errorMsg) || this;
|
|
_this.tokenType = tokenType;
|
|
return _this;
|
|
}
|
|
return TokenError;
|
|
}(ParseError));
|
|
var TokenizeResult = /** @class */ (function () {
|
|
function TokenizeResult(tokens, errors, nonNormalizedIcuExpressions) {
|
|
this.tokens = tokens;
|
|
this.errors = errors;
|
|
this.nonNormalizedIcuExpressions = nonNormalizedIcuExpressions;
|
|
}
|
|
return TokenizeResult;
|
|
}());
|
|
function tokenize(source, url, getTagDefinition, options) {
|
|
if (options === void 0) { options = {}; }
|
|
var tokenizer = new _Tokenizer(new ParseSourceFile(source, url), getTagDefinition, options);
|
|
tokenizer.tokenize();
|
|
return new TokenizeResult(mergeTextTokens(tokenizer.tokens), tokenizer.errors, tokenizer.nonNormalizedIcuExpressions);
|
|
}
|
|
var _CR_OR_CRLF_REGEXP = /\r\n?/g;
|
|
function _unexpectedCharacterErrorMsg(charCode) {
|
|
var char = charCode === $EOF ? 'EOF' : String.fromCharCode(charCode);
|
|
return "Unexpected character \"" + char + "\"";
|
|
}
|
|
function _unknownEntityErrorMsg(entitySrc) {
|
|
return "Unknown entity \"" + entitySrc + "\" - use the \"&#<decimal>;\" or \"&#x<hex>;\" syntax";
|
|
}
|
|
function _unparsableEntityErrorMsg(type, entityStr) {
|
|
return "Unable to parse entity \"" + entityStr + "\" - " + type + " character reference entities must end with \";\"";
|
|
}
|
|
var CharacterReferenceType;
|
|
(function (CharacterReferenceType) {
|
|
CharacterReferenceType["HEX"] = "hexadecimal";
|
|
CharacterReferenceType["DEC"] = "decimal";
|
|
})(CharacterReferenceType || (CharacterReferenceType = {}));
|
|
var _ControlFlowError = /** @class */ (function () {
|
|
function _ControlFlowError(error) {
|
|
this.error = error;
|
|
}
|
|
return _ControlFlowError;
|
|
}());
|
|
// See https://www.w3.org/TR/html51/syntax.html#writing-html-documents
|
|
var _Tokenizer = /** @class */ (function () {
|
|
/**
|
|
* @param _file The html source file being tokenized.
|
|
* @param _getTagDefinition A function that will retrieve a tag definition for a given tag name.
|
|
* @param options Configuration of the tokenization.
|
|
*/
|
|
function _Tokenizer(_file, _getTagDefinition, options) {
|
|
this._getTagDefinition = _getTagDefinition;
|
|
this._currentTokenStart = null;
|
|
this._currentTokenType = null;
|
|
this._expansionCaseStack = [];
|
|
this._inInterpolation = false;
|
|
this.tokens = [];
|
|
this.errors = [];
|
|
this.nonNormalizedIcuExpressions = [];
|
|
this._tokenizeIcu = options.tokenizeExpansionForms || false;
|
|
this._interpolationConfig = options.interpolationConfig || DEFAULT_INTERPOLATION_CONFIG;
|
|
this._leadingTriviaCodePoints =
|
|
options.leadingTriviaChars && options.leadingTriviaChars.map(function (c) { return c.codePointAt(0) || 0; });
|
|
var range = options.range || { endPos: _file.content.length, startPos: 0, startLine: 0, startCol: 0 };
|
|
this._cursor = options.escapedString ? new EscapedCharacterCursor(_file, range) :
|
|
new PlainCharacterCursor(_file, range);
|
|
this._preserveLineEndings = options.preserveLineEndings || false;
|
|
this._escapedString = options.escapedString || false;
|
|
this._i18nNormalizeLineEndingsInICUs = options.i18nNormalizeLineEndingsInICUs || false;
|
|
try {
|
|
this._cursor.init();
|
|
}
|
|
catch (e) {
|
|
this.handleError(e);
|
|
}
|
|
}
|
|
_Tokenizer.prototype._processCarriageReturns = function (content) {
|
|
if (this._preserveLineEndings) {
|
|
return content;
|
|
}
|
|
// https://www.w3.org/TR/html51/syntax.html#preprocessing-the-input-stream
|
|
// In order to keep the original position in the source, we can not
|
|
// pre-process it.
|
|
// Instead CRs are processed right before instantiating the tokens.
|
|
return content.replace(_CR_OR_CRLF_REGEXP, '\n');
|
|
};
|
|
_Tokenizer.prototype.tokenize = function () {
|
|
var _this = this;
|
|
while (this._cursor.peek() !== $EOF) {
|
|
var start = this._cursor.clone();
|
|
try {
|
|
if (this._attemptCharCode($LT)) {
|
|
if (this._attemptCharCode($BANG)) {
|
|
if (this._attemptCharCode($LBRACKET)) {
|
|
this._consumeCdata(start);
|
|
}
|
|
else if (this._attemptCharCode($MINUS)) {
|
|
this._consumeComment(start);
|
|
}
|
|
else {
|
|
this._consumeDocType(start);
|
|
}
|
|
}
|
|
else if (this._attemptCharCode($SLASH)) {
|
|
this._consumeTagClose(start);
|
|
}
|
|
else {
|
|
this._consumeTagOpen(start);
|
|
}
|
|
}
|
|
else if (!(this._tokenizeIcu && this._tokenizeExpansionForm())) {
|
|
// In (possibly interpolated) text the end of the text is given by `isTextEnd()`, while
|
|
// the premature end of an interpolation is given by the start of a new HTML element.
|
|
this._consumeWithInterpolation(5 /* TEXT */, 8 /* INTERPOLATION */, function () { return _this._isTextEnd(); }, function () { return _this._isTagStart(); });
|
|
}
|
|
}
|
|
catch (e) {
|
|
this.handleError(e);
|
|
}
|
|
}
|
|
this._beginToken(24 /* EOF */);
|
|
this._endToken([]);
|
|
};
|
|
/**
|
|
* @returns whether an ICU token has been created
|
|
* @internal
|
|
*/
|
|
_Tokenizer.prototype._tokenizeExpansionForm = function () {
|
|
if (this.isExpansionFormStart()) {
|
|
this._consumeExpansionFormStart();
|
|
return true;
|
|
}
|
|
if (isExpansionCaseStart(this._cursor.peek()) && this._isInExpansionForm()) {
|
|
this._consumeExpansionCaseStart();
|
|
return true;
|
|
}
|
|
if (this._cursor.peek() === $RBRACE) {
|
|
if (this._isInExpansionCase()) {
|
|
this._consumeExpansionCaseEnd();
|
|
return true;
|
|
}
|
|
if (this._isInExpansionForm()) {
|
|
this._consumeExpansionFormEnd();
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
};
|
|
_Tokenizer.prototype._beginToken = function (type, start) {
|
|
if (start === void 0) { start = this._cursor.clone(); }
|
|
this._currentTokenStart = start;
|
|
this._currentTokenType = type;
|
|
};
|
|
_Tokenizer.prototype._endToken = function (parts, end) {
|
|
if (this._currentTokenStart === null) {
|
|
throw new TokenError('Programming error - attempted to end a token when there was no start to the token', this._currentTokenType, this._cursor.getSpan(end));
|
|
}
|
|
if (this._currentTokenType === null) {
|
|
throw new TokenError('Programming error - attempted to end a token which has no token type', null, this._cursor.getSpan(this._currentTokenStart));
|
|
}
|
|
var token = {
|
|
type: this._currentTokenType,
|
|
parts: parts,
|
|
sourceSpan: (end !== null && end !== void 0 ? end : this._cursor).getSpan(this._currentTokenStart, this._leadingTriviaCodePoints),
|
|
};
|
|
this.tokens.push(token);
|
|
this._currentTokenStart = null;
|
|
this._currentTokenType = null;
|
|
return token;
|
|
};
|
|
_Tokenizer.prototype._createError = function (msg, span) {
|
|
if (this._isInExpansionForm()) {
|
|
msg += " (Do you have an unescaped \"{\" in your template? Use \"{{ '{' }}\") to escape it.)";
|
|
}
|
|
var error = new TokenError(msg, this._currentTokenType, span);
|
|
this._currentTokenStart = null;
|
|
this._currentTokenType = null;
|
|
return new _ControlFlowError(error);
|
|
};
|
|
_Tokenizer.prototype.handleError = function (e) {
|
|
if (e instanceof CursorError) {
|
|
e = this._createError(e.msg, this._cursor.getSpan(e.cursor));
|
|
}
|
|
if (e instanceof _ControlFlowError) {
|
|
this.errors.push(e.error);
|
|
}
|
|
else {
|
|
throw e;
|
|
}
|
|
};
|
|
_Tokenizer.prototype._attemptCharCode = function (charCode) {
|
|
if (this._cursor.peek() === charCode) {
|
|
this._cursor.advance();
|
|
return true;
|
|
}
|
|
return false;
|
|
};
|
|
_Tokenizer.prototype._attemptCharCodeCaseInsensitive = function (charCode) {
|
|
if (compareCharCodeCaseInsensitive(this._cursor.peek(), charCode)) {
|
|
this._cursor.advance();
|
|
return true;
|
|
}
|
|
return false;
|
|
};
|
|
_Tokenizer.prototype._requireCharCode = function (charCode) {
|
|
var location = this._cursor.clone();
|
|
if (!this._attemptCharCode(charCode)) {
|
|
throw this._createError(_unexpectedCharacterErrorMsg(this._cursor.peek()), this._cursor.getSpan(location));
|
|
}
|
|
};
|
|
_Tokenizer.prototype._attemptStr = function (chars) {
|
|
var len = chars.length;
|
|
if (this._cursor.charsLeft() < len) {
|
|
return false;
|
|
}
|
|
var initialPosition = this._cursor.clone();
|
|
for (var i = 0; i < len; i++) {
|
|
if (!this._attemptCharCode(chars.charCodeAt(i))) {
|
|
// If attempting to parse the string fails, we want to reset the parser
|
|
// to where it was before the attempt
|
|
this._cursor = initialPosition;
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
};
|
|
_Tokenizer.prototype._attemptStrCaseInsensitive = function (chars) {
|
|
for (var i = 0; i < chars.length; i++) {
|
|
if (!this._attemptCharCodeCaseInsensitive(chars.charCodeAt(i))) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
};
|
|
_Tokenizer.prototype._requireStr = function (chars) {
|
|
var location = this._cursor.clone();
|
|
if (!this._attemptStr(chars)) {
|
|
throw this._createError(_unexpectedCharacterErrorMsg(this._cursor.peek()), this._cursor.getSpan(location));
|
|
}
|
|
};
|
|
_Tokenizer.prototype._attemptCharCodeUntilFn = function (predicate) {
|
|
while (!predicate(this._cursor.peek())) {
|
|
this._cursor.advance();
|
|
}
|
|
};
|
|
_Tokenizer.prototype._requireCharCodeUntilFn = function (predicate, len) {
|
|
var start = this._cursor.clone();
|
|
this._attemptCharCodeUntilFn(predicate);
|
|
if (this._cursor.diff(start) < len) {
|
|
throw this._createError(_unexpectedCharacterErrorMsg(this._cursor.peek()), this._cursor.getSpan(start));
|
|
}
|
|
};
|
|
_Tokenizer.prototype._attemptUntilChar = function (char) {
|
|
while (this._cursor.peek() !== char) {
|
|
this._cursor.advance();
|
|
}
|
|
};
|
|
_Tokenizer.prototype._readChar = function () {
|
|
// Don't rely upon reading directly from `_input` as the actual char value
|
|
// may have been generated from an escape sequence.
|
|
var char = String.fromCodePoint(this._cursor.peek());
|
|
this._cursor.advance();
|
|
return char;
|
|
};
|
|
_Tokenizer.prototype._consumeEntity = function (textTokenType) {
|
|
this._beginToken(9 /* ENCODED_ENTITY */);
|
|
var start = this._cursor.clone();
|
|
this._cursor.advance();
|
|
if (this._attemptCharCode($HASH)) {
|
|
var isHex = this._attemptCharCode($x) || this._attemptCharCode($X);
|
|
var codeStart = this._cursor.clone();
|
|
this._attemptCharCodeUntilFn(isDigitEntityEnd);
|
|
if (this._cursor.peek() != $SEMICOLON) {
|
|
// Advance cursor to include the peeked character in the string provided to the error
|
|
// message.
|
|
this._cursor.advance();
|
|
var entityType = isHex ? CharacterReferenceType.HEX : CharacterReferenceType.DEC;
|
|
throw this._createError(_unparsableEntityErrorMsg(entityType, this._cursor.getChars(start)), this._cursor.getSpan());
|
|
}
|
|
var strNum = this._cursor.getChars(codeStart);
|
|
this._cursor.advance();
|
|
try {
|
|
var charCode = parseInt(strNum, isHex ? 16 : 10);
|
|
this._endToken([String.fromCharCode(charCode), this._cursor.getChars(start)]);
|
|
}
|
|
catch (_a) {
|
|
throw this._createError(_unknownEntityErrorMsg(this._cursor.getChars(start)), this._cursor.getSpan());
|
|
}
|
|
}
|
|
else {
|
|
var nameStart = this._cursor.clone();
|
|
this._attemptCharCodeUntilFn(isNamedEntityEnd);
|
|
if (this._cursor.peek() != $SEMICOLON) {
|
|
// No semicolon was found so abort the encoded entity token that was in progress, and treat
|
|
// this as a text token
|
|
this._beginToken(textTokenType, start);
|
|
this._cursor = nameStart;
|
|
this._endToken(['&']);
|
|
}
|
|
else {
|
|
var name = this._cursor.getChars(nameStart);
|
|
this._cursor.advance();
|
|
var char = NAMED_ENTITIES[name];
|
|
if (!char) {
|
|
throw this._createError(_unknownEntityErrorMsg(name), this._cursor.getSpan(start));
|
|
}
|
|
this._endToken([char, "&" + name + ";"]);
|
|
}
|
|
}
|
|
};
|
|
_Tokenizer.prototype._consumeRawText = function (consumeEntities, endMarkerPredicate) {
|
|
this._beginToken(consumeEntities ? 6 /* ESCAPABLE_RAW_TEXT */ : 7 /* RAW_TEXT */);
|
|
var parts = [];
|
|
while (true) {
|
|
var tagCloseStart = this._cursor.clone();
|
|
var foundEndMarker = endMarkerPredicate();
|
|
this._cursor = tagCloseStart;
|
|
if (foundEndMarker) {
|
|
break;
|
|
}
|
|
if (consumeEntities && this._cursor.peek() === $AMPERSAND) {
|
|
this._endToken([this._processCarriageReturns(parts.join(''))]);
|
|
parts.length = 0;
|
|
this._consumeEntity(6 /* ESCAPABLE_RAW_TEXT */);
|
|
this._beginToken(6 /* ESCAPABLE_RAW_TEXT */);
|
|
}
|
|
else {
|
|
parts.push(this._readChar());
|
|
}
|
|
}
|
|
this._endToken([this._processCarriageReturns(parts.join(''))]);
|
|
};
|
|
_Tokenizer.prototype._consumeComment = function (start) {
|
|
var _this = this;
|
|
this._beginToken(10 /* COMMENT_START */, start);
|
|
this._requireCharCode($MINUS);
|
|
this._endToken([]);
|
|
this._consumeRawText(false, function () { return _this._attemptStr('-->'); });
|
|
this._beginToken(11 /* COMMENT_END */);
|
|
this._requireStr('-->');
|
|
this._endToken([]);
|
|
};
|
|
_Tokenizer.prototype._consumeCdata = function (start) {
|
|
var _this = this;
|
|
this._beginToken(12 /* CDATA_START */, start);
|
|
this._requireStr('CDATA[');
|
|
this._endToken([]);
|
|
this._consumeRawText(false, function () { return _this._attemptStr(']]>'); });
|
|
this._beginToken(13 /* CDATA_END */);
|
|
this._requireStr(']]>');
|
|
this._endToken([]);
|
|
};
|
|
_Tokenizer.prototype._consumeDocType = function (start) {
|
|
this._beginToken(18 /* DOC_TYPE */, start);
|
|
var contentStart = this._cursor.clone();
|
|
this._attemptUntilChar($GT);
|
|
var content = this._cursor.getChars(contentStart);
|
|
this._cursor.advance();
|
|
this._endToken([content]);
|
|
};
|
|
_Tokenizer.prototype._consumePrefixAndName = function () {
|
|
var nameOrPrefixStart = this._cursor.clone();
|
|
var prefix = '';
|
|
while (this._cursor.peek() !== $COLON && !isPrefixEnd(this._cursor.peek())) {
|
|
this._cursor.advance();
|
|
}
|
|
var nameStart;
|
|
if (this._cursor.peek() === $COLON) {
|
|
prefix = this._cursor.getChars(nameOrPrefixStart);
|
|
this._cursor.advance();
|
|
nameStart = this._cursor.clone();
|
|
}
|
|
else {
|
|
nameStart = nameOrPrefixStart;
|
|
}
|
|
this._requireCharCodeUntilFn(isNameEnd, prefix === '' ? 0 : 1);
|
|
var name = this._cursor.getChars(nameStart);
|
|
return [prefix, name];
|
|
};
|
|
_Tokenizer.prototype._consumeTagOpen = function (start) {
|
|
var tagName;
|
|
var prefix;
|
|
var openTagToken;
|
|
try {
|
|
if (!isAsciiLetter(this._cursor.peek())) {
|
|
throw this._createError(_unexpectedCharacterErrorMsg(this._cursor.peek()), this._cursor.getSpan(start));
|
|
}
|
|
openTagToken = this._consumeTagOpenStart(start);
|
|
prefix = openTagToken.parts[0];
|
|
tagName = openTagToken.parts[1];
|
|
this._attemptCharCodeUntilFn(isNotWhitespace);
|
|
while (this._cursor.peek() !== $SLASH && this._cursor.peek() !== $GT &&
|
|
this._cursor.peek() !== $LT && this._cursor.peek() !== $EOF) {
|
|
this._consumeAttributeName();
|
|
this._attemptCharCodeUntilFn(isNotWhitespace);
|
|
if (this._attemptCharCode($EQ)) {
|
|
this._attemptCharCodeUntilFn(isNotWhitespace);
|
|
this._consumeAttributeValue();
|
|
}
|
|
this._attemptCharCodeUntilFn(isNotWhitespace);
|
|
}
|
|
this._consumeTagOpenEnd();
|
|
}
|
|
catch (e) {
|
|
if (e instanceof _ControlFlowError) {
|
|
if (openTagToken) {
|
|
// We errored before we could close the opening tag, so it is incomplete.
|
|
openTagToken.type = 4 /* INCOMPLETE_TAG_OPEN */;
|
|
}
|
|
else {
|
|
// When the start tag is invalid, assume we want a "<" as text.
|
|
// Back to back text tokens are merged at the end.
|
|
this._beginToken(5 /* TEXT */, start);
|
|
this._endToken(['<']);
|
|
}
|
|
return;
|
|
}
|
|
throw e;
|
|
}
|
|
var contentTokenType = this._getTagDefinition(tagName).getContentType(prefix);
|
|
if (contentTokenType === exports.TagContentType.RAW_TEXT) {
|
|
this._consumeRawTextWithTagClose(prefix, tagName, false);
|
|
}
|
|
else if (contentTokenType === exports.TagContentType.ESCAPABLE_RAW_TEXT) {
|
|
this._consumeRawTextWithTagClose(prefix, tagName, true);
|
|
}
|
|
};
|
|
_Tokenizer.prototype._consumeRawTextWithTagClose = function (prefix, tagName, consumeEntities) {
|
|
var _this = this;
|
|
this._consumeRawText(consumeEntities, function () {
|
|
if (!_this._attemptCharCode($LT))
|
|
return false;
|
|
if (!_this._attemptCharCode($SLASH))
|
|
return false;
|
|
_this._attemptCharCodeUntilFn(isNotWhitespace);
|
|
if (!_this._attemptStrCaseInsensitive(tagName))
|
|
return false;
|
|
_this._attemptCharCodeUntilFn(isNotWhitespace);
|
|
return _this._attemptCharCode($GT);
|
|
});
|
|
this._beginToken(3 /* TAG_CLOSE */);
|
|
this._requireCharCodeUntilFn(function (code) { return code === $GT; }, 3);
|
|
this._cursor.advance(); // Consume the `>`
|
|
this._endToken([prefix, tagName]);
|
|
};
|
|
_Tokenizer.prototype._consumeTagOpenStart = function (start) {
|
|
this._beginToken(0 /* TAG_OPEN_START */, start);
|
|
var parts = this._consumePrefixAndName();
|
|
return this._endToken(parts);
|
|
};
|
|
_Tokenizer.prototype._consumeAttributeName = function () {
|
|
var attrNameStart = this._cursor.peek();
|
|
if (attrNameStart === $SQ || attrNameStart === $DQ) {
|
|
throw this._createError(_unexpectedCharacterErrorMsg(attrNameStart), this._cursor.getSpan());
|
|
}
|
|
this._beginToken(14 /* ATTR_NAME */);
|
|
var prefixAndName = this._consumePrefixAndName();
|
|
this._endToken(prefixAndName);
|
|
};
|
|
_Tokenizer.prototype._consumeAttributeValue = function () {
|
|
var _this = this;
|
|
var value;
|
|
if (this._cursor.peek() === $SQ || this._cursor.peek() === $DQ) {
|
|
var quoteChar_1 = this._cursor.peek();
|
|
this._consumeQuote(quoteChar_1);
|
|
// In an attribute then end of the attribute value and the premature end to an interpolation
|
|
// are both triggered by the `quoteChar`.
|
|
var endPredicate = function () { return _this._cursor.peek() === quoteChar_1; };
|
|
this._consumeWithInterpolation(16 /* ATTR_VALUE_TEXT */, 17 /* ATTR_VALUE_INTERPOLATION */, endPredicate, endPredicate);
|
|
this._consumeQuote(quoteChar_1);
|
|
}
|
|
else {
|
|
var endPredicate = function () { return isNameEnd(_this._cursor.peek()); };
|
|
this._consumeWithInterpolation(16 /* ATTR_VALUE_TEXT */, 17 /* ATTR_VALUE_INTERPOLATION */, endPredicate, endPredicate);
|
|
}
|
|
};
|
|
_Tokenizer.prototype._consumeQuote = function (quoteChar) {
|
|
this._beginToken(15 /* ATTR_QUOTE */);
|
|
this._requireCharCode(quoteChar);
|
|
this._endToken([String.fromCodePoint(quoteChar)]);
|
|
};
|
|
_Tokenizer.prototype._consumeTagOpenEnd = function () {
|
|
var tokenType = this._attemptCharCode($SLASH) ? 2 /* TAG_OPEN_END_VOID */ : 1 /* TAG_OPEN_END */;
|
|
this._beginToken(tokenType);
|
|
this._requireCharCode($GT);
|
|
this._endToken([]);
|
|
};
|
|
_Tokenizer.prototype._consumeTagClose = function (start) {
|
|
this._beginToken(3 /* TAG_CLOSE */, start);
|
|
this._attemptCharCodeUntilFn(isNotWhitespace);
|
|
var prefixAndName = this._consumePrefixAndName();
|
|
this._attemptCharCodeUntilFn(isNotWhitespace);
|
|
this._requireCharCode($GT);
|
|
this._endToken(prefixAndName);
|
|
};
|
|
_Tokenizer.prototype._consumeExpansionFormStart = function () {
|
|
this._beginToken(19 /* EXPANSION_FORM_START */);
|
|
this._requireCharCode($LBRACE);
|
|
this._endToken([]);
|
|
this._expansionCaseStack.push(19 /* EXPANSION_FORM_START */);
|
|
this._beginToken(7 /* RAW_TEXT */);
|
|
var condition = this._readUntil($COMMA);
|
|
var normalizedCondition = this._processCarriageReturns(condition);
|
|
if (this._i18nNormalizeLineEndingsInICUs) {
|
|
// We explicitly want to normalize line endings for this text.
|
|
this._endToken([normalizedCondition]);
|
|
}
|
|
else {
|
|
// We are not normalizing line endings.
|
|
var conditionToken = this._endToken([condition]);
|
|
if (normalizedCondition !== condition) {
|
|
this.nonNormalizedIcuExpressions.push(conditionToken);
|
|
}
|
|
}
|
|
this._requireCharCode($COMMA);
|
|
this._attemptCharCodeUntilFn(isNotWhitespace);
|
|
this._beginToken(7 /* RAW_TEXT */);
|
|
var type = this._readUntil($COMMA);
|
|
this._endToken([type]);
|
|
this._requireCharCode($COMMA);
|
|
this._attemptCharCodeUntilFn(isNotWhitespace);
|
|
};
|
|
_Tokenizer.prototype._consumeExpansionCaseStart = function () {
|
|
this._beginToken(20 /* EXPANSION_CASE_VALUE */);
|
|
var value = this._readUntil($LBRACE).trim();
|
|
this._endToken([value]);
|
|
this._attemptCharCodeUntilFn(isNotWhitespace);
|
|
this._beginToken(21 /* EXPANSION_CASE_EXP_START */);
|
|
this._requireCharCode($LBRACE);
|
|
this._endToken([]);
|
|
this._attemptCharCodeUntilFn(isNotWhitespace);
|
|
this._expansionCaseStack.push(21 /* EXPANSION_CASE_EXP_START */);
|
|
};
|
|
_Tokenizer.prototype._consumeExpansionCaseEnd = function () {
|
|
this._beginToken(22 /* EXPANSION_CASE_EXP_END */);
|
|
this._requireCharCode($RBRACE);
|
|
this._endToken([]);
|
|
this._attemptCharCodeUntilFn(isNotWhitespace);
|
|
this._expansionCaseStack.pop();
|
|
};
|
|
_Tokenizer.prototype._consumeExpansionFormEnd = function () {
|
|
this._beginToken(23 /* EXPANSION_FORM_END */);
|
|
this._requireCharCode($RBRACE);
|
|
this._endToken([]);
|
|
this._expansionCaseStack.pop();
|
|
};
|
|
/**
|
|
* Consume a string that may contain interpolation expressions.
|
|
*
|
|
* The first token consumed will be of `tokenType` and then there will be alternating
|
|
* `interpolationTokenType` and `tokenType` tokens until the `endPredicate()` returns true.
|
|
*
|
|
* If an interpolation token ends prematurely it will have no end marker in its `parts` array.
|
|
*
|
|
* @param textTokenType the kind of tokens to interleave around interpolation tokens.
|
|
* @param interpolationTokenType the kind of tokens that contain interpolation.
|
|
* @param endPredicate a function that should return true when we should stop consuming.
|
|
* @param endInterpolation a function that should return true if there is a premature end to an
|
|
* interpolation expression - i.e. before we get to the normal interpolation closing marker.
|
|
*/
|
|
_Tokenizer.prototype._consumeWithInterpolation = function (textTokenType, interpolationTokenType, endPredicate, endInterpolation) {
|
|
this._beginToken(textTokenType);
|
|
var parts = [];
|
|
while (!endPredicate()) {
|
|
var current = this._cursor.clone();
|
|
if (this._interpolationConfig && this._attemptStr(this._interpolationConfig.start)) {
|
|
this._endToken([this._processCarriageReturns(parts.join(''))], current);
|
|
parts.length = 0;
|
|
this._consumeInterpolation(interpolationTokenType, current, endInterpolation);
|
|
this._beginToken(textTokenType);
|
|
}
|
|
else if (this._cursor.peek() === $AMPERSAND) {
|
|
this._endToken([this._processCarriageReturns(parts.join(''))]);
|
|
parts.length = 0;
|
|
this._consumeEntity(textTokenType);
|
|
this._beginToken(textTokenType);
|
|
}
|
|
else {
|
|
parts.push(this._readChar());
|
|
}
|
|
}
|
|
// It is possible that an interpolation was started but not ended inside this text token.
|
|
// Make sure that we reset the state of the lexer correctly.
|
|
this._inInterpolation = false;
|
|
this._endToken([this._processCarriageReturns(parts.join(''))]);
|
|
};
|
|
/**
|
|
* Consume a block of text that has been interpreted as an Angular interpolation.
|
|
*
|
|
* @param interpolationTokenType the type of the interpolation token to generate.
|
|
* @param interpolationStart a cursor that points to the start of this interpolation.
|
|
* @param prematureEndPredicate a function that should return true if the next characters indicate
|
|
* an end to the interpolation before its normal closing marker.
|
|
*/
|
|
_Tokenizer.prototype._consumeInterpolation = function (interpolationTokenType, interpolationStart, prematureEndPredicate) {
|
|
var parts = [];
|
|
this._beginToken(interpolationTokenType, interpolationStart);
|
|
parts.push(this._interpolationConfig.start);
|
|
// Find the end of the interpolation, ignoring content inside quotes.
|
|
var expressionStart = this._cursor.clone();
|
|
var inQuote = null;
|
|
var inComment = false;
|
|
while (this._cursor.peek() !== $EOF &&
|
|
(prematureEndPredicate === null || !prematureEndPredicate())) {
|
|
var current = this._cursor.clone();
|
|
if (this._isTagStart()) {
|
|
// We are starting what looks like an HTML element in the middle of this interpolation.
|
|
// Reset the cursor to before the `<` character and end the interpolation token.
|
|
// (This is actually wrong but here for backward compatibility).
|
|
this._cursor = current;
|
|
parts.push(this._getProcessedChars(expressionStart, current));
|
|
this._endToken(parts);
|
|
return;
|
|
}
|
|
if (inQuote === null) {
|
|
if (this._attemptStr(this._interpolationConfig.end)) {
|
|
// We are not in a string, and we hit the end interpolation marker
|
|
parts.push(this._getProcessedChars(expressionStart, current));
|
|
parts.push(this._interpolationConfig.end);
|
|
this._endToken(parts);
|
|
return;
|
|
}
|
|
else if (this._attemptStr('//')) {
|
|
// Once we are in a comment we ignore any quotes
|
|
inComment = true;
|
|
}
|
|
}
|
|
var char = this._cursor.peek();
|
|
this._cursor.advance();
|
|
if (char === $BACKSLASH) {
|
|
// Skip the next character because it was escaped.
|
|
this._cursor.advance();
|
|
}
|
|
else if (char === inQuote) {
|
|
// Exiting the current quoted string
|
|
inQuote = null;
|
|
}
|
|
else if (!inComment && inQuote === null && isQuote(char)) {
|
|
// Entering a new quoted string
|
|
inQuote = char;
|
|
}
|
|
}
|
|
// We hit EOF without finding a closing interpolation marker
|
|
parts.push(this._getProcessedChars(expressionStart, this._cursor));
|
|
this._endToken(parts);
|
|
};
|
|
_Tokenizer.prototype._getProcessedChars = function (start, end) {
|
|
return this._processCarriageReturns(end.getChars(start));
|
|
};
|
|
_Tokenizer.prototype._isTextEnd = function () {
|
|
if (this._isTagStart() || this._cursor.peek() === $EOF) {
|
|
return true;
|
|
}
|
|
if (this._tokenizeIcu && !this._inInterpolation) {
|
|
if (this.isExpansionFormStart()) {
|
|
// start of an expansion form
|
|
return true;
|
|
}
|
|
if (this._cursor.peek() === $RBRACE && this._isInExpansionCase()) {
|
|
// end of and expansion case
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
};
|
|
/**
|
|
* Returns true if the current cursor is pointing to the start of a tag
|
|
* (opening/closing/comments/cdata/etc).
|
|
*/
|
|
_Tokenizer.prototype._isTagStart = function () {
|
|
if (this._cursor.peek() === $LT) {
|
|
// We assume that `<` followed by whitespace is not the start of an HTML element.
|
|
var tmp = this._cursor.clone();
|
|
tmp.advance();
|
|
// If the next character is alphabetic, ! nor / then it is a tag start
|
|
var code = tmp.peek();
|
|
if (($a <= code && code <= $z) || ($A <= code && code <= $Z) ||
|
|
code === $SLASH || code === $BANG) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
};
|
|
_Tokenizer.prototype._readUntil = function (char) {
|
|
var start = this._cursor.clone();
|
|
this._attemptUntilChar(char);
|
|
return this._cursor.getChars(start);
|
|
};
|
|
_Tokenizer.prototype._isInExpansionCase = function () {
|
|
return this._expansionCaseStack.length > 0 &&
|
|
this._expansionCaseStack[this._expansionCaseStack.length - 1] ===
|
|
21 /* EXPANSION_CASE_EXP_START */;
|
|
};
|
|
_Tokenizer.prototype._isInExpansionForm = function () {
|
|
return this._expansionCaseStack.length > 0 &&
|
|
this._expansionCaseStack[this._expansionCaseStack.length - 1] ===
|
|
19 /* EXPANSION_FORM_START */;
|
|
};
|
|
_Tokenizer.prototype.isExpansionFormStart = function () {
|
|
if (this._cursor.peek() !== $LBRACE) {
|
|
return false;
|
|
}
|
|
if (this._interpolationConfig) {
|
|
var start = this._cursor.clone();
|
|
var isInterpolation = this._attemptStr(this._interpolationConfig.start);
|
|
this._cursor = start;
|
|
return !isInterpolation;
|
|
}
|
|
return true;
|
|
};
|
|
return _Tokenizer;
|
|
}());
|
|
function isNotWhitespace(code) {
|
|
return !isWhitespace(code) || code === $EOF;
|
|
}
|
|
function isNameEnd(code) {
|
|
return isWhitespace(code) || code === $GT || code === $LT ||
|
|
code === $SLASH || code === $SQ || code === $DQ || code === $EQ ||
|
|
code === $EOF;
|
|
}
|
|
function isPrefixEnd(code) {
|
|
return (code < $a || $z < code) && (code < $A || $Z < code) &&
|
|
(code < $0 || code > $9);
|
|
}
|
|
function isDigitEntityEnd(code) {
|
|
return code === $SEMICOLON || code === $EOF || !isAsciiHexDigit(code);
|
|
}
|
|
function isNamedEntityEnd(code) {
|
|
return code === $SEMICOLON || code === $EOF || !isAsciiLetter(code);
|
|
}
|
|
function isExpansionCaseStart(peek) {
|
|
return peek !== $RBRACE;
|
|
}
|
|
function compareCharCodeCaseInsensitive(code1, code2) {
|
|
return toUpperCaseCharCode(code1) === toUpperCaseCharCode(code2);
|
|
}
|
|
function toUpperCaseCharCode(code) {
|
|
return code >= $a && code <= $z ? code - $a + $A : code;
|
|
}
|
|
function mergeTextTokens(srcTokens) {
|
|
var dstTokens = [];
|
|
var lastDstToken = undefined;
|
|
for (var i = 0; i < srcTokens.length; i++) {
|
|
var token = srcTokens[i];
|
|
if ((lastDstToken && lastDstToken.type === 5 /* TEXT */ && token.type === 5 /* TEXT */) ||
|
|
(lastDstToken && lastDstToken.type === 16 /* ATTR_VALUE_TEXT */ &&
|
|
token.type === 16 /* ATTR_VALUE_TEXT */)) {
|
|
lastDstToken.parts[0] += token.parts[0];
|
|
lastDstToken.sourceSpan.end = token.sourceSpan.end;
|
|
}
|
|
else {
|
|
lastDstToken = token;
|
|
dstTokens.push(lastDstToken);
|
|
}
|
|
}
|
|
return dstTokens;
|
|
}
|
|
var PlainCharacterCursor = /** @class */ (function () {
|
|
function PlainCharacterCursor(fileOrCursor, range) {
|
|
if (fileOrCursor instanceof PlainCharacterCursor) {
|
|
this.file = fileOrCursor.file;
|
|
this.input = fileOrCursor.input;
|
|
this.end = fileOrCursor.end;
|
|
var state = fileOrCursor.state;
|
|
// Note: avoid using `{...fileOrCursor.state}` here as that has a severe performance penalty.
|
|
// In ES5 bundles the object spread operator is translated into the `__assign` helper, which
|
|
// is not optimized by VMs as efficiently as a raw object literal. Since this constructor is
|
|
// called in tight loops, this difference matters.
|
|
this.state = {
|
|
peek: state.peek,
|
|
offset: state.offset,
|
|
line: state.line,
|
|
column: state.column,
|
|
};
|
|
}
|
|
else {
|
|
if (!range) {
|
|
throw new Error('Programming error: the range argument must be provided with a file argument.');
|
|
}
|
|
this.file = fileOrCursor;
|
|
this.input = fileOrCursor.content;
|
|
this.end = range.endPos;
|
|
this.state = {
|
|
peek: -1,
|
|
offset: range.startPos,
|
|
line: range.startLine,
|
|
column: range.startCol,
|
|
};
|
|
}
|
|
}
|
|
PlainCharacterCursor.prototype.clone = function () {
|
|
return new PlainCharacterCursor(this);
|
|
};
|
|
PlainCharacterCursor.prototype.peek = function () {
|
|
return this.state.peek;
|
|
};
|
|
PlainCharacterCursor.prototype.charsLeft = function () {
|
|
return this.end - this.state.offset;
|
|
};
|
|
PlainCharacterCursor.prototype.diff = function (other) {
|
|
return this.state.offset - other.state.offset;
|
|
};
|
|
PlainCharacterCursor.prototype.advance = function () {
|
|
this.advanceState(this.state);
|
|
};
|
|
PlainCharacterCursor.prototype.init = function () {
|
|
this.updatePeek(this.state);
|
|
};
|
|
PlainCharacterCursor.prototype.getSpan = function (start, leadingTriviaCodePoints) {
|
|
start = start || this;
|
|
var fullStart = start;
|
|
if (leadingTriviaCodePoints) {
|
|
while (this.diff(start) > 0 && leadingTriviaCodePoints.indexOf(start.peek()) !== -1) {
|
|
if (fullStart === start) {
|
|
start = start.clone();
|
|
}
|
|
start.advance();
|
|
}
|
|
}
|
|
var startLocation = this.locationFromCursor(start);
|
|
var endLocation = this.locationFromCursor(this);
|
|
var fullStartLocation = fullStart !== start ? this.locationFromCursor(fullStart) : startLocation;
|
|
return new ParseSourceSpan(startLocation, endLocation, fullStartLocation);
|
|
};
|
|
PlainCharacterCursor.prototype.getChars = function (start) {
|
|
return this.input.substring(start.state.offset, this.state.offset);
|
|
};
|
|
PlainCharacterCursor.prototype.charAt = function (pos) {
|
|
return this.input.charCodeAt(pos);
|
|
};
|
|
PlainCharacterCursor.prototype.advanceState = function (state) {
|
|
if (state.offset >= this.end) {
|
|
this.state = state;
|
|
throw new CursorError('Unexpected character "EOF"', this);
|
|
}
|
|
var currentChar = this.charAt(state.offset);
|
|
if (currentChar === $LF) {
|
|
state.line++;
|
|
state.column = 0;
|
|
}
|
|
else if (!isNewLine(currentChar)) {
|
|
state.column++;
|
|
}
|
|
state.offset++;
|
|
this.updatePeek(state);
|
|
};
|
|
PlainCharacterCursor.prototype.updatePeek = function (state) {
|
|
state.peek = state.offset >= this.end ? $EOF : this.charAt(state.offset);
|
|
};
|
|
PlainCharacterCursor.prototype.locationFromCursor = function (cursor) {
|
|
return new ParseLocation(cursor.file, cursor.state.offset, cursor.state.line, cursor.state.column);
|
|
};
|
|
return PlainCharacterCursor;
|
|
}());
|
|
var EscapedCharacterCursor = /** @class */ (function (_super) {
|
|
__extends(EscapedCharacterCursor, _super);
|
|
function EscapedCharacterCursor(fileOrCursor, range) {
|
|
var _this = this;
|
|
if (fileOrCursor instanceof EscapedCharacterCursor) {
|
|
_this = _super.call(this, fileOrCursor) || this;
|
|
_this.internalState = Object.assign({}, fileOrCursor.internalState);
|
|
}
|
|
else {
|
|
_this = _super.call(this, fileOrCursor, range) || this;
|
|
_this.internalState = _this.state;
|
|
}
|
|
return _this;
|
|
}
|
|
EscapedCharacterCursor.prototype.advance = function () {
|
|
this.state = this.internalState;
|
|
_super.prototype.advance.call(this);
|
|
this.processEscapeSequence();
|
|
};
|
|
EscapedCharacterCursor.prototype.init = function () {
|
|
_super.prototype.init.call(this);
|
|
this.processEscapeSequence();
|
|
};
|
|
EscapedCharacterCursor.prototype.clone = function () {
|
|
return new EscapedCharacterCursor(this);
|
|
};
|
|
EscapedCharacterCursor.prototype.getChars = function (start) {
|
|
var cursor = start.clone();
|
|
var chars = '';
|
|
while (cursor.internalState.offset < this.internalState.offset) {
|
|
chars += String.fromCodePoint(cursor.peek());
|
|
cursor.advance();
|
|
}
|
|
return chars;
|
|
};
|
|
/**
|
|
* Process the escape sequence that starts at the current position in the text.
|
|
*
|
|
* This method is called to ensure that `peek` has the unescaped value of escape sequences.
|
|
*/
|
|
EscapedCharacterCursor.prototype.processEscapeSequence = function () {
|
|
var _this = this;
|
|
var peek = function () { return _this.internalState.peek; };
|
|
if (peek() === $BACKSLASH) {
|
|
// We have hit an escape sequence so we need the internal state to become independent
|
|
// of the external state.
|
|
this.internalState = Object.assign({}, this.state);
|
|
// Move past the backslash
|
|
this.advanceState(this.internalState);
|
|
// First check for standard control char sequences
|
|
if (peek() === $n) {
|
|
this.state.peek = $LF;
|
|
}
|
|
else if (peek() === $r) {
|
|
this.state.peek = $CR;
|
|
}
|
|
else if (peek() === $v) {
|
|
this.state.peek = $VTAB;
|
|
}
|
|
else if (peek() === $t) {
|
|
this.state.peek = $TAB;
|
|
}
|
|
else if (peek() === $b) {
|
|
this.state.peek = $BSPACE;
|
|
}
|
|
else if (peek() === $f) {
|
|
this.state.peek = $FF;
|
|
}
|
|
// Now consider more complex sequences
|
|
else if (peek() === $u) {
|
|
// Unicode code-point sequence
|
|
this.advanceState(this.internalState); // advance past the `u` char
|
|
if (peek() === $LBRACE) {
|
|
// Variable length Unicode, e.g. `\x{123}`
|
|
this.advanceState(this.internalState); // advance past the `{` char
|
|
// Advance past the variable number of hex digits until we hit a `}` char
|
|
var digitStart = this.clone();
|
|
var length = 0;
|
|
while (peek() !== $RBRACE) {
|
|
this.advanceState(this.internalState);
|
|
length++;
|
|
}
|
|
this.state.peek = this.decodeHexDigits(digitStart, length);
|
|
}
|
|
else {
|
|
// Fixed length Unicode, e.g. `\u1234`
|
|
var digitStart = this.clone();
|
|
this.advanceState(this.internalState);
|
|
this.advanceState(this.internalState);
|
|
this.advanceState(this.internalState);
|
|
this.state.peek = this.decodeHexDigits(digitStart, 4);
|
|
}
|
|
}
|
|
else if (peek() === $x) {
|
|
// Hex char code, e.g. `\x2F`
|
|
this.advanceState(this.internalState); // advance past the `x` char
|
|
var digitStart = this.clone();
|
|
this.advanceState(this.internalState);
|
|
this.state.peek = this.decodeHexDigits(digitStart, 2);
|
|
}
|
|
else if (isOctalDigit(peek())) {
|
|
// Octal char code, e.g. `\012`,
|
|
var octal = '';
|
|
var length = 0;
|
|
var previous = this.clone();
|
|
while (isOctalDigit(peek()) && length < 3) {
|
|
previous = this.clone();
|
|
octal += String.fromCodePoint(peek());
|
|
this.advanceState(this.internalState);
|
|
length++;
|
|
}
|
|
this.state.peek = parseInt(octal, 8);
|
|
// Backup one char
|
|
this.internalState = previous.internalState;
|
|
}
|
|
else if (isNewLine(this.internalState.peek)) {
|
|
// Line continuation `\` followed by a new line
|
|
this.advanceState(this.internalState); // advance over the newline
|
|
this.state = this.internalState;
|
|
}
|
|
else {
|
|
// If none of the `if` blocks were executed then we just have an escaped normal character.
|
|
// In that case we just, effectively, skip the backslash from the character.
|
|
this.state.peek = this.internalState.peek;
|
|
}
|
|
}
|
|
};
|
|
EscapedCharacterCursor.prototype.decodeHexDigits = function (start, length) {
|
|
var hex = this.input.substr(start.internalState.offset, length);
|
|
var charCode = parseInt(hex, 16);
|
|
if (!isNaN(charCode)) {
|
|
return charCode;
|
|
}
|
|
else {
|
|
start.state = start.internalState;
|
|
throw new CursorError('Invalid hexadecimal escape sequence', start);
|
|
}
|
|
};
|
|
return EscapedCharacterCursor;
|
|
}(PlainCharacterCursor));
|
|
var CursorError = /** @class */ (function () {
|
|
function CursorError(msg, cursor) {
|
|
this.msg = msg;
|
|
this.cursor = cursor;
|
|
}
|
|
return CursorError;
|
|
}());
|
|
|
|
var TreeError = /** @class */ (function (_super) {
|
|
__extends(TreeError, _super);
|
|
function TreeError(elementName, span, msg) {
|
|
var _this = _super.call(this, span, msg) || this;
|
|
_this.elementName = elementName;
|
|
return _this;
|
|
}
|
|
TreeError.create = function (elementName, span, msg) {
|
|
return new TreeError(elementName, span, msg);
|
|
};
|
|
return TreeError;
|
|
}(ParseError));
|
|
var ParseTreeResult = /** @class */ (function () {
|
|
function ParseTreeResult(rootNodes, errors) {
|
|
this.rootNodes = rootNodes;
|
|
this.errors = errors;
|
|
}
|
|
return ParseTreeResult;
|
|
}());
|
|
var Parser = /** @class */ (function () {
|
|
function Parser(getTagDefinition) {
|
|
this.getTagDefinition = getTagDefinition;
|
|
}
|
|
Parser.prototype.parse = function (source, url, options) {
|
|
var tokenizeResult = tokenize(source, url, this.getTagDefinition, options);
|
|
var parser = new _TreeBuilder(tokenizeResult.tokens, this.getTagDefinition);
|
|
parser.build();
|
|
return new ParseTreeResult(parser.rootNodes, tokenizeResult.errors.concat(parser.errors));
|
|
};
|
|
return Parser;
|
|
}());
|
|
var _TreeBuilder = /** @class */ (function () {
|
|
function _TreeBuilder(tokens, getTagDefinition) {
|
|
this.tokens = tokens;
|
|
this.getTagDefinition = getTagDefinition;
|
|
this._index = -1;
|
|
this._elementStack = [];
|
|
this.rootNodes = [];
|
|
this.errors = [];
|
|
this._advance();
|
|
}
|
|
_TreeBuilder.prototype.build = function () {
|
|
while (this._peek.type !== 24 /* EOF */) {
|
|
if (this._peek.type === 0 /* TAG_OPEN_START */ ||
|
|
this._peek.type === 4 /* INCOMPLETE_TAG_OPEN */) {
|
|
this._consumeStartTag(this._advance());
|
|
}
|
|
else if (this._peek.type === 3 /* TAG_CLOSE */) {
|
|
this._consumeEndTag(this._advance());
|
|
}
|
|
else if (this._peek.type === 12 /* CDATA_START */) {
|
|
this._closeVoidElement();
|
|
this._consumeCdata(this._advance());
|
|
}
|
|
else if (this._peek.type === 10 /* COMMENT_START */) {
|
|
this._closeVoidElement();
|
|
this._consumeComment(this._advance());
|
|
}
|
|
else if (this._peek.type === 5 /* TEXT */ || this._peek.type === 7 /* RAW_TEXT */ ||
|
|
this._peek.type === 6 /* ESCAPABLE_RAW_TEXT */) {
|
|
this._closeVoidElement();
|
|
this._consumeText(this._advance());
|
|
}
|
|
else if (this._peek.type === 19 /* EXPANSION_FORM_START */) {
|
|
this._consumeExpansion(this._advance());
|
|
}
|
|
else {
|
|
// Skip all other tokens...
|
|
this._advance();
|
|
}
|
|
}
|
|
};
|
|
_TreeBuilder.prototype._advance = function () {
|
|
var prev = this._peek;
|
|
if (this._index < this.tokens.length - 1) {
|
|
// Note: there is always an EOF token at the end
|
|
this._index++;
|
|
}
|
|
this._peek = this.tokens[this._index];
|
|
return prev;
|
|
};
|
|
_TreeBuilder.prototype._advanceIf = function (type) {
|
|
if (this._peek.type === type) {
|
|
return this._advance();
|
|
}
|
|
return null;
|
|
};
|
|
_TreeBuilder.prototype._consumeCdata = function (_startToken) {
|
|
this._consumeText(this._advance());
|
|
this._advanceIf(13 /* CDATA_END */);
|
|
};
|
|
_TreeBuilder.prototype._consumeComment = function (token) {
|
|
var text = this._advanceIf(7 /* RAW_TEXT */);
|
|
this._advanceIf(11 /* COMMENT_END */);
|
|
var value = text != null ? text.parts[0].trim() : null;
|
|
this._addToParent(new Comment$1(value, token.sourceSpan));
|
|
};
|
|
_TreeBuilder.prototype._consumeExpansion = function (token) {
|
|
var switchValue = this._advance();
|
|
var type = this._advance();
|
|
var cases = [];
|
|
// read =
|
|
while (this._peek.type === 20 /* EXPANSION_CASE_VALUE */) {
|
|
var expCase = this._parseExpansionCase();
|
|
if (!expCase)
|
|
return; // error
|
|
cases.push(expCase);
|
|
}
|
|
// read the final }
|
|
if (this._peek.type !== 23 /* EXPANSION_FORM_END */) {
|
|
this.errors.push(TreeError.create(null, this._peek.sourceSpan, "Invalid ICU message. Missing '}'."));
|
|
return;
|
|
}
|
|
var sourceSpan = new ParseSourceSpan(token.sourceSpan.start, this._peek.sourceSpan.end, token.sourceSpan.fullStart);
|
|
this._addToParent(new Expansion(switchValue.parts[0], type.parts[0], cases, sourceSpan, switchValue.sourceSpan));
|
|
this._advance();
|
|
};
|
|
_TreeBuilder.prototype._parseExpansionCase = function () {
|
|
var value = this._advance();
|
|
// read {
|
|
if (this._peek.type !== 21 /* EXPANSION_CASE_EXP_START */) {
|
|
this.errors.push(TreeError.create(null, this._peek.sourceSpan, "Invalid ICU message. Missing '{'."));
|
|
return null;
|
|
}
|
|
// read until }
|
|
var start = this._advance();
|
|
var exp = this._collectExpansionExpTokens(start);
|
|
if (!exp)
|
|
return null;
|
|
var end = this._advance();
|
|
exp.push({ type: 24 /* EOF */, parts: [], sourceSpan: end.sourceSpan });
|
|
// parse everything in between { and }
|
|
var expansionCaseParser = new _TreeBuilder(exp, this.getTagDefinition);
|
|
expansionCaseParser.build();
|
|
if (expansionCaseParser.errors.length > 0) {
|
|
this.errors = this.errors.concat(expansionCaseParser.errors);
|
|
return null;
|
|
}
|
|
var sourceSpan = new ParseSourceSpan(value.sourceSpan.start, end.sourceSpan.end, value.sourceSpan.fullStart);
|
|
var expSourceSpan = new ParseSourceSpan(start.sourceSpan.start, end.sourceSpan.end, start.sourceSpan.fullStart);
|
|
return new ExpansionCase(value.parts[0], expansionCaseParser.rootNodes, sourceSpan, value.sourceSpan, expSourceSpan);
|
|
};
|
|
_TreeBuilder.prototype._collectExpansionExpTokens = function (start) {
|
|
var exp = [];
|
|
var expansionFormStack = [21 /* EXPANSION_CASE_EXP_START */];
|
|
while (true) {
|
|
if (this._peek.type === 19 /* EXPANSION_FORM_START */ ||
|
|
this._peek.type === 21 /* EXPANSION_CASE_EXP_START */) {
|
|
expansionFormStack.push(this._peek.type);
|
|
}
|
|
if (this._peek.type === 22 /* EXPANSION_CASE_EXP_END */) {
|
|
if (lastOnStack(expansionFormStack, 21 /* EXPANSION_CASE_EXP_START */)) {
|
|
expansionFormStack.pop();
|
|
if (expansionFormStack.length === 0)
|
|
return exp;
|
|
}
|
|
else {
|
|
this.errors.push(TreeError.create(null, start.sourceSpan, "Invalid ICU message. Missing '}'."));
|
|
return null;
|
|
}
|
|
}
|
|
if (this._peek.type === 23 /* EXPANSION_FORM_END */) {
|
|
if (lastOnStack(expansionFormStack, 19 /* EXPANSION_FORM_START */)) {
|
|
expansionFormStack.pop();
|
|
}
|
|
else {
|
|
this.errors.push(TreeError.create(null, start.sourceSpan, "Invalid ICU message. Missing '}'."));
|
|
return null;
|
|
}
|
|
}
|
|
if (this._peek.type === 24 /* EOF */) {
|
|
this.errors.push(TreeError.create(null, start.sourceSpan, "Invalid ICU message. Missing '}'."));
|
|
return null;
|
|
}
|
|
exp.push(this._advance());
|
|
}
|
|
};
|
|
_TreeBuilder.prototype._consumeText = function (token) {
|
|
var tokens = [token];
|
|
var startSpan = token.sourceSpan;
|
|
var text = token.parts[0];
|
|
if (text.length > 0 && text[0] === '\n') {
|
|
var parent = this._getParentElement();
|
|
if (parent != null && parent.children.length === 0 &&
|
|
this.getTagDefinition(parent.name).ignoreFirstLf) {
|
|
text = text.substring(1);
|
|
tokens[0] = { type: token.type, sourceSpan: token.sourceSpan, parts: [text] };
|
|
}
|
|
}
|
|
while (this._peek.type === 8 /* INTERPOLATION */ || this._peek.type === 5 /* TEXT */ ||
|
|
this._peek.type === 9 /* ENCODED_ENTITY */) {
|
|
token = this._advance();
|
|
tokens.push(token);
|
|
if (token.type === 8 /* INTERPOLATION */) {
|
|
// For backward compatibility we decode HTML entities that appear in interpolation
|
|
// expressions. This is arguably a bug, but it could be a considerable breaking change to
|
|
// fix it. It should be addressed in a larger project to refactor the entire parser/lexer
|
|
// chain after View Engine has been removed.
|
|
text += token.parts.join('').replace(/&([^;]+);/g, decodeEntity);
|
|
}
|
|
else if (token.type === 9 /* ENCODED_ENTITY */) {
|
|
text += token.parts[0];
|
|
}
|
|
else {
|
|
text += token.parts.join('');
|
|
}
|
|
}
|
|
if (text.length > 0) {
|
|
var endSpan = token.sourceSpan;
|
|
this._addToParent(new Text$3(text, new ParseSourceSpan(startSpan.start, endSpan.end, startSpan.fullStart, startSpan.details), tokens));
|
|
}
|
|
};
|
|
_TreeBuilder.prototype._closeVoidElement = function () {
|
|
var el = this._getParentElement();
|
|
if (el && this.getTagDefinition(el.name).isVoid) {
|
|
this._elementStack.pop();
|
|
}
|
|
};
|
|
_TreeBuilder.prototype._consumeStartTag = function (startTagToken) {
|
|
var _a = __read(startTagToken.parts, 2), prefix = _a[0], name = _a[1];
|
|
var attrs = [];
|
|
while (this._peek.type === 14 /* ATTR_NAME */) {
|
|
attrs.push(this._consumeAttr(this._advance()));
|
|
}
|
|
var fullName = this._getElementFullName(prefix, name, this._getParentElement());
|
|
var selfClosing = false;
|
|
// Note: There could have been a tokenizer error
|
|
// so that we don't get a token for the end tag...
|
|
if (this._peek.type === 2 /* TAG_OPEN_END_VOID */) {
|
|
this._advance();
|
|
selfClosing = true;
|
|
var tagDef = this.getTagDefinition(fullName);
|
|
if (!(tagDef.canSelfClose || getNsPrefix(fullName) !== null || tagDef.isVoid)) {
|
|
this.errors.push(TreeError.create(fullName, startTagToken.sourceSpan, "Only void and foreign elements can be self closed \"" + startTagToken.parts[1] + "\""));
|
|
}
|
|
}
|
|
else if (this._peek.type === 1 /* TAG_OPEN_END */) {
|
|
this._advance();
|
|
selfClosing = false;
|
|
}
|
|
var end = this._peek.sourceSpan.fullStart;
|
|
var span = new ParseSourceSpan(startTagToken.sourceSpan.start, end, startTagToken.sourceSpan.fullStart);
|
|
// Create a separate `startSpan` because `span` will be modified when there is an `end` span.
|
|
var startSpan = new ParseSourceSpan(startTagToken.sourceSpan.start, end, startTagToken.sourceSpan.fullStart);
|
|
var el = new Element$1(fullName, attrs, [], span, startSpan, undefined);
|
|
this._pushElement(el);
|
|
if (selfClosing) {
|
|
// Elements that are self-closed have their `endSourceSpan` set to the full span, as the
|
|
// element start tag also represents the end tag.
|
|
this._popElement(fullName, span);
|
|
}
|
|
else if (startTagToken.type === 4 /* INCOMPLETE_TAG_OPEN */) {
|
|
// We already know the opening tag is not complete, so it is unlikely it has a corresponding
|
|
// close tag. Let's optimistically parse it as a full element and emit an error.
|
|
this._popElement(fullName, null);
|
|
this.errors.push(TreeError.create(fullName, span, "Opening tag \"" + fullName + "\" not terminated."));
|
|
}
|
|
};
|
|
_TreeBuilder.prototype._pushElement = function (el) {
|
|
var parentEl = this._getParentElement();
|
|
if (parentEl && this.getTagDefinition(parentEl.name).isClosedByChild(el.name)) {
|
|
this._elementStack.pop();
|
|
}
|
|
this._addToParent(el);
|
|
this._elementStack.push(el);
|
|
};
|
|
_TreeBuilder.prototype._consumeEndTag = function (endTagToken) {
|
|
var fullName = this._getElementFullName(endTagToken.parts[0], endTagToken.parts[1], this._getParentElement());
|
|
if (this.getTagDefinition(fullName).isVoid) {
|
|
this.errors.push(TreeError.create(fullName, endTagToken.sourceSpan, "Void elements do not have end tags \"" + endTagToken.parts[1] + "\""));
|
|
}
|
|
else if (!this._popElement(fullName, endTagToken.sourceSpan)) {
|
|
var errMsg = "Unexpected closing tag \"" + fullName + "\". It may happen when the tag has already been closed by another tag. For more info see https://www.w3.org/TR/html5/syntax.html#closing-elements-that-have-implied-end-tags";
|
|
this.errors.push(TreeError.create(fullName, endTagToken.sourceSpan, errMsg));
|
|
}
|
|
};
|
|
/**
|
|
* Closes the nearest element with the tag name `fullName` in the parse tree.
|
|
* `endSourceSpan` is the span of the closing tag, or null if the element does
|
|
* not have a closing tag (for example, this happens when an incomplete
|
|
* opening tag is recovered).
|
|
*/
|
|
_TreeBuilder.prototype._popElement = function (fullName, endSourceSpan) {
|
|
var unexpectedCloseTagDetected = false;
|
|
for (var stackIndex = this._elementStack.length - 1; stackIndex >= 0; stackIndex--) {
|
|
var el = this._elementStack[stackIndex];
|
|
if (el.name === fullName) {
|
|
// Record the parse span with the element that is being closed. Any elements that are
|
|
// removed from the element stack at this point are closed implicitly, so they won't get
|
|
// an end source span (as there is no explicit closing element).
|
|
el.endSourceSpan = endSourceSpan;
|
|
el.sourceSpan.end = endSourceSpan !== null ? endSourceSpan.end : el.sourceSpan.end;
|
|
this._elementStack.splice(stackIndex, this._elementStack.length - stackIndex);
|
|
return !unexpectedCloseTagDetected;
|
|
}
|
|
if (!this.getTagDefinition(el.name).closedByParent) {
|
|
// Note that we encountered an unexpected close tag but continue processing the element
|
|
// stack so we can assign an `endSourceSpan` if there is a corresponding start tag for this
|
|
// end tag in the stack.
|
|
unexpectedCloseTagDetected = true;
|
|
}
|
|
}
|
|
return false;
|
|
};
|
|
_TreeBuilder.prototype._consumeAttr = function (attrName) {
|
|
var fullName = mergeNsAndName(attrName.parts[0], attrName.parts[1]);
|
|
var attrEnd = attrName.sourceSpan.end;
|
|
// Consume any quote
|
|
if (this._peek.type === 15 /* ATTR_QUOTE */) {
|
|
this._advance();
|
|
}
|
|
// Consume the attribute value
|
|
var value = '';
|
|
var valueTokens = [];
|
|
var valueStartSpan = undefined;
|
|
var valueEnd = undefined;
|
|
// NOTE: We need to use a new variable `nextTokenType` here to hide the actual type of
|
|
// `_peek.type` from TS. Otherwise TS will narrow the type of `_peek.type` preventing it from
|
|
// being able to consider `ATTR_VALUE_INTERPOLATION` as an option. This is because TS is not
|
|
// able to see that `_advance()` will actually mutate `_peek`.
|
|
var nextTokenType = this._peek.type;
|
|
if (nextTokenType === 16 /* ATTR_VALUE_TEXT */) {
|
|
valueStartSpan = this._peek.sourceSpan;
|
|
valueEnd = this._peek.sourceSpan.end;
|
|
while (this._peek.type === 16 /* ATTR_VALUE_TEXT */ ||
|
|
this._peek.type === 17 /* ATTR_VALUE_INTERPOLATION */ ||
|
|
this._peek.type === 9 /* ENCODED_ENTITY */) {
|
|
var valueToken = this._advance();
|
|
valueTokens.push(valueToken);
|
|
if (valueToken.type === 17 /* ATTR_VALUE_INTERPOLATION */) {
|
|
// For backward compatibility we decode HTML entities that appear in interpolation
|
|
// expressions. This is arguably a bug, but it could be a considerable breaking change to
|
|
// fix it. It should be addressed in a larger project to refactor the entire parser/lexer
|
|
// chain after View Engine has been removed.
|
|
value += valueToken.parts.join('').replace(/&([^;]+);/g, decodeEntity);
|
|
}
|
|
else if (valueToken.type === 9 /* ENCODED_ENTITY */) {
|
|
value += valueToken.parts[0];
|
|
}
|
|
else {
|
|
value += valueToken.parts.join('');
|
|
}
|
|
valueEnd = attrEnd = valueToken.sourceSpan.end;
|
|
}
|
|
}
|
|
// Consume any quote
|
|
if (this._peek.type === 15 /* ATTR_QUOTE */) {
|
|
var quoteToken = this._advance();
|
|
attrEnd = quoteToken.sourceSpan.end;
|
|
}
|
|
var valueSpan = valueStartSpan && valueEnd &&
|
|
new ParseSourceSpan(valueStartSpan.start, valueEnd, valueStartSpan.fullStart);
|
|
return new Attribute(fullName, value, new ParseSourceSpan(attrName.sourceSpan.start, attrEnd, attrName.sourceSpan.fullStart), attrName.sourceSpan, valueSpan, valueTokens.length > 0 ? valueTokens : undefined, undefined);
|
|
};
|
|
_TreeBuilder.prototype._getParentElement = function () {
|
|
return this._elementStack.length > 0 ? this._elementStack[this._elementStack.length - 1] : null;
|
|
};
|
|
_TreeBuilder.prototype._addToParent = function (node) {
|
|
var parent = this._getParentElement();
|
|
if (parent != null) {
|
|
parent.children.push(node);
|
|
}
|
|
else {
|
|
this.rootNodes.push(node);
|
|
}
|
|
};
|
|
_TreeBuilder.prototype._getElementFullName = function (prefix, localName, parentElement) {
|
|
if (prefix === '') {
|
|
prefix = this.getTagDefinition(localName).implicitNamespacePrefix || '';
|
|
if (prefix === '' && parentElement != null) {
|
|
var parentTagName = splitNsName(parentElement.name)[1];
|
|
var parentTagDefinition = this.getTagDefinition(parentTagName);
|
|
if (!parentTagDefinition.preventNamespaceInheritance) {
|
|
prefix = getNsPrefix(parentElement.name);
|
|
}
|
|
}
|
|
}
|
|
return mergeNsAndName(prefix, localName);
|
|
};
|
|
return _TreeBuilder;
|
|
}());
|
|
function lastOnStack(stack, element) {
|
|
return stack.length > 0 && stack[stack.length - 1] === element;
|
|
}
|
|
/**
|
|
* Decode the `entity` string, which we believe is the contents of an HTML entity.
|
|
*
|
|
* If the string is not actually a valid/known entity then just return the original `match` string.
|
|
*/
|
|
function decodeEntity(match, entity) {
|
|
if (NAMED_ENTITIES[entity] !== undefined) {
|
|
return NAMED_ENTITIES[entity] || match;
|
|
}
|
|
if (/^#x[a-f0-9]+$/i.test(entity)) {
|
|
return String.fromCodePoint(parseInt(entity.slice(2), 16));
|
|
}
|
|
if (/^#\d+$/.test(entity)) {
|
|
return String.fromCodePoint(parseInt(entity.slice(1), 10));
|
|
}
|
|
return match;
|
|
}
|
|
|
|
var HtmlParser = /** @class */ (function (_super) {
|
|
__extends(HtmlParser, _super);
|
|
function HtmlParser() {
|
|
return _super.call(this, getHtmlTagDefinition) || this;
|
|
}
|
|
HtmlParser.prototype.parse = function (source, url, options) {
|
|
return _super.prototype.parse.call(this, source, url, options);
|
|
};
|
|
return HtmlParser;
|
|
}(Parser));
|
|
|
|
/**
|
|
* @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 PRESERVE_WS_ATTR_NAME = 'ngPreserveWhitespaces';
|
|
var SKIP_WS_TRIM_TAGS = new Set(['pre', 'template', 'textarea', 'script', 'style']);
|
|
// Equivalent to \s with \u00a0 (non-breaking space) excluded.
|
|
// Based on https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp
|
|
var WS_CHARS = ' \f\n\r\t\v\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff';
|
|
var NO_WS_REGEXP = new RegExp("[^" + WS_CHARS + "]");
|
|
var WS_REPLACE_REGEXP = new RegExp("[" + WS_CHARS + "]{2,}", 'g');
|
|
function hasPreserveWhitespacesAttr(attrs) {
|
|
return attrs.some(function (attr) { return attr.name === PRESERVE_WS_ATTR_NAME; });
|
|
}
|
|
/**
|
|
* Angular Dart introduced &ngsp; as a placeholder for non-removable space, see:
|
|
* https://github.com/dart-lang/angular/blob/0bb611387d29d65b5af7f9d2515ab571fd3fbee4/_tests/test/compiler/preserve_whitespace_test.dart#L25-L32
|
|
* In Angular Dart &ngsp; is converted to the 0xE500 PUA (Private Use Areas) unicode character
|
|
* and later on replaced by a space. We are re-implementing the same idea here.
|
|
*/
|
|
function replaceNgsp(value) {
|
|
// lexer is replacing the &ngsp; pseudo-entity with NGSP_UNICODE
|
|
return value.replace(new RegExp(NGSP_UNICODE, 'g'), ' ');
|
|
}
|
|
/**
|
|
* This visitor can walk HTML parse tree and remove / trim text nodes using the following rules:
|
|
* - consider spaces, tabs and new lines as whitespace characters;
|
|
* - drop text nodes consisting of whitespace characters only;
|
|
* - for all other text nodes replace consecutive whitespace characters with one space;
|
|
* - convert &ngsp; pseudo-entity to a single space;
|
|
*
|
|
* Removal and trimming of whitespaces have positive performance impact (less code to generate
|
|
* while compiling templates, faster view creation). At the same time it can be "destructive"
|
|
* in some cases (whitespaces can influence layout). Because of the potential of breaking layout
|
|
* this visitor is not activated by default in Angular 5 and people need to explicitly opt-in for
|
|
* whitespace removal. The default option for whitespace removal will be revisited in Angular 6
|
|
* and might be changed to "on" by default.
|
|
*/
|
|
var WhitespaceVisitor = /** @class */ (function () {
|
|
function WhitespaceVisitor() {
|
|
}
|
|
WhitespaceVisitor.prototype.visitElement = function (element, context) {
|
|
if (SKIP_WS_TRIM_TAGS.has(element.name) || hasPreserveWhitespacesAttr(element.attrs)) {
|
|
// don't descent into elements where we need to preserve whitespaces
|
|
// but still visit all attributes to eliminate one used as a market to preserve WS
|
|
return new Element$1(element.name, visitAll$1(this, element.attrs), element.children, element.sourceSpan, element.startSourceSpan, element.endSourceSpan, element.i18n);
|
|
}
|
|
return new Element$1(element.name, element.attrs, visitAllWithSiblings(this, element.children), element.sourceSpan, element.startSourceSpan, element.endSourceSpan, element.i18n);
|
|
};
|
|
WhitespaceVisitor.prototype.visitAttribute = function (attribute, context) {
|
|
return attribute.name !== PRESERVE_WS_ATTR_NAME ? attribute : null;
|
|
};
|
|
WhitespaceVisitor.prototype.visitText = function (text, context) {
|
|
var isNotBlank = text.value.match(NO_WS_REGEXP);
|
|
var hasExpansionSibling = context &&
|
|
(context.prev instanceof Expansion || context.next instanceof Expansion);
|
|
if (isNotBlank || hasExpansionSibling) {
|
|
// Process the whitespace in the tokens of this Text node
|
|
var tokens = text.tokens.map(function (token) { return token.type === 5 /* TEXT */ ? createWhitespaceProcessedTextToken(token) : token; });
|
|
// Process the whitespace of the value of this Text node
|
|
var value = processWhitespace(text.value);
|
|
return new Text$3(value, text.sourceSpan, tokens, text.i18n);
|
|
}
|
|
return null;
|
|
};
|
|
WhitespaceVisitor.prototype.visitComment = function (comment, context) {
|
|
return comment;
|
|
};
|
|
WhitespaceVisitor.prototype.visitExpansion = function (expansion, context) {
|
|
return expansion;
|
|
};
|
|
WhitespaceVisitor.prototype.visitExpansionCase = function (expansionCase, context) {
|
|
return expansionCase;
|
|
};
|
|
return WhitespaceVisitor;
|
|
}());
|
|
function createWhitespaceProcessedTextToken(_a) {
|
|
var type = _a.type, parts = _a.parts, sourceSpan = _a.sourceSpan;
|
|
return { type: type, parts: [processWhitespace(parts[0])], sourceSpan: sourceSpan };
|
|
}
|
|
function processWhitespace(text) {
|
|
return replaceNgsp(text).replace(WS_REPLACE_REGEXP, ' ');
|
|
}
|
|
function removeWhitespaces(htmlAstWithErrors) {
|
|
return new ParseTreeResult(visitAll$1(new WhitespaceVisitor(), htmlAstWithErrors.rootNodes), htmlAstWithErrors.errors);
|
|
}
|
|
function visitAllWithSiblings(visitor, nodes) {
|
|
var result = [];
|
|
nodes.forEach(function (ast, i) {
|
|
var context = { prev: nodes[i - 1], next: nodes[i + 1] };
|
|
var astResult = ast.visit(visitor, context);
|
|
if (astResult) {
|
|
result.push(astResult);
|
|
}
|
|
});
|
|
return result;
|
|
}
|
|
|
|
// http://cldr.unicode.org/index/cldr-spec/plural-rules
|
|
var PLURAL_CASES = ['zero', 'one', 'two', 'few', 'many', 'other'];
|
|
/**
|
|
* Expands special forms into elements.
|
|
*
|
|
* For example,
|
|
*
|
|
* ```
|
|
* { messages.length, plural,
|
|
* =0 {zero}
|
|
* =1 {one}
|
|
* other {more than one}
|
|
* }
|
|
* ```
|
|
*
|
|
* will be expanded into
|
|
*
|
|
* ```
|
|
* <ng-container [ngPlural]="messages.length">
|
|
* <ng-template ngPluralCase="=0">zero</ng-template>
|
|
* <ng-template ngPluralCase="=1">one</ng-template>
|
|
* <ng-template ngPluralCase="other">more than one</ng-template>
|
|
* </ng-container>
|
|
* ```
|
|
*/
|
|
function expandNodes(nodes) {
|
|
var expander = new _Expander();
|
|
return new ExpansionResult(visitAll$1(expander, nodes), expander.isExpanded, expander.errors);
|
|
}
|
|
var ExpansionResult = /** @class */ (function () {
|
|
function ExpansionResult(nodes, expanded, errors) {
|
|
this.nodes = nodes;
|
|
this.expanded = expanded;
|
|
this.errors = errors;
|
|
}
|
|
return ExpansionResult;
|
|
}());
|
|
var ExpansionError = /** @class */ (function (_super) {
|
|
__extends(ExpansionError, _super);
|
|
function ExpansionError(span, errorMsg) {
|
|
return _super.call(this, span, errorMsg) || this;
|
|
}
|
|
return ExpansionError;
|
|
}(ParseError));
|
|
/**
|
|
* Expand expansion forms (plural, select) to directives
|
|
*
|
|
* @internal
|
|
*/
|
|
var _Expander = /** @class */ (function () {
|
|
function _Expander() {
|
|
this.isExpanded = false;
|
|
this.errors = [];
|
|
}
|
|
_Expander.prototype.visitElement = function (element, context) {
|
|
return new Element$1(element.name, element.attrs, visitAll$1(this, element.children), element.sourceSpan, element.startSourceSpan, element.endSourceSpan);
|
|
};
|
|
_Expander.prototype.visitAttribute = function (attribute, context) {
|
|
return attribute;
|
|
};
|
|
_Expander.prototype.visitText = function (text, context) {
|
|
return text;
|
|
};
|
|
_Expander.prototype.visitComment = function (comment, context) {
|
|
return comment;
|
|
};
|
|
_Expander.prototype.visitExpansion = function (icu, context) {
|
|
this.isExpanded = true;
|
|
return icu.type === 'plural' ? _expandPluralForm(icu, this.errors) :
|
|
_expandDefaultForm(icu, this.errors);
|
|
};
|
|
_Expander.prototype.visitExpansionCase = function (icuCase, context) {
|
|
throw new Error('Should not be reached');
|
|
};
|
|
return _Expander;
|
|
}());
|
|
// Plural forms are expanded to `NgPlural` and `NgPluralCase`s
|
|
function _expandPluralForm(ast, errors) {
|
|
var children = ast.cases.map(function (c) {
|
|
if (PLURAL_CASES.indexOf(c.value) === -1 && !c.value.match(/^=\d+$/)) {
|
|
errors.push(new ExpansionError(c.valueSourceSpan, "Plural cases should be \"=<number>\" or one of " + PLURAL_CASES.join(', ')));
|
|
}
|
|
var expansionResult = expandNodes(c.expression);
|
|
errors.push.apply(errors, __spreadArray([], __read(expansionResult.errors)));
|
|
return new Element$1("ng-template", [new Attribute('ngPluralCase', "" + c.value, c.valueSourceSpan, undefined /* keySpan */, undefined /* valueSpan */, undefined /* valueTokens */, undefined /* i18n */)], expansionResult.nodes, c.sourceSpan, c.sourceSpan, c.sourceSpan);
|
|
});
|
|
var switchAttr = new Attribute('[ngPlural]', ast.switchValue, ast.switchValueSourceSpan, undefined /* keySpan */, undefined /* valueSpan */, undefined /* valueTokens */, undefined /* i18n */);
|
|
return new Element$1('ng-container', [switchAttr], children, ast.sourceSpan, ast.sourceSpan, ast.sourceSpan);
|
|
}
|
|
// ICU messages (excluding plural form) are expanded to `NgSwitch` and `NgSwitchCase`s
|
|
function _expandDefaultForm(ast, errors) {
|
|
var children = ast.cases.map(function (c) {
|
|
var expansionResult = expandNodes(c.expression);
|
|
errors.push.apply(errors, __spreadArray([], __read(expansionResult.errors)));
|
|
if (c.value === 'other') {
|
|
// other is the default case when no values match
|
|
return new Element$1("ng-template", [new Attribute('ngSwitchDefault', '', c.valueSourceSpan, undefined /* keySpan */, undefined /* valueSpan */, undefined /* valueTokens */, undefined /* i18n */)], expansionResult.nodes, c.sourceSpan, c.sourceSpan, c.sourceSpan);
|
|
}
|
|
return new Element$1("ng-template", [new Attribute('ngSwitchCase', "" + c.value, c.valueSourceSpan, undefined /* keySpan */, undefined /* valueSpan */, undefined /* valueTokens */, undefined /* i18n */)], expansionResult.nodes, c.sourceSpan, c.sourceSpan, c.sourceSpan);
|
|
});
|
|
var switchAttr = new Attribute('[ngSwitch]', ast.switchValue, ast.switchValueSourceSpan, undefined /* keySpan */, undefined /* valueSpan */, undefined /* valueTokens */, undefined /* i18n */);
|
|
return new Element$1('ng-container', [switchAttr], children, ast.sourceSpan, ast.sourceSpan, ast.sourceSpan);
|
|
}
|
|
|
|
var _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 segment of text within the template.
|
|
*/
|
|
var TextAst = /** @class */ (function () {
|
|
function TextAst(value, ngContentIndex, sourceSpan) {
|
|
this.value = value;
|
|
this.ngContentIndex = ngContentIndex;
|
|
this.sourceSpan = sourceSpan;
|
|
}
|
|
TextAst.prototype.visit = function (visitor, context) {
|
|
return visitor.visitText(this, context);
|
|
};
|
|
return TextAst;
|
|
}());
|
|
/**
|
|
* A bound expression within the text of a template.
|
|
*/
|
|
var BoundTextAst = /** @class */ (function () {
|
|
function BoundTextAst(value, ngContentIndex, sourceSpan) {
|
|
this.value = value;
|
|
this.ngContentIndex = ngContentIndex;
|
|
this.sourceSpan = sourceSpan;
|
|
}
|
|
BoundTextAst.prototype.visit = function (visitor, context) {
|
|
return visitor.visitBoundText(this, context);
|
|
};
|
|
return BoundTextAst;
|
|
}());
|
|
/**
|
|
* A plain attribute on an element.
|
|
*/
|
|
var AttrAst = /** @class */ (function () {
|
|
function AttrAst(name, value, sourceSpan) {
|
|
this.name = name;
|
|
this.value = value;
|
|
this.sourceSpan = sourceSpan;
|
|
}
|
|
AttrAst.prototype.visit = function (visitor, context) {
|
|
return visitor.visitAttr(this, context);
|
|
};
|
|
return AttrAst;
|
|
}());
|
|
var BoundPropertyMapping = (_a = {},
|
|
_a[4 /* Animation */] = 4 /* Animation */,
|
|
_a[1 /* Attribute */] = 1 /* Attribute */,
|
|
_a[2 /* Class */] = 2 /* Class */,
|
|
_a[0 /* Property */] = 0 /* Property */,
|
|
_a[3 /* Style */] = 3 /* Style */,
|
|
_a);
|
|
/**
|
|
* A binding for an element property (e.g. `[property]="expression"`) or an animation trigger (e.g.
|
|
* `[@trigger]="stateExp"`)
|
|
*/
|
|
var BoundElementPropertyAst = /** @class */ (function () {
|
|
function BoundElementPropertyAst(name, type, securityContext, value, unit, sourceSpan) {
|
|
this.name = name;
|
|
this.type = type;
|
|
this.securityContext = securityContext;
|
|
this.value = value;
|
|
this.unit = unit;
|
|
this.sourceSpan = sourceSpan;
|
|
this.isAnimation = this.type === 4 /* Animation */;
|
|
}
|
|
BoundElementPropertyAst.fromBoundProperty = function (prop) {
|
|
var type = BoundPropertyMapping[prop.type];
|
|
return new BoundElementPropertyAst(prop.name, type, prop.securityContext, prop.value, prop.unit, prop.sourceSpan);
|
|
};
|
|
BoundElementPropertyAst.prototype.visit = function (visitor, context) {
|
|
return visitor.visitElementProperty(this, context);
|
|
};
|
|
return BoundElementPropertyAst;
|
|
}());
|
|
/**
|
|
* A binding for an element event (e.g. `(event)="handler()"`) or an animation trigger event (e.g.
|
|
* `(@trigger.phase)="callback($event)"`).
|
|
*/
|
|
var BoundEventAst = /** @class */ (function () {
|
|
function BoundEventAst(name, target, phase, handler, sourceSpan, handlerSpan) {
|
|
this.name = name;
|
|
this.target = target;
|
|
this.phase = phase;
|
|
this.handler = handler;
|
|
this.sourceSpan = sourceSpan;
|
|
this.handlerSpan = handlerSpan;
|
|
this.fullName = BoundEventAst.calcFullName(this.name, this.target, this.phase);
|
|
this.isAnimation = !!this.phase;
|
|
}
|
|
BoundEventAst.calcFullName = function (name, target, phase) {
|
|
if (target) {
|
|
return target + ":" + name;
|
|
}
|
|
if (phase) {
|
|
return "@" + name + "." + phase;
|
|
}
|
|
return name;
|
|
};
|
|
BoundEventAst.fromParsedEvent = function (event) {
|
|
var target = event.type === 0 /* Regular */ ? event.targetOrPhase : null;
|
|
var phase = event.type === 1 /* Animation */ ? event.targetOrPhase : null;
|
|
return new BoundEventAst(event.name, target, phase, event.handler, event.sourceSpan, event.handlerSpan);
|
|
};
|
|
BoundEventAst.prototype.visit = function (visitor, context) {
|
|
return visitor.visitEvent(this, context);
|
|
};
|
|
return BoundEventAst;
|
|
}());
|
|
/**
|
|
* A reference declaration on an element (e.g. `let someName="expression"`).
|
|
*/
|
|
var ReferenceAst = /** @class */ (function () {
|
|
function ReferenceAst(name, value, originalValue, sourceSpan) {
|
|
this.name = name;
|
|
this.value = value;
|
|
this.originalValue = originalValue;
|
|
this.sourceSpan = sourceSpan;
|
|
}
|
|
ReferenceAst.prototype.visit = function (visitor, context) {
|
|
return visitor.visitReference(this, context);
|
|
};
|
|
return ReferenceAst;
|
|
}());
|
|
/**
|
|
* A variable declaration on a <ng-template> (e.g. `var-someName="someLocalName"`).
|
|
*/
|
|
var VariableAst = /** @class */ (function () {
|
|
function VariableAst(name, value, sourceSpan, valueSpan) {
|
|
this.name = name;
|
|
this.value = value;
|
|
this.sourceSpan = sourceSpan;
|
|
this.valueSpan = valueSpan;
|
|
}
|
|
VariableAst.fromParsedVariable = function (v) {
|
|
return new VariableAst(v.name, v.value, v.sourceSpan, v.valueSpan);
|
|
};
|
|
VariableAst.prototype.visit = function (visitor, context) {
|
|
return visitor.visitVariable(this, context);
|
|
};
|
|
return VariableAst;
|
|
}());
|
|
/**
|
|
* An element declaration in a template.
|
|
*/
|
|
var ElementAst = /** @class */ (function () {
|
|
function ElementAst(name, attrs, inputs, outputs, references, directives, providers, hasViewContainer, queryMatches, children, ngContentIndex, sourceSpan, endSourceSpan) {
|
|
this.name = name;
|
|
this.attrs = attrs;
|
|
this.inputs = inputs;
|
|
this.outputs = outputs;
|
|
this.references = references;
|
|
this.directives = directives;
|
|
this.providers = providers;
|
|
this.hasViewContainer = hasViewContainer;
|
|
this.queryMatches = queryMatches;
|
|
this.children = children;
|
|
this.ngContentIndex = ngContentIndex;
|
|
this.sourceSpan = sourceSpan;
|
|
this.endSourceSpan = endSourceSpan;
|
|
}
|
|
ElementAst.prototype.visit = function (visitor, context) {
|
|
return visitor.visitElement(this, context);
|
|
};
|
|
return ElementAst;
|
|
}());
|
|
/**
|
|
* A `<ng-template>` element included in an Angular template.
|
|
*/
|
|
var EmbeddedTemplateAst = /** @class */ (function () {
|
|
function EmbeddedTemplateAst(attrs, outputs, references, variables, directives, providers, hasViewContainer, queryMatches, children, ngContentIndex, sourceSpan) {
|
|
this.attrs = attrs;
|
|
this.outputs = outputs;
|
|
this.references = references;
|
|
this.variables = variables;
|
|
this.directives = directives;
|
|
this.providers = providers;
|
|
this.hasViewContainer = hasViewContainer;
|
|
this.queryMatches = queryMatches;
|
|
this.children = children;
|
|
this.ngContentIndex = ngContentIndex;
|
|
this.sourceSpan = sourceSpan;
|
|
}
|
|
EmbeddedTemplateAst.prototype.visit = function (visitor, context) {
|
|
return visitor.visitEmbeddedTemplate(this, context);
|
|
};
|
|
return EmbeddedTemplateAst;
|
|
}());
|
|
/**
|
|
* A directive property with a bound value (e.g. `*ngIf="condition").
|
|
*/
|
|
var BoundDirectivePropertyAst = /** @class */ (function () {
|
|
function BoundDirectivePropertyAst(directiveName, templateName, value, sourceSpan) {
|
|
this.directiveName = directiveName;
|
|
this.templateName = templateName;
|
|
this.value = value;
|
|
this.sourceSpan = sourceSpan;
|
|
}
|
|
BoundDirectivePropertyAst.prototype.visit = function (visitor, context) {
|
|
return visitor.visitDirectiveProperty(this, context);
|
|
};
|
|
return BoundDirectivePropertyAst;
|
|
}());
|
|
/**
|
|
* A directive declared on an element.
|
|
*/
|
|
var DirectiveAst = /** @class */ (function () {
|
|
function DirectiveAst(directive, inputs, hostProperties, hostEvents, contentQueryStartId, sourceSpan) {
|
|
this.directive = directive;
|
|
this.inputs = inputs;
|
|
this.hostProperties = hostProperties;
|
|
this.hostEvents = hostEvents;
|
|
this.contentQueryStartId = contentQueryStartId;
|
|
this.sourceSpan = sourceSpan;
|
|
}
|
|
DirectiveAst.prototype.visit = function (visitor, context) {
|
|
return visitor.visitDirective(this, context);
|
|
};
|
|
return DirectiveAst;
|
|
}());
|
|
/**
|
|
* A provider declared on an element
|
|
*/
|
|
var ProviderAst = /** @class */ (function () {
|
|
function ProviderAst(token, multiProvider, eager, providers, providerType, lifecycleHooks, sourceSpan, isModule) {
|
|
this.token = token;
|
|
this.multiProvider = multiProvider;
|
|
this.eager = eager;
|
|
this.providers = providers;
|
|
this.providerType = providerType;
|
|
this.lifecycleHooks = lifecycleHooks;
|
|
this.sourceSpan = sourceSpan;
|
|
this.isModule = isModule;
|
|
}
|
|
ProviderAst.prototype.visit = function (visitor, context) {
|
|
// No visit method in the visitor for now...
|
|
return null;
|
|
};
|
|
return ProviderAst;
|
|
}());
|
|
(function (ProviderAstType) {
|
|
ProviderAstType[ProviderAstType["PublicService"] = 0] = "PublicService";
|
|
ProviderAstType[ProviderAstType["PrivateService"] = 1] = "PrivateService";
|
|
ProviderAstType[ProviderAstType["Component"] = 2] = "Component";
|
|
ProviderAstType[ProviderAstType["Directive"] = 3] = "Directive";
|
|
ProviderAstType[ProviderAstType["Builtin"] = 4] = "Builtin";
|
|
})(exports.ProviderAstType || (exports.ProviderAstType = {}));
|
|
/**
|
|
* Position where content is to be projected (instance of `<ng-content>` in a template).
|
|
*/
|
|
var NgContentAst = /** @class */ (function () {
|
|
function NgContentAst(index, ngContentIndex, sourceSpan) {
|
|
this.index = index;
|
|
this.ngContentIndex = ngContentIndex;
|
|
this.sourceSpan = sourceSpan;
|
|
}
|
|
NgContentAst.prototype.visit = function (visitor, context) {
|
|
return visitor.visitNgContent(this, context);
|
|
};
|
|
return NgContentAst;
|
|
}());
|
|
/**
|
|
* A visitor that accepts each node but doesn't do anything. It is intended to be used
|
|
* as the base class for a visitor that is only interested in a subset of the node types.
|
|
*/
|
|
var NullTemplateVisitor = /** @class */ (function () {
|
|
function NullTemplateVisitor() {
|
|
}
|
|
NullTemplateVisitor.prototype.visitNgContent = function (ast, context) { };
|
|
NullTemplateVisitor.prototype.visitEmbeddedTemplate = function (ast, context) { };
|
|
NullTemplateVisitor.prototype.visitElement = function (ast, context) { };
|
|
NullTemplateVisitor.prototype.visitReference = function (ast, context) { };
|
|
NullTemplateVisitor.prototype.visitVariable = function (ast, context) { };
|
|
NullTemplateVisitor.prototype.visitEvent = function (ast, context) { };
|
|
NullTemplateVisitor.prototype.visitElementProperty = function (ast, context) { };
|
|
NullTemplateVisitor.prototype.visitAttr = function (ast, context) { };
|
|
NullTemplateVisitor.prototype.visitBoundText = function (ast, context) { };
|
|
NullTemplateVisitor.prototype.visitText = function (ast, context) { };
|
|
NullTemplateVisitor.prototype.visitDirective = function (ast, context) { };
|
|
NullTemplateVisitor.prototype.visitDirectiveProperty = function (ast, context) { };
|
|
return NullTemplateVisitor;
|
|
}());
|
|
/**
|
|
* Base class that can be used to build a visitor that visits each node
|
|
* in an template ast recursively.
|
|
*/
|
|
var RecursiveTemplateAstVisitor = /** @class */ (function (_super) {
|
|
__extends(RecursiveTemplateAstVisitor, _super);
|
|
function RecursiveTemplateAstVisitor() {
|
|
return _super.call(this) || this;
|
|
}
|
|
// Nodes with children
|
|
RecursiveTemplateAstVisitor.prototype.visitEmbeddedTemplate = function (ast, context) {
|
|
return this.visitChildren(context, function (visit) {
|
|
visit(ast.attrs);
|
|
visit(ast.references);
|
|
visit(ast.variables);
|
|
visit(ast.directives);
|
|
visit(ast.providers);
|
|
visit(ast.children);
|
|
});
|
|
};
|
|
RecursiveTemplateAstVisitor.prototype.visitElement = function (ast, context) {
|
|
return this.visitChildren(context, function (visit) {
|
|
visit(ast.attrs);
|
|
visit(ast.inputs);
|
|
visit(ast.outputs);
|
|
visit(ast.references);
|
|
visit(ast.directives);
|
|
visit(ast.providers);
|
|
visit(ast.children);
|
|
});
|
|
};
|
|
RecursiveTemplateAstVisitor.prototype.visitDirective = function (ast, context) {
|
|
return this.visitChildren(context, function (visit) {
|
|
visit(ast.inputs);
|
|
visit(ast.hostProperties);
|
|
visit(ast.hostEvents);
|
|
});
|
|
};
|
|
RecursiveTemplateAstVisitor.prototype.visitChildren = function (context, cb) {
|
|
var results = [];
|
|
var t = this;
|
|
function visit(children) {
|
|
if (children && children.length)
|
|
results.push(templateVisitAll(t, children, context));
|
|
}
|
|
cb(visit);
|
|
return Array.prototype.concat.apply([], results);
|
|
};
|
|
return RecursiveTemplateAstVisitor;
|
|
}(NullTemplateVisitor));
|
|
/**
|
|
* Visit every node in a list of {@link TemplateAst}s with the given {@link TemplateAstVisitor}.
|
|
*/
|
|
function templateVisitAll(visitor, asts, context) {
|
|
if (context === void 0) { context = null; }
|
|
var result = [];
|
|
var visit = visitor.visit ?
|
|
function (ast) { return visitor.visit(ast, context) || ast.visit(visitor, context); } :
|
|
function (ast) { return ast.visit(visitor, context); };
|
|
asts.forEach(function (ast) {
|
|
var astResult = visit(ast);
|
|
if (astResult) {
|
|
result.push(astResult);
|
|
}
|
|
});
|
|
return result;
|
|
}
|
|
|
|
var ProviderError = /** @class */ (function (_super) {
|
|
__extends(ProviderError, _super);
|
|
function ProviderError(message, span) {
|
|
return _super.call(this, span, message) || this;
|
|
}
|
|
return ProviderError;
|
|
}(ParseError));
|
|
var ProviderViewContext = /** @class */ (function () {
|
|
function ProviderViewContext(reflector, component) {
|
|
var _this = this;
|
|
this.reflector = reflector;
|
|
this.component = component;
|
|
this.errors = [];
|
|
this.viewQueries = _getViewQueries(component);
|
|
this.viewProviders = new Map();
|
|
component.viewProviders.forEach(function (provider) {
|
|
if (_this.viewProviders.get(tokenReference(provider.token)) == null) {
|
|
_this.viewProviders.set(tokenReference(provider.token), true);
|
|
}
|
|
});
|
|
}
|
|
return ProviderViewContext;
|
|
}());
|
|
var ProviderElementContext = /** @class */ (function () {
|
|
function ProviderElementContext(viewContext, _parent, _isViewRoot, _directiveAsts, attrs, refs, isTemplate, contentQueryStartId, _sourceSpan) {
|
|
var _this = this;
|
|
this.viewContext = viewContext;
|
|
this._parent = _parent;
|
|
this._isViewRoot = _isViewRoot;
|
|
this._directiveAsts = _directiveAsts;
|
|
this._sourceSpan = _sourceSpan;
|
|
this._transformedProviders = new Map();
|
|
this._seenProviders = new Map();
|
|
this._queriedTokens = new Map();
|
|
this.transformedHasViewContainer = false;
|
|
this._attrs = {};
|
|
attrs.forEach(function (attrAst) { return _this._attrs[attrAst.name] = attrAst.value; });
|
|
var directivesMeta = _directiveAsts.map(function (directiveAst) { return directiveAst.directive; });
|
|
this._allProviders =
|
|
_resolveProvidersFromDirectives(directivesMeta, _sourceSpan, viewContext.errors);
|
|
this._contentQueries = _getContentQueries(contentQueryStartId, directivesMeta);
|
|
Array.from(this._allProviders.values()).forEach(function (provider) {
|
|
_this._addQueryReadsTo(provider.token, provider.token, _this._queriedTokens);
|
|
});
|
|
if (isTemplate) {
|
|
var templateRefId = createTokenForExternalReference(this.viewContext.reflector, Identifiers$1.TemplateRef);
|
|
this._addQueryReadsTo(templateRefId, templateRefId, this._queriedTokens);
|
|
}
|
|
refs.forEach(function (refAst) {
|
|
var defaultQueryValue = refAst.value ||
|
|
createTokenForExternalReference(_this.viewContext.reflector, Identifiers$1.ElementRef);
|
|
_this._addQueryReadsTo({ value: refAst.name }, defaultQueryValue, _this._queriedTokens);
|
|
});
|
|
if (this._queriedTokens.get(this.viewContext.reflector.resolveExternalReference(Identifiers$1.ViewContainerRef))) {
|
|
this.transformedHasViewContainer = true;
|
|
}
|
|
// create the providers that we know are eager first
|
|
Array.from(this._allProviders.values()).forEach(function (provider) {
|
|
var eager = provider.eager || _this._queriedTokens.get(tokenReference(provider.token));
|
|
if (eager) {
|
|
_this._getOrCreateLocalProvider(provider.providerType, provider.token, true);
|
|
}
|
|
});
|
|
}
|
|
ProviderElementContext.prototype.afterElement = function () {
|
|
var _this = this;
|
|
// collect lazy providers
|
|
Array.from(this._allProviders.values()).forEach(function (provider) {
|
|
_this._getOrCreateLocalProvider(provider.providerType, provider.token, false);
|
|
});
|
|
};
|
|
Object.defineProperty(ProviderElementContext.prototype, "transformProviders", {
|
|
get: function () {
|
|
// Note: Maps keep their insertion order.
|
|
var lazyProviders = [];
|
|
var eagerProviders = [];
|
|
this._transformedProviders.forEach(function (provider) {
|
|
if (provider.eager) {
|
|
eagerProviders.push(provider);
|
|
}
|
|
else {
|
|
lazyProviders.push(provider);
|
|
}
|
|
});
|
|
return lazyProviders.concat(eagerProviders);
|
|
},
|
|
enumerable: false,
|
|
configurable: true
|
|
});
|
|
Object.defineProperty(ProviderElementContext.prototype, "transformedDirectiveAsts", {
|
|
get: function () {
|
|
var sortedProviderTypes = this.transformProviders.map(function (provider) { return provider.token.identifier; });
|
|
var sortedDirectives = this._directiveAsts.slice();
|
|
sortedDirectives.sort(function (dir1, dir2) { return sortedProviderTypes.indexOf(dir1.directive.type) -
|
|
sortedProviderTypes.indexOf(dir2.directive.type); });
|
|
return sortedDirectives;
|
|
},
|
|
enumerable: false,
|
|
configurable: true
|
|
});
|
|
Object.defineProperty(ProviderElementContext.prototype, "queryMatches", {
|
|
get: function () {
|
|
var allMatches = [];
|
|
this._queriedTokens.forEach(function (matches) {
|
|
allMatches.push.apply(allMatches, __spreadArray([], __read(matches)));
|
|
});
|
|
return allMatches;
|
|
},
|
|
enumerable: false,
|
|
configurable: true
|
|
});
|
|
ProviderElementContext.prototype._addQueryReadsTo = function (token, defaultValue, queryReadTokens) {
|
|
this._getQueriesFor(token).forEach(function (query) {
|
|
var queryValue = query.meta.read || defaultValue;
|
|
var tokenRef = tokenReference(queryValue);
|
|
var queryMatches = queryReadTokens.get(tokenRef);
|
|
if (!queryMatches) {
|
|
queryMatches = [];
|
|
queryReadTokens.set(tokenRef, queryMatches);
|
|
}
|
|
queryMatches.push({ queryId: query.queryId, value: queryValue });
|
|
});
|
|
};
|
|
ProviderElementContext.prototype._getQueriesFor = function (token) {
|
|
var result = [];
|
|
var currentEl = this;
|
|
var distance = 0;
|
|
var queries;
|
|
while (currentEl !== null) {
|
|
queries = currentEl._contentQueries.get(tokenReference(token));
|
|
if (queries) {
|
|
result.push.apply(result, __spreadArray([], __read(queries.filter(function (query) { return query.meta.descendants || distance <= 1; }))));
|
|
}
|
|
if (currentEl._directiveAsts.length > 0) {
|
|
distance++;
|
|
}
|
|
currentEl = currentEl._parent;
|
|
}
|
|
queries = this.viewContext.viewQueries.get(tokenReference(token));
|
|
if (queries) {
|
|
result.push.apply(result, __spreadArray([], __read(queries)));
|
|
}
|
|
return result;
|
|
};
|
|
ProviderElementContext.prototype._getOrCreateLocalProvider = function (requestingProviderType, token, eager) {
|
|
var _this = this;
|
|
var resolvedProvider = this._allProviders.get(tokenReference(token));
|
|
if (!resolvedProvider ||
|
|
((requestingProviderType === exports.ProviderAstType.Directive ||
|
|
requestingProviderType === exports.ProviderAstType.PublicService) &&
|
|
resolvedProvider.providerType === exports.ProviderAstType.PrivateService) ||
|
|
((requestingProviderType === exports.ProviderAstType.PrivateService ||
|
|
requestingProviderType === exports.ProviderAstType.PublicService) &&
|
|
resolvedProvider.providerType === exports.ProviderAstType.Builtin)) {
|
|
return null;
|
|
}
|
|
var transformedProviderAst = this._transformedProviders.get(tokenReference(token));
|
|
if (transformedProviderAst) {
|
|
return transformedProviderAst;
|
|
}
|
|
if (this._seenProviders.get(tokenReference(token)) != null) {
|
|
this.viewContext.errors.push(new ProviderError("Cannot instantiate cyclic dependency! " + tokenName(token), this._sourceSpan));
|
|
return null;
|
|
}
|
|
this._seenProviders.set(tokenReference(token), true);
|
|
var transformedProviders = resolvedProvider.providers.map(function (provider) {
|
|
var transformedUseValue = provider.useValue;
|
|
var transformedUseExisting = provider.useExisting;
|
|
var transformedDeps = undefined;
|
|
if (provider.useExisting != null) {
|
|
var existingDiDep = _this._getDependency(resolvedProvider.providerType, { token: provider.useExisting }, eager);
|
|
if (existingDiDep.token != null) {
|
|
transformedUseExisting = existingDiDep.token;
|
|
}
|
|
else {
|
|
transformedUseExisting = null;
|
|
transformedUseValue = existingDiDep.value;
|
|
}
|
|
}
|
|
else if (provider.useFactory) {
|
|
var deps = provider.deps || provider.useFactory.diDeps;
|
|
transformedDeps =
|
|
deps.map(function (dep) { return _this._getDependency(resolvedProvider.providerType, dep, eager); });
|
|
}
|
|
else if (provider.useClass) {
|
|
var deps = provider.deps || provider.useClass.diDeps;
|
|
transformedDeps =
|
|
deps.map(function (dep) { return _this._getDependency(resolvedProvider.providerType, dep, eager); });
|
|
}
|
|
return _transformProvider(provider, {
|
|
useExisting: transformedUseExisting,
|
|
useValue: transformedUseValue,
|
|
deps: transformedDeps
|
|
});
|
|
});
|
|
transformedProviderAst =
|
|
_transformProviderAst(resolvedProvider, { eager: eager, providers: transformedProviders });
|
|
this._transformedProviders.set(tokenReference(token), transformedProviderAst);
|
|
return transformedProviderAst;
|
|
};
|
|
ProviderElementContext.prototype._getLocalDependency = function (requestingProviderType, dep, eager) {
|
|
if (eager === void 0) { eager = false; }
|
|
if (dep.isAttribute) {
|
|
var attrValue = this._attrs[dep.token.value];
|
|
return { isValue: true, value: attrValue == null ? null : attrValue };
|
|
}
|
|
if (dep.token != null) {
|
|
// access builtints
|
|
if ((requestingProviderType === exports.ProviderAstType.Directive ||
|
|
requestingProviderType === exports.ProviderAstType.Component)) {
|
|
if (tokenReference(dep.token) ===
|
|
this.viewContext.reflector.resolveExternalReference(Identifiers$1.Renderer) ||
|
|
tokenReference(dep.token) ===
|
|
this.viewContext.reflector.resolveExternalReference(Identifiers$1.ElementRef) ||
|
|
tokenReference(dep.token) ===
|
|
this.viewContext.reflector.resolveExternalReference(Identifiers$1.ChangeDetectorRef) ||
|
|
tokenReference(dep.token) ===
|
|
this.viewContext.reflector.resolveExternalReference(Identifiers$1.TemplateRef)) {
|
|
return dep;
|
|
}
|
|
if (tokenReference(dep.token) ===
|
|
this.viewContext.reflector.resolveExternalReference(Identifiers$1.ViewContainerRef)) {
|
|
this.transformedHasViewContainer = true;
|
|
}
|
|
}
|
|
// access the injector
|
|
if (tokenReference(dep.token) ===
|
|
this.viewContext.reflector.resolveExternalReference(Identifiers$1.Injector)) {
|
|
return dep;
|
|
}
|
|
// access providers
|
|
if (this._getOrCreateLocalProvider(requestingProviderType, dep.token, eager) != null) {
|
|
return dep;
|
|
}
|
|
}
|
|
return null;
|
|
};
|
|
ProviderElementContext.prototype._getDependency = function (requestingProviderType, dep, eager) {
|
|
if (eager === void 0) { eager = false; }
|
|
var currElement = this;
|
|
var currEager = eager;
|
|
var result = null;
|
|
if (!dep.isSkipSelf) {
|
|
result = this._getLocalDependency(requestingProviderType, dep, eager);
|
|
}
|
|
if (dep.isSelf) {
|
|
if (!result && dep.isOptional) {
|
|
result = { isValue: true, value: null };
|
|
}
|
|
}
|
|
else {
|
|
// check parent elements
|
|
while (!result && currElement._parent) {
|
|
var prevElement = currElement;
|
|
currElement = currElement._parent;
|
|
if (prevElement._isViewRoot) {
|
|
currEager = false;
|
|
}
|
|
result = currElement._getLocalDependency(exports.ProviderAstType.PublicService, dep, currEager);
|
|
}
|
|
// check @Host restriction
|
|
if (!result) {
|
|
if (!dep.isHost || this.viewContext.component.isHost ||
|
|
this.viewContext.component.type.reference === tokenReference(dep.token) ||
|
|
this.viewContext.viewProviders.get(tokenReference(dep.token)) != null) {
|
|
result = dep;
|
|
}
|
|
else {
|
|
result = dep.isOptional ? { isValue: true, value: null } : null;
|
|
}
|
|
}
|
|
}
|
|
if (!result) {
|
|
this.viewContext.errors.push(new ProviderError("No provider for " + tokenName(dep.token), this._sourceSpan));
|
|
}
|
|
return result;
|
|
};
|
|
return ProviderElementContext;
|
|
}());
|
|
var NgModuleProviderAnalyzer = /** @class */ (function () {
|
|
function NgModuleProviderAnalyzer(reflector, ngModule, extraProviders, sourceSpan) {
|
|
var _this = this;
|
|
this.reflector = reflector;
|
|
this._transformedProviders = new Map();
|
|
this._seenProviders = new Map();
|
|
this._errors = [];
|
|
this._allProviders = new Map();
|
|
ngModule.transitiveModule.modules.forEach(function (ngModuleType) {
|
|
var ngModuleProvider = { token: { identifier: ngModuleType }, useClass: ngModuleType };
|
|
_resolveProviders([ngModuleProvider], exports.ProviderAstType.PublicService, true, sourceSpan, _this._errors, _this._allProviders, /* isModule */ true);
|
|
});
|
|
_resolveProviders(ngModule.transitiveModule.providers.map(function (entry) { return entry.provider; }).concat(extraProviders), exports.ProviderAstType.PublicService, false, sourceSpan, this._errors, this._allProviders,
|
|
/* isModule */ false);
|
|
}
|
|
NgModuleProviderAnalyzer.prototype.parse = function () {
|
|
var _this = this;
|
|
Array.from(this._allProviders.values()).forEach(function (provider) {
|
|
_this._getOrCreateLocalProvider(provider.token, provider.eager);
|
|
});
|
|
if (this._errors.length > 0) {
|
|
var errorString = this._errors.join('\n');
|
|
throw new Error("Provider parse errors:\n" + errorString);
|
|
}
|
|
// Note: Maps keep their insertion order.
|
|
var lazyProviders = [];
|
|
var eagerProviders = [];
|
|
this._transformedProviders.forEach(function (provider) {
|
|
if (provider.eager) {
|
|
eagerProviders.push(provider);
|
|
}
|
|
else {
|
|
lazyProviders.push(provider);
|
|
}
|
|
});
|
|
return lazyProviders.concat(eagerProviders);
|
|
};
|
|
NgModuleProviderAnalyzer.prototype._getOrCreateLocalProvider = function (token, eager) {
|
|
var _this = this;
|
|
var resolvedProvider = this._allProviders.get(tokenReference(token));
|
|
if (!resolvedProvider) {
|
|
return null;
|
|
}
|
|
var transformedProviderAst = this._transformedProviders.get(tokenReference(token));
|
|
if (transformedProviderAst) {
|
|
return transformedProviderAst;
|
|
}
|
|
if (this._seenProviders.get(tokenReference(token)) != null) {
|
|
this._errors.push(new ProviderError("Cannot instantiate cyclic dependency! " + tokenName(token), resolvedProvider.sourceSpan));
|
|
return null;
|
|
}
|
|
this._seenProviders.set(tokenReference(token), true);
|
|
var transformedProviders = resolvedProvider.providers.map(function (provider) {
|
|
var transformedUseValue = provider.useValue;
|
|
var transformedUseExisting = provider.useExisting;
|
|
var transformedDeps = undefined;
|
|
if (provider.useExisting != null) {
|
|
var existingDiDep = _this._getDependency({ token: provider.useExisting }, eager, resolvedProvider.sourceSpan);
|
|
if (existingDiDep.token != null) {
|
|
transformedUseExisting = existingDiDep.token;
|
|
}
|
|
else {
|
|
transformedUseExisting = null;
|
|
transformedUseValue = existingDiDep.value;
|
|
}
|
|
}
|
|
else if (provider.useFactory) {
|
|
var deps = provider.deps || provider.useFactory.diDeps;
|
|
transformedDeps =
|
|
deps.map(function (dep) { return _this._getDependency(dep, eager, resolvedProvider.sourceSpan); });
|
|
}
|
|
else if (provider.useClass) {
|
|
var deps = provider.deps || provider.useClass.diDeps;
|
|
transformedDeps =
|
|
deps.map(function (dep) { return _this._getDependency(dep, eager, resolvedProvider.sourceSpan); });
|
|
}
|
|
return _transformProvider(provider, {
|
|
useExisting: transformedUseExisting,
|
|
useValue: transformedUseValue,
|
|
deps: transformedDeps
|
|
});
|
|
});
|
|
transformedProviderAst =
|
|
_transformProviderAst(resolvedProvider, { eager: eager, providers: transformedProviders });
|
|
this._transformedProviders.set(tokenReference(token), transformedProviderAst);
|
|
return transformedProviderAst;
|
|
};
|
|
NgModuleProviderAnalyzer.prototype._getDependency = function (dep, eager, requestorSourceSpan) {
|
|
if (eager === void 0) { eager = false; }
|
|
var foundLocal = false;
|
|
if (!dep.isSkipSelf && dep.token != null) {
|
|
// access the injector
|
|
if (tokenReference(dep.token) ===
|
|
this.reflector.resolveExternalReference(Identifiers$1.Injector) ||
|
|
tokenReference(dep.token) ===
|
|
this.reflector.resolveExternalReference(Identifiers$1.ComponentFactoryResolver)) {
|
|
foundLocal = true;
|
|
// access providers
|
|
}
|
|
else if (this._getOrCreateLocalProvider(dep.token, eager) != null) {
|
|
foundLocal = true;
|
|
}
|
|
}
|
|
return dep;
|
|
};
|
|
return NgModuleProviderAnalyzer;
|
|
}());
|
|
function _transformProvider(provider, _a) {
|
|
var useExisting = _a.useExisting, useValue = _a.useValue, deps = _a.deps;
|
|
return {
|
|
token: provider.token,
|
|
useClass: provider.useClass,
|
|
useExisting: useExisting,
|
|
useFactory: provider.useFactory,
|
|
useValue: useValue,
|
|
deps: deps,
|
|
multi: provider.multi
|
|
};
|
|
}
|
|
function _transformProviderAst(provider, _a) {
|
|
var eager = _a.eager, providers = _a.providers;
|
|
return new ProviderAst(provider.token, provider.multiProvider, provider.eager || eager, providers, provider.providerType, provider.lifecycleHooks, provider.sourceSpan, provider.isModule);
|
|
}
|
|
function _resolveProvidersFromDirectives(directives, sourceSpan, targetErrors) {
|
|
var providersByToken = new Map();
|
|
directives.forEach(function (directive) {
|
|
var dirProvider = { token: { identifier: directive.type }, useClass: directive.type };
|
|
_resolveProviders([dirProvider], directive.isComponent ? exports.ProviderAstType.Component : exports.ProviderAstType.Directive, true, sourceSpan, targetErrors, providersByToken, /* isModule */ false);
|
|
});
|
|
// Note: directives need to be able to overwrite providers of a component!
|
|
var directivesWithComponentFirst = directives.filter(function (dir) { return dir.isComponent; }).concat(directives.filter(function (dir) { return !dir.isComponent; }));
|
|
directivesWithComponentFirst.forEach(function (directive) {
|
|
_resolveProviders(directive.providers, exports.ProviderAstType.PublicService, false, sourceSpan, targetErrors, providersByToken, /* isModule */ false);
|
|
_resolveProviders(directive.viewProviders, exports.ProviderAstType.PrivateService, false, sourceSpan, targetErrors, providersByToken, /* isModule */ false);
|
|
});
|
|
return providersByToken;
|
|
}
|
|
function _resolveProviders(providers, providerType, eager, sourceSpan, targetErrors, targetProvidersByToken, isModule) {
|
|
providers.forEach(function (provider) {
|
|
var resolvedProvider = targetProvidersByToken.get(tokenReference(provider.token));
|
|
if (resolvedProvider != null && !!resolvedProvider.multiProvider !== !!provider.multi) {
|
|
targetErrors.push(new ProviderError("Mixing multi and non multi provider is not possible for token " + tokenName(resolvedProvider.token), sourceSpan));
|
|
}
|
|
if (!resolvedProvider) {
|
|
var lifecycleHooks = provider.token.identifier &&
|
|
provider.token.identifier.lifecycleHooks ?
|
|
provider.token.identifier.lifecycleHooks :
|
|
[];
|
|
var isUseValue = !(provider.useClass || provider.useExisting || provider.useFactory);
|
|
resolvedProvider = new ProviderAst(provider.token, !!provider.multi, eager || isUseValue, [provider], providerType, lifecycleHooks, sourceSpan, isModule);
|
|
targetProvidersByToken.set(tokenReference(provider.token), resolvedProvider);
|
|
}
|
|
else {
|
|
if (!provider.multi) {
|
|
resolvedProvider.providers.length = 0;
|
|
}
|
|
resolvedProvider.providers.push(provider);
|
|
}
|
|
});
|
|
}
|
|
function _getViewQueries(component) {
|
|
// Note: queries start with id 1 so we can use the number in a Bloom filter!
|
|
var viewQueryId = 1;
|
|
var viewQueries = new Map();
|
|
if (component.viewQueries) {
|
|
component.viewQueries.forEach(function (query) { return _addQueryToTokenMap(viewQueries, { meta: query, queryId: viewQueryId++ }); });
|
|
}
|
|
return viewQueries;
|
|
}
|
|
function _getContentQueries(contentQueryStartId, directives) {
|
|
var contentQueryId = contentQueryStartId;
|
|
var contentQueries = new Map();
|
|
directives.forEach(function (directive, directiveIndex) {
|
|
if (directive.queries) {
|
|
directive.queries.forEach(function (query) { return _addQueryToTokenMap(contentQueries, { meta: query, queryId: contentQueryId++ }); });
|
|
}
|
|
});
|
|
return contentQueries;
|
|
}
|
|
function _addQueryToTokenMap(map, query) {
|
|
query.meta.selectors.forEach(function (token) {
|
|
var entry = map.get(tokenReference(token));
|
|
if (!entry) {
|
|
entry = [];
|
|
map.set(tokenReference(token), entry);
|
|
}
|
|
entry.push(query);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* @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 StyleWithImports = /** @class */ (function () {
|
|
function StyleWithImports(style, styleUrls) {
|
|
this.style = style;
|
|
this.styleUrls = styleUrls;
|
|
}
|
|
return StyleWithImports;
|
|
}());
|
|
function isStyleUrlResolvable(url) {
|
|
if (url == null || url.length === 0 || url[0] == '/')
|
|
return false;
|
|
var schemeMatch = url.match(URL_WITH_SCHEMA_REGEXP);
|
|
return schemeMatch === null || schemeMatch[1] == 'package' || schemeMatch[1] == 'asset';
|
|
}
|
|
/**
|
|
* Rewrites stylesheets by resolving and removing the @import urls that
|
|
* are either relative or don't have a `package:` scheme
|
|
*/
|
|
function extractStyleUrls(resolver, baseUrl, cssText) {
|
|
var foundUrls = [];
|
|
var modifiedCssText = cssText.replace(CSS_STRIPPABLE_COMMENT_REGEXP, '')
|
|
.replace(CSS_IMPORT_REGEXP, function () {
|
|
var m = [];
|
|
for (var _i = 0; _i < arguments.length; _i++) {
|
|
m[_i] = arguments[_i];
|
|
}
|
|
var url = m[1] || m[2];
|
|
if (!isStyleUrlResolvable(url)) {
|
|
// Do not attempt to resolve non-package absolute URLs with URI
|
|
// scheme
|
|
return m[0];
|
|
}
|
|
foundUrls.push(resolver.resolve(baseUrl, url));
|
|
return '';
|
|
});
|
|
return new StyleWithImports(modifiedCssText, foundUrls);
|
|
}
|
|
var CSS_IMPORT_REGEXP = /@import\s+(?:url\()?\s*(?:(?:['"]([^'"]*))|([^;\)\s]*))[^;]*;?/g;
|
|
var CSS_STRIPPABLE_COMMENT_REGEXP = /\/\*(?!#\s*(?:sourceURL|sourceMappingURL)=)[\s\S]+?\*\//g;
|
|
var URL_WITH_SCHEMA_REGEXP = /^([^:/?#]+):/;
|
|
|
|
var PROPERTY_PARTS_SEPARATOR = '.';
|
|
var ATTRIBUTE_PREFIX = 'attr';
|
|
var CLASS_PREFIX = 'class';
|
|
var STYLE_PREFIX = 'style';
|
|
var TEMPLATE_ATTR_PREFIX = '*';
|
|
var ANIMATE_PROP_PREFIX = 'animate-';
|
|
/**
|
|
* Parses bindings in templates and in the directive host area.
|
|
*/
|
|
var BindingParser = /** @class */ (function () {
|
|
function BindingParser(_exprParser, _interpolationConfig, _schemaRegistry, pipes, errors) {
|
|
this._exprParser = _exprParser;
|
|
this._interpolationConfig = _interpolationConfig;
|
|
this._schemaRegistry = _schemaRegistry;
|
|
this.errors = errors;
|
|
this.pipesByName = null;
|
|
this._usedPipes = new Map();
|
|
// When the `pipes` parameter is `null`, do not check for used pipes
|
|
// This is used in IVY when we might not know the available pipes at compile time
|
|
if (pipes) {
|
|
var pipesByName_1 = new Map();
|
|
pipes.forEach(function (pipe) { return pipesByName_1.set(pipe.name, pipe); });
|
|
this.pipesByName = pipesByName_1;
|
|
}
|
|
}
|
|
Object.defineProperty(BindingParser.prototype, "interpolationConfig", {
|
|
get: function () {
|
|
return this._interpolationConfig;
|
|
},
|
|
enumerable: false,
|
|
configurable: true
|
|
});
|
|
BindingParser.prototype.getUsedPipes = function () {
|
|
return Array.from(this._usedPipes.values());
|
|
};
|
|
BindingParser.prototype.createBoundHostProperties = function (dirMeta, sourceSpan) {
|
|
var _this = this;
|
|
if (dirMeta.hostProperties) {
|
|
var boundProps_1 = [];
|
|
Object.keys(dirMeta.hostProperties).forEach(function (propName) {
|
|
var expression = dirMeta.hostProperties[propName];
|
|
if (typeof expression === 'string') {
|
|
_this.parsePropertyBinding(propName, expression, true, sourceSpan, sourceSpan.start.offset, undefined, [],
|
|
// Use the `sourceSpan` for `keySpan`. This isn't really accurate, but neither is the
|
|
// sourceSpan, as it represents the sourceSpan of the host itself rather than the
|
|
// source of the host binding (which doesn't exist in the template). Regardless,
|
|
// neither of these values are used in Ivy but are only here to satisfy the function
|
|
// signature. This should likely be refactored in the future so that `sourceSpan`
|
|
// isn't being used inaccurately.
|
|
boundProps_1, sourceSpan);
|
|
}
|
|
else {
|
|
_this._reportError("Value of the host property binding \"" + propName + "\" needs to be a string representing an expression but got \"" + expression + "\" (" + typeof expression + ")", sourceSpan);
|
|
}
|
|
});
|
|
return boundProps_1;
|
|
}
|
|
return null;
|
|
};
|
|
BindingParser.prototype.createDirectiveHostPropertyAsts = function (dirMeta, elementSelector, sourceSpan) {
|
|
var _this = this;
|
|
var boundProps = this.createBoundHostProperties(dirMeta, sourceSpan);
|
|
return boundProps &&
|
|
boundProps.map(function (prop) { return _this.createBoundElementProperty(elementSelector, prop); });
|
|
};
|
|
BindingParser.prototype.createDirectiveHostEventAsts = function (dirMeta, sourceSpan) {
|
|
var _this = this;
|
|
if (dirMeta.hostListeners) {
|
|
var targetEvents_1 = [];
|
|
Object.keys(dirMeta.hostListeners).forEach(function (propName) {
|
|
var expression = dirMeta.hostListeners[propName];
|
|
if (typeof expression === 'string') {
|
|
// Use the `sourceSpan` for `keySpan` and `handlerSpan`. This isn't really accurate, but
|
|
// neither is the `sourceSpan`, as it represents the `sourceSpan` of the host itself
|
|
// rather than the source of the host binding (which doesn't exist in the template).
|
|
// Regardless, neither of these values are used in Ivy but are only here to satisfy the
|
|
// function signature. This should likely be refactored in the future so that `sourceSpan`
|
|
// isn't being used inaccurately.
|
|
_this.parseEvent(propName, expression, sourceSpan, sourceSpan, [], targetEvents_1, sourceSpan);
|
|
}
|
|
else {
|
|
_this._reportError("Value of the host listener \"" + propName + "\" needs to be a string representing an expression but got \"" + expression + "\" (" + typeof expression + ")", sourceSpan);
|
|
}
|
|
});
|
|
return targetEvents_1;
|
|
}
|
|
return null;
|
|
};
|
|
BindingParser.prototype.parseInterpolation = function (value, sourceSpan) {
|
|
var sourceInfo = sourceSpan.start.toString();
|
|
var absoluteOffset = sourceSpan.fullStart.offset;
|
|
try {
|
|
var ast = this._exprParser.parseInterpolation(value, sourceInfo, absoluteOffset, this._interpolationConfig);
|
|
if (ast)
|
|
this._reportExpressionParserErrors(ast.errors, sourceSpan);
|
|
this._checkPipes(ast, sourceSpan);
|
|
return ast;
|
|
}
|
|
catch (e) {
|
|
this._reportError("" + e, sourceSpan);
|
|
return this._exprParser.wrapLiteralPrimitive('ERROR', sourceInfo, absoluteOffset);
|
|
}
|
|
};
|
|
/**
|
|
* Similar to `parseInterpolation`, but treats the provided string as a single expression
|
|
* element that would normally appear within the interpolation prefix and suffix (`{{` and `}}`).
|
|
* This is used for parsing the switch expression in ICUs.
|
|
*/
|
|
BindingParser.prototype.parseInterpolationExpression = function (expression, sourceSpan) {
|
|
var sourceInfo = sourceSpan.start.toString();
|
|
var absoluteOffset = sourceSpan.start.offset;
|
|
try {
|
|
var ast = this._exprParser.parseInterpolationExpression(expression, sourceInfo, absoluteOffset);
|
|
if (ast)
|
|
this._reportExpressionParserErrors(ast.errors, sourceSpan);
|
|
this._checkPipes(ast, sourceSpan);
|
|
return ast;
|
|
}
|
|
catch (e) {
|
|
this._reportError("" + e, sourceSpan);
|
|
return this._exprParser.wrapLiteralPrimitive('ERROR', sourceInfo, absoluteOffset);
|
|
}
|
|
};
|
|
/**
|
|
* Parses the bindings in a microsyntax expression, and converts them to
|
|
* `ParsedProperty` or `ParsedVariable`.
|
|
*
|
|
* @param tplKey template binding name
|
|
* @param tplValue template binding value
|
|
* @param sourceSpan span of template binding relative to entire the template
|
|
* @param absoluteValueOffset start of the tplValue relative to the entire template
|
|
* @param targetMatchableAttrs potential attributes to match in the template
|
|
* @param targetProps target property bindings in the template
|
|
* @param targetVars target variables in the template
|
|
*/
|
|
BindingParser.prototype.parseInlineTemplateBinding = function (tplKey, tplValue, sourceSpan, absoluteValueOffset, targetMatchableAttrs, targetProps, targetVars, isIvyAst) {
|
|
var e_1, _a;
|
|
var absoluteKeyOffset = sourceSpan.start.offset + TEMPLATE_ATTR_PREFIX.length;
|
|
var bindings = this._parseTemplateBindings(tplKey, tplValue, sourceSpan, absoluteKeyOffset, absoluteValueOffset);
|
|
try {
|
|
for (var bindings_1 = __values(bindings), bindings_1_1 = bindings_1.next(); !bindings_1_1.done; bindings_1_1 = bindings_1.next()) {
|
|
var binding = bindings_1_1.value;
|
|
// sourceSpan is for the entire HTML attribute. bindingSpan is for a particular
|
|
// binding within the microsyntax expression so it's more narrow than sourceSpan.
|
|
var bindingSpan = moveParseSourceSpan(sourceSpan, binding.sourceSpan);
|
|
var key = binding.key.source;
|
|
var keySpan = moveParseSourceSpan(sourceSpan, binding.key.span);
|
|
if (binding instanceof VariableBinding) {
|
|
var value = binding.value ? binding.value.source : '$implicit';
|
|
var valueSpan = binding.value ? moveParseSourceSpan(sourceSpan, binding.value.span) : undefined;
|
|
targetVars.push(new ParsedVariable(key, value, bindingSpan, keySpan, valueSpan));
|
|
}
|
|
else if (binding.value) {
|
|
var srcSpan = isIvyAst ? bindingSpan : sourceSpan;
|
|
var valueSpan = moveParseSourceSpan(sourceSpan, binding.value.ast.sourceSpan);
|
|
this._parsePropertyAst(key, binding.value, srcSpan, keySpan, valueSpan, targetMatchableAttrs, targetProps);
|
|
}
|
|
else {
|
|
targetMatchableAttrs.push([key, '' /* value */]);
|
|
// Since this is a literal attribute with no RHS, source span should be
|
|
// just the key span.
|
|
this.parseLiteralAttr(key, null /* value */, keySpan, absoluteValueOffset, undefined /* valueSpan */, targetMatchableAttrs, targetProps, keySpan);
|
|
}
|
|
}
|
|
}
|
|
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
finally {
|
|
try {
|
|
if (bindings_1_1 && !bindings_1_1.done && (_a = bindings_1.return)) _a.call(bindings_1);
|
|
}
|
|
finally { if (e_1) throw e_1.error; }
|
|
}
|
|
};
|
|
/**
|
|
* Parses the bindings in a microsyntax expression, e.g.
|
|
* ```
|
|
* <tag *tplKey="let value1 = prop; let value2 = localVar">
|
|
* ```
|
|
*
|
|
* @param tplKey template binding name
|
|
* @param tplValue template binding value
|
|
* @param sourceSpan span of template binding relative to entire the template
|
|
* @param absoluteKeyOffset start of the `tplKey`
|
|
* @param absoluteValueOffset start of the `tplValue`
|
|
*/
|
|
BindingParser.prototype._parseTemplateBindings = function (tplKey, tplValue, sourceSpan, absoluteKeyOffset, absoluteValueOffset) {
|
|
var _this = this;
|
|
var sourceInfo = sourceSpan.start.toString();
|
|
try {
|
|
var bindingsResult = this._exprParser.parseTemplateBindings(tplKey, tplValue, sourceInfo, absoluteKeyOffset, absoluteValueOffset);
|
|
this._reportExpressionParserErrors(bindingsResult.errors, sourceSpan);
|
|
bindingsResult.templateBindings.forEach(function (binding) {
|
|
if (binding.value instanceof ASTWithSource) {
|
|
_this._checkPipes(binding.value, sourceSpan);
|
|
}
|
|
});
|
|
bindingsResult.warnings.forEach(function (warning) {
|
|
_this._reportError(warning, sourceSpan, exports.ParseErrorLevel.WARNING);
|
|
});
|
|
return bindingsResult.templateBindings;
|
|
}
|
|
catch (e) {
|
|
this._reportError("" + e, sourceSpan);
|
|
return [];
|
|
}
|
|
};
|
|
BindingParser.prototype.parseLiteralAttr = function (name, value, sourceSpan, absoluteOffset, valueSpan, targetMatchableAttrs,
|
|
// TODO(atscott): keySpan is only optional here so VE template parser implementation does not
|
|
// have to change This should be required when VE is removed.
|
|
targetProps, keySpan) {
|
|
if (isAnimationLabel(name)) {
|
|
name = name.substring(1);
|
|
if (keySpan !== undefined) {
|
|
keySpan = moveParseSourceSpan(keySpan, new AbsoluteSourceSpan(keySpan.start.offset + 1, keySpan.end.offset));
|
|
}
|
|
if (value) {
|
|
this._reportError("Assigning animation triggers via @prop=\"exp\" attributes with an expression is invalid." +
|
|
" Use property bindings (e.g. [@prop]=\"exp\") or use an attribute without a value (e.g. @prop) instead.", sourceSpan, exports.ParseErrorLevel.ERROR);
|
|
}
|
|
this._parseAnimation(name, value, sourceSpan, absoluteOffset, keySpan, valueSpan, targetMatchableAttrs, targetProps);
|
|
}
|
|
else {
|
|
targetProps.push(new ParsedProperty(name, this._exprParser.wrapLiteralPrimitive(value, '', absoluteOffset), exports.ParsedPropertyType.LITERAL_ATTR, sourceSpan, keySpan, valueSpan));
|
|
}
|
|
};
|
|
BindingParser.prototype.parsePropertyBinding = function (name, expression, isHost, sourceSpan, absoluteOffset, valueSpan,
|
|
// TODO(atscott): keySpan is only optional here so VE template parser implementation does not
|
|
// have to change This should be required when VE is removed.
|
|
targetMatchableAttrs, targetProps, keySpan) {
|
|
if (name.length === 0) {
|
|
this._reportError("Property name is missing in binding", sourceSpan);
|
|
}
|
|
var isAnimationProp = false;
|
|
if (name.startsWith(ANIMATE_PROP_PREFIX)) {
|
|
isAnimationProp = true;
|
|
name = name.substring(ANIMATE_PROP_PREFIX.length);
|
|
if (keySpan !== undefined) {
|
|
keySpan = moveParseSourceSpan(keySpan, new AbsoluteSourceSpan(keySpan.start.offset + ANIMATE_PROP_PREFIX.length, keySpan.end.offset));
|
|
}
|
|
}
|
|
else if (isAnimationLabel(name)) {
|
|
isAnimationProp = true;
|
|
name = name.substring(1);
|
|
if (keySpan !== undefined) {
|
|
keySpan = moveParseSourceSpan(keySpan, new AbsoluteSourceSpan(keySpan.start.offset + 1, keySpan.end.offset));
|
|
}
|
|
}
|
|
if (isAnimationProp) {
|
|
this._parseAnimation(name, expression, sourceSpan, absoluteOffset, keySpan, valueSpan, targetMatchableAttrs, targetProps);
|
|
}
|
|
else {
|
|
this._parsePropertyAst(name, this._parseBinding(expression, isHost, valueSpan || sourceSpan, absoluteOffset), sourceSpan, keySpan, valueSpan, targetMatchableAttrs, targetProps);
|
|
}
|
|
};
|
|
BindingParser.prototype.parsePropertyInterpolation = function (name, value, sourceSpan, valueSpan, targetMatchableAttrs,
|
|
// TODO(atscott): keySpan is only optional here so VE template parser implementation does not
|
|
// have to change This should be required when VE is removed.
|
|
targetProps, keySpan) {
|
|
var expr = this.parseInterpolation(value, valueSpan || sourceSpan);
|
|
if (expr) {
|
|
this._parsePropertyAst(name, expr, sourceSpan, keySpan, valueSpan, targetMatchableAttrs, targetProps);
|
|
return true;
|
|
}
|
|
return false;
|
|
};
|
|
BindingParser.prototype._parsePropertyAst = function (name, ast, sourceSpan, keySpan, valueSpan, targetMatchableAttrs, targetProps) {
|
|
targetMatchableAttrs.push([name, ast.source]);
|
|
targetProps.push(new ParsedProperty(name, ast, exports.ParsedPropertyType.DEFAULT, sourceSpan, keySpan, valueSpan));
|
|
};
|
|
BindingParser.prototype._parseAnimation = function (name, expression, sourceSpan, absoluteOffset, keySpan, valueSpan, targetMatchableAttrs, targetProps) {
|
|
if (name.length === 0) {
|
|
this._reportError('Animation trigger is missing', sourceSpan);
|
|
}
|
|
// This will occur when a @trigger is not paired with an expression.
|
|
// For animations it is valid to not have an expression since */void
|
|
// states will be applied by angular when the element is attached/detached
|
|
var ast = this._parseBinding(expression || 'undefined', false, valueSpan || sourceSpan, absoluteOffset);
|
|
targetMatchableAttrs.push([name, ast.source]);
|
|
targetProps.push(new ParsedProperty(name, ast, exports.ParsedPropertyType.ANIMATION, sourceSpan, keySpan, valueSpan));
|
|
};
|
|
BindingParser.prototype._parseBinding = function (value, isHostBinding, sourceSpan, absoluteOffset) {
|
|
var sourceInfo = (sourceSpan && sourceSpan.start || '(unknown)').toString();
|
|
try {
|
|
var ast = isHostBinding ?
|
|
this._exprParser.parseSimpleBinding(value, sourceInfo, absoluteOffset, this._interpolationConfig) :
|
|
this._exprParser.parseBinding(value, sourceInfo, absoluteOffset, this._interpolationConfig);
|
|
if (ast)
|
|
this._reportExpressionParserErrors(ast.errors, sourceSpan);
|
|
this._checkPipes(ast, sourceSpan);
|
|
return ast;
|
|
}
|
|
catch (e) {
|
|
this._reportError("" + e, sourceSpan);
|
|
return this._exprParser.wrapLiteralPrimitive('ERROR', sourceInfo, absoluteOffset);
|
|
}
|
|
};
|
|
BindingParser.prototype.createBoundElementProperty = function (elementSelector, boundProp, skipValidation, mapPropertyName) {
|
|
if (skipValidation === void 0) { skipValidation = false; }
|
|
if (mapPropertyName === void 0) { mapPropertyName = true; }
|
|
if (boundProp.isAnimation) {
|
|
return new BoundElementProperty(boundProp.name, 4 /* Animation */, SecurityContext.NONE, boundProp.expression, null, boundProp.sourceSpan, boundProp.keySpan, boundProp.valueSpan);
|
|
}
|
|
var unit = null;
|
|
var bindingType = undefined;
|
|
var boundPropertyName = null;
|
|
var parts = boundProp.name.split(PROPERTY_PARTS_SEPARATOR);
|
|
var securityContexts = undefined;
|
|
// Check for special cases (prefix style, attr, class)
|
|
if (parts.length > 1) {
|
|
if (parts[0] == ATTRIBUTE_PREFIX) {
|
|
boundPropertyName = parts.slice(1).join(PROPERTY_PARTS_SEPARATOR);
|
|
if (!skipValidation) {
|
|
this._validatePropertyOrAttributeName(boundPropertyName, boundProp.sourceSpan, true);
|
|
}
|
|
securityContexts = calcPossibleSecurityContexts(this._schemaRegistry, elementSelector, boundPropertyName, true);
|
|
var nsSeparatorIdx = boundPropertyName.indexOf(':');
|
|
if (nsSeparatorIdx > -1) {
|
|
var ns = boundPropertyName.substring(0, nsSeparatorIdx);
|
|
var name = boundPropertyName.substring(nsSeparatorIdx + 1);
|
|
boundPropertyName = mergeNsAndName(ns, name);
|
|
}
|
|
bindingType = 1 /* Attribute */;
|
|
}
|
|
else if (parts[0] == CLASS_PREFIX) {
|
|
boundPropertyName = parts[1];
|
|
bindingType = 2 /* Class */;
|
|
securityContexts = [SecurityContext.NONE];
|
|
}
|
|
else if (parts[0] == STYLE_PREFIX) {
|
|
unit = parts.length > 2 ? parts[2] : null;
|
|
boundPropertyName = parts[1];
|
|
bindingType = 3 /* Style */;
|
|
securityContexts = [SecurityContext.STYLE];
|
|
}
|
|
}
|
|
// If not a special case, use the full property name
|
|
if (boundPropertyName === null) {
|
|
var mappedPropName = this._schemaRegistry.getMappedPropName(boundProp.name);
|
|
boundPropertyName = mapPropertyName ? mappedPropName : boundProp.name;
|
|
securityContexts = calcPossibleSecurityContexts(this._schemaRegistry, elementSelector, mappedPropName, false);
|
|
bindingType = 0 /* Property */;
|
|
if (!skipValidation) {
|
|
this._validatePropertyOrAttributeName(mappedPropName, boundProp.sourceSpan, false);
|
|
}
|
|
}
|
|
return new BoundElementProperty(boundPropertyName, bindingType, securityContexts[0], boundProp.expression, unit, boundProp.sourceSpan, boundProp.keySpan, boundProp.valueSpan);
|
|
};
|
|
// TODO: keySpan should be required but was made optional to avoid changing VE parser.
|
|
BindingParser.prototype.parseEvent = function (name, expression, sourceSpan, handlerSpan, targetMatchableAttrs, targetEvents, keySpan) {
|
|
if (name.length === 0) {
|
|
this._reportError("Event name is missing in binding", sourceSpan);
|
|
}
|
|
if (isAnimationLabel(name)) {
|
|
name = name.substr(1);
|
|
if (keySpan !== undefined) {
|
|
keySpan = moveParseSourceSpan(keySpan, new AbsoluteSourceSpan(keySpan.start.offset + 1, keySpan.end.offset));
|
|
}
|
|
this._parseAnimationEvent(name, expression, sourceSpan, handlerSpan, targetEvents, keySpan);
|
|
}
|
|
else {
|
|
this._parseRegularEvent(name, expression, sourceSpan, handlerSpan, targetMatchableAttrs, targetEvents, keySpan);
|
|
}
|
|
};
|
|
BindingParser.prototype.calcPossibleSecurityContexts = function (selector, propName, isAttribute) {
|
|
var prop = this._schemaRegistry.getMappedPropName(propName);
|
|
return calcPossibleSecurityContexts(this._schemaRegistry, selector, prop, isAttribute);
|
|
};
|
|
BindingParser.prototype._parseAnimationEvent = function (name, expression, sourceSpan, handlerSpan, targetEvents, keySpan) {
|
|
var matches = splitAtPeriod(name, [name, '']);
|
|
var eventName = matches[0];
|
|
var phase = matches[1].toLowerCase();
|
|
var ast = this._parseAction(expression, handlerSpan);
|
|
targetEvents.push(new ParsedEvent(eventName, phase, 1 /* Animation */, ast, sourceSpan, handlerSpan, keySpan));
|
|
if (eventName.length === 0) {
|
|
this._reportError("Animation event name is missing in binding", sourceSpan);
|
|
}
|
|
if (phase) {
|
|
if (phase !== 'start' && phase !== 'done') {
|
|
this._reportError("The provided animation output phase value \"" + phase + "\" for \"@" + eventName + "\" is not supported (use start or done)", sourceSpan);
|
|
}
|
|
}
|
|
else {
|
|
this._reportError("The animation trigger output event (@" + eventName + ") is missing its phase value name (start or done are currently supported)", sourceSpan);
|
|
}
|
|
};
|
|
BindingParser.prototype._parseRegularEvent = function (name, expression, sourceSpan, handlerSpan, targetMatchableAttrs, targetEvents, keySpan) {
|
|
// long format: 'target: eventName'
|
|
var _a = __read(splitAtColon(name, [null, name]), 2), target = _a[0], eventName = _a[1];
|
|
var ast = this._parseAction(expression, handlerSpan);
|
|
targetMatchableAttrs.push([name, ast.source]);
|
|
targetEvents.push(new ParsedEvent(eventName, target, 0 /* Regular */, ast, sourceSpan, handlerSpan, keySpan));
|
|
// Don't detect directives for event names for now,
|
|
// so don't add the event name to the matchableAttrs
|
|
};
|
|
BindingParser.prototype._parseAction = function (value, sourceSpan) {
|
|
var sourceInfo = (sourceSpan && sourceSpan.start || '(unknown').toString();
|
|
var absoluteOffset = (sourceSpan && sourceSpan.start) ? sourceSpan.start.offset : 0;
|
|
try {
|
|
var ast = this._exprParser.parseAction(value, sourceInfo, absoluteOffset, this._interpolationConfig);
|
|
if (ast) {
|
|
this._reportExpressionParserErrors(ast.errors, sourceSpan);
|
|
}
|
|
if (!ast || ast.ast instanceof EmptyExpr) {
|
|
this._reportError("Empty expressions are not allowed", sourceSpan);
|
|
return this._exprParser.wrapLiteralPrimitive('ERROR', sourceInfo, absoluteOffset);
|
|
}
|
|
this._checkPipes(ast, sourceSpan);
|
|
return ast;
|
|
}
|
|
catch (e) {
|
|
this._reportError("" + e, sourceSpan);
|
|
return this._exprParser.wrapLiteralPrimitive('ERROR', sourceInfo, absoluteOffset);
|
|
}
|
|
};
|
|
BindingParser.prototype._reportError = function (message, sourceSpan, level) {
|
|
if (level === void 0) { level = exports.ParseErrorLevel.ERROR; }
|
|
this.errors.push(new ParseError(sourceSpan, message, level));
|
|
};
|
|
BindingParser.prototype._reportExpressionParserErrors = function (errors, sourceSpan) {
|
|
var e_2, _a;
|
|
try {
|
|
for (var errors_1 = __values(errors), errors_1_1 = errors_1.next(); !errors_1_1.done; errors_1_1 = errors_1.next()) {
|
|
var error = errors_1_1.value;
|
|
this._reportError(error.message, sourceSpan);
|
|
}
|
|
}
|
|
catch (e_2_1) { e_2 = { error: e_2_1 }; }
|
|
finally {
|
|
try {
|
|
if (errors_1_1 && !errors_1_1.done && (_a = errors_1.return)) _a.call(errors_1);
|
|
}
|
|
finally { if (e_2) throw e_2.error; }
|
|
}
|
|
};
|
|
// Make sure all the used pipes are known in `this.pipesByName`
|
|
BindingParser.prototype._checkPipes = function (ast, sourceSpan) {
|
|
var _this = this;
|
|
if (ast && this.pipesByName) {
|
|
var collector = new PipeCollector();
|
|
ast.visit(collector);
|
|
collector.pipes.forEach(function (ast, pipeName) {
|
|
var pipeMeta = _this.pipesByName.get(pipeName);
|
|
if (!pipeMeta) {
|
|
_this._reportError("The pipe '" + pipeName + "' could not be found", new ParseSourceSpan(sourceSpan.start.moveBy(ast.span.start), sourceSpan.start.moveBy(ast.span.end)));
|
|
}
|
|
else {
|
|
_this._usedPipes.set(pipeName, pipeMeta);
|
|
}
|
|
});
|
|
}
|
|
};
|
|
/**
|
|
* @param propName the name of the property / attribute
|
|
* @param sourceSpan
|
|
* @param isAttr true when binding to an attribute
|
|
*/
|
|
BindingParser.prototype._validatePropertyOrAttributeName = function (propName, sourceSpan, isAttr) {
|
|
var report = isAttr ? this._schemaRegistry.validateAttribute(propName) :
|
|
this._schemaRegistry.validateProperty(propName);
|
|
if (report.error) {
|
|
this._reportError(report.msg, sourceSpan, exports.ParseErrorLevel.ERROR);
|
|
}
|
|
};
|
|
return BindingParser;
|
|
}());
|
|
var PipeCollector = /** @class */ (function (_super) {
|
|
__extends(PipeCollector, _super);
|
|
function PipeCollector() {
|
|
var _this = _super.apply(this, __spreadArray([], __read(arguments))) || this;
|
|
_this.pipes = new Map();
|
|
return _this;
|
|
}
|
|
PipeCollector.prototype.visitPipe = function (ast, context) {
|
|
this.pipes.set(ast.name, ast);
|
|
ast.exp.visit(this);
|
|
this.visitAll(ast.args, context);
|
|
return null;
|
|
};
|
|
return PipeCollector;
|
|
}(RecursiveAstVisitor$1));
|
|
function isAnimationLabel(name) {
|
|
return name[0] == '@';
|
|
}
|
|
function calcPossibleSecurityContexts(registry, selector, propName, isAttribute) {
|
|
var ctxs = [];
|
|
CssSelector.parse(selector).forEach(function (selector) {
|
|
var elementNames = selector.element ? [selector.element] : registry.allKnownElementNames();
|
|
var notElementNames = new Set(selector.notSelectors.filter(function (selector) { return selector.isElementSelector(); })
|
|
.map(function (selector) { return selector.element; }));
|
|
var possibleElementNames = elementNames.filter(function (elementName) { return !notElementNames.has(elementName); });
|
|
ctxs.push.apply(ctxs, __spreadArray([], __read(possibleElementNames.map(function (elementName) { return registry.securityContext(elementName, propName, isAttribute); }))));
|
|
});
|
|
return ctxs.length === 0 ? [SecurityContext.NONE] : Array.from(new Set(ctxs)).sort();
|
|
}
|
|
/**
|
|
* Compute a new ParseSourceSpan based off an original `sourceSpan` by using
|
|
* absolute offsets from the specified `absoluteSpan`.
|
|
*
|
|
* @param sourceSpan original source span
|
|
* @param absoluteSpan absolute source span to move to
|
|
*/
|
|
function moveParseSourceSpan(sourceSpan, absoluteSpan) {
|
|
// The difference of two absolute offsets provide the relative offset
|
|
var startDiff = absoluteSpan.start - sourceSpan.start.offset;
|
|
var endDiff = absoluteSpan.end - sourceSpan.end.offset;
|
|
return new ParseSourceSpan(sourceSpan.start.moveBy(startDiff), sourceSpan.end.moveBy(endDiff), sourceSpan.fullStart.moveBy(startDiff), sourceSpan.details);
|
|
}
|
|
|
|
/**
|
|
* @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 NG_CONTENT_SELECT_ATTR = 'select';
|
|
var LINK_ELEMENT = 'link';
|
|
var LINK_STYLE_REL_ATTR = 'rel';
|
|
var LINK_STYLE_HREF_ATTR = 'href';
|
|
var LINK_STYLE_REL_VALUE = 'stylesheet';
|
|
var STYLE_ELEMENT = 'style';
|
|
var SCRIPT_ELEMENT = 'script';
|
|
var NG_NON_BINDABLE_ATTR = 'ngNonBindable';
|
|
var NG_PROJECT_AS = 'ngProjectAs';
|
|
function preparseElement(ast) {
|
|
var selectAttr = null;
|
|
var hrefAttr = null;
|
|
var relAttr = null;
|
|
var nonBindable = false;
|
|
var projectAs = '';
|
|
ast.attrs.forEach(function (attr) {
|
|
var lcAttrName = attr.name.toLowerCase();
|
|
if (lcAttrName == NG_CONTENT_SELECT_ATTR) {
|
|
selectAttr = attr.value;
|
|
}
|
|
else if (lcAttrName == LINK_STYLE_HREF_ATTR) {
|
|
hrefAttr = attr.value;
|
|
}
|
|
else if (lcAttrName == LINK_STYLE_REL_ATTR) {
|
|
relAttr = attr.value;
|
|
}
|
|
else if (attr.name == NG_NON_BINDABLE_ATTR) {
|
|
nonBindable = true;
|
|
}
|
|
else if (attr.name == NG_PROJECT_AS) {
|
|
if (attr.value.length > 0) {
|
|
projectAs = attr.value;
|
|
}
|
|
}
|
|
});
|
|
selectAttr = normalizeNgContentSelect(selectAttr);
|
|
var nodeName = ast.name.toLowerCase();
|
|
var type = PreparsedElementType.OTHER;
|
|
if (isNgContent(nodeName)) {
|
|
type = PreparsedElementType.NG_CONTENT;
|
|
}
|
|
else if (nodeName == STYLE_ELEMENT) {
|
|
type = PreparsedElementType.STYLE;
|
|
}
|
|
else if (nodeName == SCRIPT_ELEMENT) {
|
|
type = PreparsedElementType.SCRIPT;
|
|
}
|
|
else if (nodeName == LINK_ELEMENT && relAttr == LINK_STYLE_REL_VALUE) {
|
|
type = PreparsedElementType.STYLESHEET;
|
|
}
|
|
return new PreparsedElement(type, selectAttr, hrefAttr, nonBindable, projectAs);
|
|
}
|
|
var PreparsedElementType;
|
|
(function (PreparsedElementType) {
|
|
PreparsedElementType[PreparsedElementType["NG_CONTENT"] = 0] = "NG_CONTENT";
|
|
PreparsedElementType[PreparsedElementType["STYLE"] = 1] = "STYLE";
|
|
PreparsedElementType[PreparsedElementType["STYLESHEET"] = 2] = "STYLESHEET";
|
|
PreparsedElementType[PreparsedElementType["SCRIPT"] = 3] = "SCRIPT";
|
|
PreparsedElementType[PreparsedElementType["OTHER"] = 4] = "OTHER";
|
|
})(PreparsedElementType || (PreparsedElementType = {}));
|
|
var PreparsedElement = /** @class */ (function () {
|
|
function PreparsedElement(type, selectAttr, hrefAttr, nonBindable, projectAs) {
|
|
this.type = type;
|
|
this.selectAttr = selectAttr;
|
|
this.hrefAttr = hrefAttr;
|
|
this.nonBindable = nonBindable;
|
|
this.projectAs = projectAs;
|
|
}
|
|
return PreparsedElement;
|
|
}());
|
|
function normalizeNgContentSelect(selectAttr) {
|
|
if (selectAttr === null || selectAttr.length === 0) {
|
|
return '*';
|
|
}
|
|
return selectAttr;
|
|
}
|
|
|
|
var BIND_NAME_REGEXP = /^(?:(?:(?:(bind-)|(let-)|(ref-|#)|(on-)|(bindon-)|(@))(.*))|\[\(([^\)]+)\)\]|\[([^\]]+)\]|\(([^\)]+)\))$/;
|
|
// Group 1 = "bind-"
|
|
var KW_BIND_IDX = 1;
|
|
// Group 2 = "let-"
|
|
var KW_LET_IDX = 2;
|
|
// Group 3 = "ref-/#"
|
|
var KW_REF_IDX = 3;
|
|
// Group 4 = "on-"
|
|
var KW_ON_IDX = 4;
|
|
// Group 5 = "bindon-"
|
|
var KW_BINDON_IDX = 5;
|
|
// Group 6 = "@"
|
|
var KW_AT_IDX = 6;
|
|
// Group 7 = the identifier after "bind-", "let-", "ref-/#", "on-", "bindon-" or "@"
|
|
var IDENT_KW_IDX = 7;
|
|
// Group 8 = identifier inside [()]
|
|
var IDENT_BANANA_BOX_IDX = 8;
|
|
// Group 9 = identifier inside []
|
|
var IDENT_PROPERTY_IDX = 9;
|
|
// Group 10 = identifier inside ()
|
|
var IDENT_EVENT_IDX = 10;
|
|
var TEMPLATE_ATTR_PREFIX$1 = '*';
|
|
var CLASS_ATTR = 'class';
|
|
var _TEXT_CSS_SELECTOR;
|
|
function TEXT_CSS_SELECTOR() {
|
|
if (!_TEXT_CSS_SELECTOR) {
|
|
_TEXT_CSS_SELECTOR = CssSelector.parse('*')[0];
|
|
}
|
|
return _TEXT_CSS_SELECTOR;
|
|
}
|
|
var TemplateParseError = /** @class */ (function (_super) {
|
|
__extends(TemplateParseError, _super);
|
|
function TemplateParseError(message, span, level) {
|
|
return _super.call(this, span, message, level) || this;
|
|
}
|
|
return TemplateParseError;
|
|
}(ParseError));
|
|
var TemplateParseResult = /** @class */ (function () {
|
|
function TemplateParseResult(templateAst, usedPipes, errors) {
|
|
this.templateAst = templateAst;
|
|
this.usedPipes = usedPipes;
|
|
this.errors = errors;
|
|
}
|
|
return TemplateParseResult;
|
|
}());
|
|
var TemplateParser = /** @class */ (function () {
|
|
function TemplateParser(_config, _reflector, _exprParser, _schemaRegistry, _htmlParser, _console, transforms) {
|
|
this._config = _config;
|
|
this._reflector = _reflector;
|
|
this._exprParser = _exprParser;
|
|
this._schemaRegistry = _schemaRegistry;
|
|
this._htmlParser = _htmlParser;
|
|
this._console = _console;
|
|
this.transforms = transforms;
|
|
}
|
|
Object.defineProperty(TemplateParser.prototype, "expressionParser", {
|
|
get: function () {
|
|
return this._exprParser;
|
|
},
|
|
enumerable: false,
|
|
configurable: true
|
|
});
|
|
TemplateParser.prototype.parse = function (component, template, directives, pipes, schemas, templateUrl, preserveWhitespaces) {
|
|
var _a;
|
|
var result = this.tryParse(component, template, directives, pipes, schemas, templateUrl, preserveWhitespaces);
|
|
var warnings = result.errors.filter(function (error) { return error.level === exports.ParseErrorLevel.WARNING; });
|
|
var errors = result.errors.filter(function (error) { return error.level === exports.ParseErrorLevel.ERROR; });
|
|
if (warnings.length > 0) {
|
|
(_a = this._console) === null || _a === void 0 ? void 0 : _a.warn("Template parse warnings:\n" + warnings.join('\n'));
|
|
}
|
|
if (errors.length > 0) {
|
|
var errorString = errors.join('\n');
|
|
throw syntaxError("Template parse errors:\n" + errorString, errors);
|
|
}
|
|
return { template: result.templateAst, pipes: result.usedPipes };
|
|
};
|
|
TemplateParser.prototype.tryParse = function (component, template, directives, pipes, schemas, templateUrl, preserveWhitespaces) {
|
|
var htmlParseResult = typeof template === 'string' ?
|
|
this._htmlParser.parse(template, templateUrl, {
|
|
tokenizeExpansionForms: true,
|
|
interpolationConfig: this.getInterpolationConfig(component)
|
|
}) :
|
|
template;
|
|
if (!preserveWhitespaces) {
|
|
htmlParseResult = removeWhitespaces(htmlParseResult);
|
|
}
|
|
return this.tryParseHtml(this.expandHtml(htmlParseResult), component, directives, pipes, schemas);
|
|
};
|
|
TemplateParser.prototype.tryParseHtml = function (htmlAstWithErrors, component, directives, pipes, schemas) {
|
|
var result;
|
|
var errors = htmlAstWithErrors.errors;
|
|
var usedPipes = [];
|
|
if (htmlAstWithErrors.rootNodes.length > 0) {
|
|
var uniqDirectives = removeSummaryDuplicates(directives);
|
|
var uniqPipes = removeSummaryDuplicates(pipes);
|
|
var providerViewContext = new ProviderViewContext(this._reflector, component);
|
|
var interpolationConfig = undefined;
|
|
if (component.template && component.template.interpolation) {
|
|
interpolationConfig = {
|
|
start: component.template.interpolation[0],
|
|
end: component.template.interpolation[1]
|
|
};
|
|
}
|
|
var bindingParser = new BindingParser(this._exprParser, interpolationConfig, this._schemaRegistry, uniqPipes, errors);
|
|
var parseVisitor = new TemplateParseVisitor(this._reflector, this._config, providerViewContext, uniqDirectives, bindingParser, this._schemaRegistry, schemas, errors);
|
|
result = visitAll$1(parseVisitor, htmlAstWithErrors.rootNodes, EMPTY_ELEMENT_CONTEXT);
|
|
errors.push.apply(errors, __spreadArray([], __read(providerViewContext.errors)));
|
|
usedPipes.push.apply(usedPipes, __spreadArray([], __read(bindingParser.getUsedPipes())));
|
|
}
|
|
else {
|
|
result = [];
|
|
}
|
|
this._assertNoReferenceDuplicationOnTemplate(result, errors);
|
|
if (errors.length > 0) {
|
|
return new TemplateParseResult(result, usedPipes, errors);
|
|
}
|
|
if (this.transforms) {
|
|
this.transforms.forEach(function (transform) {
|
|
result = templateVisitAll(transform, result);
|
|
});
|
|
}
|
|
return new TemplateParseResult(result, usedPipes, errors);
|
|
};
|
|
TemplateParser.prototype.expandHtml = function (htmlAstWithErrors, forced) {
|
|
if (forced === void 0) { forced = false; }
|
|
var errors = htmlAstWithErrors.errors;
|
|
if (errors.length == 0 || forced) {
|
|
// Transform ICU messages to angular directives
|
|
var expandedHtmlAst = expandNodes(htmlAstWithErrors.rootNodes);
|
|
errors.push.apply(errors, __spreadArray([], __read(expandedHtmlAst.errors)));
|
|
htmlAstWithErrors = new ParseTreeResult(expandedHtmlAst.nodes, errors);
|
|
}
|
|
return htmlAstWithErrors;
|
|
};
|
|
TemplateParser.prototype.getInterpolationConfig = function (component) {
|
|
if (component.template) {
|
|
return InterpolationConfig.fromArray(component.template.interpolation);
|
|
}
|
|
return undefined;
|
|
};
|
|
/** @internal */
|
|
TemplateParser.prototype._assertNoReferenceDuplicationOnTemplate = function (result, errors) {
|
|
var existingReferences = [];
|
|
result.filter(function (element) { return !!element.references; })
|
|
.forEach(function (element) { return element.references.forEach(function (reference) {
|
|
var name = reference.name;
|
|
if (existingReferences.indexOf(name) < 0) {
|
|
existingReferences.push(name);
|
|
}
|
|
else {
|
|
var error = new TemplateParseError("Reference \"#" + name + "\" is defined several times", reference.sourceSpan, exports.ParseErrorLevel.ERROR);
|
|
errors.push(error);
|
|
}
|
|
}); });
|
|
};
|
|
return TemplateParser;
|
|
}());
|
|
var TemplateParseVisitor = /** @class */ (function () {
|
|
function TemplateParseVisitor(reflector, config, providerViewContext, directives, _bindingParser, _schemaRegistry, _schemas, _targetErrors) {
|
|
var _this = this;
|
|
this.reflector = reflector;
|
|
this.config = config;
|
|
this.providerViewContext = providerViewContext;
|
|
this._bindingParser = _bindingParser;
|
|
this._schemaRegistry = _schemaRegistry;
|
|
this._schemas = _schemas;
|
|
this._targetErrors = _targetErrors;
|
|
this.selectorMatcher = new SelectorMatcher();
|
|
this.directivesIndex = new Map();
|
|
this.ngContentCount = 0;
|
|
// Note: queries start with id 1 so we can use the number in a Bloom filter!
|
|
this.contentQueryStartId = providerViewContext.component.viewQueries.length + 1;
|
|
directives.forEach(function (directive, index) {
|
|
var selector = CssSelector.parse(directive.selector);
|
|
_this.selectorMatcher.addSelectables(selector, directive);
|
|
_this.directivesIndex.set(directive, index);
|
|
});
|
|
}
|
|
TemplateParseVisitor.prototype.visitExpansion = function (expansion, context) {
|
|
return null;
|
|
};
|
|
TemplateParseVisitor.prototype.visitExpansionCase = function (expansionCase, context) {
|
|
return null;
|
|
};
|
|
TemplateParseVisitor.prototype.visitText = function (text, parent) {
|
|
var ngContentIndex = parent.findNgContentIndex(TEXT_CSS_SELECTOR());
|
|
var valueNoNgsp = replaceNgsp(text.value);
|
|
var expr = this._bindingParser.parseInterpolation(valueNoNgsp, text.sourceSpan);
|
|
return expr ? new BoundTextAst(expr, ngContentIndex, text.sourceSpan) :
|
|
new TextAst(valueNoNgsp, ngContentIndex, text.sourceSpan);
|
|
};
|
|
TemplateParseVisitor.prototype.visitAttribute = function (attribute, context) {
|
|
return new AttrAst(attribute.name, attribute.value, attribute.sourceSpan);
|
|
};
|
|
TemplateParseVisitor.prototype.visitComment = function (comment, context) {
|
|
return null;
|
|
};
|
|
TemplateParseVisitor.prototype.visitElement = function (element, parent) {
|
|
var _this = this;
|
|
var queryStartIndex = this.contentQueryStartId;
|
|
var elName = element.name;
|
|
var preparsedElement = preparseElement(element);
|
|
if (preparsedElement.type === PreparsedElementType.SCRIPT ||
|
|
preparsedElement.type === PreparsedElementType.STYLE) {
|
|
// Skipping <script> for security reasons
|
|
// Skipping <style> as we already processed them
|
|
// in the StyleCompiler
|
|
return null;
|
|
}
|
|
if (preparsedElement.type === PreparsedElementType.STYLESHEET &&
|
|
isStyleUrlResolvable(preparsedElement.hrefAttr)) {
|
|
// Skipping stylesheets with either relative urls or package scheme as we already processed
|
|
// them in the StyleCompiler
|
|
return null;
|
|
}
|
|
var matchableAttrs = [];
|
|
var elementOrDirectiveProps = [];
|
|
var elementOrDirectiveRefs = [];
|
|
var elementVars = [];
|
|
var events = [];
|
|
var templateElementOrDirectiveProps = [];
|
|
var templateMatchableAttrs = [];
|
|
var templateElementVars = [];
|
|
var hasInlineTemplates = false;
|
|
var attrs = [];
|
|
var isTemplateElement = isNgTemplate(element.name);
|
|
element.attrs.forEach(function (attr) {
|
|
var parsedVariables = [];
|
|
var hasBinding = _this._parseAttr(isTemplateElement, attr, matchableAttrs, elementOrDirectiveProps, events, elementOrDirectiveRefs, elementVars);
|
|
elementVars.push.apply(elementVars, __spreadArray([], __read(parsedVariables.map(function (v) { return VariableAst.fromParsedVariable(v); }))));
|
|
var templateValue;
|
|
var templateKey;
|
|
var normalizedName = _this._normalizeAttributeName(attr.name);
|
|
if (normalizedName.startsWith(TEMPLATE_ATTR_PREFIX$1)) {
|
|
templateValue = attr.value;
|
|
templateKey = normalizedName.substring(TEMPLATE_ATTR_PREFIX$1.length);
|
|
}
|
|
var hasTemplateBinding = templateValue != null;
|
|
if (hasTemplateBinding) {
|
|
if (hasInlineTemplates) {
|
|
_this._reportError("Can't have multiple template bindings on one element. Use only one attribute prefixed with *", attr.sourceSpan);
|
|
}
|
|
hasInlineTemplates = true;
|
|
var parsedVariables_1 = [];
|
|
var absoluteOffset = (attr.valueSpan || attr.sourceSpan).start.offset;
|
|
_this._bindingParser.parseInlineTemplateBinding(templateKey, templateValue, attr.sourceSpan, absoluteOffset, templateMatchableAttrs, templateElementOrDirectiveProps, parsedVariables_1, false /* isIvyAst */);
|
|
templateElementVars.push.apply(templateElementVars, __spreadArray([], __read(parsedVariables_1.map(function (v) { return VariableAst.fromParsedVariable(v); }))));
|
|
}
|
|
if (!hasBinding && !hasTemplateBinding) {
|
|
// don't include the bindings as attributes as well in the AST
|
|
attrs.push(_this.visitAttribute(attr, null));
|
|
matchableAttrs.push([attr.name, attr.value]);
|
|
}
|
|
});
|
|
var elementCssSelector = createElementCssSelector(elName, matchableAttrs);
|
|
var _b = this._parseDirectives(this.selectorMatcher, elementCssSelector), directiveMetas = _b.directives, matchElement = _b.matchElement;
|
|
var references = [];
|
|
var boundDirectivePropNames = new Set();
|
|
var directiveAsts = this._createDirectiveAsts(isTemplateElement, element.name, directiveMetas, elementOrDirectiveProps, elementOrDirectiveRefs, element.sourceSpan, references, boundDirectivePropNames);
|
|
var elementProps = this._createElementPropertyAsts(element.name, elementOrDirectiveProps, boundDirectivePropNames);
|
|
var isViewRoot = parent.isTemplateElement || hasInlineTemplates;
|
|
var providerContext = new ProviderElementContext(this.providerViewContext, parent.providerContext, isViewRoot, directiveAsts, attrs, references, isTemplateElement, queryStartIndex, element.sourceSpan);
|
|
var children = visitAll$1(preparsedElement.nonBindable ? NON_BINDABLE_VISITOR : this, element.children, ElementContext.create(isTemplateElement, directiveAsts, isTemplateElement ? parent.providerContext : providerContext));
|
|
providerContext.afterElement();
|
|
// Override the actual selector when the `ngProjectAs` attribute is provided
|
|
var projectionSelector = preparsedElement.projectAs != '' ?
|
|
CssSelector.parse(preparsedElement.projectAs)[0] :
|
|
elementCssSelector;
|
|
var ngContentIndex = parent.findNgContentIndex(projectionSelector);
|
|
var parsedElement;
|
|
if (preparsedElement.type === PreparsedElementType.NG_CONTENT) {
|
|
// `<ng-content>` element
|
|
if (element.children && !element.children.every(_isEmptyTextNode)) {
|
|
this._reportError("<ng-content> element cannot have content.", element.sourceSpan);
|
|
}
|
|
parsedElement = new NgContentAst(this.ngContentCount++, hasInlineTemplates ? null : ngContentIndex, element.sourceSpan);
|
|
}
|
|
else if (isTemplateElement) {
|
|
// `<ng-template>` element
|
|
this._assertAllEventsPublishedByDirectives(directiveAsts, events);
|
|
this._assertNoComponentsNorElementBindingsOnTemplate(directiveAsts, elementProps, element.sourceSpan);
|
|
parsedElement = new EmbeddedTemplateAst(attrs, events, references, elementVars, providerContext.transformedDirectiveAsts, providerContext.transformProviders, providerContext.transformedHasViewContainer, providerContext.queryMatches, children, hasInlineTemplates ? null : ngContentIndex, element.sourceSpan);
|
|
}
|
|
else {
|
|
// element other than `<ng-content>` and `<ng-template>`
|
|
this._assertElementExists(matchElement, element);
|
|
this._assertOnlyOneComponent(directiveAsts, element.sourceSpan);
|
|
var ngContentIndex_1 = hasInlineTemplates ? null : parent.findNgContentIndex(projectionSelector);
|
|
parsedElement = new ElementAst(elName, attrs, elementProps, events, references, providerContext.transformedDirectiveAsts, providerContext.transformProviders, providerContext.transformedHasViewContainer, providerContext.queryMatches, children, hasInlineTemplates ? null : ngContentIndex_1, element.sourceSpan, element.endSourceSpan || null);
|
|
}
|
|
if (hasInlineTemplates) {
|
|
// The element as a *-attribute
|
|
var templateQueryStartIndex = this.contentQueryStartId;
|
|
var templateSelector = createElementCssSelector('ng-template', templateMatchableAttrs);
|
|
var directives = this._parseDirectives(this.selectorMatcher, templateSelector).directives;
|
|
var templateBoundDirectivePropNames = new Set();
|
|
var templateDirectiveAsts = this._createDirectiveAsts(true, elName, directives, templateElementOrDirectiveProps, [], element.sourceSpan, [], templateBoundDirectivePropNames);
|
|
var templateElementProps = this._createElementPropertyAsts(elName, templateElementOrDirectiveProps, templateBoundDirectivePropNames);
|
|
this._assertNoComponentsNorElementBindingsOnTemplate(templateDirectiveAsts, templateElementProps, element.sourceSpan);
|
|
var templateProviderContext = new ProviderElementContext(this.providerViewContext, parent.providerContext, parent.isTemplateElement, templateDirectiveAsts, [], [], true, templateQueryStartIndex, element.sourceSpan);
|
|
templateProviderContext.afterElement();
|
|
parsedElement = new EmbeddedTemplateAst([], [], [], templateElementVars, templateProviderContext.transformedDirectiveAsts, templateProviderContext.transformProviders, templateProviderContext.transformedHasViewContainer, templateProviderContext.queryMatches, [parsedElement], ngContentIndex, element.sourceSpan);
|
|
}
|
|
return parsedElement;
|
|
};
|
|
TemplateParseVisitor.prototype._parseAttr = function (isTemplateElement, attr, targetMatchableAttrs, targetProps, targetEvents, targetRefs, targetVars) {
|
|
var name = this._normalizeAttributeName(attr.name);
|
|
var value = attr.value;
|
|
var srcSpan = attr.sourceSpan;
|
|
var absoluteOffset = attr.valueSpan ? attr.valueSpan.start.offset : srcSpan.start.offset;
|
|
var boundEvents = [];
|
|
var bindParts = name.match(BIND_NAME_REGEXP);
|
|
var hasBinding = false;
|
|
if (bindParts !== null) {
|
|
hasBinding = true;
|
|
if (bindParts[KW_BIND_IDX] != null) {
|
|
this._bindingParser.parsePropertyBinding(bindParts[IDENT_KW_IDX], value, false, srcSpan, absoluteOffset, attr.valueSpan, targetMatchableAttrs, targetProps);
|
|
}
|
|
else if (bindParts[KW_LET_IDX]) {
|
|
if (isTemplateElement) {
|
|
var identifier = bindParts[IDENT_KW_IDX];
|
|
this._parseVariable(identifier, value, srcSpan, targetVars);
|
|
}
|
|
else {
|
|
this._reportError("\"let-\" is only supported on ng-template elements.", srcSpan);
|
|
}
|
|
}
|
|
else if (bindParts[KW_REF_IDX]) {
|
|
var identifier = bindParts[IDENT_KW_IDX];
|
|
this._parseReference(identifier, value, srcSpan, targetRefs);
|
|
}
|
|
else if (bindParts[KW_ON_IDX]) {
|
|
this._bindingParser.parseEvent(bindParts[IDENT_KW_IDX], value, srcSpan, attr.valueSpan || srcSpan, targetMatchableAttrs, boundEvents);
|
|
}
|
|
else if (bindParts[KW_BINDON_IDX]) {
|
|
this._bindingParser.parsePropertyBinding(bindParts[IDENT_KW_IDX], value, false, srcSpan, absoluteOffset, attr.valueSpan, targetMatchableAttrs, targetProps);
|
|
this._parseAssignmentEvent(bindParts[IDENT_KW_IDX], value, srcSpan, attr.valueSpan || srcSpan, targetMatchableAttrs, boundEvents);
|
|
}
|
|
else if (bindParts[KW_AT_IDX]) {
|
|
this._bindingParser.parseLiteralAttr(name, value, srcSpan, absoluteOffset, attr.valueSpan, targetMatchableAttrs, targetProps);
|
|
}
|
|
else if (bindParts[IDENT_BANANA_BOX_IDX]) {
|
|
this._bindingParser.parsePropertyBinding(bindParts[IDENT_BANANA_BOX_IDX], value, false, srcSpan, absoluteOffset, attr.valueSpan, targetMatchableAttrs, targetProps);
|
|
this._parseAssignmentEvent(bindParts[IDENT_BANANA_BOX_IDX], value, srcSpan, attr.valueSpan || srcSpan, targetMatchableAttrs, boundEvents);
|
|
}
|
|
else if (bindParts[IDENT_PROPERTY_IDX]) {
|
|
this._bindingParser.parsePropertyBinding(bindParts[IDENT_PROPERTY_IDX], value, false, srcSpan, absoluteOffset, attr.valueSpan, targetMatchableAttrs, targetProps);
|
|
}
|
|
else if (bindParts[IDENT_EVENT_IDX]) {
|
|
this._bindingParser.parseEvent(bindParts[IDENT_EVENT_IDX], value, srcSpan, attr.valueSpan || srcSpan, targetMatchableAttrs, boundEvents);
|
|
}
|
|
}
|
|
else {
|
|
hasBinding = this._bindingParser.parsePropertyInterpolation(name, value, srcSpan, attr.valueSpan, targetMatchableAttrs, targetProps);
|
|
}
|
|
if (!hasBinding) {
|
|
this._bindingParser.parseLiteralAttr(name, value, srcSpan, absoluteOffset, attr.valueSpan, targetMatchableAttrs, targetProps);
|
|
}
|
|
targetEvents.push.apply(targetEvents, __spreadArray([], __read(boundEvents.map(function (e) { return BoundEventAst.fromParsedEvent(e); }))));
|
|
return hasBinding;
|
|
};
|
|
TemplateParseVisitor.prototype._normalizeAttributeName = function (attrName) {
|
|
return /^data-/i.test(attrName) ? attrName.substring(5) : attrName;
|
|
};
|
|
TemplateParseVisitor.prototype._parseVariable = function (identifier, value, sourceSpan, targetVars) {
|
|
if (identifier.indexOf('-') > -1) {
|
|
this._reportError("\"-\" is not allowed in variable names", sourceSpan);
|
|
}
|
|
else if (identifier.length === 0) {
|
|
this._reportError("Variable does not have a name", sourceSpan);
|
|
}
|
|
targetVars.push(new VariableAst(identifier, value, sourceSpan));
|
|
};
|
|
TemplateParseVisitor.prototype._parseReference = function (identifier, value, sourceSpan, targetRefs) {
|
|
if (identifier.indexOf('-') > -1) {
|
|
this._reportError("\"-\" is not allowed in reference names", sourceSpan);
|
|
}
|
|
else if (identifier.length === 0) {
|
|
this._reportError("Reference does not have a name", sourceSpan);
|
|
}
|
|
targetRefs.push(new ElementOrDirectiveRef(identifier, value, sourceSpan));
|
|
};
|
|
TemplateParseVisitor.prototype._parseAssignmentEvent = function (name, expression, sourceSpan, valueSpan, targetMatchableAttrs, targetEvents) {
|
|
this._bindingParser.parseEvent(name + "Change", expression + "=$event", sourceSpan, valueSpan, targetMatchableAttrs, targetEvents);
|
|
};
|
|
TemplateParseVisitor.prototype._parseDirectives = function (selectorMatcher, elementCssSelector) {
|
|
var _this = this;
|
|
// Need to sort the directives so that we get consistent results throughout,
|
|
// as selectorMatcher uses Maps inside.
|
|
// Also deduplicate directives as they might match more than one time!
|
|
var directives = newArray(this.directivesIndex.size);
|
|
// Whether any directive selector matches on the element name
|
|
var matchElement = false;
|
|
selectorMatcher.match(elementCssSelector, function (selector, directive) {
|
|
directives[_this.directivesIndex.get(directive)] = directive;
|
|
matchElement = matchElement || selector.hasElementSelector();
|
|
});
|
|
return {
|
|
directives: directives.filter(function (dir) { return !!dir; }),
|
|
matchElement: matchElement,
|
|
};
|
|
};
|
|
TemplateParseVisitor.prototype._createDirectiveAsts = function (isTemplateElement, elementName, directives, props, elementOrDirectiveRefs, elementSourceSpan, targetReferences, targetBoundDirectivePropNames) {
|
|
var _this = this;
|
|
var matchedReferences = new Set();
|
|
var component = null;
|
|
var directiveAsts = directives.map(function (directive) {
|
|
var sourceSpan = new ParseSourceSpan(elementSourceSpan.start, elementSourceSpan.end, elementSourceSpan.fullStart, "Directive " + identifierName(directive.type));
|
|
if (directive.isComponent) {
|
|
component = directive;
|
|
}
|
|
var directiveProperties = [];
|
|
var boundProperties = _this._bindingParser.createDirectiveHostPropertyAsts(directive, elementName, sourceSpan);
|
|
var hostProperties = boundProperties.map(function (prop) { return BoundElementPropertyAst.fromBoundProperty(prop); });
|
|
// Note: We need to check the host properties here as well,
|
|
// as we don't know the element name in the DirectiveWrapperCompiler yet.
|
|
hostProperties = _this._checkPropertiesInSchema(elementName, hostProperties);
|
|
var parsedEvents = _this._bindingParser.createDirectiveHostEventAsts(directive, sourceSpan);
|
|
_this._createDirectivePropertyAsts(directive.inputs, props, directiveProperties, targetBoundDirectivePropNames);
|
|
elementOrDirectiveRefs.forEach(function (elOrDirRef) {
|
|
if ((elOrDirRef.value.length === 0 && directive.isComponent) ||
|
|
(elOrDirRef.isReferenceToDirective(directive))) {
|
|
targetReferences.push(new ReferenceAst(elOrDirRef.name, createTokenForReference(directive.type.reference), elOrDirRef.value, elOrDirRef.sourceSpan));
|
|
matchedReferences.add(elOrDirRef.name);
|
|
}
|
|
});
|
|
var hostEvents = parsedEvents.map(function (e) { return BoundEventAst.fromParsedEvent(e); });
|
|
var contentQueryStartId = _this.contentQueryStartId;
|
|
_this.contentQueryStartId += directive.queries.length;
|
|
return new DirectiveAst(directive, directiveProperties, hostProperties, hostEvents, contentQueryStartId, sourceSpan);
|
|
});
|
|
elementOrDirectiveRefs.forEach(function (elOrDirRef) {
|
|
if (elOrDirRef.value.length > 0) {
|
|
if (!matchedReferences.has(elOrDirRef.name)) {
|
|
_this._reportError("There is no directive with \"exportAs\" set to \"" + elOrDirRef.value + "\"", elOrDirRef.sourceSpan);
|
|
}
|
|
}
|
|
else if (!component) {
|
|
var refToken = null;
|
|
if (isTemplateElement) {
|
|
refToken = createTokenForExternalReference(_this.reflector, Identifiers$1.TemplateRef);
|
|
}
|
|
targetReferences.push(new ReferenceAst(elOrDirRef.name, refToken, elOrDirRef.value, elOrDirRef.sourceSpan));
|
|
}
|
|
});
|
|
return directiveAsts;
|
|
};
|
|
TemplateParseVisitor.prototype._createDirectivePropertyAsts = function (directiveProperties, boundProps, targetBoundDirectiveProps, targetBoundDirectivePropNames) {
|
|
if (directiveProperties) {
|
|
var boundPropsByName_1 = new Map();
|
|
boundProps.forEach(function (boundProp) {
|
|
var prevValue = boundPropsByName_1.get(boundProp.name);
|
|
if (!prevValue || prevValue.isLiteral) {
|
|
// give [a]="b" a higher precedence than a="b" on the same element
|
|
boundPropsByName_1.set(boundProp.name, boundProp);
|
|
}
|
|
});
|
|
Object.keys(directiveProperties).forEach(function (dirProp) {
|
|
var elProp = directiveProperties[dirProp];
|
|
var boundProp = boundPropsByName_1.get(elProp);
|
|
// Bindings are optional, so this binding only needs to be set up if an expression is given.
|
|
if (boundProp) {
|
|
targetBoundDirectivePropNames.add(boundProp.name);
|
|
if (!isEmptyExpression(boundProp.expression)) {
|
|
targetBoundDirectiveProps.push(new BoundDirectivePropertyAst(dirProp, boundProp.name, boundProp.expression, boundProp.sourceSpan));
|
|
}
|
|
}
|
|
});
|
|
}
|
|
};
|
|
TemplateParseVisitor.prototype._createElementPropertyAsts = function (elementName, props, boundDirectivePropNames) {
|
|
var _this = this;
|
|
var boundElementProps = [];
|
|
props.forEach(function (prop) {
|
|
if (!prop.isLiteral && !boundDirectivePropNames.has(prop.name)) {
|
|
var boundProp = _this._bindingParser.createBoundElementProperty(elementName, prop);
|
|
boundElementProps.push(BoundElementPropertyAst.fromBoundProperty(boundProp));
|
|
}
|
|
});
|
|
return this._checkPropertiesInSchema(elementName, boundElementProps);
|
|
};
|
|
TemplateParseVisitor.prototype._findComponentDirectives = function (directives) {
|
|
return directives.filter(function (directive) { return directive.directive.isComponent; });
|
|
};
|
|
TemplateParseVisitor.prototype._findComponentDirectiveNames = function (directives) {
|
|
return this._findComponentDirectives(directives)
|
|
.map(function (directive) { return identifierName(directive.directive.type); });
|
|
};
|
|
TemplateParseVisitor.prototype._assertOnlyOneComponent = function (directives, sourceSpan) {
|
|
var componentTypeNames = this._findComponentDirectiveNames(directives);
|
|
if (componentTypeNames.length > 1) {
|
|
this._reportError("More than one component matched on this element.\n" +
|
|
"Make sure that only one component's selector can match a given element.\n" +
|
|
("Conflicting components: " + componentTypeNames.join(',')), sourceSpan);
|
|
}
|
|
};
|
|
/**
|
|
* Make sure that non-angular tags conform to the schemas.
|
|
*
|
|
* Note: An element is considered an angular tag when at least one directive selector matches the
|
|
* tag name.
|
|
*
|
|
* @param matchElement Whether any directive has matched on the tag name
|
|
* @param element the html element
|
|
*/
|
|
TemplateParseVisitor.prototype._assertElementExists = function (matchElement, element) {
|
|
var elName = element.name.replace(/^:xhtml:/, '');
|
|
if (!matchElement && !this._schemaRegistry.hasElement(elName, this._schemas)) {
|
|
var errorMsg = "'" + elName + "' is not a known element:\n";
|
|
errorMsg += "1. If '" + elName + "' is an Angular component, then verify that it is part of this module.\n";
|
|
if (elName.indexOf('-') > -1) {
|
|
errorMsg += "2. If '" + elName + "' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule.schemas' of this component to suppress this message.";
|
|
}
|
|
else {
|
|
errorMsg +=
|
|
"2. To allow any element add 'NO_ERRORS_SCHEMA' to the '@NgModule.schemas' of this component.";
|
|
}
|
|
this._reportError(errorMsg, element.sourceSpan);
|
|
}
|
|
};
|
|
TemplateParseVisitor.prototype._assertNoComponentsNorElementBindingsOnTemplate = function (directives, elementProps, sourceSpan) {
|
|
var _this = this;
|
|
var componentTypeNames = this._findComponentDirectiveNames(directives);
|
|
if (componentTypeNames.length > 0) {
|
|
this._reportError("Components on an embedded template: " + componentTypeNames.join(','), sourceSpan);
|
|
}
|
|
elementProps.forEach(function (prop) {
|
|
_this._reportError("Property binding " + prop.name + " not used by any directive on an embedded template. Make sure that the property name is spelled correctly and all directives are listed in the \"@NgModule.declarations\".", sourceSpan);
|
|
});
|
|
};
|
|
TemplateParseVisitor.prototype._assertAllEventsPublishedByDirectives = function (directives, events) {
|
|
var _this = this;
|
|
var allDirectiveEvents = new Set();
|
|
directives.forEach(function (directive) {
|
|
Object.keys(directive.directive.outputs).forEach(function (k) {
|
|
var eventName = directive.directive.outputs[k];
|
|
allDirectiveEvents.add(eventName);
|
|
});
|
|
});
|
|
events.forEach(function (event) {
|
|
if (event.target != null || !allDirectiveEvents.has(event.name)) {
|
|
_this._reportError("Event binding " + event
|
|
.fullName + " not emitted by any directive on an embedded template. Make sure that the event name is spelled correctly and all directives are listed in the \"@NgModule.declarations\".", event.sourceSpan);
|
|
}
|
|
});
|
|
};
|
|
TemplateParseVisitor.prototype._checkPropertiesInSchema = function (elementName, boundProps) {
|
|
var _this = this;
|
|
// Note: We can't filter out empty expressions before this method,
|
|
// as we still want to validate them!
|
|
return boundProps.filter(function (boundProp) {
|
|
if (boundProp.type === 0 /* Property */ &&
|
|
!_this._schemaRegistry.hasProperty(elementName, boundProp.name, _this._schemas)) {
|
|
var errorMsg = "Can't bind to '" + boundProp.name + "' since it isn't a known property of '" + elementName + "'.";
|
|
if (elementName.startsWith('ng-')) {
|
|
errorMsg +=
|
|
"\n1. If '" + boundProp
|
|
.name + "' is an Angular directive, then add 'CommonModule' to the '@NgModule.imports' of this component." +
|
|
"\n2. To allow any property add 'NO_ERRORS_SCHEMA' to the '@NgModule.schemas' of this component.";
|
|
}
|
|
else if (elementName.indexOf('-') > -1) {
|
|
errorMsg +=
|
|
"\n1. If '" + elementName + "' is an Angular component and it has '" + boundProp.name + "' input, then verify that it is part of this module." +
|
|
("\n2. If '" + elementName + "' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule.schemas' of this component to suppress this message.") +
|
|
"\n3. To allow any property add 'NO_ERRORS_SCHEMA' to the '@NgModule.schemas' of this component.";
|
|
}
|
|
_this._reportError(errorMsg, boundProp.sourceSpan);
|
|
}
|
|
return !isEmptyExpression(boundProp.value);
|
|
});
|
|
};
|
|
TemplateParseVisitor.prototype._reportError = function (message, sourceSpan, level) {
|
|
if (level === void 0) { level = exports.ParseErrorLevel.ERROR; }
|
|
this._targetErrors.push(new ParseError(sourceSpan, message, level));
|
|
};
|
|
return TemplateParseVisitor;
|
|
}());
|
|
var NonBindableVisitor = /** @class */ (function () {
|
|
function NonBindableVisitor() {
|
|
}
|
|
NonBindableVisitor.prototype.visitElement = function (ast, parent) {
|
|
var preparsedElement = preparseElement(ast);
|
|
if (preparsedElement.type === PreparsedElementType.SCRIPT ||
|
|
preparsedElement.type === PreparsedElementType.STYLE ||
|
|
preparsedElement.type === PreparsedElementType.STYLESHEET) {
|
|
// Skipping <script> for security reasons
|
|
// Skipping <style> and stylesheets as we already processed them
|
|
// in the StyleCompiler
|
|
return null;
|
|
}
|
|
var attrNameAndValues = ast.attrs.map(function (attr) { return [attr.name, attr.value]; });
|
|
var selector = createElementCssSelector(ast.name, attrNameAndValues);
|
|
var ngContentIndex = parent.findNgContentIndex(selector);
|
|
var children = visitAll$1(this, ast.children, EMPTY_ELEMENT_CONTEXT);
|
|
return new ElementAst(ast.name, visitAll$1(this, ast.attrs), [], [], [], [], [], false, [], children, ngContentIndex, ast.sourceSpan, ast.endSourceSpan);
|
|
};
|
|
NonBindableVisitor.prototype.visitComment = function (comment, context) {
|
|
return null;
|
|
};
|
|
NonBindableVisitor.prototype.visitAttribute = function (attribute, context) {
|
|
return new AttrAst(attribute.name, attribute.value, attribute.sourceSpan);
|
|
};
|
|
NonBindableVisitor.prototype.visitText = function (text, parent) {
|
|
var ngContentIndex = parent.findNgContentIndex(TEXT_CSS_SELECTOR());
|
|
return new TextAst(text.value, ngContentIndex, text.sourceSpan);
|
|
};
|
|
NonBindableVisitor.prototype.visitExpansion = function (expansion, context) {
|
|
return expansion;
|
|
};
|
|
NonBindableVisitor.prototype.visitExpansionCase = function (expansionCase, context) {
|
|
return expansionCase;
|
|
};
|
|
return NonBindableVisitor;
|
|
}());
|
|
/**
|
|
* A reference to an element or directive in a template. E.g., the reference in this template:
|
|
*
|
|
* <div #myMenu="coolMenu">
|
|
*
|
|
* would be {name: 'myMenu', value: 'coolMenu', sourceSpan: ...}
|
|
*/
|
|
var ElementOrDirectiveRef = /** @class */ (function () {
|
|
function ElementOrDirectiveRef(name, value, sourceSpan) {
|
|
this.name = name;
|
|
this.value = value;
|
|
this.sourceSpan = sourceSpan;
|
|
}
|
|
/** Gets whether this is a reference to the given directive. */
|
|
ElementOrDirectiveRef.prototype.isReferenceToDirective = function (directive) {
|
|
return splitExportAs(directive.exportAs).indexOf(this.value) !== -1;
|
|
};
|
|
return ElementOrDirectiveRef;
|
|
}());
|
|
/** Splits a raw, potentially comma-delimited `exportAs` value into an array of names. */
|
|
function splitExportAs(exportAs) {
|
|
return exportAs ? exportAs.split(',').map(function (e) { return e.trim(); }) : [];
|
|
}
|
|
function splitClasses(classAttrValue) {
|
|
return classAttrValue.trim().split(/\s+/g);
|
|
}
|
|
var ElementContext = /** @class */ (function () {
|
|
function ElementContext(isTemplateElement, _ngContentIndexMatcher, _wildcardNgContentIndex, providerContext) {
|
|
this.isTemplateElement = isTemplateElement;
|
|
this._ngContentIndexMatcher = _ngContentIndexMatcher;
|
|
this._wildcardNgContentIndex = _wildcardNgContentIndex;
|
|
this.providerContext = providerContext;
|
|
}
|
|
ElementContext.create = function (isTemplateElement, directives, providerContext) {
|
|
var matcher = new SelectorMatcher();
|
|
var wildcardNgContentIndex = null;
|
|
var component = directives.find(function (directive) { return directive.directive.isComponent; });
|
|
if (component) {
|
|
var ngContentSelectors = component.directive.template.ngContentSelectors;
|
|
for (var i = 0; i < ngContentSelectors.length; i++) {
|
|
var selector = ngContentSelectors[i];
|
|
if (selector === '*') {
|
|
wildcardNgContentIndex = i;
|
|
}
|
|
else {
|
|
matcher.addSelectables(CssSelector.parse(ngContentSelectors[i]), i);
|
|
}
|
|
}
|
|
}
|
|
return new ElementContext(isTemplateElement, matcher, wildcardNgContentIndex, providerContext);
|
|
};
|
|
ElementContext.prototype.findNgContentIndex = function (selector) {
|
|
var ngContentIndices = [];
|
|
this._ngContentIndexMatcher.match(selector, function (selector, ngContentIndex) {
|
|
ngContentIndices.push(ngContentIndex);
|
|
});
|
|
ngContentIndices.sort();
|
|
if (this._wildcardNgContentIndex != null) {
|
|
ngContentIndices.push(this._wildcardNgContentIndex);
|
|
}
|
|
return ngContentIndices.length > 0 ? ngContentIndices[0] : null;
|
|
};
|
|
return ElementContext;
|
|
}());
|
|
function createElementCssSelector(elementName, attributes) {
|
|
var cssSelector = new CssSelector();
|
|
var elNameNoNs = splitNsName(elementName)[1];
|
|
cssSelector.setElement(elNameNoNs);
|
|
for (var i = 0; i < attributes.length; i++) {
|
|
var attrName = attributes[i][0];
|
|
var attrNameNoNs = splitNsName(attrName)[1];
|
|
var attrValue = attributes[i][1];
|
|
cssSelector.addAttribute(attrNameNoNs, attrValue);
|
|
if (attrName.toLowerCase() == CLASS_ATTR) {
|
|
var classes = splitClasses(attrValue);
|
|
classes.forEach(function (className) { return cssSelector.addClassName(className); });
|
|
}
|
|
}
|
|
return cssSelector;
|
|
}
|
|
var EMPTY_ELEMENT_CONTEXT = new ElementContext(true, new SelectorMatcher(), null, null);
|
|
var NON_BINDABLE_VISITOR = new NonBindableVisitor();
|
|
function _isEmptyTextNode(node) {
|
|
return node instanceof Text$3 && node.value.trim().length == 0;
|
|
}
|
|
function removeSummaryDuplicates(items) {
|
|
var map = new Map();
|
|
items.forEach(function (item) {
|
|
if (!map.get(item.type.reference)) {
|
|
map.set(item.type.reference, item);
|
|
}
|
|
});
|
|
return Array.from(map.values());
|
|
}
|
|
function isEmptyExpression(ast) {
|
|
if (ast instanceof ASTWithSource) {
|
|
ast = ast.ast;
|
|
}
|
|
return ast instanceof EmptyExpr;
|
|
}
|
|
|
|
/**
|
|
* @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
|
|
*/
|
|
/**
|
|
* Parses string representation of a style and converts it into object literal.
|
|
*
|
|
* @param value string representation of style as used in the `style` attribute in HTML.
|
|
* Example: `color: red; height: auto`.
|
|
* @returns An array of style property name and value pairs, e.g. `['color', 'red', 'height',
|
|
* 'auto']`
|
|
*/
|
|
function parse(value) {
|
|
// we use a string array here instead of a string map
|
|
// because a string-map is not guaranteed to retain the
|
|
// order of the entries whereas a string array can be
|
|
// constructed in a [key, value, key, value] format.
|
|
var styles = [];
|
|
var i = 0;
|
|
var parenDepth = 0;
|
|
var quote = 0 /* QuoteNone */;
|
|
var valueStart = 0;
|
|
var propStart = 0;
|
|
var currentProp = null;
|
|
var valueHasQuotes = false;
|
|
while (i < value.length) {
|
|
var token = value.charCodeAt(i++);
|
|
switch (token) {
|
|
case 40 /* OpenParen */:
|
|
parenDepth++;
|
|
break;
|
|
case 41 /* CloseParen */:
|
|
parenDepth--;
|
|
break;
|
|
case 39 /* QuoteSingle */:
|
|
// valueStart needs to be there since prop values don't
|
|
// have quotes in CSS
|
|
valueHasQuotes = valueHasQuotes || valueStart > 0;
|
|
if (quote === 0 /* QuoteNone */) {
|
|
quote = 39 /* QuoteSingle */;
|
|
}
|
|
else if (quote === 39 /* QuoteSingle */ && value.charCodeAt(i - 1) !== 92 /* BackSlash */) {
|
|
quote = 0 /* QuoteNone */;
|
|
}
|
|
break;
|
|
case 34 /* QuoteDouble */:
|
|
// same logic as above
|
|
valueHasQuotes = valueHasQuotes || valueStart > 0;
|
|
if (quote === 0 /* QuoteNone */) {
|
|
quote = 34 /* QuoteDouble */;
|
|
}
|
|
else if (quote === 34 /* QuoteDouble */ && value.charCodeAt(i - 1) !== 92 /* BackSlash */) {
|
|
quote = 0 /* QuoteNone */;
|
|
}
|
|
break;
|
|
case 58 /* Colon */:
|
|
if (!currentProp && parenDepth === 0 && quote === 0 /* QuoteNone */) {
|
|
currentProp = hyphenate(value.substring(propStart, i - 1).trim());
|
|
valueStart = i;
|
|
}
|
|
break;
|
|
case 59 /* Semicolon */:
|
|
if (currentProp && valueStart > 0 && parenDepth === 0 && quote === 0 /* QuoteNone */) {
|
|
var styleVal = value.substring(valueStart, i - 1).trim();
|
|
styles.push(currentProp, valueHasQuotes ? stripUnnecessaryQuotes(styleVal) : styleVal);
|
|
propStart = i;
|
|
valueStart = 0;
|
|
currentProp = null;
|
|
valueHasQuotes = false;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
if (currentProp && valueStart) {
|
|
var styleVal = value.substr(valueStart).trim();
|
|
styles.push(currentProp, valueHasQuotes ? stripUnnecessaryQuotes(styleVal) : styleVal);
|
|
}
|
|
return styles;
|
|
}
|
|
function stripUnnecessaryQuotes(value) {
|
|
var qS = value.charCodeAt(0);
|
|
var qE = value.charCodeAt(value.length - 1);
|
|
if (qS == qE && (qS == 39 /* QuoteSingle */ || qS == 34 /* QuoteDouble */)) {
|
|
var tempValue = value.substring(1, value.length - 1);
|
|
// special case to avoid using a multi-quoted string that was just chomped
|
|
// (e.g. `font-family: "Verdana", "sans-serif"`)
|
|
if (tempValue.indexOf('\'') == -1 && tempValue.indexOf('"') == -1) {
|
|
value = tempValue;
|
|
}
|
|
}
|
|
return value;
|
|
}
|
|
function hyphenate(value) {
|
|
return value
|
|
.replace(/[a-z][A-Z]/g, function (v) {
|
|
return v.charAt(0) + '-' + v.charAt(1);
|
|
})
|
|
.toLowerCase();
|
|
}
|
|
|
|
var IMPORTANT_FLAG = '!important';
|
|
/**
|
|
* Minimum amount of binding slots required in the runtime for style/class bindings.
|
|
*
|
|
* Styling in Angular uses up two slots in the runtime LView/TData data structures to
|
|
* record binding data, property information and metadata.
|
|
*
|
|
* When a binding is registered it will place the following information in the `LView`:
|
|
*
|
|
* slot 1) binding value
|
|
* slot 2) cached value (all other values collected before it in string form)
|
|
*
|
|
* When a binding is registered it will place the following information in the `TData`:
|
|
*
|
|
* slot 1) prop name
|
|
* slot 2) binding index that points to the previous style/class binding (and some extra config
|
|
* values)
|
|
*
|
|
* Let's imagine we have a binding that looks like so:
|
|
*
|
|
* ```
|
|
* <div [style.width]="x" [style.height]="y">
|
|
* ```
|
|
*
|
|
* Our `LView` and `TData` data-structures look like so:
|
|
*
|
|
* ```typescript
|
|
* LView = [
|
|
* // ...
|
|
* x, // value of x
|
|
* "width: x",
|
|
*
|
|
* y, // value of y
|
|
* "width: x; height: y",
|
|
* // ...
|
|
* ];
|
|
*
|
|
* TData = [
|
|
* // ...
|
|
* "width", // binding slot 20
|
|
* 0,
|
|
*
|
|
* "height",
|
|
* 20,
|
|
* // ...
|
|
* ];
|
|
* ```
|
|
*
|
|
* */
|
|
var MIN_STYLING_BINDING_SLOTS_REQUIRED = 2;
|
|
/**
|
|
* Produces creation/update instructions for all styling bindings (class and style)
|
|
*
|
|
* It also produces the creation instruction to register all initial styling values
|
|
* (which are all the static class="..." and style="..." attribute values that exist
|
|
* on an element within a template).
|
|
*
|
|
* The builder class below handles producing instructions for the following cases:
|
|
*
|
|
* - Static style/class attributes (style="..." and class="...")
|
|
* - Dynamic style/class map bindings ([style]="map" and [class]="map|string")
|
|
* - Dynamic style/class property bindings ([style.prop]="exp" and [class.name]="exp")
|
|
*
|
|
* Due to the complex relationship of all of these cases, the instructions generated
|
|
* for these attributes/properties/bindings must be done so in the correct order. The
|
|
* order which these must be generated is as follows:
|
|
*
|
|
* if (createMode) {
|
|
* styling(...)
|
|
* }
|
|
* if (updateMode) {
|
|
* styleMap(...)
|
|
* classMap(...)
|
|
* styleProp(...)
|
|
* classProp(...)
|
|
* }
|
|
*
|
|
* The creation/update methods within the builder class produce these instructions.
|
|
*/
|
|
var StylingBuilder = /** @class */ (function () {
|
|
function StylingBuilder(_directiveExpr) {
|
|
this._directiveExpr = _directiveExpr;
|
|
/** Whether or not there are any static styling values present */
|
|
this._hasInitialValues = false;
|
|
/**
|
|
* Whether or not there are any styling bindings present
|
|
* (i.e. `[style]`, `[class]`, `[style.prop]` or `[class.name]`)
|
|
*/
|
|
this.hasBindings = false;
|
|
this.hasBindingsWithPipes = false;
|
|
/** the input for [class] (if it exists) */
|
|
this._classMapInput = null;
|
|
/** the input for [style] (if it exists) */
|
|
this._styleMapInput = null;
|
|
/** an array of each [style.prop] input */
|
|
this._singleStyleInputs = null;
|
|
/** an array of each [class.name] input */
|
|
this._singleClassInputs = null;
|
|
this._lastStylingInput = null;
|
|
this._firstStylingInput = null;
|
|
// maps are used instead of hash maps because a Map will
|
|
// retain the ordering of the keys
|
|
/**
|
|
* Represents the location of each style binding in the template
|
|
* (e.g. `<div [style.width]="w" [style.height]="h">` implies
|
|
* that `width=0` and `height=1`)
|
|
*/
|
|
this._stylesIndex = new Map();
|
|
/**
|
|
* Represents the location of each class binding in the template
|
|
* (e.g. `<div [class.big]="b" [class.hidden]="h">` implies
|
|
* that `big=0` and `hidden=1`)
|
|
*/
|
|
this._classesIndex = new Map();
|
|
this._initialStyleValues = [];
|
|
this._initialClassValues = [];
|
|
}
|
|
/**
|
|
* Registers a given input to the styling builder to be later used when producing AOT code.
|
|
*
|
|
* The code below will only accept the input if it is somehow tied to styling (whether it be
|
|
* style/class bindings or static style/class attributes).
|
|
*/
|
|
StylingBuilder.prototype.registerBoundInput = function (input) {
|
|
// [attr.style] or [attr.class] are skipped in the code below,
|
|
// they should not be treated as styling-based bindings since
|
|
// they are intended to be written directly to the attr and
|
|
// will therefore skip all style/class resolution that is present
|
|
// with style="", [style]="" and [style.prop]="", class="",
|
|
// [class.prop]="". [class]="" assignments
|
|
var binding = null;
|
|
var name = input.name;
|
|
switch (input.type) {
|
|
case 0 /* Property */:
|
|
binding = this.registerInputBasedOnName(name, input.value, input.sourceSpan);
|
|
break;
|
|
case 3 /* Style */:
|
|
binding = this.registerStyleInput(name, false, input.value, input.sourceSpan, input.unit);
|
|
break;
|
|
case 2 /* Class */:
|
|
binding = this.registerClassInput(name, false, input.value, input.sourceSpan);
|
|
break;
|
|
}
|
|
return binding ? true : false;
|
|
};
|
|
StylingBuilder.prototype.registerInputBasedOnName = function (name, expression, sourceSpan) {
|
|
var binding = null;
|
|
var prefix = name.substring(0, 6);
|
|
var isStyle = name === 'style' || prefix === 'style.' || prefix === 'style!';
|
|
var isClass = !isStyle && (name === 'class' || prefix === 'class.' || prefix === 'class!');
|
|
if (isStyle || isClass) {
|
|
var isMapBased = name.charAt(5) !== '.'; // style.prop or class.prop makes this a no
|
|
var property = name.substr(isMapBased ? 5 : 6); // the dot explains why there's a +1
|
|
if (isStyle) {
|
|
binding = this.registerStyleInput(property, isMapBased, expression, sourceSpan);
|
|
}
|
|
else {
|
|
binding = this.registerClassInput(property, isMapBased, expression, sourceSpan);
|
|
}
|
|
}
|
|
return binding;
|
|
};
|
|
StylingBuilder.prototype.registerStyleInput = function (name, isMapBased, value, sourceSpan, suffix) {
|
|
if (isEmptyExpression(value)) {
|
|
return null;
|
|
}
|
|
// CSS custom properties are case-sensitive so we shouldn't normalize them.
|
|
// See: https://www.w3.org/TR/css-variables-1/#defining-variables
|
|
if (!isCssCustomProperty(name)) {
|
|
name = hyphenate(name);
|
|
}
|
|
var _a = parseProperty(name), property = _a.property, hasOverrideFlag = _a.hasOverrideFlag, bindingSuffix = _a.suffix;
|
|
suffix = typeof suffix === 'string' && suffix.length !== 0 ? suffix : bindingSuffix;
|
|
var entry = { name: property, suffix: suffix, value: value, sourceSpan: sourceSpan, hasOverrideFlag: hasOverrideFlag };
|
|
if (isMapBased) {
|
|
this._styleMapInput = entry;
|
|
}
|
|
else {
|
|
(this._singleStyleInputs = this._singleStyleInputs || []).push(entry);
|
|
registerIntoMap(this._stylesIndex, property);
|
|
}
|
|
this._lastStylingInput = entry;
|
|
this._firstStylingInput = this._firstStylingInput || entry;
|
|
this._checkForPipes(value);
|
|
this.hasBindings = true;
|
|
return entry;
|
|
};
|
|
StylingBuilder.prototype.registerClassInput = function (name, isMapBased, value, sourceSpan) {
|
|
if (isEmptyExpression(value)) {
|
|
return null;
|
|
}
|
|
var _a = parseProperty(name), property = _a.property, hasOverrideFlag = _a.hasOverrideFlag;
|
|
var entry = { name: property, value: value, sourceSpan: sourceSpan, hasOverrideFlag: hasOverrideFlag, suffix: null };
|
|
if (isMapBased) {
|
|
this._classMapInput = entry;
|
|
}
|
|
else {
|
|
(this._singleClassInputs = this._singleClassInputs || []).push(entry);
|
|
registerIntoMap(this._classesIndex, property);
|
|
}
|
|
this._lastStylingInput = entry;
|
|
this._firstStylingInput = this._firstStylingInput || entry;
|
|
this._checkForPipes(value);
|
|
this.hasBindings = true;
|
|
return entry;
|
|
};
|
|
StylingBuilder.prototype._checkForPipes = function (value) {
|
|
if ((value instanceof ASTWithSource) && (value.ast instanceof BindingPipe)) {
|
|
this.hasBindingsWithPipes = true;
|
|
}
|
|
};
|
|
/**
|
|
* Registers the element's static style string value to the builder.
|
|
*
|
|
* @param value the style string (e.g. `width:100px; height:200px;`)
|
|
*/
|
|
StylingBuilder.prototype.registerStyleAttr = function (value) {
|
|
this._initialStyleValues = parse(value);
|
|
this._hasInitialValues = true;
|
|
};
|
|
/**
|
|
* Registers the element's static class string value to the builder.
|
|
*
|
|
* @param value the className string (e.g. `disabled gold zoom`)
|
|
*/
|
|
StylingBuilder.prototype.registerClassAttr = function (value) {
|
|
this._initialClassValues = value.trim().split(/\s+/g);
|
|
this._hasInitialValues = true;
|
|
};
|
|
/**
|
|
* Appends all styling-related expressions to the provided attrs array.
|
|
*
|
|
* @param attrs an existing array where each of the styling expressions
|
|
* will be inserted into.
|
|
*/
|
|
StylingBuilder.prototype.populateInitialStylingAttrs = function (attrs) {
|
|
// [CLASS_MARKER, 'foo', 'bar', 'baz' ...]
|
|
if (this._initialClassValues.length) {
|
|
attrs.push(literal(1 /* Classes */));
|
|
for (var i = 0; i < this._initialClassValues.length; i++) {
|
|
attrs.push(literal(this._initialClassValues[i]));
|
|
}
|
|
}
|
|
// [STYLE_MARKER, 'width', '200px', 'height', '100px', ...]
|
|
if (this._initialStyleValues.length) {
|
|
attrs.push(literal(2 /* Styles */));
|
|
for (var i = 0; i < this._initialStyleValues.length; i += 2) {
|
|
attrs.push(literal(this._initialStyleValues[i]), literal(this._initialStyleValues[i + 1]));
|
|
}
|
|
}
|
|
};
|
|
/**
|
|
* Builds an instruction with all the expressions and parameters for `elementHostAttrs`.
|
|
*
|
|
* The instruction generation code below is used for producing the AOT statement code which is
|
|
* responsible for registering initial styles (within a directive hostBindings' creation block),
|
|
* as well as any of the provided attribute values, to the directive host element.
|
|
*/
|
|
StylingBuilder.prototype.assignHostAttrs = function (attrs, definitionMap) {
|
|
if (this._directiveExpr && (attrs.length || this._hasInitialValues)) {
|
|
this.populateInitialStylingAttrs(attrs);
|
|
definitionMap.set('hostAttrs', literalArr(attrs));
|
|
}
|
|
};
|
|
/**
|
|
* Builds an instruction with all the expressions and parameters for `classMap`.
|
|
*
|
|
* The instruction data will contain all expressions for `classMap` to function
|
|
* which includes the `[class]` expression params.
|
|
*/
|
|
StylingBuilder.prototype.buildClassMapInstruction = function (valueConverter) {
|
|
if (this._classMapInput) {
|
|
return this._buildMapBasedInstruction(valueConverter, true, this._classMapInput);
|
|
}
|
|
return null;
|
|
};
|
|
/**
|
|
* Builds an instruction with all the expressions and parameters for `styleMap`.
|
|
*
|
|
* The instruction data will contain all expressions for `styleMap` to function
|
|
* which includes the `[style]` expression params.
|
|
*/
|
|
StylingBuilder.prototype.buildStyleMapInstruction = function (valueConverter) {
|
|
if (this._styleMapInput) {
|
|
return this._buildMapBasedInstruction(valueConverter, false, this._styleMapInput);
|
|
}
|
|
return null;
|
|
};
|
|
StylingBuilder.prototype._buildMapBasedInstruction = function (valueConverter, isClassBased, stylingInput) {
|
|
// each styling binding value is stored in the LView
|
|
// map-based bindings allocate two slots: one for the
|
|
// previous binding value and another for the previous
|
|
// className or style attribute value.
|
|
var totalBindingSlotsRequired = MIN_STYLING_BINDING_SLOTS_REQUIRED;
|
|
// these values must be outside of the update block so that they can
|
|
// be evaluated (the AST visit call) during creation time so that any
|
|
// pipes can be picked up in time before the template is built
|
|
var mapValue = stylingInput.value.visit(valueConverter);
|
|
var reference;
|
|
if (mapValue instanceof Interpolation) {
|
|
totalBindingSlotsRequired += mapValue.expressions.length;
|
|
reference = isClassBased ? getClassMapInterpolationExpression(mapValue) :
|
|
getStyleMapInterpolationExpression(mapValue);
|
|
}
|
|
else {
|
|
reference = isClassBased ? Identifiers.classMap : Identifiers.styleMap;
|
|
}
|
|
return {
|
|
reference: reference,
|
|
calls: [{
|
|
supportsInterpolation: true,
|
|
sourceSpan: stylingInput.sourceSpan,
|
|
allocateBindingSlots: totalBindingSlotsRequired,
|
|
params: function (convertFn) {
|
|
var convertResult = convertFn(mapValue);
|
|
var params = Array.isArray(convertResult) ? convertResult : [convertResult];
|
|
return params;
|
|
}
|
|
}]
|
|
};
|
|
};
|
|
StylingBuilder.prototype._buildSingleInputs = function (reference, inputs, valueConverter, getInterpolationExpressionFn, isClassBased) {
|
|
var instructions = [];
|
|
inputs.forEach(function (input) {
|
|
var previousInstruction = instructions[instructions.length - 1];
|
|
var value = input.value.visit(valueConverter);
|
|
var referenceForCall = reference;
|
|
// each styling binding value is stored in the LView
|
|
// but there are two values stored for each binding:
|
|
// 1) the value itself
|
|
// 2) an intermediate value (concatenation of style up to this point).
|
|
// We need to store the intermediate value so that we don't allocate
|
|
// the strings on each CD.
|
|
var totalBindingSlotsRequired = MIN_STYLING_BINDING_SLOTS_REQUIRED;
|
|
if (value instanceof Interpolation) {
|
|
totalBindingSlotsRequired += value.expressions.length;
|
|
if (getInterpolationExpressionFn) {
|
|
referenceForCall = getInterpolationExpressionFn(value);
|
|
}
|
|
}
|
|
var call = {
|
|
sourceSpan: input.sourceSpan,
|
|
allocateBindingSlots: totalBindingSlotsRequired,
|
|
supportsInterpolation: !!getInterpolationExpressionFn,
|
|
params: function (convertFn) {
|
|
// params => stylingProp(propName, value, suffix)
|
|
var params = [];
|
|
params.push(literal(input.name));
|
|
var convertResult = convertFn(value);
|
|
if (Array.isArray(convertResult)) {
|
|
params.push.apply(params, __spreadArray([], __read(convertResult)));
|
|
}
|
|
else {
|
|
params.push(convertResult);
|
|
}
|
|
// [style.prop] bindings may use suffix values (e.g. px, em, etc...), therefore,
|
|
// if that is detected then we need to pass that in as an optional param.
|
|
if (!isClassBased && input.suffix !== null) {
|
|
params.push(literal(input.suffix));
|
|
}
|
|
return params;
|
|
}
|
|
};
|
|
// If we ended up generating a call to the same instruction as the previous styling property
|
|
// we can chain the calls together safely to save some bytes, otherwise we have to generate
|
|
// a separate instruction call. This is primarily a concern with interpolation instructions
|
|
// where we may start off with one `reference`, but end up using another based on the
|
|
// number of interpolations.
|
|
if (previousInstruction && previousInstruction.reference === referenceForCall) {
|
|
previousInstruction.calls.push(call);
|
|
}
|
|
else {
|
|
instructions.push({ reference: referenceForCall, calls: [call] });
|
|
}
|
|
});
|
|
return instructions;
|
|
};
|
|
StylingBuilder.prototype._buildClassInputs = function (valueConverter) {
|
|
if (this._singleClassInputs) {
|
|
return this._buildSingleInputs(Identifiers.classProp, this._singleClassInputs, valueConverter, null, true);
|
|
}
|
|
return [];
|
|
};
|
|
StylingBuilder.prototype._buildStyleInputs = function (valueConverter) {
|
|
if (this._singleStyleInputs) {
|
|
return this._buildSingleInputs(Identifiers.styleProp, this._singleStyleInputs, valueConverter, getStylePropInterpolationExpression, false);
|
|
}
|
|
return [];
|
|
};
|
|
/**
|
|
* Constructs all instructions which contain the expressions that will be placed
|
|
* into the update block of a template function or a directive hostBindings function.
|
|
*/
|
|
StylingBuilder.prototype.buildUpdateLevelInstructions = function (valueConverter) {
|
|
var instructions = [];
|
|
if (this.hasBindings) {
|
|
var styleMapInstruction = this.buildStyleMapInstruction(valueConverter);
|
|
if (styleMapInstruction) {
|
|
instructions.push(styleMapInstruction);
|
|
}
|
|
var classMapInstruction = this.buildClassMapInstruction(valueConverter);
|
|
if (classMapInstruction) {
|
|
instructions.push(classMapInstruction);
|
|
}
|
|
instructions.push.apply(instructions, __spreadArray([], __read(this._buildStyleInputs(valueConverter))));
|
|
instructions.push.apply(instructions, __spreadArray([], __read(this._buildClassInputs(valueConverter))));
|
|
}
|
|
return instructions;
|
|
};
|
|
return StylingBuilder;
|
|
}());
|
|
function registerIntoMap(map, key) {
|
|
if (!map.has(key)) {
|
|
map.set(key, map.size);
|
|
}
|
|
}
|
|
function parseProperty(name) {
|
|
var hasOverrideFlag = false;
|
|
var overrideIndex = name.indexOf(IMPORTANT_FLAG);
|
|
if (overrideIndex !== -1) {
|
|
name = overrideIndex > 0 ? name.substring(0, overrideIndex) : '';
|
|
hasOverrideFlag = true;
|
|
}
|
|
var suffix = null;
|
|
var property = name;
|
|
var unitIndex = name.lastIndexOf('.');
|
|
if (unitIndex > 0) {
|
|
suffix = name.substr(unitIndex + 1);
|
|
property = name.substring(0, unitIndex);
|
|
}
|
|
return { property: property, suffix: suffix, hasOverrideFlag: hasOverrideFlag };
|
|
}
|
|
/**
|
|
* Gets the instruction to generate for an interpolated class map.
|
|
* @param interpolation An Interpolation AST
|
|
*/
|
|
function getClassMapInterpolationExpression(interpolation) {
|
|
switch (getInterpolationArgsLength(interpolation)) {
|
|
case 1:
|
|
return Identifiers.classMap;
|
|
case 3:
|
|
return Identifiers.classMapInterpolate1;
|
|
case 5:
|
|
return Identifiers.classMapInterpolate2;
|
|
case 7:
|
|
return Identifiers.classMapInterpolate3;
|
|
case 9:
|
|
return Identifiers.classMapInterpolate4;
|
|
case 11:
|
|
return Identifiers.classMapInterpolate5;
|
|
case 13:
|
|
return Identifiers.classMapInterpolate6;
|
|
case 15:
|
|
return Identifiers.classMapInterpolate7;
|
|
case 17:
|
|
return Identifiers.classMapInterpolate8;
|
|
default:
|
|
return Identifiers.classMapInterpolateV;
|
|
}
|
|
}
|
|
/**
|
|
* Gets the instruction to generate for an interpolated style map.
|
|
* @param interpolation An Interpolation AST
|
|
*/
|
|
function getStyleMapInterpolationExpression(interpolation) {
|
|
switch (getInterpolationArgsLength(interpolation)) {
|
|
case 1:
|
|
return Identifiers.styleMap;
|
|
case 3:
|
|
return Identifiers.styleMapInterpolate1;
|
|
case 5:
|
|
return Identifiers.styleMapInterpolate2;
|
|
case 7:
|
|
return Identifiers.styleMapInterpolate3;
|
|
case 9:
|
|
return Identifiers.styleMapInterpolate4;
|
|
case 11:
|
|
return Identifiers.styleMapInterpolate5;
|
|
case 13:
|
|
return Identifiers.styleMapInterpolate6;
|
|
case 15:
|
|
return Identifiers.styleMapInterpolate7;
|
|
case 17:
|
|
return Identifiers.styleMapInterpolate8;
|
|
default:
|
|
return Identifiers.styleMapInterpolateV;
|
|
}
|
|
}
|
|
/**
|
|
* Gets the instruction to generate for an interpolated style prop.
|
|
* @param interpolation An Interpolation AST
|
|
*/
|
|
function getStylePropInterpolationExpression(interpolation) {
|
|
switch (getInterpolationArgsLength(interpolation)) {
|
|
case 1:
|
|
return Identifiers.styleProp;
|
|
case 3:
|
|
return Identifiers.stylePropInterpolate1;
|
|
case 5:
|
|
return Identifiers.stylePropInterpolate2;
|
|
case 7:
|
|
return Identifiers.stylePropInterpolate3;
|
|
case 9:
|
|
return Identifiers.stylePropInterpolate4;
|
|
case 11:
|
|
return Identifiers.stylePropInterpolate5;
|
|
case 13:
|
|
return Identifiers.stylePropInterpolate6;
|
|
case 15:
|
|
return Identifiers.stylePropInterpolate7;
|
|
case 17:
|
|
return Identifiers.stylePropInterpolate8;
|
|
default:
|
|
return Identifiers.stylePropInterpolateV;
|
|
}
|
|
}
|
|
/**
|
|
* Checks whether property name is a custom CSS property.
|
|
* See: https://www.w3.org/TR/css-variables-1
|
|
*/
|
|
function isCssCustomProperty(name) {
|
|
return name.startsWith('--');
|
|
}
|
|
|
|
/**
|
|
* @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 (TokenType) {
|
|
TokenType[TokenType["Character"] = 0] = "Character";
|
|
TokenType[TokenType["Identifier"] = 1] = "Identifier";
|
|
TokenType[TokenType["PrivateIdentifier"] = 2] = "PrivateIdentifier";
|
|
TokenType[TokenType["Keyword"] = 3] = "Keyword";
|
|
TokenType[TokenType["String"] = 4] = "String";
|
|
TokenType[TokenType["Operator"] = 5] = "Operator";
|
|
TokenType[TokenType["Number"] = 6] = "Number";
|
|
TokenType[TokenType["Error"] = 7] = "Error";
|
|
})(exports.TokenType || (exports.TokenType = {}));
|
|
var KEYWORDS = ['var', 'let', 'as', 'null', 'undefined', 'true', 'false', 'if', 'else', 'this'];
|
|
var Lexer = /** @class */ (function () {
|
|
function Lexer() {
|
|
}
|
|
Lexer.prototype.tokenize = function (text) {
|
|
var scanner = new _Scanner(text);
|
|
var tokens = [];
|
|
var token = scanner.scanToken();
|
|
while (token != null) {
|
|
tokens.push(token);
|
|
token = scanner.scanToken();
|
|
}
|
|
return tokens;
|
|
};
|
|
return Lexer;
|
|
}());
|
|
var Token = /** @class */ (function () {
|
|
function Token(index, end, type, numValue, strValue) {
|
|
this.index = index;
|
|
this.end = end;
|
|
this.type = type;
|
|
this.numValue = numValue;
|
|
this.strValue = strValue;
|
|
}
|
|
Token.prototype.isCharacter = function (code) {
|
|
return this.type == exports.TokenType.Character && this.numValue == code;
|
|
};
|
|
Token.prototype.isNumber = function () {
|
|
return this.type == exports.TokenType.Number;
|
|
};
|
|
Token.prototype.isString = function () {
|
|
return this.type == exports.TokenType.String;
|
|
};
|
|
Token.prototype.isOperator = function (operator) {
|
|
return this.type == exports.TokenType.Operator && this.strValue == operator;
|
|
};
|
|
Token.prototype.isIdentifier = function () {
|
|
return this.type == exports.TokenType.Identifier;
|
|
};
|
|
Token.prototype.isPrivateIdentifier = function () {
|
|
return this.type == exports.TokenType.PrivateIdentifier;
|
|
};
|
|
Token.prototype.isKeyword = function () {
|
|
return this.type == exports.TokenType.Keyword;
|
|
};
|
|
Token.prototype.isKeywordLet = function () {
|
|
return this.type == exports.TokenType.Keyword && this.strValue == 'let';
|
|
};
|
|
Token.prototype.isKeywordAs = function () {
|
|
return this.type == exports.TokenType.Keyword && this.strValue == 'as';
|
|
};
|
|
Token.prototype.isKeywordNull = function () {
|
|
return this.type == exports.TokenType.Keyword && this.strValue == 'null';
|
|
};
|
|
Token.prototype.isKeywordUndefined = function () {
|
|
return this.type == exports.TokenType.Keyword && this.strValue == 'undefined';
|
|
};
|
|
Token.prototype.isKeywordTrue = function () {
|
|
return this.type == exports.TokenType.Keyword && this.strValue == 'true';
|
|
};
|
|
Token.prototype.isKeywordFalse = function () {
|
|
return this.type == exports.TokenType.Keyword && this.strValue == 'false';
|
|
};
|
|
Token.prototype.isKeywordThis = function () {
|
|
return this.type == exports.TokenType.Keyword && this.strValue == 'this';
|
|
};
|
|
Token.prototype.isError = function () {
|
|
return this.type == exports.TokenType.Error;
|
|
};
|
|
Token.prototype.toNumber = function () {
|
|
return this.type == exports.TokenType.Number ? this.numValue : -1;
|
|
};
|
|
Token.prototype.toString = function () {
|
|
switch (this.type) {
|
|
case exports.TokenType.Character:
|
|
case exports.TokenType.Identifier:
|
|
case exports.TokenType.Keyword:
|
|
case exports.TokenType.Operator:
|
|
case exports.TokenType.PrivateIdentifier:
|
|
case exports.TokenType.String:
|
|
case exports.TokenType.Error:
|
|
return this.strValue;
|
|
case exports.TokenType.Number:
|
|
return this.numValue.toString();
|
|
default:
|
|
return null;
|
|
}
|
|
};
|
|
return Token;
|
|
}());
|
|
function newCharacterToken(index, end, code) {
|
|
return new Token(index, end, exports.TokenType.Character, code, String.fromCharCode(code));
|
|
}
|
|
function newIdentifierToken(index, end, text) {
|
|
return new Token(index, end, exports.TokenType.Identifier, 0, text);
|
|
}
|
|
function newPrivateIdentifierToken(index, end, text) {
|
|
return new Token(index, end, exports.TokenType.PrivateIdentifier, 0, text);
|
|
}
|
|
function newKeywordToken(index, end, text) {
|
|
return new Token(index, end, exports.TokenType.Keyword, 0, text);
|
|
}
|
|
function newOperatorToken(index, end, text) {
|
|
return new Token(index, end, exports.TokenType.Operator, 0, text);
|
|
}
|
|
function newStringToken(index, end, text) {
|
|
return new Token(index, end, exports.TokenType.String, 0, text);
|
|
}
|
|
function newNumberToken(index, end, n) {
|
|
return new Token(index, end, exports.TokenType.Number, n, '');
|
|
}
|
|
function newErrorToken(index, end, message) {
|
|
return new Token(index, end, exports.TokenType.Error, 0, message);
|
|
}
|
|
var EOF = new Token(-1, -1, exports.TokenType.Character, 0, '');
|
|
var _Scanner = /** @class */ (function () {
|
|
function _Scanner(input) {
|
|
this.input = input;
|
|
this.peek = 0;
|
|
this.index = -1;
|
|
this.length = input.length;
|
|
this.advance();
|
|
}
|
|
_Scanner.prototype.advance = function () {
|
|
this.peek = ++this.index >= this.length ? $EOF : this.input.charCodeAt(this.index);
|
|
};
|
|
_Scanner.prototype.scanToken = function () {
|
|
var input = this.input, length = this.length;
|
|
var peek = this.peek, index = this.index;
|
|
// Skip whitespace.
|
|
while (peek <= $SPACE) {
|
|
if (++index >= length) {
|
|
peek = $EOF;
|
|
break;
|
|
}
|
|
else {
|
|
peek = input.charCodeAt(index);
|
|
}
|
|
}
|
|
this.peek = peek;
|
|
this.index = index;
|
|
if (index >= length) {
|
|
return null;
|
|
}
|
|
// Handle identifiers and numbers.
|
|
if (isIdentifierStart(peek))
|
|
return this.scanIdentifier();
|
|
if (isDigit(peek))
|
|
return this.scanNumber(index);
|
|
var start = index;
|
|
switch (peek) {
|
|
case $PERIOD:
|
|
this.advance();
|
|
return isDigit(this.peek) ? this.scanNumber(start) :
|
|
newCharacterToken(start, this.index, $PERIOD);
|
|
case $LPAREN:
|
|
case $RPAREN:
|
|
case $LBRACE:
|
|
case $RBRACE:
|
|
case $LBRACKET:
|
|
case $RBRACKET:
|
|
case $COMMA:
|
|
case $COLON:
|
|
case $SEMICOLON:
|
|
return this.scanCharacter(start, peek);
|
|
case $SQ:
|
|
case $DQ:
|
|
return this.scanString();
|
|
case $HASH:
|
|
return this.scanPrivateIdentifier();
|
|
case $PLUS:
|
|
case $MINUS:
|
|
case $STAR:
|
|
case $SLASH:
|
|
case $PERCENT:
|
|
case $CARET:
|
|
return this.scanOperator(start, String.fromCharCode(peek));
|
|
case $QUESTION:
|
|
return this.scanQuestion(start);
|
|
case $LT:
|
|
case $GT:
|
|
return this.scanComplexOperator(start, String.fromCharCode(peek), $EQ, '=');
|
|
case $BANG:
|
|
case $EQ:
|
|
return this.scanComplexOperator(start, String.fromCharCode(peek), $EQ, '=', $EQ, '=');
|
|
case $AMPERSAND:
|
|
return this.scanComplexOperator(start, '&', $AMPERSAND, '&');
|
|
case $BAR:
|
|
return this.scanComplexOperator(start, '|', $BAR, '|');
|
|
case $NBSP:
|
|
while (isWhitespace(this.peek))
|
|
this.advance();
|
|
return this.scanToken();
|
|
}
|
|
this.advance();
|
|
return this.error("Unexpected character [" + String.fromCharCode(peek) + "]", 0);
|
|
};
|
|
_Scanner.prototype.scanCharacter = function (start, code) {
|
|
this.advance();
|
|
return newCharacterToken(start, this.index, code);
|
|
};
|
|
_Scanner.prototype.scanOperator = function (start, str) {
|
|
this.advance();
|
|
return newOperatorToken(start, this.index, str);
|
|
};
|
|
/**
|
|
* Tokenize a 2/3 char long operator
|
|
*
|
|
* @param start start index in the expression
|
|
* @param one first symbol (always part of the operator)
|
|
* @param twoCode code point for the second symbol
|
|
* @param two second symbol (part of the operator when the second code point matches)
|
|
* @param threeCode code point for the third symbol
|
|
* @param three third symbol (part of the operator when provided and matches source expression)
|
|
*/
|
|
_Scanner.prototype.scanComplexOperator = function (start, one, twoCode, two, threeCode, three) {
|
|
this.advance();
|
|
var str = one;
|
|
if (this.peek == twoCode) {
|
|
this.advance();
|
|
str += two;
|
|
}
|
|
if (threeCode != null && this.peek == threeCode) {
|
|
this.advance();
|
|
str += three;
|
|
}
|
|
return newOperatorToken(start, this.index, str);
|
|
};
|
|
_Scanner.prototype.scanIdentifier = function () {
|
|
var start = this.index;
|
|
this.advance();
|
|
while (isIdentifierPart(this.peek))
|
|
this.advance();
|
|
var str = this.input.substring(start, this.index);
|
|
return KEYWORDS.indexOf(str) > -1 ? newKeywordToken(start, this.index, str) :
|
|
newIdentifierToken(start, this.index, str);
|
|
};
|
|
/** Scans an ECMAScript private identifier. */
|
|
_Scanner.prototype.scanPrivateIdentifier = function () {
|
|
var start = this.index;
|
|
this.advance();
|
|
if (!isIdentifierStart(this.peek)) {
|
|
return this.error('Invalid character [#]', -1);
|
|
}
|
|
while (isIdentifierPart(this.peek))
|
|
this.advance();
|
|
var identifierName = this.input.substring(start, this.index);
|
|
return newPrivateIdentifierToken(start, this.index, identifierName);
|
|
};
|
|
_Scanner.prototype.scanNumber = function (start) {
|
|
var simple = (this.index === start);
|
|
var hasSeparators = false;
|
|
this.advance(); // Skip initial digit.
|
|
while (true) {
|
|
if (isDigit(this.peek)) {
|
|
// Do nothing.
|
|
}
|
|
else if (this.peek === $_) {
|
|
// Separators are only valid when they're surrounded by digits. E.g. `1_0_1` is
|
|
// valid while `_101` and `101_` are not. The separator can't be next to the decimal
|
|
// point or another separator either. Note that it's unlikely that we'll hit a case where
|
|
// the underscore is at the start, because that's a valid identifier and it will be picked
|
|
// up earlier in the parsing. We validate for it anyway just in case.
|
|
if (!isDigit(this.input.charCodeAt(this.index - 1)) ||
|
|
!isDigit(this.input.charCodeAt(this.index + 1))) {
|
|
return this.error('Invalid numeric separator', 0);
|
|
}
|
|
hasSeparators = true;
|
|
}
|
|
else if (this.peek === $PERIOD) {
|
|
simple = false;
|
|
}
|
|
else if (isExponentStart(this.peek)) {
|
|
this.advance();
|
|
if (isExponentSign(this.peek))
|
|
this.advance();
|
|
if (!isDigit(this.peek))
|
|
return this.error('Invalid exponent', -1);
|
|
simple = false;
|
|
}
|
|
else {
|
|
break;
|
|
}
|
|
this.advance();
|
|
}
|
|
var str = this.input.substring(start, this.index);
|
|
if (hasSeparators) {
|
|
str = str.replace(/_/g, '');
|
|
}
|
|
var value = simple ? parseIntAutoRadix(str) : parseFloat(str);
|
|
return newNumberToken(start, this.index, value);
|
|
};
|
|
_Scanner.prototype.scanString = function () {
|
|
var start = this.index;
|
|
var quote = this.peek;
|
|
this.advance(); // Skip initial quote.
|
|
var buffer = '';
|
|
var marker = this.index;
|
|
var input = this.input;
|
|
while (this.peek != quote) {
|
|
if (this.peek == $BACKSLASH) {
|
|
buffer += input.substring(marker, this.index);
|
|
this.advance();
|
|
var unescapedCode = void 0;
|
|
// Workaround for TS2.1-introduced type strictness
|
|
this.peek = this.peek;
|
|
if (this.peek == $u) {
|
|
// 4 character hex code for unicode character.
|
|
var hex = input.substring(this.index + 1, this.index + 5);
|
|
if (/^[0-9a-f]+$/i.test(hex)) {
|
|
unescapedCode = parseInt(hex, 16);
|
|
}
|
|
else {
|
|
return this.error("Invalid unicode escape [\\u" + hex + "]", 0);
|
|
}
|
|
for (var i = 0; i < 5; i++) {
|
|
this.advance();
|
|
}
|
|
}
|
|
else {
|
|
unescapedCode = unescape(this.peek);
|
|
this.advance();
|
|
}
|
|
buffer += String.fromCharCode(unescapedCode);
|
|
marker = this.index;
|
|
}
|
|
else if (this.peek == $EOF) {
|
|
return this.error('Unterminated quote', 0);
|
|
}
|
|
else {
|
|
this.advance();
|
|
}
|
|
}
|
|
var last = input.substring(marker, this.index);
|
|
this.advance(); // Skip terminating quote.
|
|
return newStringToken(start, this.index, buffer + last);
|
|
};
|
|
_Scanner.prototype.scanQuestion = function (start) {
|
|
this.advance();
|
|
var str = '?';
|
|
// Either `a ?? b` or 'a?.b'.
|
|
if (this.peek === $QUESTION || this.peek === $PERIOD) {
|
|
str += this.peek === $PERIOD ? '.' : '?';
|
|
this.advance();
|
|
}
|
|
return newOperatorToken(start, this.index, str);
|
|
};
|
|
_Scanner.prototype.error = function (message, offset) {
|
|
var position = this.index + offset;
|
|
return newErrorToken(position, this.index, "Lexer Error: " + message + " at column " + position + " in expression [" + this.input + "]");
|
|
};
|
|
return _Scanner;
|
|
}());
|
|
function isIdentifierStart(code) {
|
|
return ($a <= code && code <= $z) || ($A <= code && code <= $Z) ||
|
|
(code == $_) || (code == $$);
|
|
}
|
|
function isIdentifier(input) {
|
|
if (input.length == 0)
|
|
return false;
|
|
var scanner = new _Scanner(input);
|
|
if (!isIdentifierStart(scanner.peek))
|
|
return false;
|
|
scanner.advance();
|
|
while (scanner.peek !== $EOF) {
|
|
if (!isIdentifierPart(scanner.peek))
|
|
return false;
|
|
scanner.advance();
|
|
}
|
|
return true;
|
|
}
|
|
function isIdentifierPart(code) {
|
|
return isAsciiLetter(code) || isDigit(code) || (code == $_) ||
|
|
(code == $$);
|
|
}
|
|
function isExponentStart(code) {
|
|
return code == $e || code == $E;
|
|
}
|
|
function isExponentSign(code) {
|
|
return code == $MINUS || code == $PLUS;
|
|
}
|
|
function unescape(code) {
|
|
switch (code) {
|
|
case $n:
|
|
return $LF;
|
|
case $f:
|
|
return $FF;
|
|
case $r:
|
|
return $CR;
|
|
case $t:
|
|
return $TAB;
|
|
case $v:
|
|
return $VTAB;
|
|
default:
|
|
return code;
|
|
}
|
|
}
|
|
function parseIntAutoRadix(text) {
|
|
var result = parseInt(text);
|
|
if (isNaN(result)) {
|
|
throw new Error('Invalid integer literal when parsing ' + text);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
var SplitInterpolation = /** @class */ (function () {
|
|
function SplitInterpolation(strings, expressions, offsets) {
|
|
this.strings = strings;
|
|
this.expressions = expressions;
|
|
this.offsets = offsets;
|
|
}
|
|
return SplitInterpolation;
|
|
}());
|
|
var TemplateBindingParseResult = /** @class */ (function () {
|
|
function TemplateBindingParseResult(templateBindings, warnings, errors) {
|
|
this.templateBindings = templateBindings;
|
|
this.warnings = warnings;
|
|
this.errors = errors;
|
|
}
|
|
return TemplateBindingParseResult;
|
|
}());
|
|
var Parser$1 = /** @class */ (function () {
|
|
function Parser(_lexer) {
|
|
this._lexer = _lexer;
|
|
this.errors = [];
|
|
this.simpleExpressionChecker = SimpleExpressionChecker;
|
|
}
|
|
Parser.prototype.parseAction = function (input, location, absoluteOffset, interpolationConfig) {
|
|
if (interpolationConfig === void 0) { interpolationConfig = DEFAULT_INTERPOLATION_CONFIG; }
|
|
this._checkNoInterpolation(input, location, interpolationConfig);
|
|
var sourceToLex = this._stripComments(input);
|
|
var tokens = this._lexer.tokenize(this._stripComments(input));
|
|
var ast = new _ParseAST(input, location, absoluteOffset, tokens, sourceToLex.length, true, this.errors, input.length - sourceToLex.length)
|
|
.parseChain();
|
|
return new ASTWithSource(ast, input, location, absoluteOffset, this.errors);
|
|
};
|
|
Parser.prototype.parseBinding = function (input, location, absoluteOffset, interpolationConfig) {
|
|
if (interpolationConfig === void 0) { interpolationConfig = DEFAULT_INTERPOLATION_CONFIG; }
|
|
var ast = this._parseBindingAst(input, location, absoluteOffset, interpolationConfig);
|
|
return new ASTWithSource(ast, input, location, absoluteOffset, this.errors);
|
|
};
|
|
Parser.prototype.checkSimpleExpression = function (ast) {
|
|
var checker = new this.simpleExpressionChecker();
|
|
ast.visit(checker);
|
|
return checker.errors;
|
|
};
|
|
Parser.prototype.parseSimpleBinding = function (input, location, absoluteOffset, interpolationConfig) {
|
|
if (interpolationConfig === void 0) { interpolationConfig = DEFAULT_INTERPOLATION_CONFIG; }
|
|
var ast = this._parseBindingAst(input, location, absoluteOffset, interpolationConfig);
|
|
var errors = this.checkSimpleExpression(ast);
|
|
if (errors.length > 0) {
|
|
this._reportError("Host binding expression cannot contain " + errors.join(' '), input, location);
|
|
}
|
|
return new ASTWithSource(ast, input, location, absoluteOffset, this.errors);
|
|
};
|
|
Parser.prototype._reportError = function (message, input, errLocation, ctxLocation) {
|
|
this.errors.push(new ParserError(message, input, errLocation, ctxLocation));
|
|
};
|
|
Parser.prototype._parseBindingAst = function (input, location, absoluteOffset, interpolationConfig) {
|
|
// Quotes expressions use 3rd-party expression language. We don't want to use
|
|
// our lexer or parser for that, so we check for that ahead of time.
|
|
var quote = this._parseQuote(input, location, absoluteOffset);
|
|
if (quote != null) {
|
|
return quote;
|
|
}
|
|
this._checkNoInterpolation(input, location, interpolationConfig);
|
|
var sourceToLex = this._stripComments(input);
|
|
var tokens = this._lexer.tokenize(sourceToLex);
|
|
return new _ParseAST(input, location, absoluteOffset, tokens, sourceToLex.length, false, this.errors, input.length - sourceToLex.length)
|
|
.parseChain();
|
|
};
|
|
Parser.prototype._parseQuote = function (input, location, absoluteOffset) {
|
|
if (input == null)
|
|
return null;
|
|
var prefixSeparatorIndex = input.indexOf(':');
|
|
if (prefixSeparatorIndex == -1)
|
|
return null;
|
|
var prefix = input.substring(0, prefixSeparatorIndex).trim();
|
|
if (!isIdentifier(prefix))
|
|
return null;
|
|
var uninterpretedExpression = input.substring(prefixSeparatorIndex + 1);
|
|
var span = new ParseSpan(0, input.length);
|
|
return new Quote(span, span.toAbsolute(absoluteOffset), prefix, uninterpretedExpression, location);
|
|
};
|
|
/**
|
|
* Parse microsyntax template expression and return a list of bindings or
|
|
* parsing errors in case the given expression is invalid.
|
|
*
|
|
* For example,
|
|
* ```
|
|
* <div *ngFor="let item of items">
|
|
* ^ ^ absoluteValueOffset for `templateValue`
|
|
* absoluteKeyOffset for `templateKey`
|
|
* ```
|
|
* contains three bindings:
|
|
* 1. ngFor -> null
|
|
* 2. item -> NgForOfContext.$implicit
|
|
* 3. ngForOf -> items
|
|
*
|
|
* This is apparent from the de-sugared template:
|
|
* ```
|
|
* <ng-template ngFor let-item [ngForOf]="items">
|
|
* ```
|
|
*
|
|
* @param templateKey name of directive, without the * prefix. For example: ngIf, ngFor
|
|
* @param templateValue RHS of the microsyntax attribute
|
|
* @param templateUrl template filename if it's external, component filename if it's inline
|
|
* @param absoluteKeyOffset start of the `templateKey`
|
|
* @param absoluteValueOffset start of the `templateValue`
|
|
*/
|
|
Parser.prototype.parseTemplateBindings = function (templateKey, templateValue, templateUrl, absoluteKeyOffset, absoluteValueOffset) {
|
|
var tokens = this._lexer.tokenize(templateValue);
|
|
var parser = new _ParseAST(templateValue, templateUrl, absoluteValueOffset, tokens, templateValue.length, false /* parseAction */, this.errors, 0 /* relative offset */);
|
|
return parser.parseTemplateBindings({
|
|
source: templateKey,
|
|
span: new AbsoluteSourceSpan(absoluteKeyOffset, absoluteKeyOffset + templateKey.length),
|
|
});
|
|
};
|
|
Parser.prototype.parseInterpolation = function (input, location, absoluteOffset, interpolationConfig) {
|
|
if (interpolationConfig === void 0) { interpolationConfig = DEFAULT_INTERPOLATION_CONFIG; }
|
|
var _b = this.splitInterpolation(input, location, interpolationConfig), strings = _b.strings, expressions = _b.expressions, offsets = _b.offsets;
|
|
if (expressions.length === 0)
|
|
return null;
|
|
var expressionNodes = [];
|
|
for (var i = 0; i < expressions.length; ++i) {
|
|
var expressionText = expressions[i].text;
|
|
var sourceToLex = this._stripComments(expressionText);
|
|
var tokens = this._lexer.tokenize(sourceToLex);
|
|
var ast = new _ParseAST(input, location, absoluteOffset, tokens, sourceToLex.length, false, this.errors, offsets[i] + (expressionText.length - sourceToLex.length))
|
|
.parseChain();
|
|
expressionNodes.push(ast);
|
|
}
|
|
return this.createInterpolationAst(strings.map(function (s) { return s.text; }), expressionNodes, input, location, absoluteOffset);
|
|
};
|
|
/**
|
|
* Similar to `parseInterpolation`, but treats the provided string as a single expression
|
|
* element that would normally appear within the interpolation prefix and suffix (`{{` and `}}`).
|
|
* This is used for parsing the switch expression in ICUs.
|
|
*/
|
|
Parser.prototype.parseInterpolationExpression = function (expression, location, absoluteOffset) {
|
|
var sourceToLex = this._stripComments(expression);
|
|
var tokens = this._lexer.tokenize(sourceToLex);
|
|
var ast = new _ParseAST(expression, location, absoluteOffset, tokens, sourceToLex.length,
|
|
/* parseAction */ false, this.errors, 0)
|
|
.parseChain();
|
|
var strings = ['', '']; // The prefix and suffix strings are both empty
|
|
return this.createInterpolationAst(strings, [ast], expression, location, absoluteOffset);
|
|
};
|
|
Parser.prototype.createInterpolationAst = function (strings, expressions, input, location, absoluteOffset) {
|
|
var span = new ParseSpan(0, input.length);
|
|
var interpolation = new Interpolation(span, span.toAbsolute(absoluteOffset), strings, expressions);
|
|
return new ASTWithSource(interpolation, input, location, absoluteOffset, this.errors);
|
|
};
|
|
/**
|
|
* Splits a string of text into "raw" text segments and expressions present in interpolations in
|
|
* the string.
|
|
* Returns `null` if there are no interpolations, otherwise a
|
|
* `SplitInterpolation` with splits that look like
|
|
* <raw text> <expression> <raw text> ... <raw text> <expression> <raw text>
|
|
*/
|
|
Parser.prototype.splitInterpolation = function (input, location, interpolationConfig) {
|
|
if (interpolationConfig === void 0) { interpolationConfig = DEFAULT_INTERPOLATION_CONFIG; }
|
|
var strings = [];
|
|
var expressions = [];
|
|
var offsets = [];
|
|
var i = 0;
|
|
var atInterpolation = false;
|
|
var extendLastString = false;
|
|
var interpStart = interpolationConfig.start, interpEnd = interpolationConfig.end;
|
|
while (i < input.length) {
|
|
if (!atInterpolation) {
|
|
// parse until starting {{
|
|
var start = i;
|
|
i = input.indexOf(interpStart, i);
|
|
if (i === -1) {
|
|
i = input.length;
|
|
}
|
|
var text = input.substring(start, i);
|
|
strings.push({ text: text, start: start, end: i });
|
|
atInterpolation = true;
|
|
}
|
|
else {
|
|
// parse from starting {{ to ending }} while ignoring content inside quotes.
|
|
var fullStart = i;
|
|
var exprStart = fullStart + interpStart.length;
|
|
var exprEnd = this._getInterpolationEndIndex(input, interpEnd, exprStart);
|
|
if (exprEnd === -1) {
|
|
// Could not find the end of the interpolation; do not parse an expression.
|
|
// Instead we should extend the content on the last raw string.
|
|
atInterpolation = false;
|
|
extendLastString = true;
|
|
break;
|
|
}
|
|
var fullEnd = exprEnd + interpEnd.length;
|
|
var text = input.substring(exprStart, exprEnd);
|
|
if (text.trim().length === 0) {
|
|
this._reportError('Blank expressions are not allowed in interpolated strings', input, "at column " + i + " in", location);
|
|
}
|
|
expressions.push({ text: text, start: fullStart, end: fullEnd });
|
|
offsets.push(exprStart);
|
|
i = fullEnd;
|
|
atInterpolation = false;
|
|
}
|
|
}
|
|
if (!atInterpolation) {
|
|
// If we are now at a text section, add the remaining content as a raw string.
|
|
if (extendLastString) {
|
|
var piece = strings[strings.length - 1];
|
|
piece.text += input.substring(i);
|
|
piece.end = input.length;
|
|
}
|
|
else {
|
|
strings.push({ text: input.substring(i), start: i, end: input.length });
|
|
}
|
|
}
|
|
return new SplitInterpolation(strings, expressions, offsets);
|
|
};
|
|
Parser.prototype.wrapLiteralPrimitive = function (input, location, absoluteOffset) {
|
|
var span = new ParseSpan(0, input == null ? 0 : input.length);
|
|
return new ASTWithSource(new LiteralPrimitive(span, span.toAbsolute(absoluteOffset), input), input, location, absoluteOffset, this.errors);
|
|
};
|
|
Parser.prototype._stripComments = function (input) {
|
|
var i = this._commentStart(input);
|
|
return i != null ? input.substring(0, i).trim() : input;
|
|
};
|
|
Parser.prototype._commentStart = function (input) {
|
|
var outerQuote = null;
|
|
for (var i = 0; i < input.length - 1; i++) {
|
|
var char = input.charCodeAt(i);
|
|
var nextChar = input.charCodeAt(i + 1);
|
|
if (char === $SLASH && nextChar == $SLASH && outerQuote == null)
|
|
return i;
|
|
if (outerQuote === char) {
|
|
outerQuote = null;
|
|
}
|
|
else if (outerQuote == null && isQuote(char)) {
|
|
outerQuote = char;
|
|
}
|
|
}
|
|
return null;
|
|
};
|
|
Parser.prototype._checkNoInterpolation = function (input, location, _b) {
|
|
var e_1, _c;
|
|
var start = _b.start, end = _b.end;
|
|
var startIndex = -1;
|
|
var endIndex = -1;
|
|
try {
|
|
for (var _d = __values(this._forEachUnquotedChar(input, 0)), _e = _d.next(); !_e.done; _e = _d.next()) {
|
|
var charIndex = _e.value;
|
|
if (startIndex === -1) {
|
|
if (input.startsWith(start)) {
|
|
startIndex = charIndex;
|
|
}
|
|
}
|
|
else {
|
|
endIndex = this._getInterpolationEndIndex(input, end, charIndex);
|
|
if (endIndex > -1) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
finally {
|
|
try {
|
|
if (_e && !_e.done && (_c = _d.return)) _c.call(_d);
|
|
}
|
|
finally { if (e_1) throw e_1.error; }
|
|
}
|
|
if (startIndex > -1 && endIndex > -1) {
|
|
this._reportError("Got interpolation (" + start + end + ") where expression was expected", input, "at column " + startIndex + " in", location);
|
|
}
|
|
};
|
|
/**
|
|
* Finds the index of the end of an interpolation expression
|
|
* while ignoring comments and quoted content.
|
|
*/
|
|
Parser.prototype._getInterpolationEndIndex = function (input, expressionEnd, start) {
|
|
var e_2, _b;
|
|
try {
|
|
for (var _c = __values(this._forEachUnquotedChar(input, start)), _d = _c.next(); !_d.done; _d = _c.next()) {
|
|
var charIndex = _d.value;
|
|
if (input.startsWith(expressionEnd, charIndex)) {
|
|
return charIndex;
|
|
}
|
|
// Nothing else in the expression matters after we've
|
|
// hit a comment so look directly for the end token.
|
|
if (input.startsWith('//', charIndex)) {
|
|
return input.indexOf(expressionEnd, charIndex);
|
|
}
|
|
}
|
|
}
|
|
catch (e_2_1) { e_2 = { error: e_2_1 }; }
|
|
finally {
|
|
try {
|
|
if (_d && !_d.done && (_b = _c.return)) _b.call(_c);
|
|
}
|
|
finally { if (e_2) throw e_2.error; }
|
|
}
|
|
return -1;
|
|
};
|
|
/**
|
|
* Generator used to iterate over the character indexes of a string that are outside of quotes.
|
|
* @param input String to loop through.
|
|
* @param start Index within the string at which to start.
|
|
*/
|
|
Parser.prototype._forEachUnquotedChar = function (input, start) {
|
|
var currentQuote, escapeCount, i, char;
|
|
return __generator(this, function (_b) {
|
|
switch (_b.label) {
|
|
case 0:
|
|
currentQuote = null;
|
|
escapeCount = 0;
|
|
i = start;
|
|
_b.label = 1;
|
|
case 1:
|
|
if (!(i < input.length)) return [3 /*break*/, 6];
|
|
char = input[i];
|
|
if (!(isQuote(input.charCodeAt(i)) && (currentQuote === null || currentQuote === char) &&
|
|
escapeCount % 2 === 0)) return [3 /*break*/, 2];
|
|
currentQuote = currentQuote === null ? char : null;
|
|
return [3 /*break*/, 4];
|
|
case 2:
|
|
if (!(currentQuote === null)) return [3 /*break*/, 4];
|
|
return [4 /*yield*/, i];
|
|
case 3:
|
|
_b.sent();
|
|
_b.label = 4;
|
|
case 4:
|
|
escapeCount = char === '\\' ? escapeCount + 1 : 0;
|
|
_b.label = 5;
|
|
case 5:
|
|
i++;
|
|
return [3 /*break*/, 1];
|
|
case 6: return [2 /*return*/];
|
|
}
|
|
});
|
|
};
|
|
return Parser;
|
|
}());
|
|
var IvyParser = /** @class */ (function (_super) {
|
|
__extends(IvyParser, _super);
|
|
function IvyParser() {
|
|
var _this = _super.apply(this, __spreadArray([], __read(arguments))) || this;
|
|
_this.simpleExpressionChecker = IvySimpleExpressionChecker;
|
|
return _this;
|
|
}
|
|
return IvyParser;
|
|
}(Parser$1));
|
|
/** Describes a stateful context an expression parser is in. */
|
|
var ParseContextFlags;
|
|
(function (ParseContextFlags) {
|
|
ParseContextFlags[ParseContextFlags["None"] = 0] = "None";
|
|
/**
|
|
* A Writable context is one in which a value may be written to an lvalue.
|
|
* For example, after we see a property access, we may expect a write to the
|
|
* property via the "=" operator.
|
|
* prop
|
|
* ^ possible "=" after
|
|
*/
|
|
ParseContextFlags[ParseContextFlags["Writable"] = 1] = "Writable";
|
|
})(ParseContextFlags || (ParseContextFlags = {}));
|
|
var _ParseAST = /** @class */ (function () {
|
|
function _ParseAST(input, location, absoluteOffset, tokens, inputLength, parseAction, errors, offset) {
|
|
this.input = input;
|
|
this.location = location;
|
|
this.absoluteOffset = absoluteOffset;
|
|
this.tokens = tokens;
|
|
this.inputLength = inputLength;
|
|
this.parseAction = parseAction;
|
|
this.errors = errors;
|
|
this.offset = offset;
|
|
this.rparensExpected = 0;
|
|
this.rbracketsExpected = 0;
|
|
this.rbracesExpected = 0;
|
|
this.context = ParseContextFlags.None;
|
|
// Cache of expression start and input indeces to the absolute source span they map to, used to
|
|
// prevent creating superfluous source spans in `sourceSpan`.
|
|
// A serial of the expression start and input index is used for mapping because both are stateful
|
|
// and may change for subsequent expressions visited by the parser.
|
|
this.sourceSpanCache = new Map();
|
|
this.index = 0;
|
|
}
|
|
_ParseAST.prototype.peek = function (offset) {
|
|
var i = this.index + offset;
|
|
return i < this.tokens.length ? this.tokens[i] : EOF;
|
|
};
|
|
Object.defineProperty(_ParseAST.prototype, "next", {
|
|
get: function () {
|
|
return this.peek(0);
|
|
},
|
|
enumerable: false,
|
|
configurable: true
|
|
});
|
|
Object.defineProperty(_ParseAST.prototype, "atEOF", {
|
|
/** Whether all the parser input has been processed. */
|
|
get: function () {
|
|
return this.index >= this.tokens.length;
|
|
},
|
|
enumerable: false,
|
|
configurable: true
|
|
});
|
|
Object.defineProperty(_ParseAST.prototype, "inputIndex", {
|
|
/**
|
|
* Index of the next token to be processed, or the end of the last token if all have been
|
|
* processed.
|
|
*/
|
|
get: function () {
|
|
return this.atEOF ? this.currentEndIndex : this.next.index + this.offset;
|
|
},
|
|
enumerable: false,
|
|
configurable: true
|
|
});
|
|
Object.defineProperty(_ParseAST.prototype, "currentEndIndex", {
|
|
/**
|
|
* End index of the last processed token, or the start of the first token if none have been
|
|
* processed.
|
|
*/
|
|
get: function () {
|
|
if (this.index > 0) {
|
|
var curToken = this.peek(-1);
|
|
return curToken.end + this.offset;
|
|
}
|
|
// No tokens have been processed yet; return the next token's start or the length of the input
|
|
// if there is no token.
|
|
if (this.tokens.length === 0) {
|
|
return this.inputLength + this.offset;
|
|
}
|
|
return this.next.index + this.offset;
|
|
},
|
|
enumerable: false,
|
|
configurable: true
|
|
});
|
|
Object.defineProperty(_ParseAST.prototype, "currentAbsoluteOffset", {
|
|
/**
|
|
* Returns the absolute offset of the start of the current token.
|
|
*/
|
|
get: function () {
|
|
return this.absoluteOffset + this.inputIndex;
|
|
},
|
|
enumerable: false,
|
|
configurable: true
|
|
});
|
|
/**
|
|
* Retrieve a `ParseSpan` from `start` to the current position (or to `artificialEndIndex` if
|
|
* provided).
|
|
*
|
|
* @param start Position from which the `ParseSpan` will start.
|
|
* @param artificialEndIndex Optional ending index to be used if provided (and if greater than the
|
|
* natural ending index)
|
|
*/
|
|
_ParseAST.prototype.span = function (start, artificialEndIndex) {
|
|
var endIndex = this.currentEndIndex;
|
|
if (artificialEndIndex !== undefined && artificialEndIndex > this.currentEndIndex) {
|
|
endIndex = artificialEndIndex;
|
|
}
|
|
// In some unusual parsing scenarios (like when certain tokens are missing and an `EmptyExpr` is
|
|
// being created), the current token may already be advanced beyond the `currentEndIndex`. This
|
|
// appears to be a deep-seated parser bug.
|
|
//
|
|
// As a workaround for now, swap the start and end indices to ensure a valid `ParseSpan`.
|
|
// TODO(alxhub): fix the bug upstream in the parser state, and remove this workaround.
|
|
if (start > endIndex) {
|
|
var tmp = endIndex;
|
|
endIndex = start;
|
|
start = tmp;
|
|
}
|
|
return new ParseSpan(start, endIndex);
|
|
};
|
|
_ParseAST.prototype.sourceSpan = function (start, artificialEndIndex) {
|
|
var serial = start + "@" + this.inputIndex + ":" + artificialEndIndex;
|
|
if (!this.sourceSpanCache.has(serial)) {
|
|
this.sourceSpanCache.set(serial, this.span(start, artificialEndIndex).toAbsolute(this.absoluteOffset));
|
|
}
|
|
return this.sourceSpanCache.get(serial);
|
|
};
|
|
_ParseAST.prototype.advance = function () {
|
|
this.index++;
|
|
};
|
|
/**
|
|
* Executes a callback in the provided context.
|
|
*/
|
|
_ParseAST.prototype.withContext = function (context, cb) {
|
|
this.context |= context;
|
|
var ret = cb();
|
|
this.context ^= context;
|
|
return ret;
|
|
};
|
|
_ParseAST.prototype.consumeOptionalCharacter = function (code) {
|
|
if (this.next.isCharacter(code)) {
|
|
this.advance();
|
|
return true;
|
|
}
|
|
else {
|
|
return false;
|
|
}
|
|
};
|
|
_ParseAST.prototype.peekKeywordLet = function () {
|
|
return this.next.isKeywordLet();
|
|
};
|
|
_ParseAST.prototype.peekKeywordAs = function () {
|
|
return this.next.isKeywordAs();
|
|
};
|
|
/**
|
|
* Consumes an expected character, otherwise emits an error about the missing expected character
|
|
* and skips over the token stream until reaching a recoverable point.
|
|
*
|
|
* See `this.error` and `this.skip` for more details.
|
|
*/
|
|
_ParseAST.prototype.expectCharacter = function (code) {
|
|
if (this.consumeOptionalCharacter(code))
|
|
return;
|
|
this.error("Missing expected " + String.fromCharCode(code));
|
|
};
|
|
_ParseAST.prototype.consumeOptionalOperator = function (op) {
|
|
if (this.next.isOperator(op)) {
|
|
this.advance();
|
|
return true;
|
|
}
|
|
else {
|
|
return false;
|
|
}
|
|
};
|
|
_ParseAST.prototype.expectOperator = function (operator) {
|
|
if (this.consumeOptionalOperator(operator))
|
|
return;
|
|
this.error("Missing expected operator " + operator);
|
|
};
|
|
_ParseAST.prototype.prettyPrintToken = function (tok) {
|
|
return tok === EOF ? 'end of input' : "token " + tok;
|
|
};
|
|
_ParseAST.prototype.expectIdentifierOrKeyword = function () {
|
|
var n = this.next;
|
|
if (!n.isIdentifier() && !n.isKeyword()) {
|
|
if (n.isPrivateIdentifier()) {
|
|
this._reportErrorForPrivateIdentifier(n, 'expected identifier or keyword');
|
|
}
|
|
else {
|
|
this.error("Unexpected " + this.prettyPrintToken(n) + ", expected identifier or keyword");
|
|
}
|
|
return null;
|
|
}
|
|
this.advance();
|
|
return n.toString();
|
|
};
|
|
_ParseAST.prototype.expectIdentifierOrKeywordOrString = function () {
|
|
var n = this.next;
|
|
if (!n.isIdentifier() && !n.isKeyword() && !n.isString()) {
|
|
if (n.isPrivateIdentifier()) {
|
|
this._reportErrorForPrivateIdentifier(n, 'expected identifier, keyword or string');
|
|
}
|
|
else {
|
|
this.error("Unexpected " + this.prettyPrintToken(n) + ", expected identifier, keyword, or string");
|
|
}
|
|
return '';
|
|
}
|
|
this.advance();
|
|
return n.toString();
|
|
};
|
|
_ParseAST.prototype.parseChain = function () {
|
|
var exprs = [];
|
|
var start = this.inputIndex;
|
|
while (this.index < this.tokens.length) {
|
|
var expr = this.parsePipe();
|
|
exprs.push(expr);
|
|
if (this.consumeOptionalCharacter($SEMICOLON)) {
|
|
if (!this.parseAction) {
|
|
this.error('Binding expression cannot contain chained expression');
|
|
}
|
|
while (this.consumeOptionalCharacter($SEMICOLON)) {
|
|
} // read all semicolons
|
|
}
|
|
else if (this.index < this.tokens.length) {
|
|
this.error("Unexpected token '" + this.next + "'");
|
|
}
|
|
}
|
|
if (exprs.length == 0) {
|
|
// We have no expressions so create an empty expression that spans the entire input length
|
|
var artificialStart = this.offset;
|
|
var artificialEnd = this.offset + this.inputLength;
|
|
return new EmptyExpr(this.span(artificialStart, artificialEnd), this.sourceSpan(artificialStart, artificialEnd));
|
|
}
|
|
if (exprs.length == 1)
|
|
return exprs[0];
|
|
return new Chain(this.span(start), this.sourceSpan(start), exprs);
|
|
};
|
|
_ParseAST.prototype.parsePipe = function () {
|
|
var start = this.inputIndex;
|
|
var result = this.parseExpression();
|
|
if (this.consumeOptionalOperator('|')) {
|
|
if (this.parseAction) {
|
|
this.error('Cannot have a pipe in an action expression');
|
|
}
|
|
do {
|
|
var nameStart = this.inputIndex;
|
|
var nameId = this.expectIdentifierOrKeyword();
|
|
var nameSpan = void 0;
|
|
var fullSpanEnd = undefined;
|
|
if (nameId !== null) {
|
|
nameSpan = this.sourceSpan(nameStart);
|
|
}
|
|
else {
|
|
// No valid identifier was found, so we'll assume an empty pipe name ('').
|
|
nameId = '';
|
|
// However, there may have been whitespace present between the pipe character and the next
|
|
// token in the sequence (or the end of input). We want to track this whitespace so that
|
|
// the `BindingPipe` we produce covers not just the pipe character, but any trailing
|
|
// whitespace beyond it. Another way of thinking about this is that the zero-length name
|
|
// is assumed to be at the end of any whitespace beyond the pipe character.
|
|
//
|
|
// Therefore, we push the end of the `ParseSpan` for this pipe all the way up to the
|
|
// beginning of the next token, or until the end of input if the next token is EOF.
|
|
fullSpanEnd = this.next.index !== -1 ? this.next.index : this.inputLength + this.offset;
|
|
// The `nameSpan` for an empty pipe name is zero-length at the end of any whitespace
|
|
// beyond the pipe character.
|
|
nameSpan = new ParseSpan(fullSpanEnd, fullSpanEnd).toAbsolute(this.absoluteOffset);
|
|
}
|
|
var args = [];
|
|
while (this.consumeOptionalCharacter($COLON)) {
|
|
args.push(this.parseExpression());
|
|
// If there are additional expressions beyond the name, then the artificial end for the
|
|
// name is no longer relevant.
|
|
}
|
|
result = new BindingPipe(this.span(start), this.sourceSpan(start, fullSpanEnd), result, nameId, args, nameSpan);
|
|
} while (this.consumeOptionalOperator('|'));
|
|
}
|
|
return result;
|
|
};
|
|
_ParseAST.prototype.parseExpression = function () {
|
|
return this.parseConditional();
|
|
};
|
|
_ParseAST.prototype.parseConditional = function () {
|
|
var start = this.inputIndex;
|
|
var result = this.parseLogicalOr();
|
|
if (this.consumeOptionalOperator('?')) {
|
|
var yes = this.parsePipe();
|
|
var no = void 0;
|
|
if (!this.consumeOptionalCharacter($COLON)) {
|
|
var end = this.inputIndex;
|
|
var expression = this.input.substring(start, end);
|
|
this.error("Conditional expression " + expression + " requires all 3 expressions");
|
|
no = new EmptyExpr(this.span(start), this.sourceSpan(start));
|
|
}
|
|
else {
|
|
no = this.parsePipe();
|
|
}
|
|
return new Conditional(this.span(start), this.sourceSpan(start), result, yes, no);
|
|
}
|
|
else {
|
|
return result;
|
|
}
|
|
};
|
|
_ParseAST.prototype.parseLogicalOr = function () {
|
|
// '||'
|
|
var start = this.inputIndex;
|
|
var result = this.parseLogicalAnd();
|
|
while (this.consumeOptionalOperator('||')) {
|
|
var right = this.parseLogicalAnd();
|
|
result = new Binary(this.span(start), this.sourceSpan(start), '||', result, right);
|
|
}
|
|
return result;
|
|
};
|
|
_ParseAST.prototype.parseLogicalAnd = function () {
|
|
// '&&'
|
|
var start = this.inputIndex;
|
|
var result = this.parseNullishCoalescing();
|
|
while (this.consumeOptionalOperator('&&')) {
|
|
var right = this.parseNullishCoalescing();
|
|
result = new Binary(this.span(start), this.sourceSpan(start), '&&', result, right);
|
|
}
|
|
return result;
|
|
};
|
|
_ParseAST.prototype.parseNullishCoalescing = function () {
|
|
// '??'
|
|
var start = this.inputIndex;
|
|
var result = this.parseEquality();
|
|
while (this.consumeOptionalOperator('??')) {
|
|
var right = this.parseEquality();
|
|
result = new Binary(this.span(start), this.sourceSpan(start), '??', result, right);
|
|
}
|
|
return result;
|
|
};
|
|
_ParseAST.prototype.parseEquality = function () {
|
|
// '==','!=','===','!=='
|
|
var start = this.inputIndex;
|
|
var result = this.parseRelational();
|
|
while (this.next.type == exports.TokenType.Operator) {
|
|
var operator = this.next.strValue;
|
|
switch (operator) {
|
|
case '==':
|
|
case '===':
|
|
case '!=':
|
|
case '!==':
|
|
this.advance();
|
|
var right = this.parseRelational();
|
|
result = new Binary(this.span(start), this.sourceSpan(start), operator, result, right);
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
return result;
|
|
};
|
|
_ParseAST.prototype.parseRelational = function () {
|
|
// '<', '>', '<=', '>='
|
|
var start = this.inputIndex;
|
|
var result = this.parseAdditive();
|
|
while (this.next.type == exports.TokenType.Operator) {
|
|
var operator = this.next.strValue;
|
|
switch (operator) {
|
|
case '<':
|
|
case '>':
|
|
case '<=':
|
|
case '>=':
|
|
this.advance();
|
|
var right = this.parseAdditive();
|
|
result = new Binary(this.span(start), this.sourceSpan(start), operator, result, right);
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
return result;
|
|
};
|
|
_ParseAST.prototype.parseAdditive = function () {
|
|
// '+', '-'
|
|
var start = this.inputIndex;
|
|
var result = this.parseMultiplicative();
|
|
while (this.next.type == exports.TokenType.Operator) {
|
|
var operator = this.next.strValue;
|
|
switch (operator) {
|
|
case '+':
|
|
case '-':
|
|
this.advance();
|
|
var right = this.parseMultiplicative();
|
|
result = new Binary(this.span(start), this.sourceSpan(start), operator, result, right);
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
return result;
|
|
};
|
|
_ParseAST.prototype.parseMultiplicative = function () {
|
|
// '*', '%', '/'
|
|
var start = this.inputIndex;
|
|
var result = this.parsePrefix();
|
|
while (this.next.type == exports.TokenType.Operator) {
|
|
var operator = this.next.strValue;
|
|
switch (operator) {
|
|
case '*':
|
|
case '%':
|
|
case '/':
|
|
this.advance();
|
|
var right = this.parsePrefix();
|
|
result = new Binary(this.span(start), this.sourceSpan(start), operator, result, right);
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
return result;
|
|
};
|
|
_ParseAST.prototype.parsePrefix = function () {
|
|
if (this.next.type == exports.TokenType.Operator) {
|
|
var start = this.inputIndex;
|
|
var operator = this.next.strValue;
|
|
var result = void 0;
|
|
switch (operator) {
|
|
case '+':
|
|
this.advance();
|
|
result = this.parsePrefix();
|
|
return Unary.createPlus(this.span(start), this.sourceSpan(start), result);
|
|
case '-':
|
|
this.advance();
|
|
result = this.parsePrefix();
|
|
return Unary.createMinus(this.span(start), this.sourceSpan(start), result);
|
|
case '!':
|
|
this.advance();
|
|
result = this.parsePrefix();
|
|
return new PrefixNot(this.span(start), this.sourceSpan(start), result);
|
|
}
|
|
}
|
|
return this.parseCallChain();
|
|
};
|
|
_ParseAST.prototype.parseCallChain = function () {
|
|
var start = this.inputIndex;
|
|
var result = this.parsePrimary();
|
|
while (true) {
|
|
if (this.consumeOptionalCharacter($PERIOD)) {
|
|
result = this.parseAccessMemberOrMethodCall(result, start, false);
|
|
}
|
|
else if (this.consumeOptionalOperator('?.')) {
|
|
result = this.consumeOptionalCharacter($LBRACKET) ?
|
|
this.parseKeyedReadOrWrite(result, start, true) :
|
|
this.parseAccessMemberOrMethodCall(result, start, true);
|
|
}
|
|
else if (this.consumeOptionalCharacter($LBRACKET)) {
|
|
result = this.parseKeyedReadOrWrite(result, start, false);
|
|
}
|
|
else if (this.consumeOptionalCharacter($LPAREN)) {
|
|
this.rparensExpected++;
|
|
var args = this.parseCallArguments();
|
|
this.rparensExpected--;
|
|
this.expectCharacter($RPAREN);
|
|
result = new FunctionCall(this.span(start), this.sourceSpan(start), result, args);
|
|
}
|
|
else if (this.consumeOptionalOperator('!')) {
|
|
result = new NonNullAssert(this.span(start), this.sourceSpan(start), result);
|
|
}
|
|
else {
|
|
return result;
|
|
}
|
|
}
|
|
};
|
|
_ParseAST.prototype.parsePrimary = function () {
|
|
var start = this.inputIndex;
|
|
if (this.consumeOptionalCharacter($LPAREN)) {
|
|
this.rparensExpected++;
|
|
var result = this.parsePipe();
|
|
this.rparensExpected--;
|
|
this.expectCharacter($RPAREN);
|
|
return result;
|
|
}
|
|
else if (this.next.isKeywordNull()) {
|
|
this.advance();
|
|
return new LiteralPrimitive(this.span(start), this.sourceSpan(start), null);
|
|
}
|
|
else if (this.next.isKeywordUndefined()) {
|
|
this.advance();
|
|
return new LiteralPrimitive(this.span(start), this.sourceSpan(start), void 0);
|
|
}
|
|
else if (this.next.isKeywordTrue()) {
|
|
this.advance();
|
|
return new LiteralPrimitive(this.span(start), this.sourceSpan(start), true);
|
|
}
|
|
else if (this.next.isKeywordFalse()) {
|
|
this.advance();
|
|
return new LiteralPrimitive(this.span(start), this.sourceSpan(start), false);
|
|
}
|
|
else if (this.next.isKeywordThis()) {
|
|
this.advance();
|
|
return new ThisReceiver(this.span(start), this.sourceSpan(start));
|
|
}
|
|
else if (this.consumeOptionalCharacter($LBRACKET)) {
|
|
this.rbracketsExpected++;
|
|
var elements = this.parseExpressionList($RBRACKET);
|
|
this.rbracketsExpected--;
|
|
this.expectCharacter($RBRACKET);
|
|
return new LiteralArray(this.span(start), this.sourceSpan(start), elements);
|
|
}
|
|
else if (this.next.isCharacter($LBRACE)) {
|
|
return this.parseLiteralMap();
|
|
}
|
|
else if (this.next.isIdentifier()) {
|
|
return this.parseAccessMemberOrMethodCall(new ImplicitReceiver(this.span(start), this.sourceSpan(start)), start, false);
|
|
}
|
|
else if (this.next.isNumber()) {
|
|
var value = this.next.toNumber();
|
|
this.advance();
|
|
return new LiteralPrimitive(this.span(start), this.sourceSpan(start), value);
|
|
}
|
|
else if (this.next.isString()) {
|
|
var literalValue = this.next.toString();
|
|
this.advance();
|
|
return new LiteralPrimitive(this.span(start), this.sourceSpan(start), literalValue);
|
|
}
|
|
else if (this.next.isPrivateIdentifier()) {
|
|
this._reportErrorForPrivateIdentifier(this.next, null);
|
|
return new EmptyExpr(this.span(start), this.sourceSpan(start));
|
|
}
|
|
else if (this.index >= this.tokens.length) {
|
|
this.error("Unexpected end of expression: " + this.input);
|
|
return new EmptyExpr(this.span(start), this.sourceSpan(start));
|
|
}
|
|
else {
|
|
this.error("Unexpected token " + this.next);
|
|
return new EmptyExpr(this.span(start), this.sourceSpan(start));
|
|
}
|
|
};
|
|
_ParseAST.prototype.parseExpressionList = function (terminator) {
|
|
var result = [];
|
|
do {
|
|
if (!this.next.isCharacter(terminator)) {
|
|
result.push(this.parsePipe());
|
|
}
|
|
else {
|
|
break;
|
|
}
|
|
} while (this.consumeOptionalCharacter($COMMA));
|
|
return result;
|
|
};
|
|
_ParseAST.prototype.parseLiteralMap = function () {
|
|
var keys = [];
|
|
var values = [];
|
|
var start = this.inputIndex;
|
|
this.expectCharacter($LBRACE);
|
|
if (!this.consumeOptionalCharacter($RBRACE)) {
|
|
this.rbracesExpected++;
|
|
do {
|
|
var keyStart = this.inputIndex;
|
|
var quoted = this.next.isString();
|
|
var key = this.expectIdentifierOrKeywordOrString();
|
|
keys.push({ key: key, quoted: quoted });
|
|
// Properties with quoted keys can't use the shorthand syntax.
|
|
if (quoted) {
|
|
this.expectCharacter($COLON);
|
|
values.push(this.parsePipe());
|
|
}
|
|
else if (this.consumeOptionalCharacter($COLON)) {
|
|
values.push(this.parsePipe());
|
|
}
|
|
else {
|
|
var span = this.span(keyStart);
|
|
var sourceSpan = this.sourceSpan(keyStart);
|
|
values.push(new PropertyRead(span, sourceSpan, sourceSpan, new ImplicitReceiver(span, sourceSpan), key));
|
|
}
|
|
} while (this.consumeOptionalCharacter($COMMA));
|
|
this.rbracesExpected--;
|
|
this.expectCharacter($RBRACE);
|
|
}
|
|
return new LiteralMap(this.span(start), this.sourceSpan(start), keys, values);
|
|
};
|
|
_ParseAST.prototype.parseAccessMemberOrMethodCall = function (receiver, start, isSafe) {
|
|
var _this = this;
|
|
var nameStart = this.inputIndex;
|
|
var id = this.withContext(ParseContextFlags.Writable, function () {
|
|
var _a;
|
|
var id = (_a = _this.expectIdentifierOrKeyword()) !== null && _a !== void 0 ? _a : '';
|
|
if (id.length === 0) {
|
|
_this.error("Expected identifier for property access", receiver.span.end);
|
|
}
|
|
return id;
|
|
});
|
|
var nameSpan = this.sourceSpan(nameStart);
|
|
if (this.consumeOptionalCharacter($LPAREN)) {
|
|
var argumentStart = this.inputIndex;
|
|
this.rparensExpected++;
|
|
var args = this.parseCallArguments();
|
|
var argumentSpan = this.span(argumentStart, this.inputIndex).toAbsolute(this.absoluteOffset);
|
|
this.expectCharacter($RPAREN);
|
|
this.rparensExpected--;
|
|
var span = this.span(start);
|
|
var sourceSpan = this.sourceSpan(start);
|
|
return isSafe ?
|
|
new SafeMethodCall(span, sourceSpan, nameSpan, receiver, id, args, argumentSpan) :
|
|
new MethodCall(span, sourceSpan, nameSpan, receiver, id, args, argumentSpan);
|
|
}
|
|
else {
|
|
if (isSafe) {
|
|
if (this.consumeOptionalOperator('=')) {
|
|
this.error('The \'?.\' operator cannot be used in the assignment');
|
|
return new EmptyExpr(this.span(start), this.sourceSpan(start));
|
|
}
|
|
else {
|
|
return new SafePropertyRead(this.span(start), this.sourceSpan(start), nameSpan, receiver, id);
|
|
}
|
|
}
|
|
else {
|
|
if (this.consumeOptionalOperator('=')) {
|
|
if (!this.parseAction) {
|
|
this.error('Bindings cannot contain assignments');
|
|
return new EmptyExpr(this.span(start), this.sourceSpan(start));
|
|
}
|
|
var value = this.parseConditional();
|
|
return new PropertyWrite(this.span(start), this.sourceSpan(start), nameSpan, receiver, id, value);
|
|
}
|
|
else {
|
|
return new PropertyRead(this.span(start), this.sourceSpan(start), nameSpan, receiver, id);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
_ParseAST.prototype.parseCallArguments = function () {
|
|
if (this.next.isCharacter($RPAREN))
|
|
return [];
|
|
var positionals = [];
|
|
do {
|
|
positionals.push(this.parsePipe());
|
|
} while (this.consumeOptionalCharacter($COMMA));
|
|
return positionals;
|
|
};
|
|
/**
|
|
* Parses an identifier, a keyword, a string with an optional `-` in between,
|
|
* and returns the string along with its absolute source span.
|
|
*/
|
|
_ParseAST.prototype.expectTemplateBindingKey = function () {
|
|
var result = '';
|
|
var operatorFound = false;
|
|
var start = this.currentAbsoluteOffset;
|
|
do {
|
|
result += this.expectIdentifierOrKeywordOrString();
|
|
operatorFound = this.consumeOptionalOperator('-');
|
|
if (operatorFound) {
|
|
result += '-';
|
|
}
|
|
} while (operatorFound);
|
|
return {
|
|
source: result,
|
|
span: new AbsoluteSourceSpan(start, start + result.length),
|
|
};
|
|
};
|
|
/**
|
|
* Parse microsyntax template expression and return a list of bindings or
|
|
* parsing errors in case the given expression is invalid.
|
|
*
|
|
* For example,
|
|
* ```
|
|
* <div *ngFor="let item of items; index as i; trackBy: func">
|
|
* ```
|
|
* contains five bindings:
|
|
* 1. ngFor -> null
|
|
* 2. item -> NgForOfContext.$implicit
|
|
* 3. ngForOf -> items
|
|
* 4. i -> NgForOfContext.index
|
|
* 5. ngForTrackBy -> func
|
|
*
|
|
* For a full description of the microsyntax grammar, see
|
|
* https://gist.github.com/mhevery/d3530294cff2e4a1b3fe15ff75d08855
|
|
*
|
|
* @param templateKey name of the microsyntax directive, like ngIf, ngFor,
|
|
* without the *, along with its absolute span.
|
|
*/
|
|
_ParseAST.prototype.parseTemplateBindings = function (templateKey) {
|
|
var bindings = [];
|
|
// The first binding is for the template key itself
|
|
// In *ngFor="let item of items", key = "ngFor", value = null
|
|
// In *ngIf="cond | pipe", key = "ngIf", value = "cond | pipe"
|
|
bindings.push.apply(bindings, __spreadArray([], __read(this.parseDirectiveKeywordBindings(templateKey))));
|
|
while (this.index < this.tokens.length) {
|
|
// If it starts with 'let', then this must be variable declaration
|
|
var letBinding = this.parseLetBinding();
|
|
if (letBinding) {
|
|
bindings.push(letBinding);
|
|
}
|
|
else {
|
|
// Two possible cases here, either `value "as" key` or
|
|
// "directive-keyword expression". We don't know which case, but both
|
|
// "value" and "directive-keyword" are template binding key, so consume
|
|
// the key first.
|
|
var key = this.expectTemplateBindingKey();
|
|
// Peek at the next token, if it is "as" then this must be variable
|
|
// declaration.
|
|
var binding = this.parseAsBinding(key);
|
|
if (binding) {
|
|
bindings.push(binding);
|
|
}
|
|
else {
|
|
// Otherwise the key must be a directive keyword, like "of". Transform
|
|
// the key to actual key. Eg. of -> ngForOf, trackBy -> ngForTrackBy
|
|
key.source =
|
|
templateKey.source + key.source.charAt(0).toUpperCase() + key.source.substring(1);
|
|
bindings.push.apply(bindings, __spreadArray([], __read(this.parseDirectiveKeywordBindings(key))));
|
|
}
|
|
}
|
|
this.consumeStatementTerminator();
|
|
}
|
|
return new TemplateBindingParseResult(bindings, [] /* warnings */, this.errors);
|
|
};
|
|
_ParseAST.prototype.parseKeyedReadOrWrite = function (receiver, start, isSafe) {
|
|
var _this = this;
|
|
return this.withContext(ParseContextFlags.Writable, function () {
|
|
_this.rbracketsExpected++;
|
|
var key = _this.parsePipe();
|
|
if (key instanceof EmptyExpr) {
|
|
_this.error("Key access cannot be empty");
|
|
}
|
|
_this.rbracketsExpected--;
|
|
_this.expectCharacter($RBRACKET);
|
|
if (_this.consumeOptionalOperator('=')) {
|
|
if (isSafe) {
|
|
_this.error('The \'?.\' operator cannot be used in the assignment');
|
|
}
|
|
else {
|
|
var value = _this.parseConditional();
|
|
return new KeyedWrite(_this.span(start), _this.sourceSpan(start), receiver, key, value);
|
|
}
|
|
}
|
|
else {
|
|
return isSafe ? new SafeKeyedRead(_this.span(start), _this.sourceSpan(start), receiver, key) :
|
|
new KeyedRead(_this.span(start), _this.sourceSpan(start), receiver, key);
|
|
}
|
|
return new EmptyExpr(_this.span(start), _this.sourceSpan(start));
|
|
});
|
|
};
|
|
/**
|
|
* Parse a directive keyword, followed by a mandatory expression.
|
|
* For example, "of items", "trackBy: func".
|
|
* The bindings are: ngForOf -> items, ngForTrackBy -> func
|
|
* There could be an optional "as" binding that follows the expression.
|
|
* For example,
|
|
* ```
|
|
* *ngFor="let item of items | slice:0:1 as collection".
|
|
* ^^ ^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^
|
|
* keyword bound target optional 'as' binding
|
|
* ```
|
|
*
|
|
* @param key binding key, for example, ngFor, ngIf, ngForOf, along with its
|
|
* absolute span.
|
|
*/
|
|
_ParseAST.prototype.parseDirectiveKeywordBindings = function (key) {
|
|
var bindings = [];
|
|
this.consumeOptionalCharacter($COLON); // trackBy: trackByFunction
|
|
var value = this.getDirectiveBoundTarget();
|
|
var spanEnd = this.currentAbsoluteOffset;
|
|
// The binding could optionally be followed by "as". For example,
|
|
// *ngIf="cond | pipe as x". In this case, the key in the "as" binding
|
|
// is "x" and the value is the template key itself ("ngIf"). Note that the
|
|
// 'key' in the current context now becomes the "value" in the next binding.
|
|
var asBinding = this.parseAsBinding(key);
|
|
if (!asBinding) {
|
|
this.consumeStatementTerminator();
|
|
spanEnd = this.currentAbsoluteOffset;
|
|
}
|
|
var sourceSpan = new AbsoluteSourceSpan(key.span.start, spanEnd);
|
|
bindings.push(new ExpressionBinding(sourceSpan, key, value));
|
|
if (asBinding) {
|
|
bindings.push(asBinding);
|
|
}
|
|
return bindings;
|
|
};
|
|
/**
|
|
* Return the expression AST for the bound target of a directive keyword
|
|
* binding. For example,
|
|
* ```
|
|
* *ngIf="condition | pipe"
|
|
* ^^^^^^^^^^^^^^^^ bound target for "ngIf"
|
|
* *ngFor="let item of items"
|
|
* ^^^^^ bound target for "ngForOf"
|
|
* ```
|
|
*/
|
|
_ParseAST.prototype.getDirectiveBoundTarget = function () {
|
|
if (this.next === EOF || this.peekKeywordAs() || this.peekKeywordLet()) {
|
|
return null;
|
|
}
|
|
var ast = this.parsePipe(); // example: "condition | async"
|
|
var _b = ast.span, start = _b.start, end = _b.end;
|
|
var value = this.input.substring(start, end);
|
|
return new ASTWithSource(ast, value, this.location, this.absoluteOffset + start, this.errors);
|
|
};
|
|
/**
|
|
* Return the binding for a variable declared using `as`. Note that the order
|
|
* of the key-value pair in this declaration is reversed. For example,
|
|
* ```
|
|
* *ngFor="let item of items; index as i"
|
|
* ^^^^^ ^
|
|
* value key
|
|
* ```
|
|
*
|
|
* @param value name of the value in the declaration, "ngIf" in the example
|
|
* above, along with its absolute span.
|
|
*/
|
|
_ParseAST.prototype.parseAsBinding = function (value) {
|
|
if (!this.peekKeywordAs()) {
|
|
return null;
|
|
}
|
|
this.advance(); // consume the 'as' keyword
|
|
var key = this.expectTemplateBindingKey();
|
|
this.consumeStatementTerminator();
|
|
var sourceSpan = new AbsoluteSourceSpan(value.span.start, this.currentAbsoluteOffset);
|
|
return new VariableBinding(sourceSpan, key, value);
|
|
};
|
|
/**
|
|
* Return the binding for a variable declared using `let`. For example,
|
|
* ```
|
|
* *ngFor="let item of items; let i=index;"
|
|
* ^^^^^^^^ ^^^^^^^^^^^
|
|
* ```
|
|
* In the first binding, `item` is bound to `NgForOfContext.$implicit`.
|
|
* In the second binding, `i` is bound to `NgForOfContext.index`.
|
|
*/
|
|
_ParseAST.prototype.parseLetBinding = function () {
|
|
if (!this.peekKeywordLet()) {
|
|
return null;
|
|
}
|
|
var spanStart = this.currentAbsoluteOffset;
|
|
this.advance(); // consume the 'let' keyword
|
|
var key = this.expectTemplateBindingKey();
|
|
var value = null;
|
|
if (this.consumeOptionalOperator('=')) {
|
|
value = this.expectTemplateBindingKey();
|
|
}
|
|
this.consumeStatementTerminator();
|
|
var sourceSpan = new AbsoluteSourceSpan(spanStart, this.currentAbsoluteOffset);
|
|
return new VariableBinding(sourceSpan, key, value);
|
|
};
|
|
/**
|
|
* Consume the optional statement terminator: semicolon or comma.
|
|
*/
|
|
_ParseAST.prototype.consumeStatementTerminator = function () {
|
|
this.consumeOptionalCharacter($SEMICOLON) || this.consumeOptionalCharacter($COMMA);
|
|
};
|
|
/**
|
|
* Records an error and skips over the token stream until reaching a recoverable point. See
|
|
* `this.skip` for more details on token skipping.
|
|
*/
|
|
_ParseAST.prototype.error = function (message, index) {
|
|
if (index === void 0) { index = null; }
|
|
this.errors.push(new ParserError(message, this.input, this.locationText(index), this.location));
|
|
this.skip();
|
|
};
|
|
_ParseAST.prototype.locationText = function (index) {
|
|
if (index === void 0) { index = null; }
|
|
if (index == null)
|
|
index = this.index;
|
|
return (index < this.tokens.length) ? "at column " + (this.tokens[index].index + 1) + " in" :
|
|
"at the end of the expression";
|
|
};
|
|
/**
|
|
* Records an error for an unexpected private identifier being discovered.
|
|
* @param token Token representing a private identifier.
|
|
* @param extraMessage Optional additional message being appended to the error.
|
|
*/
|
|
_ParseAST.prototype._reportErrorForPrivateIdentifier = function (token, extraMessage) {
|
|
var errorMessage = "Private identifiers are not supported. Unexpected private identifier: " + token;
|
|
if (extraMessage !== null) {
|
|
errorMessage += ", " + extraMessage;
|
|
}
|
|
this.error(errorMessage);
|
|
};
|
|
/**
|
|
* Error recovery should skip tokens until it encounters a recovery point.
|
|
*
|
|
* The following are treated as unconditional recovery points:
|
|
* - end of input
|
|
* - ';' (parseChain() is always the root production, and it expects a ';')
|
|
* - '|' (since pipes may be chained and each pipe expression may be treated independently)
|
|
*
|
|
* The following are conditional recovery points:
|
|
* - ')', '}', ']' if one of calling productions is expecting one of these symbols
|
|
* - This allows skip() to recover from errors such as '(a.) + 1' allowing more of the AST to
|
|
* be retained (it doesn't skip any tokens as the ')' is retained because of the '(' begins
|
|
* an '(' <expr> ')' production).
|
|
* The recovery points of grouping symbols must be conditional as they must be skipped if
|
|
* none of the calling productions are not expecting the closing token else we will never
|
|
* make progress in the case of an extraneous group closing symbol (such as a stray ')').
|
|
* That is, we skip a closing symbol if we are not in a grouping production.
|
|
* - '=' in a `Writable` context
|
|
* - In this context, we are able to recover after seeing the `=` operator, which
|
|
* signals the presence of an independent rvalue expression following the `=` operator.
|
|
*
|
|
* If a production expects one of these token it increments the corresponding nesting count,
|
|
* and then decrements it just prior to checking if the token is in the input.
|
|
*/
|
|
_ParseAST.prototype.skip = function () {
|
|
var n = this.next;
|
|
while (this.index < this.tokens.length && !n.isCharacter($SEMICOLON) &&
|
|
!n.isOperator('|') && (this.rparensExpected <= 0 || !n.isCharacter($RPAREN)) &&
|
|
(this.rbracesExpected <= 0 || !n.isCharacter($RBRACE)) &&
|
|
(this.rbracketsExpected <= 0 || !n.isCharacter($RBRACKET)) &&
|
|
(!(this.context & ParseContextFlags.Writable) || !n.isOperator('='))) {
|
|
if (this.next.isError()) {
|
|
this.errors.push(new ParserError(this.next.toString(), this.input, this.locationText(), this.location));
|
|
}
|
|
this.advance();
|
|
n = this.next;
|
|
}
|
|
};
|
|
return _ParseAST;
|
|
}());
|
|
var SimpleExpressionChecker = /** @class */ (function () {
|
|
function SimpleExpressionChecker() {
|
|
this.errors = [];
|
|
}
|
|
SimpleExpressionChecker.prototype.visitImplicitReceiver = function (ast, context) { };
|
|
SimpleExpressionChecker.prototype.visitThisReceiver = function (ast, context) { };
|
|
SimpleExpressionChecker.prototype.visitInterpolation = function (ast, context) { };
|
|
SimpleExpressionChecker.prototype.visitLiteralPrimitive = function (ast, context) { };
|
|
SimpleExpressionChecker.prototype.visitPropertyRead = function (ast, context) { };
|
|
SimpleExpressionChecker.prototype.visitPropertyWrite = function (ast, context) { };
|
|
SimpleExpressionChecker.prototype.visitSafePropertyRead = function (ast, context) { };
|
|
SimpleExpressionChecker.prototype.visitMethodCall = function (ast, context) { };
|
|
SimpleExpressionChecker.prototype.visitSafeMethodCall = function (ast, context) { };
|
|
SimpleExpressionChecker.prototype.visitFunctionCall = function (ast, context) { };
|
|
SimpleExpressionChecker.prototype.visitLiteralArray = function (ast, context) {
|
|
this.visitAll(ast.expressions, context);
|
|
};
|
|
SimpleExpressionChecker.prototype.visitLiteralMap = function (ast, context) {
|
|
this.visitAll(ast.values, context);
|
|
};
|
|
SimpleExpressionChecker.prototype.visitUnary = function (ast, context) { };
|
|
SimpleExpressionChecker.prototype.visitBinary = function (ast, context) { };
|
|
SimpleExpressionChecker.prototype.visitPrefixNot = function (ast, context) { };
|
|
SimpleExpressionChecker.prototype.visitNonNullAssert = function (ast, context) { };
|
|
SimpleExpressionChecker.prototype.visitConditional = function (ast, context) { };
|
|
SimpleExpressionChecker.prototype.visitPipe = function (ast, context) {
|
|
this.errors.push('pipes');
|
|
};
|
|
SimpleExpressionChecker.prototype.visitKeyedRead = function (ast, context) { };
|
|
SimpleExpressionChecker.prototype.visitKeyedWrite = function (ast, context) { };
|
|
SimpleExpressionChecker.prototype.visitAll = function (asts, context) {
|
|
var _this = this;
|
|
return asts.map(function (node) { return node.visit(_this, context); });
|
|
};
|
|
SimpleExpressionChecker.prototype.visitChain = function (ast, context) { };
|
|
SimpleExpressionChecker.prototype.visitQuote = function (ast, context) { };
|
|
SimpleExpressionChecker.prototype.visitSafeKeyedRead = function (ast, context) { };
|
|
return SimpleExpressionChecker;
|
|
}());
|
|
/**
|
|
* This class implements SimpleExpressionChecker used in View Engine and performs more strict checks
|
|
* to make sure host bindings do not contain pipes. In View Engine, having pipes in host bindings is
|
|
* not supported as well, but in some cases (like `!(value | async)`) the error is not triggered at
|
|
* compile time. In order to preserve View Engine behavior, more strict checks are introduced for
|
|
* Ivy mode only.
|
|
*/
|
|
var IvySimpleExpressionChecker = /** @class */ (function (_super) {
|
|
__extends(IvySimpleExpressionChecker, _super);
|
|
function IvySimpleExpressionChecker() {
|
|
var _this = _super.apply(this, __spreadArray([], __read(arguments))) || this;
|
|
_this.errors = [];
|
|
return _this;
|
|
}
|
|
IvySimpleExpressionChecker.prototype.visitPipe = function () {
|
|
this.errors.push('pipes');
|
|
};
|
|
return IvySimpleExpressionChecker;
|
|
}(RecursiveAstVisitor$1));
|
|
|
|
/**
|
|
* @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 mapEntry(key, value) {
|
|
return { key: key, value: value, quoted: false };
|
|
}
|
|
function mapLiteral(obj, quoted) {
|
|
if (quoted === void 0) { quoted = false; }
|
|
return literalMap(Object.keys(obj).map(function (key) { return ({
|
|
key: key,
|
|
quoted: quoted,
|
|
value: obj[key],
|
|
}); }));
|
|
}
|
|
|
|
// =================================================================================================
|
|
// =================================================================================================
|
|
// =========== 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 '*'. */
|
|
var _SECURITY_SCHEMA;
|
|
function SECURITY_SCHEMA() {
|
|
if (!_SECURITY_SCHEMA) {
|
|
_SECURITY_SCHEMA = {};
|
|
// Case is insignificant below, all element and attribute names are lower-cased for lookup.
|
|
registerContext(SecurityContext.HTML, [
|
|
'iframe|srcdoc',
|
|
'*|innerHTML',
|
|
'*|outerHTML',
|
|
]);
|
|
registerContext(SecurityContext.STYLE, ['*|style']);
|
|
// NB: no SCRIPT contexts here, they are never allowed due to the parser stripping them.
|
|
registerContext(SecurityContext.URL, [
|
|
'*|formAction', 'area|href', 'area|ping', 'audio|src', 'a|href',
|
|
'a|ping', 'blockquote|cite', 'body|background', 'del|cite', 'form|action',
|
|
'img|src', 'img|srcset', 'input|src', 'ins|cite', 'q|cite',
|
|
'source|src', 'source|srcset', 'track|src', 'video|poster', 'video|src',
|
|
]);
|
|
registerContext(SecurityContext.RESOURCE_URL, [
|
|
'applet|code',
|
|
'applet|codebase',
|
|
'base|href',
|
|
'embed|src',
|
|
'frame|src',
|
|
'head|profile',
|
|
'html|manifest',
|
|
'iframe|src',
|
|
'link|href',
|
|
'media|src',
|
|
'object|codebase',
|
|
'object|data',
|
|
'script|src',
|
|
]);
|
|
}
|
|
return _SECURITY_SCHEMA;
|
|
}
|
|
function registerContext(ctx, specs) {
|
|
var e_1, _a;
|
|
try {
|
|
for (var specs_1 = __values(specs), specs_1_1 = specs_1.next(); !specs_1_1.done; specs_1_1 = specs_1.next()) {
|
|
var spec = specs_1_1.value;
|
|
_SECURITY_SCHEMA[spec.toLowerCase()] = ctx;
|
|
}
|
|
}
|
|
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
finally {
|
|
try {
|
|
if (specs_1_1 && !specs_1_1.done && (_a = specs_1.return)) _a.call(specs_1);
|
|
}
|
|
finally { if (e_1) throw e_1.error; }
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @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 ElementSchemaRegistry = /** @class */ (function () {
|
|
function ElementSchemaRegistry() {
|
|
}
|
|
return ElementSchemaRegistry;
|
|
}());
|
|
|
|
var BOOLEAN = 'boolean';
|
|
var NUMBER = 'number';
|
|
var STRING = 'string';
|
|
var OBJECT = 'object';
|
|
/**
|
|
* This array represents the DOM schema. It encodes inheritance, properties, and events.
|
|
*
|
|
* ## Overview
|
|
*
|
|
* Each line represents one kind of element. The `element_inheritance` and properties are joined
|
|
* using `element_inheritance|properties` syntax.
|
|
*
|
|
* ## Element Inheritance
|
|
*
|
|
* The `element_inheritance` can be further subdivided as `element1,element2,...^parentElement`.
|
|
* Here the individual elements are separated by `,` (commas). Every element in the list
|
|
* has identical properties.
|
|
*
|
|
* An `element` may inherit additional properties from `parentElement` If no `^parentElement` is
|
|
* specified then `""` (blank) element is assumed.
|
|
*
|
|
* NOTE: The blank element inherits from root `[Element]` element, the super element of all
|
|
* elements.
|
|
*
|
|
* NOTE an element prefix such as `:svg:` has no special meaning to the schema.
|
|
*
|
|
* ## Properties
|
|
*
|
|
* Each element has a set of properties separated by `,` (commas). Each property can be prefixed
|
|
* by a special character designating its type:
|
|
*
|
|
* - (no prefix): property is a string.
|
|
* - `*`: property represents an event.
|
|
* - `!`: property is a boolean.
|
|
* - `#`: property is a number.
|
|
* - `%`: property is an object.
|
|
*
|
|
* ## Query
|
|
*
|
|
* The class creates an internal squas representation which allows to easily answer the query of
|
|
* if a given property exist on a given element.
|
|
*
|
|
* NOTE: We don't yet support querying for types or events.
|
|
* NOTE: This schema is auto extracted from `schema_extractor.ts` located in the test folder,
|
|
* see dom_element_schema_registry_spec.ts
|
|
*/
|
|
// =================================================================================================
|
|
// =================================================================================================
|
|
// =========== 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 DOM SCHEMA WITHOUT A SECURITY REVIEW!
|
|
//
|
|
// Newly added properties must be security reviewed and assigned an appropriate SecurityContext in
|
|
// dom_security_schema.ts. Reach out to mprobst & rjamet for details.
|
|
//
|
|
// =================================================================================================
|
|
var SCHEMA = [
|
|
'[Element]|textContent,%classList,className,id,innerHTML,*beforecopy,*beforecut,*beforepaste,*copy,*cut,*paste,*search,*selectstart,*webkitfullscreenchange,*webkitfullscreenerror,*wheel,outerHTML,#scrollLeft,#scrollTop,slot' +
|
|
/* added manually to avoid breaking changes */
|
|
',*message,*mozfullscreenchange,*mozfullscreenerror,*mozpointerlockchange,*mozpointerlockerror,*webglcontextcreationerror,*webglcontextlost,*webglcontextrestored',
|
|
'[HTMLElement]^[Element]|accessKey,contentEditable,dir,!draggable,!hidden,innerText,lang,*abort,*auxclick,*blur,*cancel,*canplay,*canplaythrough,*change,*click,*close,*contextmenu,*cuechange,*dblclick,*drag,*dragend,*dragenter,*dragleave,*dragover,*dragstart,*drop,*durationchange,*emptied,*ended,*error,*focus,*gotpointercapture,*input,*invalid,*keydown,*keypress,*keyup,*load,*loadeddata,*loadedmetadata,*loadstart,*lostpointercapture,*mousedown,*mouseenter,*mouseleave,*mousemove,*mouseout,*mouseover,*mouseup,*mousewheel,*pause,*play,*playing,*pointercancel,*pointerdown,*pointerenter,*pointerleave,*pointermove,*pointerout,*pointerover,*pointerup,*progress,*ratechange,*reset,*resize,*scroll,*seeked,*seeking,*select,*show,*stalled,*submit,*suspend,*timeupdate,*toggle,*volumechange,*waiting,outerText,!spellcheck,%style,#tabIndex,title,!translate',
|
|
'abbr,address,article,aside,b,bdi,bdo,cite,code,dd,dfn,dt,em,figcaption,figure,footer,header,i,kbd,main,mark,nav,noscript,rb,rp,rt,rtc,ruby,s,samp,section,small,strong,sub,sup,u,var,wbr^[HTMLElement]|accessKey,contentEditable,dir,!draggable,!hidden,innerText,lang,*abort,*auxclick,*blur,*cancel,*canplay,*canplaythrough,*change,*click,*close,*contextmenu,*cuechange,*dblclick,*drag,*dragend,*dragenter,*dragleave,*dragover,*dragstart,*drop,*durationchange,*emptied,*ended,*error,*focus,*gotpointercapture,*input,*invalid,*keydown,*keypress,*keyup,*load,*loadeddata,*loadedmetadata,*loadstart,*lostpointercapture,*mousedown,*mouseenter,*mouseleave,*mousemove,*mouseout,*mouseover,*mouseup,*mousewheel,*pause,*play,*playing,*pointercancel,*pointerdown,*pointerenter,*pointerleave,*pointermove,*pointerout,*pointerover,*pointerup,*progress,*ratechange,*reset,*resize,*scroll,*seeked,*seeking,*select,*show,*stalled,*submit,*suspend,*timeupdate,*toggle,*volumechange,*waiting,outerText,!spellcheck,%style,#tabIndex,title,!translate',
|
|
'media^[HTMLElement]|!autoplay,!controls,%controlsList,%crossOrigin,#currentTime,!defaultMuted,#defaultPlaybackRate,!disableRemotePlayback,!loop,!muted,*encrypted,*waitingforkey,#playbackRate,preload,src,%srcObject,#volume',
|
|
':svg:^[HTMLElement]|*abort,*auxclick,*blur,*cancel,*canplay,*canplaythrough,*change,*click,*close,*contextmenu,*cuechange,*dblclick,*drag,*dragend,*dragenter,*dragleave,*dragover,*dragstart,*drop,*durationchange,*emptied,*ended,*error,*focus,*gotpointercapture,*input,*invalid,*keydown,*keypress,*keyup,*load,*loadeddata,*loadedmetadata,*loadstart,*lostpointercapture,*mousedown,*mouseenter,*mouseleave,*mousemove,*mouseout,*mouseover,*mouseup,*mousewheel,*pause,*play,*playing,*pointercancel,*pointerdown,*pointerenter,*pointerleave,*pointermove,*pointerout,*pointerover,*pointerup,*progress,*ratechange,*reset,*resize,*scroll,*seeked,*seeking,*select,*show,*stalled,*submit,*suspend,*timeupdate,*toggle,*volumechange,*waiting,%style,#tabIndex',
|
|
':svg:graphics^:svg:|',
|
|
':svg:animation^:svg:|*begin,*end,*repeat',
|
|
':svg:geometry^:svg:|',
|
|
':svg:componentTransferFunction^:svg:|',
|
|
':svg:gradient^:svg:|',
|
|
':svg:textContent^:svg:graphics|',
|
|
':svg:textPositioning^:svg:textContent|',
|
|
'a^[HTMLElement]|charset,coords,download,hash,host,hostname,href,hreflang,name,password,pathname,ping,port,protocol,referrerPolicy,rel,rev,search,shape,target,text,type,username',
|
|
'area^[HTMLElement]|alt,coords,download,hash,host,hostname,href,!noHref,password,pathname,ping,port,protocol,referrerPolicy,rel,search,shape,target,username',
|
|
'audio^media|',
|
|
'br^[HTMLElement]|clear',
|
|
'base^[HTMLElement]|href,target',
|
|
'body^[HTMLElement]|aLink,background,bgColor,link,*beforeunload,*blur,*error,*focus,*hashchange,*languagechange,*load,*message,*offline,*online,*pagehide,*pageshow,*popstate,*rejectionhandled,*resize,*scroll,*storage,*unhandledrejection,*unload,text,vLink',
|
|
'button^[HTMLElement]|!autofocus,!disabled,formAction,formEnctype,formMethod,!formNoValidate,formTarget,name,type,value',
|
|
'canvas^[HTMLElement]|#height,#width',
|
|
'content^[HTMLElement]|select',
|
|
'dl^[HTMLElement]|!compact',
|
|
'datalist^[HTMLElement]|',
|
|
'details^[HTMLElement]|!open',
|
|
'dialog^[HTMLElement]|!open,returnValue',
|
|
'dir^[HTMLElement]|!compact',
|
|
'div^[HTMLElement]|align',
|
|
'embed^[HTMLElement]|align,height,name,src,type,width',
|
|
'fieldset^[HTMLElement]|!disabled,name',
|
|
'font^[HTMLElement]|color,face,size',
|
|
'form^[HTMLElement]|acceptCharset,action,autocomplete,encoding,enctype,method,name,!noValidate,target',
|
|
'frame^[HTMLElement]|frameBorder,longDesc,marginHeight,marginWidth,name,!noResize,scrolling,src',
|
|
'frameset^[HTMLElement]|cols,*beforeunload,*blur,*error,*focus,*hashchange,*languagechange,*load,*message,*offline,*online,*pagehide,*pageshow,*popstate,*rejectionhandled,*resize,*scroll,*storage,*unhandledrejection,*unload,rows',
|
|
'hr^[HTMLElement]|align,color,!noShade,size,width',
|
|
'head^[HTMLElement]|',
|
|
'h1,h2,h3,h4,h5,h6^[HTMLElement]|align',
|
|
'html^[HTMLElement]|version',
|
|
'iframe^[HTMLElement]|align,!allowFullscreen,frameBorder,height,longDesc,marginHeight,marginWidth,name,referrerPolicy,%sandbox,scrolling,src,srcdoc,width',
|
|
'img^[HTMLElement]|align,alt,border,%crossOrigin,#height,#hspace,!isMap,longDesc,lowsrc,name,referrerPolicy,sizes,src,srcset,useMap,#vspace,#width',
|
|
'input^[HTMLElement]|accept,align,alt,autocapitalize,autocomplete,!autofocus,!checked,!defaultChecked,defaultValue,dirName,!disabled,%files,formAction,formEnctype,formMethod,!formNoValidate,formTarget,#height,!incremental,!indeterminate,max,#maxLength,min,#minLength,!multiple,name,pattern,placeholder,!readOnly,!required,selectionDirection,#selectionEnd,#selectionStart,#size,src,step,type,useMap,value,%valueAsDate,#valueAsNumber,#width',
|
|
'li^[HTMLElement]|type,#value',
|
|
'label^[HTMLElement]|htmlFor',
|
|
'legend^[HTMLElement]|align',
|
|
'link^[HTMLElement]|as,charset,%crossOrigin,!disabled,href,hreflang,integrity,media,referrerPolicy,rel,%relList,rev,%sizes,target,type',
|
|
'map^[HTMLElement]|name',
|
|
'marquee^[HTMLElement]|behavior,bgColor,direction,height,#hspace,#loop,#scrollAmount,#scrollDelay,!trueSpeed,#vspace,width',
|
|
'menu^[HTMLElement]|!compact',
|
|
'meta^[HTMLElement]|content,httpEquiv,name,scheme',
|
|
'meter^[HTMLElement]|#high,#low,#max,#min,#optimum,#value',
|
|
'ins,del^[HTMLElement]|cite,dateTime',
|
|
'ol^[HTMLElement]|!compact,!reversed,#start,type',
|
|
'object^[HTMLElement]|align,archive,border,code,codeBase,codeType,data,!declare,height,#hspace,name,standby,type,useMap,#vspace,width',
|
|
'optgroup^[HTMLElement]|!disabled,label',
|
|
'option^[HTMLElement]|!defaultSelected,!disabled,label,!selected,text,value',
|
|
'output^[HTMLElement]|defaultValue,%htmlFor,name,value',
|
|
'p^[HTMLElement]|align',
|
|
'param^[HTMLElement]|name,type,value,valueType',
|
|
'picture^[HTMLElement]|',
|
|
'pre^[HTMLElement]|#width',
|
|
'progress^[HTMLElement]|#max,#value',
|
|
'q,blockquote,cite^[HTMLElement]|',
|
|
'script^[HTMLElement]|!async,charset,%crossOrigin,!defer,event,htmlFor,integrity,src,text,type',
|
|
'select^[HTMLElement]|autocomplete,!autofocus,!disabled,#length,!multiple,name,!required,#selectedIndex,#size,value',
|
|
'shadow^[HTMLElement]|',
|
|
'slot^[HTMLElement]|name',
|
|
'source^[HTMLElement]|media,sizes,src,srcset,type',
|
|
'span^[HTMLElement]|',
|
|
'style^[HTMLElement]|!disabled,media,type',
|
|
'caption^[HTMLElement]|align',
|
|
'th,td^[HTMLElement]|abbr,align,axis,bgColor,ch,chOff,#colSpan,headers,height,!noWrap,#rowSpan,scope,vAlign,width',
|
|
'col,colgroup^[HTMLElement]|align,ch,chOff,#span,vAlign,width',
|
|
'table^[HTMLElement]|align,bgColor,border,%caption,cellPadding,cellSpacing,frame,rules,summary,%tFoot,%tHead,width',
|
|
'tr^[HTMLElement]|align,bgColor,ch,chOff,vAlign',
|
|
'tfoot,thead,tbody^[HTMLElement]|align,ch,chOff,vAlign',
|
|
'template^[HTMLElement]|',
|
|
'textarea^[HTMLElement]|autocapitalize,autocomplete,!autofocus,#cols,defaultValue,dirName,!disabled,#maxLength,#minLength,name,placeholder,!readOnly,!required,#rows,selectionDirection,#selectionEnd,#selectionStart,value,wrap',
|
|
'title^[HTMLElement]|text',
|
|
'track^[HTMLElement]|!default,kind,label,src,srclang',
|
|
'ul^[HTMLElement]|!compact,type',
|
|
'unknown^[HTMLElement]|',
|
|
'video^media|#height,poster,#width',
|
|
':svg:a^:svg:graphics|',
|
|
':svg:animate^:svg:animation|',
|
|
':svg:animateMotion^:svg:animation|',
|
|
':svg:animateTransform^:svg:animation|',
|
|
':svg:circle^:svg:geometry|',
|
|
':svg:clipPath^:svg:graphics|',
|
|
':svg:defs^:svg:graphics|',
|
|
':svg:desc^:svg:|',
|
|
':svg:discard^:svg:|',
|
|
':svg:ellipse^:svg:geometry|',
|
|
':svg:feBlend^:svg:|',
|
|
':svg:feColorMatrix^:svg:|',
|
|
':svg:feComponentTransfer^:svg:|',
|
|
':svg:feComposite^:svg:|',
|
|
':svg:feConvolveMatrix^:svg:|',
|
|
':svg:feDiffuseLighting^:svg:|',
|
|
':svg:feDisplacementMap^:svg:|',
|
|
':svg:feDistantLight^:svg:|',
|
|
':svg:feDropShadow^:svg:|',
|
|
':svg:feFlood^:svg:|',
|
|
':svg:feFuncA^:svg:componentTransferFunction|',
|
|
':svg:feFuncB^:svg:componentTransferFunction|',
|
|
':svg:feFuncG^:svg:componentTransferFunction|',
|
|
':svg:feFuncR^:svg:componentTransferFunction|',
|
|
':svg:feGaussianBlur^:svg:|',
|
|
':svg:feImage^:svg:|',
|
|
':svg:feMerge^:svg:|',
|
|
':svg:feMergeNode^:svg:|',
|
|
':svg:feMorphology^:svg:|',
|
|
':svg:feOffset^:svg:|',
|
|
':svg:fePointLight^:svg:|',
|
|
':svg:feSpecularLighting^:svg:|',
|
|
':svg:feSpotLight^:svg:|',
|
|
':svg:feTile^:svg:|',
|
|
':svg:feTurbulence^:svg:|',
|
|
':svg:filter^:svg:|',
|
|
':svg:foreignObject^:svg:graphics|',
|
|
':svg:g^:svg:graphics|',
|
|
':svg:image^:svg:graphics|',
|
|
':svg:line^:svg:geometry|',
|
|
':svg:linearGradient^:svg:gradient|',
|
|
':svg:mpath^:svg:|',
|
|
':svg:marker^:svg:|',
|
|
':svg:mask^:svg:|',
|
|
':svg:metadata^:svg:|',
|
|
':svg:path^:svg:geometry|',
|
|
':svg:pattern^:svg:|',
|
|
':svg:polygon^:svg:geometry|',
|
|
':svg:polyline^:svg:geometry|',
|
|
':svg:radialGradient^:svg:gradient|',
|
|
':svg:rect^:svg:geometry|',
|
|
':svg:svg^:svg:graphics|#currentScale,#zoomAndPan',
|
|
':svg:script^:svg:|type',
|
|
':svg:set^:svg:animation|',
|
|
':svg:stop^:svg:|',
|
|
':svg:style^:svg:|!disabled,media,title,type',
|
|
':svg:switch^:svg:graphics|',
|
|
':svg:symbol^:svg:|',
|
|
':svg:tspan^:svg:textPositioning|',
|
|
':svg:text^:svg:textPositioning|',
|
|
':svg:textPath^:svg:textContent|',
|
|
':svg:title^:svg:|',
|
|
':svg:use^:svg:graphics|',
|
|
':svg:view^:svg:|#zoomAndPan',
|
|
'data^[HTMLElement]|value',
|
|
'keygen^[HTMLElement]|!autofocus,challenge,!disabled,form,keytype,name',
|
|
'menuitem^[HTMLElement]|type,label,icon,!disabled,!checked,radiogroup,!default',
|
|
'summary^[HTMLElement]|',
|
|
'time^[HTMLElement]|dateTime',
|
|
':svg:cursor^:svg:|',
|
|
];
|
|
var _ATTR_TO_PROP = {
|
|
'class': 'className',
|
|
'for': 'htmlFor',
|
|
'formaction': 'formAction',
|
|
'innerHtml': 'innerHTML',
|
|
'readonly': 'readOnly',
|
|
'tabindex': 'tabIndex',
|
|
};
|
|
// Invert _ATTR_TO_PROP.
|
|
var _PROP_TO_ATTR = Object.keys(_ATTR_TO_PROP).reduce(function (inverted, attr) {
|
|
inverted[_ATTR_TO_PROP[attr]] = attr;
|
|
return inverted;
|
|
}, {});
|
|
var DomElementSchemaRegistry = /** @class */ (function (_super) {
|
|
__extends(DomElementSchemaRegistry, _super);
|
|
function DomElementSchemaRegistry() {
|
|
var _this = _super.call(this) || this;
|
|
_this._schema = {};
|
|
SCHEMA.forEach(function (encodedType) {
|
|
var type = {};
|
|
var _b = __read(encodedType.split('|'), 2), strType = _b[0], strProperties = _b[1];
|
|
var properties = strProperties.split(',');
|
|
var _c = __read(strType.split('^'), 2), typeNames = _c[0], superName = _c[1];
|
|
typeNames.split(',').forEach(function (tag) { return _this._schema[tag.toLowerCase()] = type; });
|
|
var superType = superName && _this._schema[superName.toLowerCase()];
|
|
if (superType) {
|
|
Object.keys(superType).forEach(function (prop) {
|
|
type[prop] = superType[prop];
|
|
});
|
|
}
|
|
properties.forEach(function (property) {
|
|
if (property.length > 0) {
|
|
switch (property[0]) {
|
|
case '*':
|
|
// We don't yet support events.
|
|
// If ever allowing to bind to events, GO THROUGH A SECURITY REVIEW, allowing events
|
|
// will
|
|
// almost certainly introduce bad XSS vulnerabilities.
|
|
// type[property.substring(1)] = EVENT;
|
|
break;
|
|
case '!':
|
|
type[property.substring(1)] = BOOLEAN;
|
|
break;
|
|
case '#':
|
|
type[property.substring(1)] = NUMBER;
|
|
break;
|
|
case '%':
|
|
type[property.substring(1)] = OBJECT;
|
|
break;
|
|
default:
|
|
type[property] = STRING;
|
|
}
|
|
}
|
|
});
|
|
});
|
|
return _this;
|
|
}
|
|
DomElementSchemaRegistry.prototype.hasProperty = function (tagName, propName, schemaMetas) {
|
|
if (schemaMetas.some(function (schema) { return schema.name === NO_ERRORS_SCHEMA.name; })) {
|
|
return true;
|
|
}
|
|
if (tagName.indexOf('-') > -1) {
|
|
if (isNgContainer(tagName) || isNgContent(tagName)) {
|
|
return false;
|
|
}
|
|
if (schemaMetas.some(function (schema) { return schema.name === CUSTOM_ELEMENTS_SCHEMA.name; })) {
|
|
// Can't tell now as we don't know which properties a custom element will get
|
|
// once it is instantiated
|
|
return true;
|
|
}
|
|
}
|
|
var elementProperties = this._schema[tagName.toLowerCase()] || this._schema['unknown'];
|
|
return !!elementProperties[propName];
|
|
};
|
|
DomElementSchemaRegistry.prototype.hasElement = function (tagName, schemaMetas) {
|
|
if (schemaMetas.some(function (schema) { return schema.name === NO_ERRORS_SCHEMA.name; })) {
|
|
return true;
|
|
}
|
|
if (tagName.indexOf('-') > -1) {
|
|
if (isNgContainer(tagName) || isNgContent(tagName)) {
|
|
return true;
|
|
}
|
|
if (schemaMetas.some(function (schema) { return schema.name === CUSTOM_ELEMENTS_SCHEMA.name; })) {
|
|
// Allow any custom elements
|
|
return true;
|
|
}
|
|
}
|
|
return !!this._schema[tagName.toLowerCase()];
|
|
};
|
|
/**
|
|
* securityContext returns the security context for the given property on the given DOM tag.
|
|
*
|
|
* Tag and property name are statically known and cannot change at runtime, i.e. it is not
|
|
* possible to bind a value into a changing attribute or tag name.
|
|
*
|
|
* The filtering is based on a list of allowed tags|attributes. All attributes in the schema
|
|
* above are assumed to have the 'NONE' security context, i.e. that they are safe inert
|
|
* string values. Only specific well known attack vectors are assigned their appropriate context.
|
|
*/
|
|
DomElementSchemaRegistry.prototype.securityContext = function (tagName, propName, isAttribute) {
|
|
if (isAttribute) {
|
|
// NB: For security purposes, use the mapped property name, not the attribute name.
|
|
propName = this.getMappedPropName(propName);
|
|
}
|
|
// Make sure comparisons are case insensitive, so that case differences between attribute and
|
|
// property names do not have a security impact.
|
|
tagName = tagName.toLowerCase();
|
|
propName = propName.toLowerCase();
|
|
var ctx = SECURITY_SCHEMA()[tagName + '|' + propName];
|
|
if (ctx) {
|
|
return ctx;
|
|
}
|
|
ctx = SECURITY_SCHEMA()['*|' + propName];
|
|
return ctx ? ctx : SecurityContext.NONE;
|
|
};
|
|
DomElementSchemaRegistry.prototype.getMappedPropName = function (propName) {
|
|
return _ATTR_TO_PROP[propName] || propName;
|
|
};
|
|
DomElementSchemaRegistry.prototype.getDefaultComponentElementName = function () {
|
|
return 'ng-component';
|
|
};
|
|
DomElementSchemaRegistry.prototype.validateProperty = function (name) {
|
|
if (name.toLowerCase().startsWith('on')) {
|
|
var msg = "Binding to event property '" + name + "' is disallowed for security reasons, " +
|
|
("please use (" + name.slice(2) + ")=...") +
|
|
("\nIf '" + name + "' is a directive input, make sure the directive is imported by the") +
|
|
" current module.";
|
|
return { error: true, msg: msg };
|
|
}
|
|
else {
|
|
return { error: false };
|
|
}
|
|
};
|
|
DomElementSchemaRegistry.prototype.validateAttribute = function (name) {
|
|
if (name.toLowerCase().startsWith('on')) {
|
|
var msg = "Binding to event attribute '" + name + "' is disallowed for security reasons, " +
|
|
("please use (" + name.slice(2) + ")=...");
|
|
return { error: true, msg: msg };
|
|
}
|
|
else {
|
|
return { error: false };
|
|
}
|
|
};
|
|
DomElementSchemaRegistry.prototype.allKnownElementNames = function () {
|
|
return Object.keys(this._schema);
|
|
};
|
|
DomElementSchemaRegistry.prototype.allKnownAttributesOfElement = function (tagName) {
|
|
var elementProperties = this._schema[tagName.toLowerCase()] || this._schema['unknown'];
|
|
// Convert properties to attributes.
|
|
return Object.keys(elementProperties).map(function (prop) { var _a; return (_a = _PROP_TO_ATTR[prop]) !== null && _a !== void 0 ? _a : prop; });
|
|
};
|
|
DomElementSchemaRegistry.prototype.normalizeAnimationStyleProperty = function (propName) {
|
|
return dashCaseToCamelCase(propName);
|
|
};
|
|
DomElementSchemaRegistry.prototype.normalizeAnimationStyleValue = function (camelCaseProp, userProvidedProp, val) {
|
|
var unit = '';
|
|
var strVal = val.toString().trim();
|
|
var errorMsg = null;
|
|
if (_isPixelDimensionStyle(camelCaseProp) && val !== 0 && val !== '0') {
|
|
if (typeof val === 'number') {
|
|
unit = 'px';
|
|
}
|
|
else {
|
|
var valAndSuffixMatch = val.match(/^[+-]?[\d\.]+([a-z]*)$/);
|
|
if (valAndSuffixMatch && valAndSuffixMatch[1].length == 0) {
|
|
errorMsg = "Please provide a CSS unit value for " + userProvidedProp + ":" + val;
|
|
}
|
|
}
|
|
}
|
|
return { error: errorMsg, value: strVal + unit };
|
|
};
|
|
return DomElementSchemaRegistry;
|
|
}(ElementSchemaRegistry));
|
|
function _isPixelDimensionStyle(prop) {
|
|
switch (prop) {
|
|
case 'width':
|
|
case 'height':
|
|
case 'minWidth':
|
|
case 'minHeight':
|
|
case 'maxWidth':
|
|
case 'maxHeight':
|
|
case 'left':
|
|
case 'top':
|
|
case 'bottom':
|
|
case 'right':
|
|
case 'fontSize':
|
|
case 'outlineWidth':
|
|
case 'outlineOffset':
|
|
case 'paddingTop':
|
|
case 'paddingLeft':
|
|
case 'paddingBottom':
|
|
case 'paddingRight':
|
|
case 'marginTop':
|
|
case 'marginLeft':
|
|
case 'marginBottom':
|
|
case 'marginRight':
|
|
case 'borderRadius':
|
|
case 'borderWidth':
|
|
case 'borderTopWidth':
|
|
case 'borderLeftWidth':
|
|
case 'borderRightWidth':
|
|
case 'borderBottomWidth':
|
|
case 'textIndent':
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @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
|
|
*/
|
|
/**
|
|
* Set of tagName|propertyName corresponding to Trusted Types sinks. Properties applying to all
|
|
* tags use '*'.
|
|
*
|
|
* Extracted from, and should be kept in sync with
|
|
* https://w3c.github.io/webappsec-trusted-types/dist/spec/#integrations
|
|
*/
|
|
var TRUSTED_TYPES_SINKS = new Set([
|
|
// NOTE: All strings in this set *must* be lowercase!
|
|
// TrustedHTML
|
|
'iframe|srcdoc',
|
|
'*|innerhtml',
|
|
'*|outerhtml',
|
|
// NB: no TrustedScript here, as the corresponding tags are stripped by the compiler.
|
|
// TrustedScriptURL
|
|
'embed|src',
|
|
'object|codebase',
|
|
'object|data',
|
|
]);
|
|
/**
|
|
* isTrustedTypesSink returns true if the given property on the given DOM tag is a Trusted Types
|
|
* sink. In that case, use `ElementSchemaRegistry.securityContext` to determine which particular
|
|
* Trusted Type is required for values passed to the sink:
|
|
* - SecurityContext.HTML corresponds to TrustedHTML
|
|
* - SecurityContext.RESOURCE_URL corresponds to TrustedScriptURL
|
|
*/
|
|
function isTrustedTypesSink(tagName, propName) {
|
|
// Make sure comparisons are case insensitive, so that case differences between attribute and
|
|
// property names do not have a security impact.
|
|
tagName = tagName.toLowerCase();
|
|
propName = propName.toLowerCase();
|
|
return TRUSTED_TYPES_SINKS.has(tagName + '|' + propName) ||
|
|
TRUSTED_TYPES_SINKS.has('*|' + propName);
|
|
}
|
|
|
|
var BIND_NAME_REGEXP$1 = /^(?:(bind-)|(let-)|(ref-|#)|(on-)|(bindon-)|(@))(.*)$/;
|
|
// Group 1 = "bind-"
|
|
var KW_BIND_IDX$1 = 1;
|
|
// Group 2 = "let-"
|
|
var KW_LET_IDX$1 = 2;
|
|
// Group 3 = "ref-/#"
|
|
var KW_REF_IDX$1 = 3;
|
|
// Group 4 = "on-"
|
|
var KW_ON_IDX$1 = 4;
|
|
// Group 5 = "bindon-"
|
|
var KW_BINDON_IDX$1 = 5;
|
|
// Group 6 = "@"
|
|
var KW_AT_IDX$1 = 6;
|
|
// Group 7 = the identifier after "bind-", "let-", "ref-/#", "on-", "bindon-" or "@"
|
|
var IDENT_KW_IDX$1 = 7;
|
|
var BINDING_DELIMS = {
|
|
BANANA_BOX: { start: '[(', end: ')]' },
|
|
PROPERTY: { start: '[', end: ']' },
|
|
EVENT: { start: '(', end: ')' },
|
|
};
|
|
var TEMPLATE_ATTR_PREFIX$2 = '*';
|
|
function htmlAstToRender3Ast(htmlNodes, bindingParser, options) {
|
|
var transformer = new HtmlAstToIvyAst(bindingParser, options);
|
|
var ivyNodes = visitAll$1(transformer, htmlNodes);
|
|
// Errors might originate in either the binding parser or the html to ivy transformer
|
|
var allErrors = bindingParser.errors.concat(transformer.errors);
|
|
var result = {
|
|
nodes: ivyNodes,
|
|
errors: allErrors,
|
|
styleUrls: transformer.styleUrls,
|
|
styles: transformer.styles,
|
|
ngContentSelectors: transformer.ngContentSelectors
|
|
};
|
|
if (options.collectCommentNodes) {
|
|
result.commentNodes = transformer.commentNodes;
|
|
}
|
|
return result;
|
|
}
|
|
var HtmlAstToIvyAst = /** @class */ (function () {
|
|
function HtmlAstToIvyAst(bindingParser, options) {
|
|
this.bindingParser = bindingParser;
|
|
this.options = options;
|
|
this.errors = [];
|
|
this.styles = [];
|
|
this.styleUrls = [];
|
|
this.ngContentSelectors = [];
|
|
// This array will be populated if `Render3ParseOptions['collectCommentNodes']` is true
|
|
this.commentNodes = [];
|
|
this.inI18nBlock = false;
|
|
}
|
|
// HTML visitor
|
|
HtmlAstToIvyAst.prototype.visitElement = function (element) {
|
|
var e_1, _a;
|
|
var _this = this;
|
|
var isI18nRootElement = isI18nRootNode(element.i18n);
|
|
if (isI18nRootElement) {
|
|
if (this.inI18nBlock) {
|
|
this.reportError('Cannot mark an element as translatable inside of a translatable section. Please remove the nested i18n marker.', element.sourceSpan);
|
|
}
|
|
this.inI18nBlock = true;
|
|
}
|
|
var preparsedElement = preparseElement(element);
|
|
if (preparsedElement.type === PreparsedElementType.SCRIPT) {
|
|
return null;
|
|
}
|
|
else if (preparsedElement.type === PreparsedElementType.STYLE) {
|
|
var contents = textContents(element);
|
|
if (contents !== null) {
|
|
this.styles.push(contents);
|
|
}
|
|
return null;
|
|
}
|
|
else if (preparsedElement.type === PreparsedElementType.STYLESHEET &&
|
|
isStyleUrlResolvable(preparsedElement.hrefAttr)) {
|
|
this.styleUrls.push(preparsedElement.hrefAttr);
|
|
return null;
|
|
}
|
|
// Whether the element is a `<ng-template>`
|
|
var isTemplateElement = isNgTemplate(element.name);
|
|
var parsedProperties = [];
|
|
var boundEvents = [];
|
|
var variables = [];
|
|
var references = [];
|
|
var attributes = [];
|
|
var i18nAttrsMeta = {};
|
|
var templateParsedProperties = [];
|
|
var templateVariables = [];
|
|
// Whether the element has any *-attribute
|
|
var elementHasInlineTemplate = false;
|
|
try {
|
|
for (var _b = __values(element.attrs), _c = _b.next(); !_c.done; _c = _b.next()) {
|
|
var attribute = _c.value;
|
|
var hasBinding = false;
|
|
var normalizedName = normalizeAttributeName(attribute.name);
|
|
// `*attr` defines template bindings
|
|
var isTemplateBinding = false;
|
|
if (attribute.i18n) {
|
|
i18nAttrsMeta[attribute.name] = attribute.i18n;
|
|
}
|
|
if (normalizedName.startsWith(TEMPLATE_ATTR_PREFIX$2)) {
|
|
// *-attributes
|
|
if (elementHasInlineTemplate) {
|
|
this.reportError("Can't have multiple template bindings on one element. Use only one attribute prefixed with *", attribute.sourceSpan);
|
|
}
|
|
isTemplateBinding = true;
|
|
elementHasInlineTemplate = true;
|
|
var templateValue = attribute.value;
|
|
var templateKey = normalizedName.substring(TEMPLATE_ATTR_PREFIX$2.length);
|
|
var parsedVariables = [];
|
|
var absoluteValueOffset = attribute.valueSpan ?
|
|
attribute.valueSpan.start.offset :
|
|
// If there is no value span the attribute does not have a value, like `attr` in
|
|
//`<div attr></div>`. In this case, point to one character beyond the last character of
|
|
// the attribute name.
|
|
attribute.sourceSpan.start.offset + attribute.name.length;
|
|
this.bindingParser.parseInlineTemplateBinding(templateKey, templateValue, attribute.sourceSpan, absoluteValueOffset, [], templateParsedProperties, parsedVariables, true /* isIvyAst */);
|
|
templateVariables.push.apply(templateVariables, __spreadArray([], __read(parsedVariables.map(function (v) { return new Variable(v.name, v.value, v.sourceSpan, v.keySpan, v.valueSpan); }))));
|
|
}
|
|
else {
|
|
// Check for variables, events, property bindings, interpolation
|
|
hasBinding = this.parseAttribute(isTemplateElement, attribute, [], parsedProperties, boundEvents, variables, references);
|
|
}
|
|
if (!hasBinding && !isTemplateBinding) {
|
|
// don't include the bindings as attributes as well in the AST
|
|
attributes.push(this.visitAttribute(attribute));
|
|
}
|
|
}
|
|
}
|
|
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
finally {
|
|
try {
|
|
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
|
|
}
|
|
finally { if (e_1) throw e_1.error; }
|
|
}
|
|
var children = visitAll$1(preparsedElement.nonBindable ? NON_BINDABLE_VISITOR$1 : this, element.children);
|
|
var parsedElement;
|
|
if (preparsedElement.type === PreparsedElementType.NG_CONTENT) {
|
|
// `<ng-content>`
|
|
if (element.children &&
|
|
!element.children.every(function (node) { return isEmptyTextNode(node) || isCommentNode(node); })) {
|
|
this.reportError("<ng-content> element cannot have content.", element.sourceSpan);
|
|
}
|
|
var selector = preparsedElement.selectAttr;
|
|
var attrs = element.attrs.map(function (attr) { return _this.visitAttribute(attr); });
|
|
parsedElement = new Content(selector, attrs, element.sourceSpan, element.i18n);
|
|
this.ngContentSelectors.push(selector);
|
|
}
|
|
else if (isTemplateElement) {
|
|
// `<ng-template>`
|
|
var attrs = this.extractAttributes(element.name, parsedProperties, i18nAttrsMeta);
|
|
parsedElement = new Template(element.name, attributes, attrs.bound, boundEvents, [ /* no template attributes */], children, references, variables, element.sourceSpan, element.startSourceSpan, element.endSourceSpan, element.i18n);
|
|
}
|
|
else {
|
|
var attrs = this.extractAttributes(element.name, parsedProperties, i18nAttrsMeta);
|
|
parsedElement = new Element(element.name, attributes, attrs.bound, boundEvents, children, references, element.sourceSpan, element.startSourceSpan, element.endSourceSpan, element.i18n);
|
|
}
|
|
if (elementHasInlineTemplate) {
|
|
// If this node is an inline-template (e.g. has *ngFor) then we need to create a template
|
|
// node that contains this node.
|
|
// Moreover, if the node is an element, then we need to hoist its attributes to the template
|
|
// node for matching against content projection selectors.
|
|
var attrs = this.extractAttributes('ng-template', templateParsedProperties, i18nAttrsMeta);
|
|
var templateAttrs_1 = [];
|
|
attrs.literal.forEach(function (attr) { return templateAttrs_1.push(attr); });
|
|
attrs.bound.forEach(function (attr) { return templateAttrs_1.push(attr); });
|
|
var hoistedAttrs = parsedElement instanceof Element ?
|
|
{
|
|
attributes: parsedElement.attributes,
|
|
inputs: parsedElement.inputs,
|
|
outputs: parsedElement.outputs,
|
|
} :
|
|
{ attributes: [], inputs: [], outputs: [] };
|
|
// For <ng-template>s with structural directives on them, avoid passing i18n information to
|
|
// the wrapping template to prevent unnecessary i18n instructions from being generated. The
|
|
// necessary i18n meta information will be extracted from child elements.
|
|
var i18n = isTemplateElement && isI18nRootElement ? undefined : element.i18n;
|
|
// TODO(pk): test for this case
|
|
parsedElement = new Template(parsedElement.name, hoistedAttrs.attributes, hoistedAttrs.inputs, hoistedAttrs.outputs, templateAttrs_1, [parsedElement], [ /* no references */], templateVariables, element.sourceSpan, element.startSourceSpan, element.endSourceSpan, i18n);
|
|
}
|
|
if (isI18nRootElement) {
|
|
this.inI18nBlock = false;
|
|
}
|
|
return parsedElement;
|
|
};
|
|
HtmlAstToIvyAst.prototype.visitAttribute = function (attribute) {
|
|
return new TextAttribute(attribute.name, attribute.value, attribute.sourceSpan, attribute.keySpan, attribute.valueSpan, attribute.i18n);
|
|
};
|
|
HtmlAstToIvyAst.prototype.visitText = function (text) {
|
|
return this._visitTextWithInterpolation(text.value, text.sourceSpan, text.i18n);
|
|
};
|
|
HtmlAstToIvyAst.prototype.visitExpansion = function (expansion) {
|
|
var _this = this;
|
|
if (!expansion.i18n) {
|
|
// do not generate Icu in case it was created
|
|
// outside of i18n block in a template
|
|
return null;
|
|
}
|
|
if (!isI18nRootNode(expansion.i18n)) {
|
|
throw new Error("Invalid type \"" + expansion.i18n.constructor + "\" for \"i18n\" property of " + expansion.sourceSpan.toString() + ". Expected a \"Message\"");
|
|
}
|
|
var message = expansion.i18n;
|
|
var vars = {};
|
|
var placeholders = {};
|
|
// extract VARs from ICUs - we process them separately while
|
|
// assembling resulting message via goog.getMsg function, since
|
|
// we need to pass them to top-level goog.getMsg call
|
|
Object.keys(message.placeholders).forEach(function (key) {
|
|
var value = message.placeholders[key];
|
|
if (key.startsWith(I18N_ICU_VAR_PREFIX)) {
|
|
// Currently when the `plural` or `select` keywords in an ICU contain trailing spaces (e.g.
|
|
// `{count, select , ...}`), these spaces are also included into the key names in ICU vars
|
|
// (e.g. "VAR_SELECT "). These trailing spaces are not desirable, since they will later be
|
|
// converted into `_` symbols while normalizing placeholder names, which might lead to
|
|
// mismatches at runtime (i.e. placeholder will not be replaced with the correct value).
|
|
var formattedKey = key.trim();
|
|
var ast = _this.bindingParser.parseInterpolationExpression(value.text, value.sourceSpan);
|
|
vars[formattedKey] = new BoundText(ast, value.sourceSpan);
|
|
}
|
|
else {
|
|
placeholders[key] = _this._visitTextWithInterpolation(value.text, value.sourceSpan);
|
|
}
|
|
});
|
|
return new Icu(vars, placeholders, expansion.sourceSpan, message);
|
|
};
|
|
HtmlAstToIvyAst.prototype.visitExpansionCase = function (expansionCase) {
|
|
return null;
|
|
};
|
|
HtmlAstToIvyAst.prototype.visitComment = function (comment) {
|
|
if (this.options.collectCommentNodes) {
|
|
this.commentNodes.push(new Comment(comment.value || '', comment.sourceSpan));
|
|
}
|
|
return null;
|
|
};
|
|
// convert view engine `ParsedProperty` to a format suitable for IVY
|
|
HtmlAstToIvyAst.prototype.extractAttributes = function (elementName, properties, i18nPropsMeta) {
|
|
var _this = this;
|
|
var bound = [];
|
|
var literal = [];
|
|
properties.forEach(function (prop) {
|
|
var i18n = i18nPropsMeta[prop.name];
|
|
if (prop.isLiteral) {
|
|
literal.push(new TextAttribute(prop.name, prop.expression.source || '', prop.sourceSpan, prop.keySpan, prop.valueSpan, i18n));
|
|
}
|
|
else {
|
|
// Note that validation is skipped and property mapping is disabled
|
|
// due to the fact that we need to make sure a given prop is not an
|
|
// input of a directive and directive matching happens at runtime.
|
|
var bep = _this.bindingParser.createBoundElementProperty(elementName, prop, /* skipValidation */ true, /* mapPropertyName */ false);
|
|
bound.push(BoundAttribute.fromBoundElementProperty(bep, i18n));
|
|
}
|
|
});
|
|
return { bound: bound, literal: literal };
|
|
};
|
|
HtmlAstToIvyAst.prototype.parseAttribute = function (isTemplateElement, attribute, matchableAttributes, parsedProperties, boundEvents, variables, references) {
|
|
var name = normalizeAttributeName(attribute.name);
|
|
var value = attribute.value;
|
|
var srcSpan = attribute.sourceSpan;
|
|
var absoluteOffset = attribute.valueSpan ? attribute.valueSpan.start.offset : srcSpan.start.offset;
|
|
function createKeySpan(srcSpan, prefix, identifier) {
|
|
// We need to adjust the start location for the keySpan to account for the removed 'data-'
|
|
// prefix from `normalizeAttributeName`.
|
|
var normalizationAdjustment = attribute.name.length - name.length;
|
|
var keySpanStart = srcSpan.start.moveBy(prefix.length + normalizationAdjustment);
|
|
var keySpanEnd = keySpanStart.moveBy(identifier.length);
|
|
return new ParseSourceSpan(keySpanStart, keySpanEnd, keySpanStart, identifier);
|
|
}
|
|
var bindParts = name.match(BIND_NAME_REGEXP$1);
|
|
if (bindParts) {
|
|
if (bindParts[KW_BIND_IDX$1] != null) {
|
|
var identifier = bindParts[IDENT_KW_IDX$1];
|
|
var keySpan_1 = createKeySpan(srcSpan, bindParts[KW_BIND_IDX$1], identifier);
|
|
this.bindingParser.parsePropertyBinding(identifier, value, false, srcSpan, absoluteOffset, attribute.valueSpan, matchableAttributes, parsedProperties, keySpan_1);
|
|
}
|
|
else if (bindParts[KW_LET_IDX$1]) {
|
|
if (isTemplateElement) {
|
|
var identifier = bindParts[IDENT_KW_IDX$1];
|
|
var keySpan_2 = createKeySpan(srcSpan, bindParts[KW_LET_IDX$1], identifier);
|
|
this.parseVariable(identifier, value, srcSpan, keySpan_2, attribute.valueSpan, variables);
|
|
}
|
|
else {
|
|
this.reportError("\"let-\" is only supported on ng-template elements.", srcSpan);
|
|
}
|
|
}
|
|
else if (bindParts[KW_REF_IDX$1]) {
|
|
var identifier = bindParts[IDENT_KW_IDX$1];
|
|
var keySpan_3 = createKeySpan(srcSpan, bindParts[KW_REF_IDX$1], identifier);
|
|
this.parseReference(identifier, value, srcSpan, keySpan_3, attribute.valueSpan, references);
|
|
}
|
|
else if (bindParts[KW_ON_IDX$1]) {
|
|
var events = [];
|
|
var identifier = bindParts[IDENT_KW_IDX$1];
|
|
var keySpan_4 = createKeySpan(srcSpan, bindParts[KW_ON_IDX$1], identifier);
|
|
this.bindingParser.parseEvent(identifier, value, srcSpan, attribute.valueSpan || srcSpan, matchableAttributes, events, keySpan_4);
|
|
addEvents(events, boundEvents);
|
|
}
|
|
else if (bindParts[KW_BINDON_IDX$1]) {
|
|
var identifier = bindParts[IDENT_KW_IDX$1];
|
|
var keySpan_5 = createKeySpan(srcSpan, bindParts[KW_BINDON_IDX$1], identifier);
|
|
this.bindingParser.parsePropertyBinding(identifier, value, false, srcSpan, absoluteOffset, attribute.valueSpan, matchableAttributes, parsedProperties, keySpan_5);
|
|
this.parseAssignmentEvent(identifier, value, srcSpan, attribute.valueSpan, matchableAttributes, boundEvents, keySpan_5);
|
|
}
|
|
else if (bindParts[KW_AT_IDX$1]) {
|
|
var keySpan_6 = createKeySpan(srcSpan, '', name);
|
|
this.bindingParser.parseLiteralAttr(name, value, srcSpan, absoluteOffset, attribute.valueSpan, matchableAttributes, parsedProperties, keySpan_6);
|
|
}
|
|
return true;
|
|
}
|
|
// We didn't see a kw-prefixed property binding, but we have not yet checked
|
|
// for the []/()/[()] syntax.
|
|
var delims = null;
|
|
if (name.startsWith(BINDING_DELIMS.BANANA_BOX.start)) {
|
|
delims = BINDING_DELIMS.BANANA_BOX;
|
|
}
|
|
else if (name.startsWith(BINDING_DELIMS.PROPERTY.start)) {
|
|
delims = BINDING_DELIMS.PROPERTY;
|
|
}
|
|
else if (name.startsWith(BINDING_DELIMS.EVENT.start)) {
|
|
delims = BINDING_DELIMS.EVENT;
|
|
}
|
|
if (delims !== null &&
|
|
// NOTE: older versions of the parser would match a start/end delimited
|
|
// binding iff the property name was terminated by the ending delimiter
|
|
// and the identifier in the binding was non-empty.
|
|
// TODO(ayazhafiz): update this to handle malformed bindings.
|
|
name.endsWith(delims.end) && name.length > delims.start.length + delims.end.length) {
|
|
var identifier = name.substring(delims.start.length, name.length - delims.end.length);
|
|
var keySpan_7 = createKeySpan(srcSpan, delims.start, identifier);
|
|
if (delims.start === BINDING_DELIMS.BANANA_BOX.start) {
|
|
this.bindingParser.parsePropertyBinding(identifier, value, false, srcSpan, absoluteOffset, attribute.valueSpan, matchableAttributes, parsedProperties, keySpan_7);
|
|
this.parseAssignmentEvent(identifier, value, srcSpan, attribute.valueSpan, matchableAttributes, boundEvents, keySpan_7);
|
|
}
|
|
else if (delims.start === BINDING_DELIMS.PROPERTY.start) {
|
|
this.bindingParser.parsePropertyBinding(identifier, value, false, srcSpan, absoluteOffset, attribute.valueSpan, matchableAttributes, parsedProperties, keySpan_7);
|
|
}
|
|
else {
|
|
var events = [];
|
|
this.bindingParser.parseEvent(identifier, value, srcSpan, attribute.valueSpan || srcSpan, matchableAttributes, events, keySpan_7);
|
|
addEvents(events, boundEvents);
|
|
}
|
|
return true;
|
|
}
|
|
// No explicit binding found.
|
|
var keySpan = createKeySpan(srcSpan, '' /* prefix */, name);
|
|
var hasBinding = this.bindingParser.parsePropertyInterpolation(name, value, srcSpan, attribute.valueSpan, matchableAttributes, parsedProperties, keySpan);
|
|
return hasBinding;
|
|
};
|
|
HtmlAstToIvyAst.prototype._visitTextWithInterpolation = function (value, sourceSpan, i18n) {
|
|
var valueNoNgsp = replaceNgsp(value);
|
|
var expr = this.bindingParser.parseInterpolation(valueNoNgsp, sourceSpan);
|
|
return expr ? new BoundText(expr, sourceSpan, i18n) : new Text(valueNoNgsp, sourceSpan);
|
|
};
|
|
HtmlAstToIvyAst.prototype.parseVariable = function (identifier, value, sourceSpan, keySpan, valueSpan, variables) {
|
|
if (identifier.indexOf('-') > -1) {
|
|
this.reportError("\"-\" is not allowed in variable names", sourceSpan);
|
|
}
|
|
else if (identifier.length === 0) {
|
|
this.reportError("Variable does not have a name", sourceSpan);
|
|
}
|
|
variables.push(new Variable(identifier, value, sourceSpan, keySpan, valueSpan));
|
|
};
|
|
HtmlAstToIvyAst.prototype.parseReference = function (identifier, value, sourceSpan, keySpan, valueSpan, references) {
|
|
if (identifier.indexOf('-') > -1) {
|
|
this.reportError("\"-\" is not allowed in reference names", sourceSpan);
|
|
}
|
|
else if (identifier.length === 0) {
|
|
this.reportError("Reference does not have a name", sourceSpan);
|
|
}
|
|
else if (references.some(function (reference) { return reference.name === identifier; })) {
|
|
this.reportError("Reference \"#" + identifier + "\" is defined more than once", sourceSpan);
|
|
}
|
|
references.push(new Reference(identifier, value, sourceSpan, keySpan, valueSpan));
|
|
};
|
|
HtmlAstToIvyAst.prototype.parseAssignmentEvent = function (name, expression, sourceSpan, valueSpan, targetMatchableAttrs, boundEvents, keySpan) {
|
|
var events = [];
|
|
this.bindingParser.parseEvent(name + "Change", expression + "=$event", sourceSpan, valueSpan || sourceSpan, targetMatchableAttrs, events, keySpan);
|
|
addEvents(events, boundEvents);
|
|
};
|
|
HtmlAstToIvyAst.prototype.reportError = function (message, sourceSpan, level) {
|
|
if (level === void 0) { level = exports.ParseErrorLevel.ERROR; }
|
|
this.errors.push(new ParseError(sourceSpan, message, level));
|
|
};
|
|
return HtmlAstToIvyAst;
|
|
}());
|
|
var NonBindableVisitor$1 = /** @class */ (function () {
|
|
function NonBindableVisitor() {
|
|
}
|
|
NonBindableVisitor.prototype.visitElement = function (ast) {
|
|
var preparsedElement = preparseElement(ast);
|
|
if (preparsedElement.type === PreparsedElementType.SCRIPT ||
|
|
preparsedElement.type === PreparsedElementType.STYLE ||
|
|
preparsedElement.type === PreparsedElementType.STYLESHEET) {
|
|
// Skipping <script> for security reasons
|
|
// Skipping <style> and stylesheets as we already processed them
|
|
// in the StyleCompiler
|
|
return null;
|
|
}
|
|
var children = visitAll$1(this, ast.children, null);
|
|
return new Element(ast.name, visitAll$1(this, ast.attrs),
|
|
/* inputs */ [], /* outputs */ [], children, /* references */ [], ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan);
|
|
};
|
|
NonBindableVisitor.prototype.visitComment = function (comment) {
|
|
return null;
|
|
};
|
|
NonBindableVisitor.prototype.visitAttribute = function (attribute) {
|
|
return new TextAttribute(attribute.name, attribute.value, attribute.sourceSpan, attribute.keySpan, attribute.valueSpan, attribute.i18n);
|
|
};
|
|
NonBindableVisitor.prototype.visitText = function (text) {
|
|
return new Text(text.value, text.sourceSpan);
|
|
};
|
|
NonBindableVisitor.prototype.visitExpansion = function (expansion) {
|
|
return null;
|
|
};
|
|
NonBindableVisitor.prototype.visitExpansionCase = function (expansionCase) {
|
|
return null;
|
|
};
|
|
return NonBindableVisitor;
|
|
}());
|
|
var NON_BINDABLE_VISITOR$1 = new NonBindableVisitor$1();
|
|
function normalizeAttributeName(attrName) {
|
|
return /^data-/i.test(attrName) ? attrName.substring(5) : attrName;
|
|
}
|
|
function addEvents(events, boundEvents) {
|
|
boundEvents.push.apply(boundEvents, __spreadArray([], __read(events.map(function (e) { return BoundEvent.fromParsedEvent(e); }))));
|
|
}
|
|
function isEmptyTextNode(node) {
|
|
return node instanceof Text$3 && node.value.trim().length == 0;
|
|
}
|
|
function isCommentNode(node) {
|
|
return node instanceof Comment$1;
|
|
}
|
|
function textContents(node) {
|
|
if (node.children.length !== 1 || !(node.children[0] instanceof Text$3)) {
|
|
return null;
|
|
}
|
|
else {
|
|
return node.children[0].value;
|
|
}
|
|
}
|
|
|
|
var TagType;
|
|
(function (TagType) {
|
|
TagType[TagType["ELEMENT"] = 0] = "ELEMENT";
|
|
TagType[TagType["TEMPLATE"] = 1] = "TEMPLATE";
|
|
})(TagType || (TagType = {}));
|
|
/**
|
|
* Generates an object that is used as a shared state between parent and all child contexts.
|
|
*/
|
|
function setupRegistry() {
|
|
return { getUniqueId: getSeqNumberGenerator(), icus: new Map() };
|
|
}
|
|
/**
|
|
* I18nContext is a helper class which keeps track of all i18n-related aspects
|
|
* (accumulates placeholders, bindings, etc) between i18nStart and i18nEnd instructions.
|
|
*
|
|
* When we enter a nested template, the top-level context is being passed down
|
|
* to the nested component, which uses this context to generate a child instance
|
|
* of I18nContext class (to handle nested template) and at the end, reconciles it back
|
|
* with the parent context.
|
|
*
|
|
* @param index Instruction index of i18nStart, which initiates this context
|
|
* @param ref Reference to a translation const that represents the content if thus context
|
|
* @param level Nestng level defined for child contexts
|
|
* @param templateIndex Instruction index of a template which this context belongs to
|
|
* @param meta Meta information (id, meaning, description, etc) associated with this context
|
|
*/
|
|
var I18nContext = /** @class */ (function () {
|
|
function I18nContext(index, ref, level, templateIndex, meta, registry) {
|
|
if (level === void 0) { level = 0; }
|
|
if (templateIndex === void 0) { templateIndex = null; }
|
|
this.index = index;
|
|
this.ref = ref;
|
|
this.level = level;
|
|
this.templateIndex = templateIndex;
|
|
this.meta = meta;
|
|
this.registry = registry;
|
|
this.bindings = new Set();
|
|
this.placeholders = new Map();
|
|
this.isEmitted = false;
|
|
this._unresolvedCtxCount = 0;
|
|
this._registry = registry || setupRegistry();
|
|
this.id = this._registry.getUniqueId();
|
|
}
|
|
I18nContext.prototype.appendTag = function (type, node, index, closed) {
|
|
if (node.isVoid && closed) {
|
|
return; // ignore "close" for void tags
|
|
}
|
|
var ph = node.isVoid || !closed ? node.startName : node.closeName;
|
|
var content = { type: type, index: index, ctx: this.id, isVoid: node.isVoid, closed: closed };
|
|
updatePlaceholderMap(this.placeholders, ph, content);
|
|
};
|
|
Object.defineProperty(I18nContext.prototype, "icus", {
|
|
get: function () {
|
|
return this._registry.icus;
|
|
},
|
|
enumerable: false,
|
|
configurable: true
|
|
});
|
|
Object.defineProperty(I18nContext.prototype, "isRoot", {
|
|
get: function () {
|
|
return this.level === 0;
|
|
},
|
|
enumerable: false,
|
|
configurable: true
|
|
});
|
|
Object.defineProperty(I18nContext.prototype, "isResolved", {
|
|
get: function () {
|
|
return this._unresolvedCtxCount === 0;
|
|
},
|
|
enumerable: false,
|
|
configurable: true
|
|
});
|
|
I18nContext.prototype.getSerializedPlaceholders = function () {
|
|
var result = new Map();
|
|
this.placeholders.forEach(function (values, key) { return result.set(key, values.map(serializePlaceholderValue)); });
|
|
return result;
|
|
};
|
|
// public API to accumulate i18n-related content
|
|
I18nContext.prototype.appendBinding = function (binding) {
|
|
this.bindings.add(binding);
|
|
};
|
|
I18nContext.prototype.appendIcu = function (name, ref) {
|
|
updatePlaceholderMap(this._registry.icus, name, ref);
|
|
};
|
|
I18nContext.prototype.appendBoundText = function (node) {
|
|
var _this = this;
|
|
var phs = assembleBoundTextPlaceholders(node, this.bindings.size, this.id);
|
|
phs.forEach(function (values, key) { return updatePlaceholderMap.apply(void 0, __spreadArray([_this.placeholders, key], __read(values))); });
|
|
};
|
|
I18nContext.prototype.appendTemplate = function (node, index) {
|
|
// add open and close tags at the same time,
|
|
// since we process nested templates separately
|
|
this.appendTag(TagType.TEMPLATE, node, index, false);
|
|
this.appendTag(TagType.TEMPLATE, node, index, true);
|
|
this._unresolvedCtxCount++;
|
|
};
|
|
I18nContext.prototype.appendElement = function (node, index, closed) {
|
|
this.appendTag(TagType.ELEMENT, node, index, closed);
|
|
};
|
|
I18nContext.prototype.appendProjection = function (node, index) {
|
|
// Add open and close tags at the same time, since `<ng-content>` has no content,
|
|
// so when we come across `<ng-content>` we can register both open and close tags.
|
|
// Note: runtime i18n logic doesn't distinguish `<ng-content>` tag placeholders and
|
|
// regular element tag placeholders, so we generate element placeholders for both types.
|
|
this.appendTag(TagType.ELEMENT, node, index, false);
|
|
this.appendTag(TagType.ELEMENT, node, index, true);
|
|
};
|
|
/**
|
|
* Generates an instance of a child context based on the root one,
|
|
* when we enter a nested template within I18n section.
|
|
*
|
|
* @param index Instruction index of corresponding i18nStart, which initiates this context
|
|
* @param templateIndex Instruction index of a template which this context belongs to
|
|
* @param meta Meta information (id, meaning, description, etc) associated with this context
|
|
*
|
|
* @returns I18nContext instance
|
|
*/
|
|
I18nContext.prototype.forkChildContext = function (index, templateIndex, meta) {
|
|
return new I18nContext(index, this.ref, this.level + 1, templateIndex, meta, this._registry);
|
|
};
|
|
/**
|
|
* Reconciles child context into parent one once the end of the i18n block is reached (i18nEnd).
|
|
*
|
|
* @param context Child I18nContext instance to be reconciled with parent context.
|
|
*/
|
|
I18nContext.prototype.reconcileChildContext = function (context) {
|
|
var _this = this;
|
|
// set the right context id for open and close
|
|
// template tags, so we can use it as sub-block ids
|
|
['start', 'close'].forEach(function (op) {
|
|
var key = context.meta[op + "Name"];
|
|
var phs = _this.placeholders.get(key) || [];
|
|
var tag = phs.find(findTemplateFn(_this.id, context.templateIndex));
|
|
if (tag) {
|
|
tag.ctx = context.id;
|
|
}
|
|
});
|
|
// reconcile placeholders
|
|
var childPhs = context.placeholders;
|
|
childPhs.forEach(function (values, key) {
|
|
var phs = _this.placeholders.get(key);
|
|
if (!phs) {
|
|
_this.placeholders.set(key, values);
|
|
return;
|
|
}
|
|
// try to find matching template...
|
|
var tmplIdx = phs.findIndex(findTemplateFn(context.id, context.templateIndex));
|
|
if (tmplIdx >= 0) {
|
|
// ... if found - replace it with nested template content
|
|
var isCloseTag = key.startsWith('CLOSE');
|
|
var isTemplateTag = key.endsWith('NG-TEMPLATE');
|
|
if (isTemplateTag) {
|
|
// current template's content is placed before or after
|
|
// parent template tag, depending on the open/close atrribute
|
|
phs.splice.apply(phs, __spreadArray([tmplIdx + (isCloseTag ? 0 : 1), 0], __read(values)));
|
|
}
|
|
else {
|
|
var idx = isCloseTag ? values.length - 1 : 0;
|
|
values[idx].tmpl = phs[tmplIdx];
|
|
phs.splice.apply(phs, __spreadArray([tmplIdx, 1], __read(values)));
|
|
}
|
|
}
|
|
else {
|
|
// ... otherwise just append content to placeholder value
|
|
phs.push.apply(phs, __spreadArray([], __read(values)));
|
|
}
|
|
_this.placeholders.set(key, phs);
|
|
});
|
|
this._unresolvedCtxCount--;
|
|
};
|
|
return I18nContext;
|
|
}());
|
|
//
|
|
// Helper methods
|
|
//
|
|
function wrap(symbol, index, contextId, closed) {
|
|
var state = closed ? '/' : '';
|
|
return wrapI18nPlaceholder("" + state + symbol + index, contextId);
|
|
}
|
|
function wrapTag(symbol, _a, closed) {
|
|
var index = _a.index, ctx = _a.ctx, isVoid = _a.isVoid;
|
|
return isVoid ? wrap(symbol, index, ctx) + wrap(symbol, index, ctx, true) :
|
|
wrap(symbol, index, ctx, closed);
|
|
}
|
|
function findTemplateFn(ctx, templateIndex) {
|
|
return function (token) { return typeof token === 'object' && token.type === TagType.TEMPLATE &&
|
|
token.index === templateIndex && token.ctx === ctx; };
|
|
}
|
|
function serializePlaceholderValue(value) {
|
|
var element = function (data, closed) { return wrapTag('#', data, closed); };
|
|
var template = function (data, closed) { return wrapTag('*', data, closed); };
|
|
var projection = function (data, closed) { return wrapTag('!', data, closed); };
|
|
switch (value.type) {
|
|
case TagType.ELEMENT:
|
|
// close element tag
|
|
if (value.closed) {
|
|
return element(value, true) + (value.tmpl ? template(value.tmpl, true) : '');
|
|
}
|
|
// open element tag that also initiates a template
|
|
if (value.tmpl) {
|
|
return template(value.tmpl) + element(value) +
|
|
(value.isVoid ? template(value.tmpl, true) : '');
|
|
}
|
|
return element(value);
|
|
case TagType.TEMPLATE:
|
|
return template(value, value.closed);
|
|
default:
|
|
return 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
|
|
*/
|
|
var IcuSerializerVisitor = /** @class */ (function () {
|
|
function IcuSerializerVisitor() {
|
|
}
|
|
IcuSerializerVisitor.prototype.visitText = function (text) {
|
|
return text.value;
|
|
};
|
|
IcuSerializerVisitor.prototype.visitContainer = function (container) {
|
|
var _this = this;
|
|
return container.children.map(function (child) { return child.visit(_this); }).join('');
|
|
};
|
|
IcuSerializerVisitor.prototype.visitIcu = function (icu) {
|
|
var _this = this;
|
|
var strCases = Object.keys(icu.cases).map(function (k) { return k + " {" + icu.cases[k].visit(_this) + "}"; });
|
|
var result = "{" + icu.expressionPlaceholder + ", " + icu.type + ", " + strCases.join(' ') + "}";
|
|
return result;
|
|
};
|
|
IcuSerializerVisitor.prototype.visitTagPlaceholder = function (ph) {
|
|
var _this = this;
|
|
return ph.isVoid ?
|
|
this.formatPh(ph.startName) :
|
|
"" + this.formatPh(ph.startName) + ph.children.map(function (child) { return child.visit(_this); }).join('') + this.formatPh(ph.closeName);
|
|
};
|
|
IcuSerializerVisitor.prototype.visitPlaceholder = function (ph) {
|
|
return this.formatPh(ph.name);
|
|
};
|
|
IcuSerializerVisitor.prototype.visitIcuPlaceholder = function (ph, context) {
|
|
return this.formatPh(ph.name);
|
|
};
|
|
IcuSerializerVisitor.prototype.formatPh = function (value) {
|
|
return "{" + formatI18nPlaceholderName(value, /* useCamelCase */ false) + "}";
|
|
};
|
|
return IcuSerializerVisitor;
|
|
}());
|
|
var serializer = new IcuSerializerVisitor();
|
|
function serializeIcuNode(icu) {
|
|
return icu.visit(serializer);
|
|
}
|
|
|
|
/**
|
|
* @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 TAG_TO_PLACEHOLDER_NAMES = {
|
|
'A': 'LINK',
|
|
'B': 'BOLD_TEXT',
|
|
'BR': 'LINE_BREAK',
|
|
'EM': 'EMPHASISED_TEXT',
|
|
'H1': 'HEADING_LEVEL1',
|
|
'H2': 'HEADING_LEVEL2',
|
|
'H3': 'HEADING_LEVEL3',
|
|
'H4': 'HEADING_LEVEL4',
|
|
'H5': 'HEADING_LEVEL5',
|
|
'H6': 'HEADING_LEVEL6',
|
|
'HR': 'HORIZONTAL_RULE',
|
|
'I': 'ITALIC_TEXT',
|
|
'LI': 'LIST_ITEM',
|
|
'LINK': 'MEDIA_LINK',
|
|
'OL': 'ORDERED_LIST',
|
|
'P': 'PARAGRAPH',
|
|
'Q': 'QUOTATION',
|
|
'S': 'STRIKETHROUGH_TEXT',
|
|
'SMALL': 'SMALL_TEXT',
|
|
'SUB': 'SUBSTRIPT',
|
|
'SUP': 'SUPERSCRIPT',
|
|
'TBODY': 'TABLE_BODY',
|
|
'TD': 'TABLE_CELL',
|
|
'TFOOT': 'TABLE_FOOTER',
|
|
'TH': 'TABLE_HEADER_CELL',
|
|
'THEAD': 'TABLE_HEADER',
|
|
'TR': 'TABLE_ROW',
|
|
'TT': 'MONOSPACED_TEXT',
|
|
'U': 'UNDERLINED_TEXT',
|
|
'UL': 'UNORDERED_LIST',
|
|
};
|
|
/**
|
|
* Creates unique names for placeholder with different content.
|
|
*
|
|
* Returns the same placeholder name when the content is identical.
|
|
*/
|
|
var PlaceholderRegistry = /** @class */ (function () {
|
|
function PlaceholderRegistry() {
|
|
// Count the occurrence of the base name top generate a unique name
|
|
this._placeHolderNameCounts = {};
|
|
// Maps signature to placeholder names
|
|
this._signatureToName = {};
|
|
}
|
|
PlaceholderRegistry.prototype.getStartTagPlaceholderName = function (tag, attrs, isVoid) {
|
|
var signature = this._hashTag(tag, attrs, isVoid);
|
|
if (this._signatureToName[signature]) {
|
|
return this._signatureToName[signature];
|
|
}
|
|
var upperTag = tag.toUpperCase();
|
|
var baseName = TAG_TO_PLACEHOLDER_NAMES[upperTag] || "TAG_" + upperTag;
|
|
var name = this._generateUniqueName(isVoid ? baseName : "START_" + baseName);
|
|
this._signatureToName[signature] = name;
|
|
return name;
|
|
};
|
|
PlaceholderRegistry.prototype.getCloseTagPlaceholderName = function (tag) {
|
|
var signature = this._hashClosingTag(tag);
|
|
if (this._signatureToName[signature]) {
|
|
return this._signatureToName[signature];
|
|
}
|
|
var upperTag = tag.toUpperCase();
|
|
var baseName = TAG_TO_PLACEHOLDER_NAMES[upperTag] || "TAG_" + upperTag;
|
|
var name = this._generateUniqueName("CLOSE_" + baseName);
|
|
this._signatureToName[signature] = name;
|
|
return name;
|
|
};
|
|
PlaceholderRegistry.prototype.getPlaceholderName = function (name, content) {
|
|
var upperName = name.toUpperCase();
|
|
var signature = "PH: " + upperName + "=" + content;
|
|
if (this._signatureToName[signature]) {
|
|
return this._signatureToName[signature];
|
|
}
|
|
var uniqueName = this._generateUniqueName(upperName);
|
|
this._signatureToName[signature] = uniqueName;
|
|
return uniqueName;
|
|
};
|
|
PlaceholderRegistry.prototype.getUniquePlaceholder = function (name) {
|
|
return this._generateUniqueName(name.toUpperCase());
|
|
};
|
|
// Generate a hash for a tag - does not take attribute order into account
|
|
PlaceholderRegistry.prototype._hashTag = function (tag, attrs, isVoid) {
|
|
var start = "<" + tag;
|
|
var strAttrs = Object.keys(attrs).sort().map(function (name) { return " " + name + "=" + attrs[name]; }).join('');
|
|
var end = isVoid ? '/>' : "></" + tag + ">";
|
|
return start + strAttrs + end;
|
|
};
|
|
PlaceholderRegistry.prototype._hashClosingTag = function (tag) {
|
|
return this._hashTag("/" + tag, {}, false);
|
|
};
|
|
PlaceholderRegistry.prototype._generateUniqueName = function (base) {
|
|
var seen = this._placeHolderNameCounts.hasOwnProperty(base);
|
|
if (!seen) {
|
|
this._placeHolderNameCounts[base] = 1;
|
|
return base;
|
|
}
|
|
var id = this._placeHolderNameCounts[base];
|
|
this._placeHolderNameCounts[base] = id + 1;
|
|
return base + "_" + id;
|
|
};
|
|
return PlaceholderRegistry;
|
|
}());
|
|
|
|
var _expParser = new Parser$1(new Lexer());
|
|
/**
|
|
* Returns a function converting html nodes to an i18n Message given an interpolationConfig
|
|
*/
|
|
function createI18nMessageFactory(interpolationConfig) {
|
|
var visitor = new _I18nVisitor(_expParser, interpolationConfig);
|
|
return function (nodes, meaning, description, customId, visitNodeFn) { return visitor.toI18nMessage(nodes, meaning, description, customId, visitNodeFn); };
|
|
}
|
|
function noopVisitNodeFn(_html, i18n) {
|
|
return i18n;
|
|
}
|
|
var _I18nVisitor = /** @class */ (function () {
|
|
function _I18nVisitor(_expressionParser, _interpolationConfig) {
|
|
this._expressionParser = _expressionParser;
|
|
this._interpolationConfig = _interpolationConfig;
|
|
}
|
|
_I18nVisitor.prototype.toI18nMessage = function (nodes, meaning, description, customId, visitNodeFn) {
|
|
if (meaning === void 0) { meaning = ''; }
|
|
if (description === void 0) { description = ''; }
|
|
if (customId === void 0) { customId = ''; }
|
|
var context = {
|
|
isIcu: nodes.length == 1 && nodes[0] instanceof Expansion,
|
|
icuDepth: 0,
|
|
placeholderRegistry: new PlaceholderRegistry(),
|
|
placeholderToContent: {},
|
|
placeholderToMessage: {},
|
|
visitNodeFn: visitNodeFn || noopVisitNodeFn,
|
|
};
|
|
var i18nodes = visitAll$1(this, nodes, context);
|
|
return new Message(i18nodes, context.placeholderToContent, context.placeholderToMessage, meaning, description, customId);
|
|
};
|
|
_I18nVisitor.prototype.visitElement = function (el, context) {
|
|
var _a;
|
|
var children = visitAll$1(this, el.children, context);
|
|
var attrs = {};
|
|
el.attrs.forEach(function (attr) {
|
|
// Do not visit the attributes, translatable ones are top-level ASTs
|
|
attrs[attr.name] = attr.value;
|
|
});
|
|
var isVoid = getHtmlTagDefinition(el.name).isVoid;
|
|
var startPhName = context.placeholderRegistry.getStartTagPlaceholderName(el.name, attrs, isVoid);
|
|
context.placeholderToContent[startPhName] = {
|
|
text: el.startSourceSpan.toString(),
|
|
sourceSpan: el.startSourceSpan,
|
|
};
|
|
var closePhName = '';
|
|
if (!isVoid) {
|
|
closePhName = context.placeholderRegistry.getCloseTagPlaceholderName(el.name);
|
|
context.placeholderToContent[closePhName] = {
|
|
text: "</" + el.name + ">",
|
|
sourceSpan: (_a = el.endSourceSpan) !== null && _a !== void 0 ? _a : el.sourceSpan,
|
|
};
|
|
}
|
|
var node = new TagPlaceholder(el.name, attrs, startPhName, closePhName, children, isVoid, el.sourceSpan, el.startSourceSpan, el.endSourceSpan);
|
|
return context.visitNodeFn(el, node);
|
|
};
|
|
_I18nVisitor.prototype.visitAttribute = function (attribute, context) {
|
|
var node = attribute.valueTokens === undefined || attribute.valueTokens.length === 1 ?
|
|
new Text$1(attribute.value, attribute.valueSpan || attribute.sourceSpan) :
|
|
this._visitTextWithInterpolation(attribute.valueTokens, attribute.valueSpan || attribute.sourceSpan, context, attribute.i18n);
|
|
return context.visitNodeFn(attribute, node);
|
|
};
|
|
_I18nVisitor.prototype.visitText = function (text, context) {
|
|
var node = text.tokens.length === 1 ?
|
|
new Text$1(text.value, text.sourceSpan) :
|
|
this._visitTextWithInterpolation(text.tokens, text.sourceSpan, context, text.i18n);
|
|
return context.visitNodeFn(text, node);
|
|
};
|
|
_I18nVisitor.prototype.visitComment = function (comment, context) {
|
|
return null;
|
|
};
|
|
_I18nVisitor.prototype.visitExpansion = function (icu, context) {
|
|
var _this = this;
|
|
context.icuDepth++;
|
|
var i18nIcuCases = {};
|
|
var i18nIcu = new Icu$1(icu.switchValue, icu.type, i18nIcuCases, icu.sourceSpan);
|
|
icu.cases.forEach(function (caze) {
|
|
i18nIcuCases[caze.value] = new Container(caze.expression.map(function (node) { return node.visit(_this, context); }), caze.expSourceSpan);
|
|
});
|
|
context.icuDepth--;
|
|
if (context.isIcu || context.icuDepth > 0) {
|
|
// Returns an ICU node when:
|
|
// - the message (vs a part of the message) is an ICU message, or
|
|
// - the ICU message is nested.
|
|
var expPh = context.placeholderRegistry.getUniquePlaceholder("VAR_" + icu.type);
|
|
i18nIcu.expressionPlaceholder = expPh;
|
|
context.placeholderToContent[expPh] = {
|
|
text: icu.switchValue,
|
|
sourceSpan: icu.switchValueSourceSpan,
|
|
};
|
|
return context.visitNodeFn(icu, i18nIcu);
|
|
}
|
|
// Else returns a placeholder
|
|
// ICU placeholders should not be replaced with their original content but with the their
|
|
// translations.
|
|
// TODO(vicb): add a html.Node -> i18n.Message cache to avoid having to re-create the msg
|
|
var phName = context.placeholderRegistry.getPlaceholderName('ICU', icu.sourceSpan.toString());
|
|
context.placeholderToMessage[phName] = this.toI18nMessage([icu], '', '', '', undefined);
|
|
var node = new IcuPlaceholder(i18nIcu, phName, icu.sourceSpan);
|
|
return context.visitNodeFn(icu, node);
|
|
};
|
|
_I18nVisitor.prototype.visitExpansionCase = function (_icuCase, _context) {
|
|
throw new Error('Unreachable code');
|
|
};
|
|
/**
|
|
* Convert, text and interpolated tokens up into text and placeholder pieces.
|
|
*
|
|
* @param tokens The text and interpolated tokens.
|
|
* @param sourceSpan The span of the whole of the `text` string.
|
|
* @param context The current context of the visitor, used to compute and store placeholders.
|
|
* @param previousI18n Any i18n metadata associated with this `text` from a previous pass.
|
|
*/
|
|
_I18nVisitor.prototype._visitTextWithInterpolation = function (tokens, sourceSpan, context, previousI18n) {
|
|
var e_1, _b;
|
|
// Return a sequence of `Text` and `Placeholder` nodes grouped in a `Container`.
|
|
var nodes = [];
|
|
// We will only create a container if there are actually interpolations,
|
|
// so this flag tracks that.
|
|
var hasInterpolation = false;
|
|
try {
|
|
for (var tokens_1 = __values(tokens), tokens_1_1 = tokens_1.next(); !tokens_1_1.done; tokens_1_1 = tokens_1.next()) {
|
|
var token = tokens_1_1.value;
|
|
switch (token.type) {
|
|
case 8 /* INTERPOLATION */:
|
|
case 17 /* ATTR_VALUE_INTERPOLATION */:
|
|
hasInterpolation = true;
|
|
var expression = token.parts[1];
|
|
var baseName = extractPlaceholderName(expression) || 'INTERPOLATION';
|
|
var phName = context.placeholderRegistry.getPlaceholderName(baseName, expression);
|
|
context.placeholderToContent[phName] = {
|
|
text: token.parts.join(''),
|
|
sourceSpan: token.sourceSpan
|
|
};
|
|
nodes.push(new Placeholder(expression, phName, token.sourceSpan));
|
|
break;
|
|
default:
|
|
if (token.parts[0].length > 0) {
|
|
// This token is text or an encoded entity.
|
|
// If it is following on from a previous text node then merge it into that node
|
|
// Otherwise, if it is following an interpolation, then add a new node.
|
|
var previous = nodes[nodes.length - 1];
|
|
if (previous instanceof Text$1) {
|
|
previous.value += token.parts[0];
|
|
previous.sourceSpan = new ParseSourceSpan(previous.sourceSpan.start, token.sourceSpan.end, previous.sourceSpan.fullStart, previous.sourceSpan.details);
|
|
}
|
|
else {
|
|
nodes.push(new Text$1(token.parts[0], token.sourceSpan));
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
finally {
|
|
try {
|
|
if (tokens_1_1 && !tokens_1_1.done && (_b = tokens_1.return)) _b.call(tokens_1);
|
|
}
|
|
finally { if (e_1) throw e_1.error; }
|
|
}
|
|
if (hasInterpolation) {
|
|
// Whitespace removal may have invalidated the interpolation source-spans.
|
|
reusePreviousSourceSpans(nodes, previousI18n);
|
|
return new Container(nodes, sourceSpan);
|
|
}
|
|
else {
|
|
return nodes[0];
|
|
}
|
|
};
|
|
return _I18nVisitor;
|
|
}());
|
|
/**
|
|
* Re-use the source-spans from `previousI18n` metadata for the `nodes`.
|
|
*
|
|
* Whitespace removal can invalidate the source-spans of interpolation nodes, so we
|
|
* reuse the source-span stored from a previous pass before the whitespace was removed.
|
|
*
|
|
* @param nodes The `Text` and `Placeholder` nodes to be processed.
|
|
* @param previousI18n Any i18n metadata for these `nodes` stored from a previous pass.
|
|
*/
|
|
function reusePreviousSourceSpans(nodes, previousI18n) {
|
|
if (previousI18n instanceof Message) {
|
|
// The `previousI18n` is an i18n `Message`, so we are processing an `Attribute` with i18n
|
|
// metadata. The `Message` should consist only of a single `Container` that contains the
|
|
// parts (`Text` and `Placeholder`) to process.
|
|
assertSingleContainerMessage(previousI18n);
|
|
previousI18n = previousI18n.nodes[0];
|
|
}
|
|
if (previousI18n instanceof Container) {
|
|
// The `previousI18n` is a `Container`, which means that this is a second i18n extraction pass
|
|
// after whitespace has been removed from the AST nodes.
|
|
assertEquivalentNodes(previousI18n.children, nodes);
|
|
// Reuse the source-spans from the first pass.
|
|
for (var i = 0; i < nodes.length; i++) {
|
|
nodes[i].sourceSpan = previousI18n.children[i].sourceSpan;
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* Asserts that the `message` contains exactly one `Container` node.
|
|
*/
|
|
function assertSingleContainerMessage(message) {
|
|
var nodes = message.nodes;
|
|
if (nodes.length !== 1 || !(nodes[0] instanceof Container)) {
|
|
throw new Error('Unexpected previous i18n message - expected it to consist of only a single `Container` node.');
|
|
}
|
|
}
|
|
/**
|
|
* Asserts that the `previousNodes` and `node` collections have the same number of elements and
|
|
* corresponding elements have the same node type.
|
|
*/
|
|
function assertEquivalentNodes(previousNodes, nodes) {
|
|
if (previousNodes.length !== nodes.length) {
|
|
throw new Error('The number of i18n message children changed between first and second pass.');
|
|
}
|
|
if (previousNodes.some(function (node, i) { return nodes[i].constructor !== node.constructor; })) {
|
|
throw new Error('The types of the i18n message children changed between first and second pass.');
|
|
}
|
|
}
|
|
var _CUSTOM_PH_EXP = /\/\/[\s\S]*i18n[\s\S]*\([\s\S]*ph[\s\S]*=[\s\S]*("|')([\s\S]*?)\1[\s\S]*\)/g;
|
|
function extractPlaceholderName(input) {
|
|
return input.split(_CUSTOM_PH_EXP)[2];
|
|
}
|
|
|
|
/**
|
|
* An i18n error.
|
|
*/
|
|
var I18nError = /** @class */ (function (_super) {
|
|
__extends(I18nError, _super);
|
|
function I18nError(span, msg) {
|
|
return _super.call(this, span, msg) || this;
|
|
}
|
|
return I18nError;
|
|
}(ParseError));
|
|
|
|
var setI18nRefs = function (htmlNode, i18nNode) {
|
|
if (htmlNode instanceof NodeWithI18n) {
|
|
if (i18nNode instanceof IcuPlaceholder && htmlNode.i18n instanceof Message) {
|
|
// This html node represents an ICU but this is a second processing pass, and the legacy id
|
|
// was computed in the previous pass and stored in the `i18n` property as a message.
|
|
// We are about to wipe out that property so capture the previous message to be reused when
|
|
// generating the message for this ICU later. See `_generateI18nMessage()`.
|
|
i18nNode.previousMessage = htmlNode.i18n;
|
|
}
|
|
htmlNode.i18n = i18nNode;
|
|
}
|
|
return i18nNode;
|
|
};
|
|
/**
|
|
* This visitor walks over HTML parse tree and converts information stored in
|
|
* i18n-related attributes ("i18n" and "i18n-*") into i18n meta object that is
|
|
* stored with other element's and attribute's information.
|
|
*/
|
|
var I18nMetaVisitor = /** @class */ (function () {
|
|
function I18nMetaVisitor(interpolationConfig, keepI18nAttrs, enableI18nLegacyMessageIdFormat) {
|
|
if (interpolationConfig === void 0) { interpolationConfig = DEFAULT_INTERPOLATION_CONFIG; }
|
|
if (keepI18nAttrs === void 0) { keepI18nAttrs = false; }
|
|
if (enableI18nLegacyMessageIdFormat === void 0) { enableI18nLegacyMessageIdFormat = false; }
|
|
this.interpolationConfig = interpolationConfig;
|
|
this.keepI18nAttrs = keepI18nAttrs;
|
|
this.enableI18nLegacyMessageIdFormat = enableI18nLegacyMessageIdFormat;
|
|
// whether visited nodes contain i18n information
|
|
this.hasI18nMeta = false;
|
|
this._errors = [];
|
|
// i18n message generation factory
|
|
this._createI18nMessage = createI18nMessageFactory(this.interpolationConfig);
|
|
}
|
|
I18nMetaVisitor.prototype._generateI18nMessage = function (nodes, meta, visitNodeFn) {
|
|
if (meta === void 0) { meta = ''; }
|
|
var _a = this._parseMetadata(meta), meaning = _a.meaning, description = _a.description, customId = _a.customId;
|
|
var message = this._createI18nMessage(nodes, meaning, description, customId, visitNodeFn);
|
|
this._setMessageId(message, meta);
|
|
this._setLegacyIds(message, meta);
|
|
return message;
|
|
};
|
|
I18nMetaVisitor.prototype.visitAllWithErrors = function (nodes) {
|
|
var _this = this;
|
|
var result = nodes.map(function (node) { return node.visit(_this, null); });
|
|
return new ParseTreeResult(result, this._errors);
|
|
};
|
|
I18nMetaVisitor.prototype.visitElement = function (element) {
|
|
var e_1, _a, e_2, _b;
|
|
if (hasI18nAttrs(element)) {
|
|
this.hasI18nMeta = true;
|
|
var attrs = [];
|
|
var attrsMeta = {};
|
|
try {
|
|
for (var _c = __values(element.attrs), _d = _c.next(); !_d.done; _d = _c.next()) {
|
|
var attr = _d.value;
|
|
if (attr.name === I18N_ATTR) {
|
|
// root 'i18n' node attribute
|
|
var i18n_1 = element.i18n || attr.value;
|
|
var message = this._generateI18nMessage(element.children, i18n_1, setI18nRefs);
|
|
// do not assign empty i18n meta
|
|
if (message.nodes.length) {
|
|
element.i18n = message;
|
|
}
|
|
}
|
|
else if (attr.name.startsWith(I18N_ATTR_PREFIX)) {
|
|
// 'i18n-*' attributes
|
|
var name = attr.name.slice(I18N_ATTR_PREFIX.length);
|
|
if (isTrustedTypesSink(element.name, name)) {
|
|
this._reportError(attr, "Translating attribute '" + name + "' is disallowed for security reasons.");
|
|
}
|
|
else {
|
|
attrsMeta[name] = attr.value;
|
|
}
|
|
}
|
|
else {
|
|
// non-i18n attributes
|
|
attrs.push(attr);
|
|
}
|
|
}
|
|
}
|
|
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
finally {
|
|
try {
|
|
if (_d && !_d.done && (_a = _c.return)) _a.call(_c);
|
|
}
|
|
finally { if (e_1) throw e_1.error; }
|
|
}
|
|
// set i18n meta for attributes
|
|
if (Object.keys(attrsMeta).length) {
|
|
try {
|
|
for (var attrs_1 = __values(attrs), attrs_1_1 = attrs_1.next(); !attrs_1_1.done; attrs_1_1 = attrs_1.next()) {
|
|
var attr = attrs_1_1.value;
|
|
var meta = attrsMeta[attr.name];
|
|
// do not create translation for empty attributes
|
|
if (meta !== undefined && attr.value) {
|
|
attr.i18n = this._generateI18nMessage([attr], attr.i18n || meta);
|
|
}
|
|
}
|
|
}
|
|
catch (e_2_1) { e_2 = { error: e_2_1 }; }
|
|
finally {
|
|
try {
|
|
if (attrs_1_1 && !attrs_1_1.done && (_b = attrs_1.return)) _b.call(attrs_1);
|
|
}
|
|
finally { if (e_2) throw e_2.error; }
|
|
}
|
|
}
|
|
if (!this.keepI18nAttrs) {
|
|
// update element's attributes,
|
|
// keeping only non-i18n related ones
|
|
element.attrs = attrs;
|
|
}
|
|
}
|
|
visitAll$1(this, element.children, element.i18n);
|
|
return element;
|
|
};
|
|
I18nMetaVisitor.prototype.visitExpansion = function (expansion, currentMessage) {
|
|
var message;
|
|
var meta = expansion.i18n;
|
|
this.hasI18nMeta = true;
|
|
if (meta instanceof IcuPlaceholder) {
|
|
// set ICU placeholder name (e.g. "ICU_1"),
|
|
// generated while processing root element contents,
|
|
// so we can reference it when we output translation
|
|
var name = meta.name;
|
|
message = this._generateI18nMessage([expansion], meta);
|
|
var icu = icuFromI18nMessage(message);
|
|
icu.name = name;
|
|
}
|
|
else {
|
|
// ICU is a top level message, try to use metadata from container element if provided via
|
|
// `context` argument. Note: context may not be available for standalone ICUs (without
|
|
// wrapping element), so fallback to ICU metadata in this case.
|
|
message = this._generateI18nMessage([expansion], currentMessage || meta);
|
|
}
|
|
expansion.i18n = message;
|
|
return expansion;
|
|
};
|
|
I18nMetaVisitor.prototype.visitText = function (text) {
|
|
return text;
|
|
};
|
|
I18nMetaVisitor.prototype.visitAttribute = function (attribute) {
|
|
return attribute;
|
|
};
|
|
I18nMetaVisitor.prototype.visitComment = function (comment) {
|
|
return comment;
|
|
};
|
|
I18nMetaVisitor.prototype.visitExpansionCase = function (expansionCase) {
|
|
return expansionCase;
|
|
};
|
|
/**
|
|
* Parse the general form `meta` passed into extract the explicit metadata needed to create a
|
|
* `Message`.
|
|
*
|
|
* There are three possibilities for the `meta` variable
|
|
* 1) a string from an `i18n` template attribute: parse it to extract the metadata values.
|
|
* 2) a `Message` from a previous processing pass: reuse the metadata values in the message.
|
|
* 4) other: ignore this and just process the message metadata as normal
|
|
*
|
|
* @param meta the bucket that holds information about the message
|
|
* @returns the parsed metadata.
|
|
*/
|
|
I18nMetaVisitor.prototype._parseMetadata = function (meta) {
|
|
return typeof meta === 'string' ? parseI18nMeta(meta) :
|
|
meta instanceof Message ? meta : {};
|
|
};
|
|
/**
|
|
* Generate (or restore) message id if not specified already.
|
|
*/
|
|
I18nMetaVisitor.prototype._setMessageId = function (message, meta) {
|
|
if (!message.id) {
|
|
message.id = meta instanceof Message && meta.id || decimalDigest(message);
|
|
}
|
|
};
|
|
/**
|
|
* Update the `message` with a `legacyId` if necessary.
|
|
*
|
|
* @param message the message whose legacy id should be set
|
|
* @param meta information about the message being processed
|
|
*/
|
|
I18nMetaVisitor.prototype._setLegacyIds = function (message, meta) {
|
|
if (this.enableI18nLegacyMessageIdFormat) {
|
|
message.legacyIds = [computeDigest(message), computeDecimalDigest(message)];
|
|
}
|
|
else if (typeof meta !== 'string') {
|
|
// This occurs if we are doing the 2nd pass after whitespace removal (see `parseTemplate()` in
|
|
// `packages/compiler/src/render3/view/template.ts`).
|
|
// In that case we want to reuse the legacy message generated in the 1st pass (see
|
|
// `setI18nRefs()`).
|
|
var previousMessage = meta instanceof Message ?
|
|
meta :
|
|
meta instanceof IcuPlaceholder ? meta.previousMessage : undefined;
|
|
message.legacyIds = previousMessage ? previousMessage.legacyIds : [];
|
|
}
|
|
};
|
|
I18nMetaVisitor.prototype._reportError = function (node, msg) {
|
|
this._errors.push(new I18nError(node.sourceSpan, msg));
|
|
};
|
|
return I18nMetaVisitor;
|
|
}());
|
|
/** I18n separators for metadata **/
|
|
var I18N_MEANING_SEPARATOR = '|';
|
|
var I18N_ID_SEPARATOR = '@@';
|
|
/**
|
|
* Parses i18n metas like:
|
|
* - "@@id",
|
|
* - "description[@@id]",
|
|
* - "meaning|description[@@id]"
|
|
* and returns an object with parsed output.
|
|
*
|
|
* @param meta String that represents i18n meta
|
|
* @returns Object with id, meaning and description fields
|
|
*/
|
|
function parseI18nMeta(meta) {
|
|
var _a, _b;
|
|
if (meta === void 0) { meta = ''; }
|
|
var customId;
|
|
var meaning;
|
|
var description;
|
|
meta = meta.trim();
|
|
if (meta) {
|
|
var idIndex = meta.indexOf(I18N_ID_SEPARATOR);
|
|
var descIndex = meta.indexOf(I18N_MEANING_SEPARATOR);
|
|
var meaningAndDesc = void 0;
|
|
_a = __read((idIndex > -1) ? [meta.slice(0, idIndex), meta.slice(idIndex + 2)] : [meta, ''], 2), meaningAndDesc = _a[0], customId = _a[1];
|
|
_b = __read((descIndex > -1) ?
|
|
[meaningAndDesc.slice(0, descIndex), meaningAndDesc.slice(descIndex + 1)] :
|
|
['', meaningAndDesc], 2), meaning = _b[0], description = _b[1];
|
|
}
|
|
return { customId: customId, meaning: meaning, description: description };
|
|
}
|
|
// Converts i18n meta information for a message (id, description, meaning)
|
|
// to a JsDoc statement formatted as expected by the Closure compiler.
|
|
function i18nMetaToJSDoc(meta) {
|
|
var tags = [];
|
|
if (meta.description) {
|
|
tags.push({ tagName: "desc" /* Desc */, text: meta.description });
|
|
}
|
|
if (meta.meaning) {
|
|
tags.push({ tagName: "meaning" /* Meaning */, text: meta.meaning });
|
|
}
|
|
return tags.length == 0 ? null : jsDocComment(tags);
|
|
}
|
|
|
|
/** Closure uses `goog.getMsg(message)` to lookup translations */
|
|
var GOOG_GET_MSG = 'goog.getMsg';
|
|
function createGoogleGetMsgStatements(variable$1, message, closureVar, params) {
|
|
var messageString = serializeI18nMessageForGetMsg(message);
|
|
var args = [literal(messageString)];
|
|
if (Object.keys(params).length) {
|
|
args.push(mapLiteral(params, true));
|
|
}
|
|
// /**
|
|
// * @desc description of message
|
|
// * @meaning meaning of message
|
|
// */
|
|
// const MSG_... = goog.getMsg(..);
|
|
// I18N_X = MSG_...;
|
|
var googGetMsgStmt = closureVar.set(variable(GOOG_GET_MSG).callFn(args)).toConstDecl();
|
|
var metaComment = i18nMetaToJSDoc(message);
|
|
if (metaComment !== null) {
|
|
googGetMsgStmt.addLeadingComment(metaComment);
|
|
}
|
|
var i18nAssignmentStmt = new ExpressionStatement(variable$1.set(closureVar));
|
|
return [googGetMsgStmt, i18nAssignmentStmt];
|
|
}
|
|
/**
|
|
* This visitor walks over i18n tree and generates its string representation, including ICUs and
|
|
* placeholders in `{$placeholder}` (for plain messages) or `{PLACEHOLDER}` (inside ICUs) format.
|
|
*/
|
|
var GetMsgSerializerVisitor = /** @class */ (function () {
|
|
function GetMsgSerializerVisitor() {
|
|
}
|
|
GetMsgSerializerVisitor.prototype.formatPh = function (value) {
|
|
return "{$" + formatI18nPlaceholderName(value) + "}";
|
|
};
|
|
GetMsgSerializerVisitor.prototype.visitText = function (text) {
|
|
return text.value;
|
|
};
|
|
GetMsgSerializerVisitor.prototype.visitContainer = function (container) {
|
|
var _this = this;
|
|
return container.children.map(function (child) { return child.visit(_this); }).join('');
|
|
};
|
|
GetMsgSerializerVisitor.prototype.visitIcu = function (icu) {
|
|
return serializeIcuNode(icu);
|
|
};
|
|
GetMsgSerializerVisitor.prototype.visitTagPlaceholder = function (ph) {
|
|
var _this = this;
|
|
return ph.isVoid ?
|
|
this.formatPh(ph.startName) :
|
|
"" + this.formatPh(ph.startName) + ph.children.map(function (child) { return child.visit(_this); }).join('') + this.formatPh(ph.closeName);
|
|
};
|
|
GetMsgSerializerVisitor.prototype.visitPlaceholder = function (ph) {
|
|
return this.formatPh(ph.name);
|
|
};
|
|
GetMsgSerializerVisitor.prototype.visitIcuPlaceholder = function (ph, context) {
|
|
return this.formatPh(ph.name);
|
|
};
|
|
return GetMsgSerializerVisitor;
|
|
}());
|
|
var serializerVisitor$1 = new GetMsgSerializerVisitor();
|
|
function serializeI18nMessageForGetMsg(message) {
|
|
return message.nodes.map(function (node) { return node.visit(serializerVisitor$1, null); }).join('');
|
|
}
|
|
|
|
function createLocalizeStatements(variable, message, params) {
|
|
var _c = serializeI18nMessageForLocalize(message), messageParts = _c.messageParts, placeHolders = _c.placeHolders;
|
|
var sourceSpan = getSourceSpan(message);
|
|
var expressions = placeHolders.map(function (ph) { return params[ph.text]; });
|
|
var localizedString$1 = localizedString(message, messageParts, placeHolders, expressions, sourceSpan);
|
|
var variableInitialization = variable.set(localizedString$1);
|
|
return [new ExpressionStatement(variableInitialization)];
|
|
}
|
|
/**
|
|
* This visitor walks over an i18n tree, capturing literal strings and placeholders.
|
|
*
|
|
* The result can be used for generating the `$localize` tagged template literals.
|
|
*/
|
|
var LocalizeSerializerVisitor = /** @class */ (function () {
|
|
function LocalizeSerializerVisitor() {
|
|
}
|
|
LocalizeSerializerVisitor.prototype.visitText = function (text, context) {
|
|
if (context[context.length - 1] instanceof LiteralPiece) {
|
|
// Two literal pieces in a row means that there was some comment node in-between.
|
|
context[context.length - 1].text += text.value;
|
|
}
|
|
else {
|
|
var sourceSpan = new ParseSourceSpan(text.sourceSpan.fullStart, text.sourceSpan.end, text.sourceSpan.fullStart, text.sourceSpan.details);
|
|
context.push(new LiteralPiece(text.value, sourceSpan));
|
|
}
|
|
};
|
|
LocalizeSerializerVisitor.prototype.visitContainer = function (container, context) {
|
|
var _this = this;
|
|
container.children.forEach(function (child) { return child.visit(_this, context); });
|
|
};
|
|
LocalizeSerializerVisitor.prototype.visitIcu = function (icu, context) {
|
|
context.push(new LiteralPiece(serializeIcuNode(icu), icu.sourceSpan));
|
|
};
|
|
LocalizeSerializerVisitor.prototype.visitTagPlaceholder = function (ph, context) {
|
|
var _this = this;
|
|
var _a, _b;
|
|
context.push(this.createPlaceholderPiece(ph.startName, (_a = ph.startSourceSpan) !== null && _a !== void 0 ? _a : ph.sourceSpan));
|
|
if (!ph.isVoid) {
|
|
ph.children.forEach(function (child) { return child.visit(_this, context); });
|
|
context.push(this.createPlaceholderPiece(ph.closeName, (_b = ph.endSourceSpan) !== null && _b !== void 0 ? _b : ph.sourceSpan));
|
|
}
|
|
};
|
|
LocalizeSerializerVisitor.prototype.visitPlaceholder = function (ph, context) {
|
|
context.push(this.createPlaceholderPiece(ph.name, ph.sourceSpan));
|
|
};
|
|
LocalizeSerializerVisitor.prototype.visitIcuPlaceholder = function (ph, context) {
|
|
context.push(this.createPlaceholderPiece(ph.name, ph.sourceSpan));
|
|
};
|
|
LocalizeSerializerVisitor.prototype.createPlaceholderPiece = function (name, sourceSpan) {
|
|
return new PlaceholderPiece(formatI18nPlaceholderName(name, /* useCamelCase */ false), sourceSpan);
|
|
};
|
|
return LocalizeSerializerVisitor;
|
|
}());
|
|
var serializerVisitor$2 = new LocalizeSerializerVisitor();
|
|
/**
|
|
* Serialize an i18n message into two arrays: messageParts and placeholders.
|
|
*
|
|
* These arrays will be used to generate `$localize` tagged template literals.
|
|
*
|
|
* @param message The message to be serialized.
|
|
* @returns an object containing the messageParts and placeholders.
|
|
*/
|
|
function serializeI18nMessageForLocalize(message) {
|
|
var pieces = [];
|
|
message.nodes.forEach(function (node) { return node.visit(serializerVisitor$2, pieces); });
|
|
return processMessagePieces(pieces);
|
|
}
|
|
function getSourceSpan(message) {
|
|
var startNode = message.nodes[0];
|
|
var endNode = message.nodes[message.nodes.length - 1];
|
|
return new ParseSourceSpan(startNode.sourceSpan.fullStart, endNode.sourceSpan.end, startNode.sourceSpan.fullStart, startNode.sourceSpan.details);
|
|
}
|
|
/**
|
|
* Convert the list of serialized MessagePieces into two arrays.
|
|
*
|
|
* One contains the literal string pieces and the other the placeholders that will be replaced by
|
|
* expressions when rendering `$localize` tagged template literals.
|
|
*
|
|
* @param pieces The pieces to process.
|
|
* @returns an object containing the messageParts and placeholders.
|
|
*/
|
|
function processMessagePieces(pieces) {
|
|
var messageParts = [];
|
|
var placeHolders = [];
|
|
if (pieces[0] instanceof PlaceholderPiece) {
|
|
// The first piece was a placeholder so we need to add an initial empty message part.
|
|
messageParts.push(createEmptyMessagePart(pieces[0].sourceSpan.start));
|
|
}
|
|
for (var i = 0; i < pieces.length; i++) {
|
|
var part = pieces[i];
|
|
if (part instanceof LiteralPiece) {
|
|
messageParts.push(part);
|
|
}
|
|
else {
|
|
placeHolders.push(part);
|
|
if (pieces[i - 1] instanceof PlaceholderPiece) {
|
|
// There were two placeholders in a row, so we need to add an empty message part.
|
|
messageParts.push(createEmptyMessagePart(pieces[i - 1].sourceSpan.end));
|
|
}
|
|
}
|
|
}
|
|
if (pieces[pieces.length - 1] instanceof PlaceholderPiece) {
|
|
// The last piece was a placeholder so we need to add a final empty message part.
|
|
messageParts.push(createEmptyMessagePart(pieces[pieces.length - 1].sourceSpan.end));
|
|
}
|
|
return { messageParts: messageParts, placeHolders: placeHolders };
|
|
}
|
|
function createEmptyMessagePart(location) {
|
|
return new LiteralPiece('', new ParseSourceSpan(location, location));
|
|
}
|
|
|
|
// Selector attribute name of `<ng-content>`
|
|
var NG_CONTENT_SELECT_ATTR$1 = 'select';
|
|
// Attribute name of `ngProjectAs`.
|
|
var NG_PROJECT_AS_ATTR_NAME = 'ngProjectAs';
|
|
// Global symbols available only inside event bindings.
|
|
var EVENT_BINDING_SCOPE_GLOBALS = new Set(['$event']);
|
|
// List of supported global targets for event listeners
|
|
var GLOBAL_TARGET_RESOLVERS = new Map([['window', Identifiers.resolveWindow], ['document', Identifiers.resolveDocument], ['body', Identifiers.resolveBody]]);
|
|
var LEADING_TRIVIA_CHARS = [' ', '\n', '\r', '\t'];
|
|
// if (rf & flags) { .. }
|
|
function renderFlagCheckIfStmt(flags, statements) {
|
|
return ifStmt(variable(RENDER_FLAGS).bitwiseAnd(literal(flags), null, false), statements);
|
|
}
|
|
function prepareEventListenerParameters(eventAst, handlerName, scope) {
|
|
if (handlerName === void 0) { handlerName = null; }
|
|
if (scope === void 0) { scope = null; }
|
|
var type = eventAst.type, name = eventAst.name, target = eventAst.target, phase = eventAst.phase, handler = eventAst.handler;
|
|
if (target && !GLOBAL_TARGET_RESOLVERS.has(target)) {
|
|
throw new Error("Unexpected global target '" + target + "' defined for '" + name + "' event.\n Supported list of global targets: " + Array.from(GLOBAL_TARGET_RESOLVERS.keys()) + ".");
|
|
}
|
|
var eventArgumentName = '$event';
|
|
var implicitReceiverAccesses = new Set();
|
|
var implicitReceiverExpr = (scope === null || scope.bindingLevel === 0) ?
|
|
variable(CONTEXT_NAME) :
|
|
scope.getOrCreateSharedContextVar(0);
|
|
var bindingExpr = convertActionBinding(scope, implicitReceiverExpr, handler, 'b', function () { return error('Unexpected interpolation'); }, eventAst.handlerSpan, implicitReceiverAccesses, EVENT_BINDING_SCOPE_GLOBALS);
|
|
var statements = [];
|
|
if (scope) {
|
|
// `variableDeclarations` needs to run first, because
|
|
// `restoreViewStatement` depends on the result.
|
|
statements.push.apply(statements, __spreadArray([], __read(scope.variableDeclarations())));
|
|
statements.unshift.apply(statements, __spreadArray([], __read(scope.restoreViewStatement())));
|
|
}
|
|
statements.push.apply(statements, __spreadArray([], __read(bindingExpr.render3Stmts)));
|
|
var eventName = type === 1 /* Animation */ ? prepareSyntheticListenerName(name, phase) : name;
|
|
var fnName = handlerName && sanitizeIdentifier(handlerName);
|
|
var fnArgs = [];
|
|
if (implicitReceiverAccesses.has(eventArgumentName)) {
|
|
fnArgs.push(new FnParam(eventArgumentName, DYNAMIC_TYPE));
|
|
}
|
|
var handlerFn = fn(fnArgs, statements, INFERRED_TYPE, null, fnName);
|
|
var params = [literal(eventName), handlerFn];
|
|
if (target) {
|
|
params.push(literal(false), // `useCapture` flag, defaults to `false`
|
|
importExpr(GLOBAL_TARGET_RESOLVERS.get(target)));
|
|
}
|
|
return params;
|
|
}
|
|
function createComponentDefConsts() {
|
|
return {
|
|
prepareStatements: [],
|
|
constExpressions: [],
|
|
i18nVarRefsCache: new Map(),
|
|
};
|
|
}
|
|
var TemplateDefinitionBuilder = /** @class */ (function () {
|
|
function TemplateDefinitionBuilder(constantPool, parentBindingScope, level, contextName, i18nContext, templateIndex, templateName, directiveMatcher, directives, pipeTypeByName, pipes, _namespace, relativeContextFilePath, i18nUseExternalIds, _constants) {
|
|
var _this = this;
|
|
if (level === void 0) { level = 0; }
|
|
if (_constants === void 0) { _constants = createComponentDefConsts(); }
|
|
this.constantPool = constantPool;
|
|
this.level = level;
|
|
this.contextName = contextName;
|
|
this.i18nContext = i18nContext;
|
|
this.templateIndex = templateIndex;
|
|
this.templateName = templateName;
|
|
this.directiveMatcher = directiveMatcher;
|
|
this.directives = directives;
|
|
this.pipeTypeByName = pipeTypeByName;
|
|
this.pipes = pipes;
|
|
this._namespace = _namespace;
|
|
this.i18nUseExternalIds = i18nUseExternalIds;
|
|
this._constants = _constants;
|
|
this._dataIndex = 0;
|
|
this._bindingContext = 0;
|
|
this._prefixCode = [];
|
|
/**
|
|
* List of callbacks to generate creation mode instructions. We store them here as we process
|
|
* the template so bindings in listeners are resolved only once all nodes have been visited.
|
|
* This ensures all local refs and context variables are available for matching.
|
|
*/
|
|
this._creationCodeFns = [];
|
|
/**
|
|
* List of callbacks to generate update mode instructions. We store them here as we process
|
|
* the template so bindings are resolved only once all nodes have been visited. This ensures
|
|
* all local refs and context variables are available for matching.
|
|
*/
|
|
this._updateCodeFns = [];
|
|
/** Index of the currently-selected node. */
|
|
this._currentIndex = 0;
|
|
/** Temporary variable declarations generated from visiting pipes, literals, etc. */
|
|
this._tempVariables = [];
|
|
/**
|
|
* List of callbacks to build nested templates. Nested templates must not be visited until
|
|
* after the parent template has finished visiting all of its nodes. This ensures that all
|
|
* local ref bindings in nested templates are able to find local ref values if the refs
|
|
* are defined after the template declaration.
|
|
*/
|
|
this._nestedTemplateFns = [];
|
|
this._unsupported = unsupported;
|
|
// i18n context local to this template
|
|
this.i18n = null;
|
|
// Number of slots to reserve for pureFunctions
|
|
this._pureFunctionSlots = 0;
|
|
// Number of binding slots
|
|
this._bindingSlots = 0;
|
|
// Projection slots found in the template. Projection slots can distribute projected
|
|
// nodes based on a selector, or can just use the wildcard selector to match
|
|
// all nodes which aren't matching any selector.
|
|
this._ngContentReservedSlots = [];
|
|
// Number of non-default selectors found in all parent templates of this template. We need to
|
|
// track it to properly adjust projection slot index in the `projection` instruction.
|
|
this._ngContentSelectorsOffset = 0;
|
|
// Expression that should be used as implicit receiver when converting template
|
|
// expressions to output AST.
|
|
this._implicitReceiverExpr = null;
|
|
// These should be handled in the template or element directly.
|
|
this.visitReference = invalid$1;
|
|
this.visitVariable = invalid$1;
|
|
this.visitTextAttribute = invalid$1;
|
|
this.visitBoundAttribute = invalid$1;
|
|
this.visitBoundEvent = invalid$1;
|
|
this._bindingScope = parentBindingScope.nestedScope(level);
|
|
// Turn the relative context file path into an identifier by replacing non-alphanumeric
|
|
// characters with underscores.
|
|
this.fileBasedI18nSuffix = relativeContextFilePath.replace(/[^A-Za-z0-9]/g, '_') + '_';
|
|
this._valueConverter = new ValueConverter(constantPool, function () { return _this.allocateDataSlot(); }, function (numSlots) { return _this.allocatePureFunctionSlots(numSlots); }, function (name, localName, slot, value) {
|
|
var pipeType = pipeTypeByName.get(name);
|
|
if (pipeType) {
|
|
_this.pipes.add(pipeType);
|
|
}
|
|
_this._bindingScope.set(_this.level, localName, value);
|
|
_this.creationInstruction(null, Identifiers.pipe, [literal(slot), literal(name)]);
|
|
});
|
|
}
|
|
TemplateDefinitionBuilder.prototype.buildTemplateFunction = function (nodes, variables, ngContentSelectorsOffset, i18n) {
|
|
var _this = this;
|
|
if (ngContentSelectorsOffset === void 0) { ngContentSelectorsOffset = 0; }
|
|
this._ngContentSelectorsOffset = ngContentSelectorsOffset;
|
|
if (this._namespace !== Identifiers.namespaceHTML) {
|
|
this.creationInstruction(null, this._namespace);
|
|
}
|
|
// Create variable bindings
|
|
variables.forEach(function (v) { return _this.registerContextVariables(v); });
|
|
// Initiate i18n context in case:
|
|
// - this template has parent i18n context
|
|
// - or the template has i18n meta associated with it,
|
|
// but it's not initiated by the Element (e.g. <ng-template i18n>)
|
|
var initI18nContext = this.i18nContext ||
|
|
(isI18nRootNode(i18n) && !isSingleI18nIcu(i18n) &&
|
|
!(isSingleElementTemplate(nodes) && nodes[0].i18n === i18n));
|
|
var selfClosingI18nInstruction = hasTextChildrenOnly(nodes);
|
|
if (initI18nContext) {
|
|
this.i18nStart(null, i18n, selfClosingI18nInstruction);
|
|
}
|
|
// This is the initial pass through the nodes of this template. In this pass, we
|
|
// queue all creation mode and update mode instructions for generation in the second
|
|
// pass. It's necessary to separate the passes to ensure local refs are defined before
|
|
// resolving bindings. We also count bindings in this pass as we walk bound expressions.
|
|
visitAll(this, nodes);
|
|
// Add total binding count to pure function count so pure function instructions are
|
|
// generated with the correct slot offset when update instructions are processed.
|
|
this._pureFunctionSlots += this._bindingSlots;
|
|
// Pipes are walked in the first pass (to enqueue `pipe()` creation instructions and
|
|
// `pipeBind` update instructions), so we have to update the slot offsets manually
|
|
// to account for bindings.
|
|
this._valueConverter.updatePipeSlotOffsets(this._bindingSlots);
|
|
// Nested templates must be processed before creation instructions so template()
|
|
// instructions can be generated with the correct internal const count.
|
|
this._nestedTemplateFns.forEach(function (buildTemplateFn) { return buildTemplateFn(); });
|
|
// Output the `projectionDef` instruction when some `<ng-content>` tags are present.
|
|
// The `projectionDef` instruction is only emitted for the component template and
|
|
// is skipped for nested templates (<ng-template> tags).
|
|
if (this.level === 0 && this._ngContentReservedSlots.length) {
|
|
var parameters = [];
|
|
// By default the `projectionDef` instructions creates one slot for the wildcard
|
|
// selector if no parameters are passed. Therefore we only want to allocate a new
|
|
// array for the projection slots if the default projection slot is not sufficient.
|
|
if (this._ngContentReservedSlots.length > 1 || this._ngContentReservedSlots[0] !== '*') {
|
|
var r3ReservedSlots = this._ngContentReservedSlots.map(function (s) { return s !== '*' ? parseSelectorToR3Selector(s) : s; });
|
|
parameters.push(this.constantPool.getConstLiteral(asLiteral(r3ReservedSlots), true));
|
|
}
|
|
// Since we accumulate ngContent selectors while processing template elements,
|
|
// we *prepend* `projectionDef` to creation instructions block, to put it before
|
|
// any `projection` instructions
|
|
this.creationInstruction(null, Identifiers.projectionDef, parameters, /* prepend */ true);
|
|
}
|
|
if (initI18nContext) {
|
|
this.i18nEnd(null, selfClosingI18nInstruction);
|
|
}
|
|
// Generate all the creation mode instructions (e.g. resolve bindings in listeners)
|
|
var creationStatements = this._creationCodeFns.map(function (fn) { return fn(); });
|
|
// Generate all the update mode instructions (e.g. resolve property or text bindings)
|
|
var updateStatements = this._updateCodeFns.map(function (fn) { return fn(); });
|
|
// Variable declaration must occur after binding resolution so we can generate context
|
|
// instructions that build on each other.
|
|
// e.g. const b = nextContext().$implicit(); const b = nextContext();
|
|
var creationVariables = this._bindingScope.viewSnapshotStatements();
|
|
var updateVariables = this._bindingScope.variableDeclarations().concat(this._tempVariables);
|
|
var creationBlock = creationStatements.length > 0 ?
|
|
[renderFlagCheckIfStmt(1 /* Create */, creationVariables.concat(creationStatements))] :
|
|
[];
|
|
var updateBlock = updateStatements.length > 0 ?
|
|
[renderFlagCheckIfStmt(2 /* Update */, updateVariables.concat(updateStatements))] :
|
|
[];
|
|
return fn(
|
|
// i.e. (rf: RenderFlags, ctx: any)
|
|
[new FnParam(RENDER_FLAGS, NUMBER_TYPE), new FnParam(CONTEXT_NAME, null)], __spreadArray(__spreadArray(__spreadArray([], __read(this._prefixCode)), __read(creationBlock)), __read(updateBlock)), INFERRED_TYPE, null, this.templateName);
|
|
};
|
|
// LocalResolver
|
|
TemplateDefinitionBuilder.prototype.getLocal = function (name) {
|
|
return this._bindingScope.get(name);
|
|
};
|
|
// LocalResolver
|
|
TemplateDefinitionBuilder.prototype.notifyImplicitReceiverUse = function () {
|
|
this._bindingScope.notifyImplicitReceiverUse();
|
|
};
|
|
// LocalResolver
|
|
TemplateDefinitionBuilder.prototype.maybeRestoreView = function () {
|
|
this._bindingScope.maybeRestoreView();
|
|
};
|
|
TemplateDefinitionBuilder.prototype.i18nTranslate = function (message, params, ref, transformFn) {
|
|
var _c;
|
|
if (params === void 0) { params = {}; }
|
|
var _ref = ref || this.i18nGenerateMainBlockVar();
|
|
// Closure Compiler requires const names to start with `MSG_` but disallows any other const to
|
|
// start with `MSG_`. We define a variable starting with `MSG_` just for the `goog.getMsg` call
|
|
var closureVar = this.i18nGenerateClosureVar(message.id);
|
|
var statements = getTranslationDeclStmts(message, _ref, closureVar, params, transformFn);
|
|
(_c = this._constants.prepareStatements).push.apply(_c, __spreadArray([], __read(statements)));
|
|
return _ref;
|
|
};
|
|
TemplateDefinitionBuilder.prototype.registerContextVariables = function (variable$1) {
|
|
var scopedName = this._bindingScope.freshReferenceName();
|
|
var retrievalLevel = this.level;
|
|
var lhs = variable(variable$1.name + scopedName);
|
|
this._bindingScope.set(retrievalLevel, variable$1.name, lhs, 1 /* CONTEXT */, function (scope, relativeLevel) {
|
|
var rhs;
|
|
if (scope.bindingLevel === retrievalLevel) {
|
|
if (scope.isListenerScope() && scope.hasRestoreViewVariable()) {
|
|
// e.g. restoredCtx.
|
|
// We have to get the context from a view reference, if one is available, because
|
|
// the context that was passed in during creation may not be correct anymore.
|
|
// For more information see: https://github.com/angular/angular/pull/40360.
|
|
rhs = variable(RESTORED_VIEW_CONTEXT_NAME);
|
|
scope.notifyRestoredViewContextUse();
|
|
}
|
|
else {
|
|
// e.g. ctx
|
|
rhs = variable(CONTEXT_NAME);
|
|
}
|
|
}
|
|
else {
|
|
var sharedCtxVar = scope.getSharedContextName(retrievalLevel);
|
|
// e.g. ctx_r0 OR x(2);
|
|
rhs = sharedCtxVar ? sharedCtxVar : generateNextContextExpr(relativeLevel);
|
|
}
|
|
// e.g. const $item$ = x(2).$implicit;
|
|
return [lhs.set(rhs.prop(variable$1.value || IMPLICIT_REFERENCE)).toConstDecl()];
|
|
});
|
|
};
|
|
TemplateDefinitionBuilder.prototype.i18nAppendBindings = function (expressions) {
|
|
var _this = this;
|
|
if (expressions.length > 0) {
|
|
expressions.forEach(function (expression) { return _this.i18n.appendBinding(expression); });
|
|
}
|
|
};
|
|
TemplateDefinitionBuilder.prototype.i18nBindProps = function (props) {
|
|
var _this = this;
|
|
var bound = {};
|
|
Object.keys(props).forEach(function (key) {
|
|
var prop = props[key];
|
|
if (prop instanceof Text) {
|
|
bound[key] = literal(prop.value);
|
|
}
|
|
else {
|
|
var value = prop.value.visit(_this._valueConverter);
|
|
_this.allocateBindingSlots(value);
|
|
if (value instanceof Interpolation) {
|
|
var strings = value.strings, expressions = value.expressions;
|
|
var _c = _this.i18n, id = _c.id, bindings = _c.bindings;
|
|
var label = assembleI18nBoundString(strings, bindings.size, id);
|
|
_this.i18nAppendBindings(expressions);
|
|
bound[key] = literal(label);
|
|
}
|
|
}
|
|
});
|
|
return bound;
|
|
};
|
|
// Generates top level vars for i18n blocks (i.e. `i18n_N`).
|
|
TemplateDefinitionBuilder.prototype.i18nGenerateMainBlockVar = function () {
|
|
return variable(this.constantPool.uniqueName(TRANSLATION_VAR_PREFIX));
|
|
};
|
|
// Generates vars with Closure-specific names for i18n blocks (i.e. `MSG_XXX`).
|
|
TemplateDefinitionBuilder.prototype.i18nGenerateClosureVar = function (messageId) {
|
|
var name;
|
|
var suffix = this.fileBasedI18nSuffix.toUpperCase();
|
|
if (this.i18nUseExternalIds) {
|
|
var prefix = getTranslationConstPrefix("EXTERNAL_");
|
|
var uniqueSuffix = this.constantPool.uniqueName(suffix);
|
|
name = "" + prefix + sanitizeIdentifier(messageId) + "$$" + uniqueSuffix;
|
|
}
|
|
else {
|
|
var prefix = getTranslationConstPrefix(suffix);
|
|
name = this.constantPool.uniqueName(prefix);
|
|
}
|
|
return variable(name);
|
|
};
|
|
TemplateDefinitionBuilder.prototype.i18nUpdateRef = function (context) {
|
|
var icus = context.icus, meta = context.meta, isRoot = context.isRoot, isResolved = context.isResolved, isEmitted = context.isEmitted;
|
|
if (isRoot && isResolved && !isEmitted && !isSingleI18nIcu(meta)) {
|
|
context.isEmitted = true;
|
|
var placeholders = context.getSerializedPlaceholders();
|
|
var icuMapping_1 = {};
|
|
var params_1 = placeholders.size ? placeholdersToParams(placeholders) : {};
|
|
if (icus.size) {
|
|
icus.forEach(function (refs, key) {
|
|
if (refs.length === 1) {
|
|
// if we have one ICU defined for a given
|
|
// placeholder - just output its reference
|
|
params_1[key] = refs[0];
|
|
}
|
|
else {
|
|
// ... otherwise we need to activate post-processing
|
|
// to replace ICU placeholders with proper values
|
|
var placeholder = wrapI18nPlaceholder("" + I18N_ICU_MAPPING_PREFIX + key);
|
|
params_1[key] = literal(placeholder);
|
|
icuMapping_1[key] = literalArr(refs);
|
|
}
|
|
});
|
|
}
|
|
// translation requires post processing in 2 cases:
|
|
// - if we have placeholders with multiple values (ex. `START_DIV`: [�#1�, �#2�, ...])
|
|
// - if we have multiple ICUs that refer to the same placeholder name
|
|
var needsPostprocessing = Array.from(placeholders.values()).some(function (value) { return value.length > 1; }) ||
|
|
Object.keys(icuMapping_1).length;
|
|
var transformFn = void 0;
|
|
if (needsPostprocessing) {
|
|
transformFn = function (raw) {
|
|
var args = [raw];
|
|
if (Object.keys(icuMapping_1).length) {
|
|
args.push(mapLiteral(icuMapping_1, true));
|
|
}
|
|
return instruction(null, Identifiers.i18nPostprocess, args);
|
|
};
|
|
}
|
|
this.i18nTranslate(meta, params_1, context.ref, transformFn);
|
|
}
|
|
};
|
|
TemplateDefinitionBuilder.prototype.i18nStart = function (span, meta, selfClosing) {
|
|
if (span === void 0) { span = null; }
|
|
var index = this.allocateDataSlot();
|
|
this.i18n = this.i18nContext ?
|
|
this.i18nContext.forkChildContext(index, this.templateIndex, meta) :
|
|
new I18nContext(index, this.i18nGenerateMainBlockVar(), 0, this.templateIndex, meta);
|
|
// generate i18nStart instruction
|
|
var _c = this.i18n, id = _c.id, ref = _c.ref;
|
|
var params = [literal(index), this.addToConsts(ref)];
|
|
if (id > 0) {
|
|
// do not push 3rd argument (sub-block id)
|
|
// into i18nStart call for top level i18n context
|
|
params.push(literal(id));
|
|
}
|
|
this.creationInstruction(span, selfClosing ? Identifiers.i18n : Identifiers.i18nStart, params);
|
|
};
|
|
TemplateDefinitionBuilder.prototype.i18nEnd = function (span, selfClosing) {
|
|
var _this = this;
|
|
if (span === void 0) { span = null; }
|
|
if (!this.i18n) {
|
|
throw new Error('i18nEnd is executed with no i18n context present');
|
|
}
|
|
if (this.i18nContext) {
|
|
this.i18nContext.reconcileChildContext(this.i18n);
|
|
this.i18nUpdateRef(this.i18nContext);
|
|
}
|
|
else {
|
|
this.i18nUpdateRef(this.i18n);
|
|
}
|
|
// setup accumulated bindings
|
|
var _c = this.i18n, index = _c.index, bindings = _c.bindings;
|
|
if (bindings.size) {
|
|
var chainBindings_1 = [];
|
|
bindings.forEach(function (binding) {
|
|
chainBindings_1.push({ sourceSpan: span, value: function () { return _this.convertPropertyBinding(binding); } });
|
|
});
|
|
// for i18n block, advance to the most recent element index (by taking the current number of
|
|
// elements and subtracting one) before invoking `i18nExp` instructions, to make sure the
|
|
// necessary lifecycle hooks of components/directives are properly flushed.
|
|
this.updateInstructionChainWithAdvance(this.getConstCount() - 1, Identifiers.i18nExp, chainBindings_1);
|
|
this.updateInstruction(span, Identifiers.i18nApply, [literal(index)]);
|
|
}
|
|
if (!selfClosing) {
|
|
this.creationInstruction(span, Identifiers.i18nEnd);
|
|
}
|
|
this.i18n = null; // reset local i18n context
|
|
};
|
|
TemplateDefinitionBuilder.prototype.i18nAttributesInstruction = function (nodeIndex, attrs, sourceSpan) {
|
|
var _this = this;
|
|
var hasBindings = false;
|
|
var i18nAttrArgs = [];
|
|
var bindings = [];
|
|
attrs.forEach(function (attr) {
|
|
var message = attr.i18n;
|
|
var converted = attr.value.visit(_this._valueConverter);
|
|
_this.allocateBindingSlots(converted);
|
|
if (converted instanceof Interpolation) {
|
|
var placeholders = assembleBoundTextPlaceholders(message);
|
|
var params = placeholdersToParams(placeholders);
|
|
i18nAttrArgs.push(literal(attr.name), _this.i18nTranslate(message, params));
|
|
converted.expressions.forEach(function (expression) {
|
|
hasBindings = true;
|
|
bindings.push({
|
|
sourceSpan: sourceSpan,
|
|
value: function () { return _this.convertPropertyBinding(expression); },
|
|
});
|
|
});
|
|
}
|
|
});
|
|
if (bindings.length > 0) {
|
|
this.updateInstructionChainWithAdvance(nodeIndex, Identifiers.i18nExp, bindings);
|
|
}
|
|
if (i18nAttrArgs.length > 0) {
|
|
var index = literal(this.allocateDataSlot());
|
|
var constIndex = this.addToConsts(literalArr(i18nAttrArgs));
|
|
this.creationInstruction(sourceSpan, Identifiers.i18nAttributes, [index, constIndex]);
|
|
if (hasBindings) {
|
|
this.updateInstruction(sourceSpan, Identifiers.i18nApply, [index]);
|
|
}
|
|
}
|
|
};
|
|
TemplateDefinitionBuilder.prototype.getNamespaceInstruction = function (namespaceKey) {
|
|
switch (namespaceKey) {
|
|
case 'math':
|
|
return Identifiers.namespaceMathML;
|
|
case 'svg':
|
|
return Identifiers.namespaceSVG;
|
|
default:
|
|
return Identifiers.namespaceHTML;
|
|
}
|
|
};
|
|
TemplateDefinitionBuilder.prototype.addNamespaceInstruction = function (nsInstruction, element) {
|
|
this._namespace = nsInstruction;
|
|
this.creationInstruction(element.startSourceSpan, nsInstruction);
|
|
};
|
|
/**
|
|
* Adds an update instruction for an interpolated property or attribute, such as
|
|
* `prop="{{value}}"` or `attr.title="{{value}}"`
|
|
*/
|
|
TemplateDefinitionBuilder.prototype.interpolatedUpdateInstruction = function (instruction, elementIndex, attrName, input, value, params) {
|
|
var _this = this;
|
|
this.updateInstructionWithAdvance(elementIndex, input.sourceSpan, instruction, function () { return __spreadArray(__spreadArray([literal(attrName)], __read(_this.getUpdateInstructionArguments(value))), __read(params)); });
|
|
};
|
|
TemplateDefinitionBuilder.prototype.visitContent = function (ngContent) {
|
|
var slot = this.allocateDataSlot();
|
|
var projectionSlotIdx = this._ngContentSelectorsOffset + this._ngContentReservedSlots.length;
|
|
var parameters = [literal(slot)];
|
|
this._ngContentReservedSlots.push(ngContent.selector);
|
|
var nonContentSelectAttributes = ngContent.attributes.filter(function (attr) { return attr.name.toLowerCase() !== NG_CONTENT_SELECT_ATTR$1; });
|
|
var attributes = this.getAttributeExpressions(ngContent.name, nonContentSelectAttributes, [], []);
|
|
if (attributes.length > 0) {
|
|
parameters.push(literal(projectionSlotIdx), literalArr(attributes));
|
|
}
|
|
else if (projectionSlotIdx !== 0) {
|
|
parameters.push(literal(projectionSlotIdx));
|
|
}
|
|
this.creationInstruction(ngContent.sourceSpan, Identifiers.projection, parameters);
|
|
if (this.i18n) {
|
|
this.i18n.appendProjection(ngContent.i18n, slot);
|
|
}
|
|
};
|
|
TemplateDefinitionBuilder.prototype.visitElement = function (element) {
|
|
var e_1, _c;
|
|
var _this = this;
|
|
var _a, _b;
|
|
var elementIndex = this.allocateDataSlot();
|
|
var stylingBuilder = new StylingBuilder(null);
|
|
var isNonBindableMode = false;
|
|
var isI18nRootElement = isI18nRootNode(element.i18n) && !isSingleI18nIcu(element.i18n);
|
|
var outputAttrs = [];
|
|
var _d = __read(splitNsName(element.name), 2), namespaceKey = _d[0], elementName = _d[1];
|
|
var isNgContainer$1 = isNgContainer(element.name);
|
|
try {
|
|
// Handle styling, i18n, ngNonBindable attributes
|
|
for (var _e = __values(element.attributes), _f = _e.next(); !_f.done; _f = _e.next()) {
|
|
var attr = _f.value;
|
|
var name = attr.name, value = attr.value;
|
|
if (name === NON_BINDABLE_ATTR) {
|
|
isNonBindableMode = true;
|
|
}
|
|
else if (name === 'style') {
|
|
stylingBuilder.registerStyleAttr(value);
|
|
}
|
|
else if (name === 'class') {
|
|
stylingBuilder.registerClassAttr(value);
|
|
}
|
|
else {
|
|
outputAttrs.push(attr);
|
|
}
|
|
}
|
|
}
|
|
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
finally {
|
|
try {
|
|
if (_f && !_f.done && (_c = _e.return)) _c.call(_e);
|
|
}
|
|
finally { if (e_1) throw e_1.error; }
|
|
}
|
|
// Match directives on non i18n attributes
|
|
this.matchDirectives(element.name, element);
|
|
// Regular element or ng-container creation mode
|
|
var parameters = [literal(elementIndex)];
|
|
if (!isNgContainer$1) {
|
|
parameters.push(literal(elementName));
|
|
}
|
|
// Add the attributes
|
|
var allOtherInputs = [];
|
|
var boundI18nAttrs = [];
|
|
element.inputs.forEach(function (input) {
|
|
var stylingInputWasSet = stylingBuilder.registerBoundInput(input);
|
|
if (!stylingInputWasSet) {
|
|
if (input.type === 0 /* Property */ && input.i18n) {
|
|
boundI18nAttrs.push(input);
|
|
}
|
|
else {
|
|
allOtherInputs.push(input);
|
|
}
|
|
}
|
|
});
|
|
// add attributes for directive and projection matching purposes
|
|
var attributes = this.getAttributeExpressions(element.name, outputAttrs, allOtherInputs, element.outputs, stylingBuilder, [], boundI18nAttrs);
|
|
parameters.push(this.addAttrsToConsts(attributes));
|
|
// local refs (ex.: <div #foo #bar="baz">)
|
|
var refs = this.prepareRefsArray(element.references);
|
|
parameters.push(this.addToConsts(refs));
|
|
var wasInNamespace = this._namespace;
|
|
var currentNamespace = this.getNamespaceInstruction(namespaceKey);
|
|
// If the namespace is changing now, include an instruction to change it
|
|
// during element creation.
|
|
if (currentNamespace !== wasInNamespace) {
|
|
this.addNamespaceInstruction(currentNamespace, element);
|
|
}
|
|
if (this.i18n) {
|
|
this.i18n.appendElement(element.i18n, elementIndex);
|
|
}
|
|
// Note that we do not append text node instructions and ICUs inside i18n section,
|
|
// so we exclude them while calculating whether current element has children
|
|
var hasChildren = (!isI18nRootElement && this.i18n) ? !hasTextChildrenOnly(element.children) :
|
|
element.children.length > 0;
|
|
var createSelfClosingInstruction = !stylingBuilder.hasBindingsWithPipes &&
|
|
element.outputs.length === 0 && boundI18nAttrs.length === 0 && !hasChildren;
|
|
var createSelfClosingI18nInstruction = !createSelfClosingInstruction && hasTextChildrenOnly(element.children);
|
|
if (createSelfClosingInstruction) {
|
|
this.creationInstruction(element.sourceSpan, isNgContainer$1 ? Identifiers.elementContainer : Identifiers.element, trimTrailingNulls(parameters));
|
|
}
|
|
else {
|
|
this.creationInstruction(element.startSourceSpan, isNgContainer$1 ? Identifiers.elementContainerStart : Identifiers.elementStart, trimTrailingNulls(parameters));
|
|
if (isNonBindableMode) {
|
|
this.creationInstruction(element.startSourceSpan, Identifiers.disableBindings);
|
|
}
|
|
if (boundI18nAttrs.length > 0) {
|
|
this.i18nAttributesInstruction(elementIndex, boundI18nAttrs, (_a = element.startSourceSpan) !== null && _a !== void 0 ? _a : element.sourceSpan);
|
|
}
|
|
// Generate Listeners (outputs)
|
|
if (element.outputs.length > 0) {
|
|
var listeners = element.outputs.map(function (outputAst) { return ({
|
|
sourceSpan: outputAst.sourceSpan,
|
|
params: _this.prepareListenerParameter(element.name, outputAst, elementIndex)
|
|
}); });
|
|
this.creationInstructionChain(Identifiers.listener, listeners);
|
|
}
|
|
// Note: it's important to keep i18n/i18nStart instructions after i18nAttributes and
|
|
// listeners, to make sure i18nAttributes instruction targets current element at runtime.
|
|
if (isI18nRootElement) {
|
|
this.i18nStart(element.startSourceSpan, element.i18n, createSelfClosingI18nInstruction);
|
|
}
|
|
}
|
|
// the code here will collect all update-level styling instructions and add them to the
|
|
// update block of the template function AOT code. Instructions like `styleProp`,
|
|
// `styleMap`, `classMap`, `classProp`
|
|
// are all generated and assigned in the code below.
|
|
var stylingInstructions = stylingBuilder.buildUpdateLevelInstructions(this._valueConverter);
|
|
var limit = stylingInstructions.length - 1;
|
|
for (var i = 0; i <= limit; i++) {
|
|
var instruction_1 = stylingInstructions[i];
|
|
this._bindingSlots += this.processStylingUpdateInstruction(elementIndex, instruction_1);
|
|
}
|
|
// the reason why `undefined` is used is because the renderer understands this as a
|
|
// special value to symbolize that there is no RHS to this binding
|
|
// TODO (matsko): revisit this once FW-959 is approached
|
|
var emptyValueBindInstruction = literal(undefined);
|
|
var propertyBindings = [];
|
|
var attributeBindings = [];
|
|
// Generate element input bindings
|
|
allOtherInputs.forEach(function (input) {
|
|
var inputType = input.type;
|
|
if (inputType === 4 /* Animation */) {
|
|
var value_1 = input.value.visit(_this._valueConverter);
|
|
// animation bindings can be presented in the following formats:
|
|
// 1. [@binding]="fooExp"
|
|
// 2. [@binding]="{value:fooExp, params:{...}}"
|
|
// 3. [@binding]
|
|
// 4. @binding
|
|
// All formats will be valid for when a synthetic binding is created.
|
|
// The reasoning for this is because the renderer should get each
|
|
// synthetic binding value in the order of the array that they are
|
|
// defined in...
|
|
var hasValue_1 = value_1 instanceof LiteralPrimitive ? !!value_1.value : true;
|
|
_this.allocateBindingSlots(value_1);
|
|
propertyBindings.push({
|
|
name: prepareSyntheticPropertyName(input.name),
|
|
sourceSpan: input.sourceSpan,
|
|
value: function () { return hasValue_1 ? _this.convertPropertyBinding(value_1) : emptyValueBindInstruction; }
|
|
});
|
|
}
|
|
else {
|
|
// we must skip attributes with associated i18n context, since these attributes are handled
|
|
// separately and corresponding `i18nExp` and `i18nApply` instructions will be generated
|
|
if (input.i18n)
|
|
return;
|
|
var value_2 = input.value.visit(_this._valueConverter);
|
|
if (value_2 !== undefined) {
|
|
var params_2 = [];
|
|
var _c = __read(splitNsName(input.name), 2), attrNamespace = _c[0], attrName_1 = _c[1];
|
|
var isAttributeBinding = inputType === 1 /* Attribute */;
|
|
var sanitizationRef = resolveSanitizationFn(input.securityContext, isAttributeBinding);
|
|
if (sanitizationRef)
|
|
params_2.push(sanitizationRef);
|
|
if (attrNamespace) {
|
|
var namespaceLiteral = literal(attrNamespace);
|
|
if (sanitizationRef) {
|
|
params_2.push(namespaceLiteral);
|
|
}
|
|
else {
|
|
// If there wasn't a sanitization ref, we need to add
|
|
// an extra param so that we can pass in the namespace.
|
|
params_2.push(literal(null), namespaceLiteral);
|
|
}
|
|
}
|
|
_this.allocateBindingSlots(value_2);
|
|
if (inputType === 0 /* Property */) {
|
|
if (value_2 instanceof Interpolation) {
|
|
// prop="{{value}}" and friends
|
|
_this.interpolatedUpdateInstruction(getPropertyInterpolationExpression(value_2), elementIndex, attrName_1, input, value_2, params_2);
|
|
}
|
|
else {
|
|
// [prop]="value"
|
|
// Collect all the properties so that we can chain into a single function at the end.
|
|
propertyBindings.push({
|
|
name: attrName_1,
|
|
sourceSpan: input.sourceSpan,
|
|
value: function () { return _this.convertPropertyBinding(value_2); },
|
|
params: params_2
|
|
});
|
|
}
|
|
}
|
|
else if (inputType === 1 /* Attribute */) {
|
|
if (value_2 instanceof Interpolation && getInterpolationArgsLength(value_2) > 1) {
|
|
// attr.name="text{{value}}" and friends
|
|
_this.interpolatedUpdateInstruction(getAttributeInterpolationExpression(value_2), elementIndex, attrName_1, input, value_2, params_2);
|
|
}
|
|
else {
|
|
var boundValue_1 = value_2 instanceof Interpolation ? value_2.expressions[0] : value_2;
|
|
// [attr.name]="value" or attr.name="{{value}}"
|
|
// Collect the attribute bindings so that they can be chained at the end.
|
|
attributeBindings.push({
|
|
name: attrName_1,
|
|
sourceSpan: input.sourceSpan,
|
|
value: function () { return _this.convertPropertyBinding(boundValue_1); },
|
|
params: params_2
|
|
});
|
|
}
|
|
}
|
|
else {
|
|
// class prop
|
|
_this.updateInstructionWithAdvance(elementIndex, input.sourceSpan, Identifiers.classProp, function () {
|
|
return __spreadArray([
|
|
literal(elementIndex), literal(attrName_1), _this.convertPropertyBinding(value_2)
|
|
], __read(params_2));
|
|
});
|
|
}
|
|
}
|
|
}
|
|
});
|
|
if (propertyBindings.length > 0) {
|
|
this.updateInstructionChainWithAdvance(elementIndex, Identifiers.property, propertyBindings);
|
|
}
|
|
if (attributeBindings.length > 0) {
|
|
this.updateInstructionChainWithAdvance(elementIndex, Identifiers.attribute, attributeBindings);
|
|
}
|
|
// Traverse element child nodes
|
|
visitAll(this, element.children);
|
|
if (!isI18nRootElement && this.i18n) {
|
|
this.i18n.appendElement(element.i18n, elementIndex, true);
|
|
}
|
|
if (!createSelfClosingInstruction) {
|
|
// Finish element construction mode.
|
|
var span = (_b = element.endSourceSpan) !== null && _b !== void 0 ? _b : element.sourceSpan;
|
|
if (isI18nRootElement) {
|
|
this.i18nEnd(span, createSelfClosingI18nInstruction);
|
|
}
|
|
if (isNonBindableMode) {
|
|
this.creationInstruction(span, Identifiers.enableBindings);
|
|
}
|
|
this.creationInstruction(span, isNgContainer$1 ? Identifiers.elementContainerEnd : Identifiers.elementEnd);
|
|
}
|
|
};
|
|
TemplateDefinitionBuilder.prototype.visitTemplate = function (template) {
|
|
var _this = this;
|
|
var _a;
|
|
var NG_TEMPLATE_TAG_NAME = 'ng-template';
|
|
var templateIndex = this.allocateDataSlot();
|
|
if (this.i18n) {
|
|
this.i18n.appendTemplate(template.i18n, templateIndex);
|
|
}
|
|
var tagNameWithoutNamespace = template.tagName ? splitNsName(template.tagName)[1] : template.tagName;
|
|
var contextName = "" + this.contextName + (template.tagName ? '_' + sanitizeIdentifier(template.tagName) : '') + "_" + templateIndex;
|
|
var templateName = contextName + "_Template";
|
|
var parameters = [
|
|
literal(templateIndex),
|
|
variable(templateName),
|
|
// We don't care about the tag's namespace here, because we infer
|
|
// it based on the parent nodes inside the template instruction.
|
|
literal(tagNameWithoutNamespace),
|
|
];
|
|
// find directives matching on a given <ng-template> node
|
|
this.matchDirectives(NG_TEMPLATE_TAG_NAME, template);
|
|
// prepare attributes parameter (including attributes used for directive matching)
|
|
var attrsExprs = this.getAttributeExpressions(NG_TEMPLATE_TAG_NAME, template.attributes, template.inputs, template.outputs, undefined /* styles */, template.templateAttrs);
|
|
parameters.push(this.addAttrsToConsts(attrsExprs));
|
|
// local refs (ex.: <ng-template #foo>)
|
|
if (template.references && template.references.length) {
|
|
var refs = this.prepareRefsArray(template.references);
|
|
parameters.push(this.addToConsts(refs));
|
|
parameters.push(importExpr(Identifiers.templateRefExtractor));
|
|
}
|
|
// Create the template function
|
|
var templateVisitor = new TemplateDefinitionBuilder(this.constantPool, this._bindingScope, this.level + 1, contextName, this.i18n, templateIndex, templateName, this.directiveMatcher, this.directives, this.pipeTypeByName, this.pipes, this._namespace, this.fileBasedI18nSuffix, this.i18nUseExternalIds, this._constants);
|
|
// Nested templates must not be visited until after their parent templates have completed
|
|
// processing, so they are queued here until after the initial pass. Otherwise, we wouldn't
|
|
// be able to support bindings in nested templates to local refs that occur after the
|
|
// template definition. e.g. <div *ngIf="showing">{{ foo }}</div> <div #foo></div>
|
|
this._nestedTemplateFns.push(function () {
|
|
var _c;
|
|
var templateFunctionExpr = templateVisitor.buildTemplateFunction(template.children, template.variables, _this._ngContentReservedSlots.length + _this._ngContentSelectorsOffset, template.i18n);
|
|
_this.constantPool.statements.push(templateFunctionExpr.toDeclStmt(templateName));
|
|
if (templateVisitor._ngContentReservedSlots.length) {
|
|
(_c = _this._ngContentReservedSlots).push.apply(_c, __spreadArray([], __read(templateVisitor._ngContentReservedSlots)));
|
|
}
|
|
});
|
|
// e.g. template(1, MyComp_Template_1)
|
|
this.creationInstruction(template.sourceSpan, Identifiers.templateCreate, function () {
|
|
parameters.splice(2, 0, literal(templateVisitor.getConstCount()), literal(templateVisitor.getVarCount()));
|
|
return trimTrailingNulls(parameters);
|
|
});
|
|
// handle property bindings e.g. ɵɵproperty('ngForOf', ctx.items), et al;
|
|
this.templatePropertyBindings(templateIndex, template.templateAttrs);
|
|
// Only add normal input/output binding instructions on explicit <ng-template> elements.
|
|
if (tagNameWithoutNamespace === NG_TEMPLATE_TAG_NAME) {
|
|
var _c = __read(partitionArray(template.inputs, hasI18nMeta), 2), i18nInputs = _c[0], inputs = _c[1];
|
|
// Add i18n attributes that may act as inputs to directives. If such attributes are present,
|
|
// generate `i18nAttributes` instruction. Note: we generate it only for explicit <ng-template>
|
|
// elements, in case of inline templates, corresponding instructions will be generated in the
|
|
// nested template function.
|
|
if (i18nInputs.length > 0) {
|
|
this.i18nAttributesInstruction(templateIndex, i18nInputs, (_a = template.startSourceSpan) !== null && _a !== void 0 ? _a : template.sourceSpan);
|
|
}
|
|
// Add the input bindings
|
|
if (inputs.length > 0) {
|
|
this.templatePropertyBindings(templateIndex, inputs);
|
|
}
|
|
// Generate listeners for directive output
|
|
if (template.outputs.length > 0) {
|
|
var listeners = template.outputs.map(function (outputAst) { return ({
|
|
sourceSpan: outputAst.sourceSpan,
|
|
params: _this.prepareListenerParameter('ng_template', outputAst, templateIndex)
|
|
}); });
|
|
this.creationInstructionChain(Identifiers.listener, listeners);
|
|
}
|
|
}
|
|
};
|
|
TemplateDefinitionBuilder.prototype.visitBoundText = function (text) {
|
|
var _this = this;
|
|
if (this.i18n) {
|
|
var value_3 = text.value.visit(this._valueConverter);
|
|
this.allocateBindingSlots(value_3);
|
|
if (value_3 instanceof Interpolation) {
|
|
this.i18n.appendBoundText(text.i18n);
|
|
this.i18nAppendBindings(value_3.expressions);
|
|
}
|
|
return;
|
|
}
|
|
var nodeIndex = this.allocateDataSlot();
|
|
this.creationInstruction(text.sourceSpan, Identifiers.text, [literal(nodeIndex)]);
|
|
var value = text.value.visit(this._valueConverter);
|
|
this.allocateBindingSlots(value);
|
|
if (value instanceof Interpolation) {
|
|
this.updateInstructionWithAdvance(nodeIndex, text.sourceSpan, getTextInterpolationExpression(value), function () { return _this.getUpdateInstructionArguments(value); });
|
|
}
|
|
else {
|
|
error('Text nodes should be interpolated and never bound directly.');
|
|
}
|
|
};
|
|
TemplateDefinitionBuilder.prototype.visitText = function (text) {
|
|
// when a text element is located within a translatable
|
|
// block, we exclude this text element from instructions set,
|
|
// since it will be captured in i18n content and processed at runtime
|
|
if (!this.i18n) {
|
|
this.creationInstruction(text.sourceSpan, Identifiers.text, [literal(this.allocateDataSlot()), literal(text.value)]);
|
|
}
|
|
};
|
|
TemplateDefinitionBuilder.prototype.visitIcu = function (icu) {
|
|
var initWasInvoked = false;
|
|
// if an ICU was created outside of i18n block, we still treat
|
|
// it as a translatable entity and invoke i18nStart and i18nEnd
|
|
// to generate i18n context and the necessary instructions
|
|
if (!this.i18n) {
|
|
initWasInvoked = true;
|
|
this.i18nStart(null, icu.i18n, true);
|
|
}
|
|
var i18n = this.i18n;
|
|
var vars = this.i18nBindProps(icu.vars);
|
|
var placeholders = this.i18nBindProps(icu.placeholders);
|
|
// output ICU directly and keep ICU reference in context
|
|
var message = icu.i18n;
|
|
// we always need post-processing function for ICUs, to make sure that:
|
|
// - all placeholders in a form of {PLACEHOLDER} are replaced with actual values (note:
|
|
// `goog.getMsg` does not process ICUs and uses the `{PLACEHOLDER}` format for placeholders
|
|
// inside ICUs)
|
|
// - all ICU vars (such as `VAR_SELECT` or `VAR_PLURAL`) are replaced with correct values
|
|
var transformFn = function (raw) {
|
|
var params = Object.assign(Object.assign({}, vars), placeholders);
|
|
var formatted = i18nFormatPlaceholderNames(params, /* useCamelCase */ false);
|
|
return instruction(null, Identifiers.i18nPostprocess, [raw, mapLiteral(formatted, true)]);
|
|
};
|
|
// in case the whole i18n message is a single ICU - we do not need to
|
|
// create a separate top-level translation, we can use the root ref instead
|
|
// and make this ICU a top-level translation
|
|
// note: ICU placeholders are replaced with actual values in `i18nPostprocess` function
|
|
// separately, so we do not pass placeholders into `i18nTranslate` function.
|
|
if (isSingleI18nIcu(i18n.meta)) {
|
|
this.i18nTranslate(message, /* placeholders */ {}, i18n.ref, transformFn);
|
|
}
|
|
else {
|
|
// output ICU directly and keep ICU reference in context
|
|
var ref = this.i18nTranslate(message, /* placeholders */ {}, /* ref */ undefined, transformFn);
|
|
i18n.appendIcu(icuFromI18nMessage(message).name, ref);
|
|
}
|
|
if (initWasInvoked) {
|
|
this.i18nEnd(null, true);
|
|
}
|
|
return null;
|
|
};
|
|
TemplateDefinitionBuilder.prototype.allocateDataSlot = function () {
|
|
return this._dataIndex++;
|
|
};
|
|
TemplateDefinitionBuilder.prototype.getConstCount = function () {
|
|
return this._dataIndex;
|
|
};
|
|
TemplateDefinitionBuilder.prototype.getVarCount = function () {
|
|
return this._pureFunctionSlots;
|
|
};
|
|
TemplateDefinitionBuilder.prototype.getConsts = function () {
|
|
return this._constants;
|
|
};
|
|
TemplateDefinitionBuilder.prototype.getNgContentSelectors = function () {
|
|
return this._ngContentReservedSlots.length ?
|
|
this.constantPool.getConstLiteral(asLiteral(this._ngContentReservedSlots), true) :
|
|
null;
|
|
};
|
|
TemplateDefinitionBuilder.prototype.bindingContext = function () {
|
|
return "" + this._bindingContext++;
|
|
};
|
|
TemplateDefinitionBuilder.prototype.templatePropertyBindings = function (templateIndex, attrs) {
|
|
var _this = this;
|
|
var propertyBindings = [];
|
|
attrs.forEach(function (input) {
|
|
if (input instanceof BoundAttribute) {
|
|
var value_4 = input.value.visit(_this._valueConverter);
|
|
if (value_4 !== undefined) {
|
|
_this.allocateBindingSlots(value_4);
|
|
if (value_4 instanceof Interpolation) {
|
|
// Params typically contain attribute namespace and value sanitizer, which is applicable
|
|
// for regular HTML elements, but not applicable for <ng-template> (since props act as
|
|
// inputs to directives), so keep params array empty.
|
|
var params = [];
|
|
// prop="{{value}}" case
|
|
_this.interpolatedUpdateInstruction(getPropertyInterpolationExpression(value_4), templateIndex, input.name, input, value_4, params);
|
|
}
|
|
else {
|
|
// [prop]="value" case
|
|
propertyBindings.push({
|
|
name: input.name,
|
|
sourceSpan: input.sourceSpan,
|
|
value: function () { return _this.convertPropertyBinding(value_4); }
|
|
});
|
|
}
|
|
}
|
|
}
|
|
});
|
|
if (propertyBindings.length > 0) {
|
|
this.updateInstructionChainWithAdvance(templateIndex, Identifiers.property, propertyBindings);
|
|
}
|
|
};
|
|
// Bindings must only be resolved after all local refs have been visited, so all
|
|
// instructions are queued in callbacks that execute once the initial pass has completed.
|
|
// Otherwise, we wouldn't be able to support local refs that are defined after their
|
|
// bindings. e.g. {{ foo }} <div #foo></div>
|
|
TemplateDefinitionBuilder.prototype.instructionFn = function (fns, span, reference, paramsOrFn, prepend) {
|
|
if (prepend === void 0) { prepend = false; }
|
|
fns[prepend ? 'unshift' : 'push'](function () {
|
|
var params = Array.isArray(paramsOrFn) ? paramsOrFn : paramsOrFn();
|
|
return instruction(span, reference, params).toStmt();
|
|
});
|
|
};
|
|
TemplateDefinitionBuilder.prototype.processStylingUpdateInstruction = function (elementIndex, instruction) {
|
|
var _this = this;
|
|
var allocateBindingSlots = 0;
|
|
if (instruction) {
|
|
var calls_1 = [];
|
|
instruction.calls.forEach(function (call) {
|
|
allocateBindingSlots += call.allocateBindingSlots;
|
|
calls_1.push({
|
|
sourceSpan: call.sourceSpan,
|
|
value: function () {
|
|
return call.params(function (value) { return (call.supportsInterpolation && value instanceof Interpolation) ?
|
|
_this.getUpdateInstructionArguments(value) :
|
|
_this.convertPropertyBinding(value); });
|
|
}
|
|
});
|
|
});
|
|
this.updateInstructionChainWithAdvance(elementIndex, instruction.reference, calls_1);
|
|
}
|
|
return allocateBindingSlots;
|
|
};
|
|
TemplateDefinitionBuilder.prototype.creationInstruction = function (span, reference, paramsOrFn, prepend) {
|
|
this.instructionFn(this._creationCodeFns, span, reference, paramsOrFn || [], prepend);
|
|
};
|
|
TemplateDefinitionBuilder.prototype.creationInstructionChain = function (reference, calls) {
|
|
var span = calls.length ? calls[0].sourceSpan : null;
|
|
this._creationCodeFns.push(function () {
|
|
return chainedInstruction(reference, calls.map(function (call) { return call.params(); }), span).toStmt();
|
|
});
|
|
};
|
|
TemplateDefinitionBuilder.prototype.updateInstructionWithAdvance = function (nodeIndex, span, reference, paramsOrFn) {
|
|
this.addAdvanceInstructionIfNecessary(nodeIndex, span);
|
|
this.updateInstruction(span, reference, paramsOrFn);
|
|
};
|
|
TemplateDefinitionBuilder.prototype.updateInstruction = function (span, reference, paramsOrFn) {
|
|
this.instructionFn(this._updateCodeFns, span, reference, paramsOrFn || []);
|
|
};
|
|
TemplateDefinitionBuilder.prototype.updateInstructionChain = function (reference, bindings) {
|
|
var span = bindings.length ? bindings[0].sourceSpan : null;
|
|
this._updateCodeFns.push(function () {
|
|
var calls = bindings.map(function (property) {
|
|
var value = property.value();
|
|
var fnParams = Array.isArray(value) ? value : [value];
|
|
if (property.params) {
|
|
fnParams.push.apply(fnParams, __spreadArray([], __read(property.params)));
|
|
}
|
|
if (property.name) {
|
|
// We want the property name to always be the first function parameter.
|
|
fnParams.unshift(literal(property.name));
|
|
}
|
|
return fnParams;
|
|
});
|
|
return chainedInstruction(reference, calls, span).toStmt();
|
|
});
|
|
};
|
|
TemplateDefinitionBuilder.prototype.updateInstructionChainWithAdvance = function (nodeIndex, reference, bindings) {
|
|
this.addAdvanceInstructionIfNecessary(nodeIndex, bindings.length ? bindings[0].sourceSpan : null);
|
|
this.updateInstructionChain(reference, bindings);
|
|
};
|
|
TemplateDefinitionBuilder.prototype.addAdvanceInstructionIfNecessary = function (nodeIndex, span) {
|
|
if (nodeIndex !== this._currentIndex) {
|
|
var delta = nodeIndex - this._currentIndex;
|
|
if (delta < 1) {
|
|
throw new Error('advance instruction can only go forwards');
|
|
}
|
|
this.instructionFn(this._updateCodeFns, span, Identifiers.advance, [literal(delta)]);
|
|
this._currentIndex = nodeIndex;
|
|
}
|
|
};
|
|
TemplateDefinitionBuilder.prototype.allocatePureFunctionSlots = function (numSlots) {
|
|
var originalSlots = this._pureFunctionSlots;
|
|
this._pureFunctionSlots += numSlots;
|
|
return originalSlots;
|
|
};
|
|
TemplateDefinitionBuilder.prototype.allocateBindingSlots = function (value) {
|
|
this._bindingSlots += value instanceof Interpolation ? value.expressions.length : 1;
|
|
};
|
|
/**
|
|
* Gets an expression that refers to the implicit receiver. The implicit
|
|
* receiver is always the root level context.
|
|
*/
|
|
TemplateDefinitionBuilder.prototype.getImplicitReceiverExpr = function () {
|
|
if (this._implicitReceiverExpr) {
|
|
return this._implicitReceiverExpr;
|
|
}
|
|
return this._implicitReceiverExpr = this.level === 0 ?
|
|
variable(CONTEXT_NAME) :
|
|
this._bindingScope.getOrCreateSharedContextVar(0);
|
|
};
|
|
TemplateDefinitionBuilder.prototype.convertPropertyBinding = function (value) {
|
|
var _c;
|
|
var convertedPropertyBinding = convertPropertyBinding(this, this.getImplicitReceiverExpr(), value, this.bindingContext(), BindingForm.Expression, function () { return error('Unexpected interpolation'); });
|
|
var valExpr = convertedPropertyBinding.currValExpr;
|
|
(_c = this._tempVariables).push.apply(_c, __spreadArray([], __read(convertedPropertyBinding.stmts)));
|
|
return valExpr;
|
|
};
|
|
/**
|
|
* Gets a list of argument expressions to pass to an update instruction expression. Also updates
|
|
* the temp variables state with temp variables that were identified as needing to be created
|
|
* while visiting the arguments.
|
|
* @param value The original expression we will be resolving an arguments list from.
|
|
*/
|
|
TemplateDefinitionBuilder.prototype.getUpdateInstructionArguments = function (value) {
|
|
var _c;
|
|
var _d = convertUpdateArguments(this, this.getImplicitReceiverExpr(), value, this.bindingContext()), args = _d.args, stmts = _d.stmts;
|
|
(_c = this._tempVariables).push.apply(_c, __spreadArray([], __read(stmts)));
|
|
return args;
|
|
};
|
|
TemplateDefinitionBuilder.prototype.matchDirectives = function (elementName, elOrTpl) {
|
|
var _this = this;
|
|
if (this.directiveMatcher) {
|
|
var selector = createCssSelector(elementName, getAttrsForDirectiveMatching(elOrTpl));
|
|
this.directiveMatcher.match(selector, function (cssSelector, staticType) {
|
|
_this.directives.add(staticType);
|
|
});
|
|
}
|
|
};
|
|
/**
|
|
* Prepares all attribute expression values for the `TAttributes` array.
|
|
*
|
|
* The purpose of this function is to properly construct an attributes array that
|
|
* is passed into the `elementStart` (or just `element`) functions. Because there
|
|
* are many different types of attributes, the array needs to be constructed in a
|
|
* special way so that `elementStart` can properly evaluate them.
|
|
*
|
|
* The format looks like this:
|
|
*
|
|
* ```
|
|
* attrs = [prop, value, prop2, value2,
|
|
* PROJECT_AS, selector,
|
|
* CLASSES, class1, class2,
|
|
* STYLES, style1, value1, style2, value2,
|
|
* BINDINGS, name1, name2, name3,
|
|
* TEMPLATE, name4, name5, name6,
|
|
* I18N, name7, name8, ...]
|
|
* ```
|
|
*
|
|
* Note that this function will fully ignore all synthetic (@foo) attribute values
|
|
* because those values are intended to always be generated as property instructions.
|
|
*/
|
|
TemplateDefinitionBuilder.prototype.getAttributeExpressions = function (elementName, renderAttributes, inputs, outputs, styles, templateAttrs, boundI18nAttrs) {
|
|
var e_2, _c;
|
|
if (templateAttrs === void 0) { templateAttrs = []; }
|
|
if (boundI18nAttrs === void 0) { boundI18nAttrs = []; }
|
|
var alreadySeen = new Set();
|
|
var attrExprs = [];
|
|
var ngProjectAsAttr;
|
|
try {
|
|
for (var renderAttributes_1 = __values(renderAttributes), renderAttributes_1_1 = renderAttributes_1.next(); !renderAttributes_1_1.done; renderAttributes_1_1 = renderAttributes_1.next()) {
|
|
var attr = renderAttributes_1_1.value;
|
|
if (attr.name === NG_PROJECT_AS_ATTR_NAME) {
|
|
ngProjectAsAttr = attr;
|
|
}
|
|
// Note that static i18n attributes aren't in the i18n array,
|
|
// because they're treated in the same way as regular attributes.
|
|
if (attr.i18n) {
|
|
// When i18n attributes are present on elements with structural directives
|
|
// (e.g. `<div *ngIf title="Hello" i18n-title>`), we want to avoid generating
|
|
// duplicate i18n translation blocks for `ɵɵtemplate` and `ɵɵelement` instruction
|
|
// attributes. So we do a cache lookup to see if suitable i18n translation block
|
|
// already exists.
|
|
var i18nVarRefsCache = this._constants.i18nVarRefsCache;
|
|
var i18nVarRef = void 0;
|
|
if (i18nVarRefsCache.has(attr.i18n)) {
|
|
i18nVarRef = i18nVarRefsCache.get(attr.i18n);
|
|
}
|
|
else {
|
|
i18nVarRef = this.i18nTranslate(attr.i18n);
|
|
i18nVarRefsCache.set(attr.i18n, i18nVarRef);
|
|
}
|
|
attrExprs.push(literal(attr.name), i18nVarRef);
|
|
}
|
|
else {
|
|
attrExprs.push.apply(attrExprs, __spreadArray(__spreadArray([], __read(getAttributeNameLiterals(attr.name))), [trustedConstAttribute(elementName, attr)]));
|
|
}
|
|
}
|
|
}
|
|
catch (e_2_1) { e_2 = { error: e_2_1 }; }
|
|
finally {
|
|
try {
|
|
if (renderAttributes_1_1 && !renderAttributes_1_1.done && (_c = renderAttributes_1.return)) _c.call(renderAttributes_1);
|
|
}
|
|
finally { if (e_2) throw e_2.error; }
|
|
}
|
|
// Keep ngProjectAs next to the other name, value pairs so we can verify that we match
|
|
// ngProjectAs marker in the attribute name slot.
|
|
if (ngProjectAsAttr) {
|
|
attrExprs.push.apply(attrExprs, __spreadArray([], __read(getNgProjectAsLiteral(ngProjectAsAttr))));
|
|
}
|
|
function addAttrExpr(key, value) {
|
|
if (typeof key === 'string') {
|
|
if (!alreadySeen.has(key)) {
|
|
attrExprs.push.apply(attrExprs, __spreadArray([], __read(getAttributeNameLiterals(key))));
|
|
value !== undefined && attrExprs.push(value);
|
|
alreadySeen.add(key);
|
|
}
|
|
}
|
|
else {
|
|
attrExprs.push(literal(key));
|
|
}
|
|
}
|
|
// it's important that this occurs before BINDINGS and TEMPLATE because once `elementStart`
|
|
// comes across the BINDINGS or TEMPLATE markers then it will continue reading each value as
|
|
// as single property value cell by cell.
|
|
if (styles) {
|
|
styles.populateInitialStylingAttrs(attrExprs);
|
|
}
|
|
if (inputs.length || outputs.length) {
|
|
var attrsLengthBeforeInputs = attrExprs.length;
|
|
for (var i = 0; i < inputs.length; i++) {
|
|
var input = inputs[i];
|
|
// We don't want the animation and attribute bindings in the
|
|
// attributes array since they aren't used for directive matching.
|
|
if (input.type !== 4 /* Animation */ && input.type !== 1 /* Attribute */) {
|
|
addAttrExpr(input.name);
|
|
}
|
|
}
|
|
for (var i = 0; i < outputs.length; i++) {
|
|
var output = outputs[i];
|
|
if (output.type !== 1 /* Animation */) {
|
|
addAttrExpr(output.name);
|
|
}
|
|
}
|
|
// this is a cheap way of adding the marker only after all the input/output
|
|
// values have been filtered (by not including the animation ones) and added
|
|
// to the expressions. The marker is important because it tells the runtime
|
|
// code that this is where attributes without values start...
|
|
if (attrExprs.length !== attrsLengthBeforeInputs) {
|
|
attrExprs.splice(attrsLengthBeforeInputs, 0, literal(3 /* Bindings */));
|
|
}
|
|
}
|
|
if (templateAttrs.length) {
|
|
attrExprs.push(literal(4 /* Template */));
|
|
templateAttrs.forEach(function (attr) { return addAttrExpr(attr.name); });
|
|
}
|
|
if (boundI18nAttrs.length) {
|
|
attrExprs.push(literal(6 /* I18n */));
|
|
boundI18nAttrs.forEach(function (attr) { return addAttrExpr(attr.name); });
|
|
}
|
|
return attrExprs;
|
|
};
|
|
TemplateDefinitionBuilder.prototype.addToConsts = function (expression) {
|
|
if (isNull(expression)) {
|
|
return TYPED_NULL_EXPR;
|
|
}
|
|
var consts = this._constants.constExpressions;
|
|
// Try to reuse a literal that's already in the array, if possible.
|
|
for (var i = 0; i < consts.length; i++) {
|
|
if (consts[i].isEquivalent(expression)) {
|
|
return literal(i);
|
|
}
|
|
}
|
|
return literal(consts.push(expression) - 1);
|
|
};
|
|
TemplateDefinitionBuilder.prototype.addAttrsToConsts = function (attrs) {
|
|
return attrs.length > 0 ? this.addToConsts(literalArr(attrs)) : TYPED_NULL_EXPR;
|
|
};
|
|
TemplateDefinitionBuilder.prototype.prepareRefsArray = function (references) {
|
|
var _this = this;
|
|
if (!references || references.length === 0) {
|
|
return TYPED_NULL_EXPR;
|
|
}
|
|
var refsParam = flatten(references.map(function (reference) {
|
|
var slot = _this.allocateDataSlot();
|
|
// Generate the update temporary.
|
|
var variableName = _this._bindingScope.freshReferenceName();
|
|
var retrievalLevel = _this.level;
|
|
var lhs = variable(variableName);
|
|
_this._bindingScope.set(retrievalLevel, reference.name, lhs, 0 /* DEFAULT */, function (scope, relativeLevel) {
|
|
// e.g. nextContext(2);
|
|
var nextContextStmt = relativeLevel > 0 ? [generateNextContextExpr(relativeLevel).toStmt()] : [];
|
|
// e.g. const $foo$ = reference(1);
|
|
var refExpr = lhs.set(importExpr(Identifiers.reference).callFn([literal(slot)]));
|
|
return nextContextStmt.concat(refExpr.toConstDecl());
|
|
}, true);
|
|
return [reference.name, reference.value];
|
|
}));
|
|
return asLiteral(refsParam);
|
|
};
|
|
TemplateDefinitionBuilder.prototype.prepareListenerParameter = function (tagName, outputAst, index) {
|
|
var _this = this;
|
|
return function () {
|
|
var eventName = outputAst.name;
|
|
var bindingFnName = outputAst.type === 1 /* Animation */ ?
|
|
// synthetic @listener.foo values are treated the exact same as are standard listeners
|
|
prepareSyntheticListenerFunctionName(eventName, outputAst.phase) :
|
|
sanitizeIdentifier(eventName);
|
|
var handlerName = _this.templateName + "_" + tagName + "_" + bindingFnName + "_" + index + "_listener";
|
|
var scope = _this._bindingScope.nestedScope(_this._bindingScope.bindingLevel, EVENT_BINDING_SCOPE_GLOBALS);
|
|
return prepareEventListenerParameters(outputAst, handlerName, scope);
|
|
};
|
|
};
|
|
return TemplateDefinitionBuilder;
|
|
}());
|
|
var ValueConverter = /** @class */ (function (_super) {
|
|
__extends(ValueConverter, _super);
|
|
function ValueConverter(constantPool, allocateSlot, allocatePureFunctionSlots, definePipe) {
|
|
var _this = _super.call(this) || this;
|
|
_this.constantPool = constantPool;
|
|
_this.allocateSlot = allocateSlot;
|
|
_this.allocatePureFunctionSlots = allocatePureFunctionSlots;
|
|
_this.definePipe = definePipe;
|
|
_this._pipeBindExprs = [];
|
|
return _this;
|
|
}
|
|
// AstMemoryEfficientTransformer
|
|
ValueConverter.prototype.visitPipe = function (pipe, context) {
|
|
// Allocate a slot to create the pipe
|
|
var slot = this.allocateSlot();
|
|
var slotPseudoLocal = "PIPE:" + slot;
|
|
// Allocate one slot for the result plus one slot per pipe argument
|
|
var pureFunctionSlot = this.allocatePureFunctionSlots(2 + pipe.args.length);
|
|
var target = new PropertyRead(pipe.span, pipe.sourceSpan, pipe.nameSpan, new ImplicitReceiver(pipe.span, pipe.sourceSpan), slotPseudoLocal);
|
|
var _c = pipeBindingCallInfo(pipe.args), identifier = _c.identifier, isVarLength = _c.isVarLength;
|
|
this.definePipe(pipe.name, slotPseudoLocal, slot, importExpr(identifier));
|
|
var args = __spreadArray([pipe.exp], __read(pipe.args));
|
|
var convertedArgs = isVarLength ?
|
|
this.visitAll([new LiteralArray(pipe.span, pipe.sourceSpan, args)]) :
|
|
this.visitAll(args);
|
|
var pipeBindExpr = new FunctionCall(pipe.span, pipe.sourceSpan, target, __spreadArray([
|
|
new LiteralPrimitive(pipe.span, pipe.sourceSpan, slot),
|
|
new LiteralPrimitive(pipe.span, pipe.sourceSpan, pureFunctionSlot)
|
|
], __read(convertedArgs)));
|
|
this._pipeBindExprs.push(pipeBindExpr);
|
|
return pipeBindExpr;
|
|
};
|
|
ValueConverter.prototype.updatePipeSlotOffsets = function (bindingSlots) {
|
|
this._pipeBindExprs.forEach(function (pipe) {
|
|
// update the slot offset arg (index 1) to account for binding slots
|
|
var slotOffset = pipe.args[1];
|
|
slotOffset.value += bindingSlots;
|
|
});
|
|
};
|
|
ValueConverter.prototype.visitLiteralArray = function (array, context) {
|
|
var _this = this;
|
|
return new BuiltinFunctionCall(array.span, array.sourceSpan, this.visitAll(array.expressions), function (values) {
|
|
// If the literal has calculated (non-literal) elements transform it into
|
|
// calls to literal factories that compose the literal and will cache intermediate
|
|
// values.
|
|
var literal = literalArr(values);
|
|
return getLiteralFactory(_this.constantPool, literal, _this.allocatePureFunctionSlots);
|
|
});
|
|
};
|
|
ValueConverter.prototype.visitLiteralMap = function (map, context) {
|
|
var _this = this;
|
|
return new BuiltinFunctionCall(map.span, map.sourceSpan, this.visitAll(map.values), function (values) {
|
|
// If the literal has calculated (non-literal) elements transform it into
|
|
// calls to literal factories that compose the literal and will cache intermediate
|
|
// values.
|
|
var literal = literalMap(values.map(function (value, index) { return ({ key: map.keys[index].key, value: value, quoted: map.keys[index].quoted }); }));
|
|
return getLiteralFactory(_this.constantPool, literal, _this.allocatePureFunctionSlots);
|
|
});
|
|
};
|
|
return ValueConverter;
|
|
}(AstMemoryEfficientTransformer));
|
|
// Pipes always have at least one parameter, the value they operate on
|
|
var pipeBindingIdentifiers = [Identifiers.pipeBind1, Identifiers.pipeBind2, Identifiers.pipeBind3, Identifiers.pipeBind4];
|
|
function pipeBindingCallInfo(args) {
|
|
var identifier = pipeBindingIdentifiers[args.length];
|
|
return {
|
|
identifier: identifier || Identifiers.pipeBindV,
|
|
isVarLength: !identifier,
|
|
};
|
|
}
|
|
var pureFunctionIdentifiers = [
|
|
Identifiers.pureFunction0, Identifiers.pureFunction1, Identifiers.pureFunction2, Identifiers.pureFunction3, Identifiers.pureFunction4,
|
|
Identifiers.pureFunction5, Identifiers.pureFunction6, Identifiers.pureFunction7, Identifiers.pureFunction8
|
|
];
|
|
function pureFunctionCallInfo(args) {
|
|
var identifier = pureFunctionIdentifiers[args.length];
|
|
return {
|
|
identifier: identifier || Identifiers.pureFunctionV,
|
|
isVarLength: !identifier,
|
|
};
|
|
}
|
|
function instruction(span, reference, params) {
|
|
return importExpr(reference, null, span).callFn(params, span);
|
|
}
|
|
// e.g. x(2);
|
|
function generateNextContextExpr(relativeLevelDiff) {
|
|
return importExpr(Identifiers.nextContext)
|
|
.callFn(relativeLevelDiff > 1 ? [literal(relativeLevelDiff)] : []);
|
|
}
|
|
function getLiteralFactory(constantPool, literal$1, allocateSlots) {
|
|
var _c = constantPool.getLiteralFactory(literal$1), literalFactory = _c.literalFactory, literalFactoryArguments = _c.literalFactoryArguments;
|
|
// Allocate 1 slot for the result plus 1 per argument
|
|
var startSlot = allocateSlots(1 + literalFactoryArguments.length);
|
|
var _d = pureFunctionCallInfo(literalFactoryArguments), identifier = _d.identifier, isVarLength = _d.isVarLength;
|
|
// Literal factories are pure functions that only need to be re-invoked when the parameters
|
|
// change.
|
|
var args = [literal(startSlot), literalFactory];
|
|
if (isVarLength) {
|
|
args.push(literalArr(literalFactoryArguments));
|
|
}
|
|
else {
|
|
args.push.apply(args, __spreadArray([], __read(literalFactoryArguments)));
|
|
}
|
|
return importExpr(identifier).callFn(args);
|
|
}
|
|
/**
|
|
* Gets an array of literals that can be added to an expression
|
|
* to represent the name and namespace of an attribute. E.g.
|
|
* `:xlink:href` turns into `[AttributeMarker.NamespaceURI, 'xlink', 'href']`.
|
|
*
|
|
* @param name Name of the attribute, including the namespace.
|
|
*/
|
|
function getAttributeNameLiterals(name) {
|
|
var _c = __read(splitNsName(name), 2), attributeNamespace = _c[0], attributeName = _c[1];
|
|
var nameLiteral = literal(attributeName);
|
|
if (attributeNamespace) {
|
|
return [
|
|
literal(0 /* NamespaceURI */), literal(attributeNamespace), nameLiteral
|
|
];
|
|
}
|
|
return [nameLiteral];
|
|
}
|
|
/** The prefix used to get a shared context in BindingScope's map. */
|
|
var SHARED_CONTEXT_KEY = '$$shared_ctx$$';
|
|
var BindingScope = /** @class */ (function () {
|
|
function BindingScope(bindingLevel, parent, globals) {
|
|
var e_3, _c;
|
|
if (bindingLevel === void 0) { bindingLevel = 0; }
|
|
if (parent === void 0) { parent = null; }
|
|
this.bindingLevel = bindingLevel;
|
|
this.parent = parent;
|
|
this.globals = globals;
|
|
/** Keeps a map from local variables to their BindingData. */
|
|
this.map = new Map();
|
|
this.referenceNameIndex = 0;
|
|
this.restoreViewVariable = null;
|
|
this.usesRestoredViewContext = false;
|
|
if (globals !== undefined) {
|
|
try {
|
|
for (var globals_1 = __values(globals), globals_1_1 = globals_1.next(); !globals_1_1.done; globals_1_1 = globals_1.next()) {
|
|
var name = globals_1_1.value;
|
|
this.set(0, name, variable(name));
|
|
}
|
|
}
|
|
catch (e_3_1) { e_3 = { error: e_3_1 }; }
|
|
finally {
|
|
try {
|
|
if (globals_1_1 && !globals_1_1.done && (_c = globals_1.return)) _c.call(globals_1);
|
|
}
|
|
finally { if (e_3) throw e_3.error; }
|
|
}
|
|
}
|
|
}
|
|
BindingScope.createRootScope = function () {
|
|
return new BindingScope();
|
|
};
|
|
BindingScope.prototype.get = function (name) {
|
|
var current = this;
|
|
while (current) {
|
|
var value = current.map.get(name);
|
|
if (value != null) {
|
|
if (current !== this) {
|
|
// make a local copy and reset the `declare` state
|
|
value = {
|
|
retrievalLevel: value.retrievalLevel,
|
|
lhs: value.lhs,
|
|
declareLocalCallback: value.declareLocalCallback,
|
|
declare: false,
|
|
priority: value.priority
|
|
};
|
|
// Cache the value locally.
|
|
this.map.set(name, value);
|
|
// Possibly generate a shared context var
|
|
this.maybeGenerateSharedContextVar(value);
|
|
this.maybeRestoreView();
|
|
}
|
|
if (value.declareLocalCallback && !value.declare) {
|
|
value.declare = true;
|
|
}
|
|
return value.lhs;
|
|
}
|
|
current = current.parent;
|
|
}
|
|
// If we get to this point, we are looking for a property on the top level component
|
|
// - If level === 0, we are on the top and don't need to re-declare `ctx`.
|
|
// - If level > 0, we are in an embedded view. We need to retrieve the name of the
|
|
// local var we used to store the component context, e.g. const $comp$ = x();
|
|
return this.bindingLevel === 0 ? null : this.getComponentProperty(name);
|
|
};
|
|
/**
|
|
* Create a local variable for later reference.
|
|
*
|
|
* @param retrievalLevel The level from which this value can be retrieved
|
|
* @param name Name of the variable.
|
|
* @param lhs AST representing the left hand side of the `let lhs = rhs;`.
|
|
* @param priority The sorting priority of this var
|
|
* @param declareLocalCallback The callback to invoke when declaring this local var
|
|
* @param localRef Whether or not this is a local ref
|
|
*/
|
|
BindingScope.prototype.set = function (retrievalLevel, name, lhs, priority /* DEFAULT */, declareLocalCallback, localRef) {
|
|
if (priority === void 0) { priority = 0; }
|
|
if (this.map.has(name)) {
|
|
if (localRef) {
|
|
// Do not throw an error if it's a local ref and do not update existing value,
|
|
// so the first defined ref is always returned.
|
|
return this;
|
|
}
|
|
error("The name " + name + " is already defined in scope to be " + this.map.get(name));
|
|
}
|
|
this.map.set(name, {
|
|
retrievalLevel: retrievalLevel,
|
|
lhs: lhs,
|
|
declare: false,
|
|
declareLocalCallback: declareLocalCallback,
|
|
priority: priority,
|
|
});
|
|
return this;
|
|
};
|
|
// Implemented as part of LocalResolver.
|
|
BindingScope.prototype.getLocal = function (name) {
|
|
return this.get(name);
|
|
};
|
|
// Implemented as part of LocalResolver.
|
|
BindingScope.prototype.notifyImplicitReceiverUse = function () {
|
|
if (this.bindingLevel !== 0) {
|
|
// Since the implicit receiver is accessed in an embedded view, we need to
|
|
// ensure that we declare a shared context variable for the current template
|
|
// in the update variables.
|
|
this.map.get(SHARED_CONTEXT_KEY + 0).declare = true;
|
|
}
|
|
};
|
|
BindingScope.prototype.nestedScope = function (level, globals) {
|
|
var newScope = new BindingScope(level, this, globals);
|
|
if (level > 0)
|
|
newScope.generateSharedContextVar(0);
|
|
return newScope;
|
|
};
|
|
/**
|
|
* Gets or creates a shared context variable and returns its expression. Note that
|
|
* this does not mean that the shared variable will be declared. Variables in the
|
|
* binding scope will be only declared if they are used.
|
|
*/
|
|
BindingScope.prototype.getOrCreateSharedContextVar = function (retrievalLevel) {
|
|
var bindingKey = SHARED_CONTEXT_KEY + retrievalLevel;
|
|
if (!this.map.has(bindingKey)) {
|
|
this.generateSharedContextVar(retrievalLevel);
|
|
}
|
|
// Shared context variables are always generated as "ReadVarExpr".
|
|
return this.map.get(bindingKey).lhs;
|
|
};
|
|
BindingScope.prototype.getSharedContextName = function (retrievalLevel) {
|
|
var sharedCtxObj = this.map.get(SHARED_CONTEXT_KEY + retrievalLevel);
|
|
// Shared context variables are always generated as "ReadVarExpr".
|
|
return sharedCtxObj && sharedCtxObj.declare ? sharedCtxObj.lhs : null;
|
|
};
|
|
BindingScope.prototype.maybeGenerateSharedContextVar = function (value) {
|
|
if (value.priority === 1 /* CONTEXT */ &&
|
|
value.retrievalLevel < this.bindingLevel) {
|
|
var sharedCtxObj = this.map.get(SHARED_CONTEXT_KEY + value.retrievalLevel);
|
|
if (sharedCtxObj) {
|
|
sharedCtxObj.declare = true;
|
|
}
|
|
else {
|
|
this.generateSharedContextVar(value.retrievalLevel);
|
|
}
|
|
}
|
|
};
|
|
BindingScope.prototype.generateSharedContextVar = function (retrievalLevel) {
|
|
var lhs = variable(CONTEXT_NAME + this.freshReferenceName());
|
|
this.map.set(SHARED_CONTEXT_KEY + retrievalLevel, {
|
|
retrievalLevel: retrievalLevel,
|
|
lhs: lhs,
|
|
declareLocalCallback: function (scope, relativeLevel) {
|
|
// const ctx_r0 = nextContext(2);
|
|
return [lhs.set(generateNextContextExpr(relativeLevel)).toConstDecl()];
|
|
},
|
|
declare: false,
|
|
priority: 2 /* SHARED_CONTEXT */,
|
|
});
|
|
};
|
|
BindingScope.prototype.getComponentProperty = function (name) {
|
|
var componentValue = this.map.get(SHARED_CONTEXT_KEY + 0);
|
|
componentValue.declare = true;
|
|
this.maybeRestoreView();
|
|
return componentValue.lhs.prop(name);
|
|
};
|
|
BindingScope.prototype.maybeRestoreView = function () {
|
|
// View restoration is required for listener instructions inside embedded views, because
|
|
// they only run in creation mode and they can have references to the context object.
|
|
// If the context object changes in update mode, the reference will be incorrect, because
|
|
// it was established during creation.
|
|
if (this.isListenerScope()) {
|
|
if (!this.parent.restoreViewVariable) {
|
|
// parent saves variable to generate a shared `const $s$ = getCurrentView();` instruction
|
|
this.parent.restoreViewVariable = variable(this.parent.freshReferenceName());
|
|
}
|
|
this.restoreViewVariable = this.parent.restoreViewVariable;
|
|
}
|
|
};
|
|
BindingScope.prototype.restoreViewStatement = function () {
|
|
var statements = [];
|
|
if (this.restoreViewVariable) {
|
|
var restoreCall = instruction(null, Identifiers.restoreView, [this.restoreViewVariable]);
|
|
// Either `const restoredCtx = restoreView($state$);` or `restoreView($state$);`
|
|
// depending on whether it is being used.
|
|
statements.push(this.usesRestoredViewContext ?
|
|
variable(RESTORED_VIEW_CONTEXT_NAME).set(restoreCall).toConstDecl() :
|
|
restoreCall.toStmt());
|
|
}
|
|
return statements;
|
|
};
|
|
BindingScope.prototype.viewSnapshotStatements = function () {
|
|
// const $state$ = getCurrentView();
|
|
return this.restoreViewVariable ?
|
|
[this.restoreViewVariable.set(instruction(null, Identifiers.getCurrentView, [])).toConstDecl()] :
|
|
[];
|
|
};
|
|
BindingScope.prototype.isListenerScope = function () {
|
|
return this.parent && this.parent.bindingLevel === this.bindingLevel;
|
|
};
|
|
BindingScope.prototype.variableDeclarations = function () {
|
|
var _this = this;
|
|
var currentContextLevel = 0;
|
|
return Array.from(this.map.values())
|
|
.filter(function (value) { return value.declare; })
|
|
.sort(function (a, b) { return b.retrievalLevel - a.retrievalLevel || b.priority - a.priority; })
|
|
.reduce(function (stmts, value) {
|
|
var levelDiff = _this.bindingLevel - value.retrievalLevel;
|
|
var currStmts = value.declareLocalCallback(_this, levelDiff - currentContextLevel);
|
|
currentContextLevel = levelDiff;
|
|
return stmts.concat(currStmts);
|
|
}, []);
|
|
};
|
|
BindingScope.prototype.freshReferenceName = function () {
|
|
var current = this;
|
|
// Find the top scope as it maintains the global reference count
|
|
while (current.parent)
|
|
current = current.parent;
|
|
var ref = "" + REFERENCE_PREFIX + current.referenceNameIndex++;
|
|
return ref;
|
|
};
|
|
BindingScope.prototype.hasRestoreViewVariable = function () {
|
|
return !!this.restoreViewVariable;
|
|
};
|
|
BindingScope.prototype.notifyRestoredViewContextUse = function () {
|
|
this.usesRestoredViewContext = true;
|
|
};
|
|
return BindingScope;
|
|
}());
|
|
/**
|
|
* Creates a `CssSelector` given a tag name and a map of attributes
|
|
*/
|
|
function createCssSelector(elementName, attributes) {
|
|
var cssSelector = new CssSelector();
|
|
var elementNameNoNs = splitNsName(elementName)[1];
|
|
cssSelector.setElement(elementNameNoNs);
|
|
Object.getOwnPropertyNames(attributes).forEach(function (name) {
|
|
var nameNoNs = splitNsName(name)[1];
|
|
var value = attributes[name];
|
|
cssSelector.addAttribute(nameNoNs, value);
|
|
if (name.toLowerCase() === 'class') {
|
|
var classes = value.trim().split(/\s+/);
|
|
classes.forEach(function (className) { return cssSelector.addClassName(className); });
|
|
}
|
|
});
|
|
return cssSelector;
|
|
}
|
|
/**
|
|
* Creates an array of expressions out of an `ngProjectAs` attributes
|
|
* which can be added to the instruction parameters.
|
|
*/
|
|
function getNgProjectAsLiteral(attribute) {
|
|
// Parse the attribute value into a CssSelectorList. Note that we only take the
|
|
// first selector, because we don't support multiple selectors in ngProjectAs.
|
|
var parsedR3Selector = parseSelectorToR3Selector(attribute.value)[0];
|
|
return [literal(5 /* ProjectAs */), asLiteral(parsedR3Selector)];
|
|
}
|
|
/**
|
|
* Gets the instruction to generate for an interpolated property
|
|
* @param interpolation An Interpolation AST
|
|
*/
|
|
function getPropertyInterpolationExpression(interpolation) {
|
|
switch (getInterpolationArgsLength(interpolation)) {
|
|
case 1:
|
|
return Identifiers.propertyInterpolate;
|
|
case 3:
|
|
return Identifiers.propertyInterpolate1;
|
|
case 5:
|
|
return Identifiers.propertyInterpolate2;
|
|
case 7:
|
|
return Identifiers.propertyInterpolate3;
|
|
case 9:
|
|
return Identifiers.propertyInterpolate4;
|
|
case 11:
|
|
return Identifiers.propertyInterpolate5;
|
|
case 13:
|
|
return Identifiers.propertyInterpolate6;
|
|
case 15:
|
|
return Identifiers.propertyInterpolate7;
|
|
case 17:
|
|
return Identifiers.propertyInterpolate8;
|
|
default:
|
|
return Identifiers.propertyInterpolateV;
|
|
}
|
|
}
|
|
/**
|
|
* Gets the instruction to generate for an interpolated attribute
|
|
* @param interpolation An Interpolation AST
|
|
*/
|
|
function getAttributeInterpolationExpression(interpolation) {
|
|
switch (getInterpolationArgsLength(interpolation)) {
|
|
case 3:
|
|
return Identifiers.attributeInterpolate1;
|
|
case 5:
|
|
return Identifiers.attributeInterpolate2;
|
|
case 7:
|
|
return Identifiers.attributeInterpolate3;
|
|
case 9:
|
|
return Identifiers.attributeInterpolate4;
|
|
case 11:
|
|
return Identifiers.attributeInterpolate5;
|
|
case 13:
|
|
return Identifiers.attributeInterpolate6;
|
|
case 15:
|
|
return Identifiers.attributeInterpolate7;
|
|
case 17:
|
|
return Identifiers.attributeInterpolate8;
|
|
default:
|
|
return Identifiers.attributeInterpolateV;
|
|
}
|
|
}
|
|
/**
|
|
* Gets the instruction to generate for interpolated text.
|
|
* @param interpolation An Interpolation AST
|
|
*/
|
|
function getTextInterpolationExpression(interpolation) {
|
|
switch (getInterpolationArgsLength(interpolation)) {
|
|
case 1:
|
|
return Identifiers.textInterpolate;
|
|
case 3:
|
|
return Identifiers.textInterpolate1;
|
|
case 5:
|
|
return Identifiers.textInterpolate2;
|
|
case 7:
|
|
return Identifiers.textInterpolate3;
|
|
case 9:
|
|
return Identifiers.textInterpolate4;
|
|
case 11:
|
|
return Identifiers.textInterpolate5;
|
|
case 13:
|
|
return Identifiers.textInterpolate6;
|
|
case 15:
|
|
return Identifiers.textInterpolate7;
|
|
case 17:
|
|
return Identifiers.textInterpolate8;
|
|
default:
|
|
return Identifiers.textInterpolateV;
|
|
}
|
|
}
|
|
/**
|
|
* Parse a template into render3 `Node`s and additional metadata, with no other dependencies.
|
|
*
|
|
* @param template text of the template to parse
|
|
* @param templateUrl URL to use for source mapping of the parsed template
|
|
* @param options options to modify how the template is parsed
|
|
*/
|
|
function parseTemplate(template, templateUrl, options) {
|
|
if (options === void 0) { options = {}; }
|
|
var interpolationConfig = options.interpolationConfig, preserveWhitespaces = options.preserveWhitespaces, enableI18nLegacyMessageIdFormat = options.enableI18nLegacyMessageIdFormat;
|
|
var bindingParser = makeBindingParser(interpolationConfig);
|
|
var htmlParser = new HtmlParser();
|
|
var parseResult = htmlParser.parse(template, templateUrl, Object.assign(Object.assign({ leadingTriviaChars: LEADING_TRIVIA_CHARS }, options), { tokenizeExpansionForms: true }));
|
|
if (!options.alwaysAttemptHtmlToR3AstConversion && parseResult.errors &&
|
|
parseResult.errors.length > 0) {
|
|
var parsedTemplate_1 = {
|
|
interpolationConfig: interpolationConfig,
|
|
preserveWhitespaces: preserveWhitespaces,
|
|
errors: parseResult.errors,
|
|
nodes: [],
|
|
styleUrls: [],
|
|
styles: [],
|
|
ngContentSelectors: []
|
|
};
|
|
if (options.collectCommentNodes) {
|
|
parsedTemplate_1.commentNodes = [];
|
|
}
|
|
return parsedTemplate_1;
|
|
}
|
|
var rootNodes = parseResult.rootNodes;
|
|
// process i18n meta information (scan attributes, generate ids)
|
|
// before we run whitespace removal process, because existing i18n
|
|
// extraction process (ng extract-i18n) relies on a raw content to generate
|
|
// message ids
|
|
var i18nMetaVisitor = new I18nMetaVisitor(interpolationConfig, /* keepI18nAttrs */ !preserveWhitespaces, enableI18nLegacyMessageIdFormat);
|
|
var i18nMetaResult = i18nMetaVisitor.visitAllWithErrors(rootNodes);
|
|
if (!options.alwaysAttemptHtmlToR3AstConversion && i18nMetaResult.errors &&
|
|
i18nMetaResult.errors.length > 0) {
|
|
var parsedTemplate_2 = {
|
|
interpolationConfig: interpolationConfig,
|
|
preserveWhitespaces: preserveWhitespaces,
|
|
errors: i18nMetaResult.errors,
|
|
nodes: [],
|
|
styleUrls: [],
|
|
styles: [],
|
|
ngContentSelectors: []
|
|
};
|
|
if (options.collectCommentNodes) {
|
|
parsedTemplate_2.commentNodes = [];
|
|
}
|
|
return parsedTemplate_2;
|
|
}
|
|
rootNodes = i18nMetaResult.rootNodes;
|
|
if (!preserveWhitespaces) {
|
|
rootNodes = visitAll$1(new WhitespaceVisitor(), rootNodes);
|
|
// run i18n meta visitor again in case whitespaces are removed (because that might affect
|
|
// generated i18n message content) and first pass indicated that i18n content is present in a
|
|
// template. During this pass i18n IDs generated at the first pass will be preserved, so we can
|
|
// mimic existing extraction process (ng extract-i18n)
|
|
if (i18nMetaVisitor.hasI18nMeta) {
|
|
rootNodes = visitAll$1(new I18nMetaVisitor(interpolationConfig, /* keepI18nAttrs */ false), rootNodes);
|
|
}
|
|
}
|
|
var _c = htmlAstToRender3Ast(rootNodes, bindingParser, { collectCommentNodes: !!options.collectCommentNodes }), nodes = _c.nodes, errors = _c.errors, styleUrls = _c.styleUrls, styles = _c.styles, ngContentSelectors = _c.ngContentSelectors, commentNodes = _c.commentNodes;
|
|
errors.push.apply(errors, __spreadArray(__spreadArray([], __read(parseResult.errors)), __read(i18nMetaResult.errors)));
|
|
var parsedTemplate = {
|
|
interpolationConfig: interpolationConfig,
|
|
preserveWhitespaces: preserveWhitespaces,
|
|
errors: errors.length > 0 ? errors : null,
|
|
nodes: nodes,
|
|
styleUrls: styleUrls,
|
|
styles: styles,
|
|
ngContentSelectors: ngContentSelectors
|
|
};
|
|
if (options.collectCommentNodes) {
|
|
parsedTemplate.commentNodes = commentNodes;
|
|
}
|
|
return parsedTemplate;
|
|
}
|
|
var elementRegistry = new DomElementSchemaRegistry();
|
|
/**
|
|
* Construct a `BindingParser` with a default configuration.
|
|
*/
|
|
function makeBindingParser(interpolationConfig) {
|
|
if (interpolationConfig === void 0) { interpolationConfig = DEFAULT_INTERPOLATION_CONFIG; }
|
|
return new BindingParser(new IvyParser(new Lexer()), interpolationConfig, elementRegistry, null, []);
|
|
}
|
|
function resolveSanitizationFn(context, isAttribute) {
|
|
switch (context) {
|
|
case SecurityContext.HTML:
|
|
return importExpr(Identifiers.sanitizeHtml);
|
|
case SecurityContext.SCRIPT:
|
|
return importExpr(Identifiers.sanitizeScript);
|
|
case SecurityContext.STYLE:
|
|
// the compiler does not fill in an instruction for [style.prop?] binding
|
|
// values because the style algorithm knows internally what props are subject
|
|
// to sanitization (only [attr.style] values are explicitly sanitized)
|
|
return isAttribute ? importExpr(Identifiers.sanitizeStyle) : null;
|
|
case SecurityContext.URL:
|
|
return importExpr(Identifiers.sanitizeUrl);
|
|
case SecurityContext.RESOURCE_URL:
|
|
return importExpr(Identifiers.sanitizeResourceUrl);
|
|
default:
|
|
return null;
|
|
}
|
|
}
|
|
function trustedConstAttribute(tagName, attr) {
|
|
var value = asLiteral(attr.value);
|
|
if (isTrustedTypesSink(tagName, attr.name)) {
|
|
switch (elementRegistry.securityContext(tagName, attr.name, /* isAttribute */ true)) {
|
|
case SecurityContext.HTML:
|
|
return taggedTemplate(importExpr(Identifiers.trustConstantHtml), new TemplateLiteral([new TemplateLiteralElement(attr.value)], []), undefined, attr.valueSpan);
|
|
// NB: no SecurityContext.SCRIPT here, as the corresponding tags are stripped by the compiler.
|
|
case SecurityContext.RESOURCE_URL:
|
|
return taggedTemplate(importExpr(Identifiers.trustConstantResourceUrl), new TemplateLiteral([new TemplateLiteralElement(attr.value)], []), undefined, attr.valueSpan);
|
|
default:
|
|
return value;
|
|
}
|
|
}
|
|
else {
|
|
return value;
|
|
}
|
|
}
|
|
function isSingleElementTemplate(children) {
|
|
return children.length === 1 && children[0] instanceof Element;
|
|
}
|
|
function isTextNode(node) {
|
|
return node instanceof Text || node instanceof BoundText || node instanceof Icu;
|
|
}
|
|
function hasTextChildrenOnly(children) {
|
|
return children.every(isTextNode);
|
|
}
|
|
/** Name of the global variable that is used to determine if we use Closure translations or not */
|
|
var NG_I18N_CLOSURE_MODE = 'ngI18nClosureMode';
|
|
/**
|
|
* Generate statements that define a given translation message.
|
|
*
|
|
* ```
|
|
* var I18N_1;
|
|
* if (typeof ngI18nClosureMode !== undefined && ngI18nClosureMode) {
|
|
* var MSG_EXTERNAL_XXX = goog.getMsg(
|
|
* "Some message with {$interpolation}!",
|
|
* { "interpolation": "\uFFFD0\uFFFD" }
|
|
* );
|
|
* I18N_1 = MSG_EXTERNAL_XXX;
|
|
* }
|
|
* else {
|
|
* I18N_1 = $localize`Some message with ${'\uFFFD0\uFFFD'}!`;
|
|
* }
|
|
* ```
|
|
*
|
|
* @param message The original i18n AST message node
|
|
* @param variable The variable that will be assigned the translation, e.g. `I18N_1`.
|
|
* @param closureVar The variable for Closure `goog.getMsg` calls, e.g. `MSG_EXTERNAL_XXX`.
|
|
* @param params Object mapping placeholder names to their values (e.g.
|
|
* `{ "interpolation": "\uFFFD0\uFFFD" }`).
|
|
* @param transformFn Optional transformation function that will be applied to the translation (e.g.
|
|
* post-processing).
|
|
* @returns An array of statements that defined a given translation.
|
|
*/
|
|
function getTranslationDeclStmts(message, variable, closureVar, params, transformFn) {
|
|
if (params === void 0) { params = {}; }
|
|
var statements = [
|
|
declareI18nVariable(variable),
|
|
ifStmt(createClosureModeGuard(), createGoogleGetMsgStatements(variable, message, closureVar, i18nFormatPlaceholderNames(params, /* useCamelCase */ true)), createLocalizeStatements(variable, message, i18nFormatPlaceholderNames(params, /* useCamelCase */ false))),
|
|
];
|
|
if (transformFn) {
|
|
statements.push(new ExpressionStatement(variable.set(transformFn(variable))));
|
|
}
|
|
return statements;
|
|
}
|
|
/**
|
|
* Create the expression that will be used to guard the closure mode block
|
|
* It is equivalent to:
|
|
*
|
|
* ```
|
|
* typeof ngI18nClosureMode !== undefined && ngI18nClosureMode
|
|
* ```
|
|
*/
|
|
function createClosureModeGuard() {
|
|
return typeofExpr(variable(NG_I18N_CLOSURE_MODE))
|
|
.notIdentical(literal('undefined', STRING_TYPE))
|
|
.and(variable(NG_I18N_CLOSURE_MODE));
|
|
}
|
|
|
|
// This regex matches any binding names that contain the "attr." prefix, e.g. "attr.required"
|
|
// If there is a match, the first matching group will contain the attribute name to bind.
|
|
var ATTR_REGEX = /attr\.([^\]]+)/;
|
|
function baseDirectiveFields(meta, constantPool, bindingParser) {
|
|
var definitionMap = new DefinitionMap();
|
|
var selectors = parseSelectorToR3Selector(meta.selector);
|
|
// e.g. `type: MyDirective`
|
|
definitionMap.set('type', meta.internalType);
|
|
// e.g. `selectors: [['', 'someDir', '']]`
|
|
if (selectors.length > 0) {
|
|
definitionMap.set('selectors', asLiteral(selectors));
|
|
}
|
|
if (meta.queries.length > 0) {
|
|
// e.g. `contentQueries: (rf, ctx, dirIndex) => { ... }
|
|
definitionMap.set('contentQueries', createContentQueriesFunction(meta.queries, constantPool, meta.name));
|
|
}
|
|
if (meta.viewQueries.length) {
|
|
definitionMap.set('viewQuery', createViewQueriesFunction(meta.viewQueries, constantPool, meta.name));
|
|
}
|
|
// e.g. `hostBindings: (rf, ctx) => { ... }
|
|
definitionMap.set('hostBindings', createHostBindingsFunction(meta.host, meta.typeSourceSpan, bindingParser, constantPool, meta.selector || '', meta.name, definitionMap));
|
|
// e.g 'inputs: {a: 'a'}`
|
|
definitionMap.set('inputs', conditionallyCreateMapObjectLiteral(meta.inputs, true));
|
|
// e.g 'outputs: {a: 'a'}`
|
|
definitionMap.set('outputs', conditionallyCreateMapObjectLiteral(meta.outputs));
|
|
if (meta.exportAs !== null) {
|
|
definitionMap.set('exportAs', literalArr(meta.exportAs.map(function (e) { return literal(e); })));
|
|
}
|
|
return definitionMap;
|
|
}
|
|
/**
|
|
* Add features to the definition map.
|
|
*/
|
|
function addFeatures(definitionMap, meta) {
|
|
// e.g. `features: [NgOnChangesFeature]`
|
|
var features = [];
|
|
var providers = meta.providers;
|
|
var viewProviders = meta.viewProviders;
|
|
if (providers || viewProviders) {
|
|
var args = [providers || new LiteralArrayExpr([])];
|
|
if (viewProviders) {
|
|
args.push(viewProviders);
|
|
}
|
|
features.push(importExpr(Identifiers.ProvidersFeature).callFn(args));
|
|
}
|
|
if (meta.usesInheritance) {
|
|
features.push(importExpr(Identifiers.InheritDefinitionFeature));
|
|
}
|
|
if (meta.fullInheritance) {
|
|
features.push(importExpr(Identifiers.CopyDefinitionFeature));
|
|
}
|
|
if (meta.lifecycle.usesOnChanges) {
|
|
features.push(importExpr(Identifiers.NgOnChangesFeature));
|
|
}
|
|
if (features.length) {
|
|
definitionMap.set('features', literalArr(features));
|
|
}
|
|
}
|
|
/**
|
|
* Compile a directive for the render3 runtime as defined by the `R3DirectiveMetadata`.
|
|
*/
|
|
function compileDirectiveFromMetadata(meta, constantPool, bindingParser) {
|
|
var definitionMap = baseDirectiveFields(meta, constantPool, bindingParser);
|
|
addFeatures(definitionMap, meta);
|
|
var expression = importExpr(Identifiers.defineDirective).callFn([definitionMap.toLiteralMap()], undefined, true);
|
|
var type = createDirectiveType(meta);
|
|
return { expression: expression, type: type, statements: [] };
|
|
}
|
|
/**
|
|
* Compile a component for the render3 runtime as defined by the `R3ComponentMetadata`.
|
|
*/
|
|
function compileComponentFromMetadata(meta, constantPool, bindingParser) {
|
|
var e_1, _a;
|
|
var definitionMap = baseDirectiveFields(meta, constantPool, bindingParser);
|
|
addFeatures(definitionMap, meta);
|
|
var selector = meta.selector && CssSelector.parse(meta.selector);
|
|
var firstSelector = selector && selector[0];
|
|
// e.g. `attr: ["class", ".my.app"]`
|
|
// This is optional an only included if the first selector of a component specifies attributes.
|
|
if (firstSelector) {
|
|
var selectorAttributes = firstSelector.getAttrs();
|
|
if (selectorAttributes.length) {
|
|
definitionMap.set('attrs', constantPool.getConstLiteral(literalArr(selectorAttributes.map(function (value) { return value != null ? literal(value) : literal(undefined); })),
|
|
/* forceShared */ true));
|
|
}
|
|
}
|
|
// Generate the CSS matcher that recognize directive
|
|
var directiveMatcher = null;
|
|
if (meta.directives.length > 0) {
|
|
var matcher = new SelectorMatcher();
|
|
try {
|
|
for (var _b = __values(meta.directives), _c = _b.next(); !_c.done; _c = _b.next()) {
|
|
var _d = _c.value, selector_1 = _d.selector, type_1 = _d.type;
|
|
matcher.addSelectables(CssSelector.parse(selector_1), type_1);
|
|
}
|
|
}
|
|
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
finally {
|
|
try {
|
|
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
|
|
}
|
|
finally { if (e_1) throw e_1.error; }
|
|
}
|
|
directiveMatcher = matcher;
|
|
}
|
|
// e.g. `template: function MyComponent_Template(_ctx, _cm) {...}`
|
|
var templateTypeName = meta.name;
|
|
var templateName = templateTypeName ? templateTypeName + "_Template" : null;
|
|
var directivesUsed = new Set();
|
|
var pipesUsed = new Set();
|
|
var changeDetection = meta.changeDetection;
|
|
var template = meta.template;
|
|
var templateBuilder = new TemplateDefinitionBuilder(constantPool, BindingScope.createRootScope(), 0, templateTypeName, null, null, templateName, directiveMatcher, directivesUsed, meta.pipes, pipesUsed, Identifiers.namespaceHTML, meta.relativeContextFilePath, meta.i18nUseExternalIds);
|
|
var templateFunctionExpression = templateBuilder.buildTemplateFunction(template.nodes, []);
|
|
// We need to provide this so that dynamically generated components know what
|
|
// projected content blocks to pass through to the component when it is instantiated.
|
|
var ngContentSelectors = templateBuilder.getNgContentSelectors();
|
|
if (ngContentSelectors) {
|
|
definitionMap.set('ngContentSelectors', ngContentSelectors);
|
|
}
|
|
// e.g. `decls: 2`
|
|
definitionMap.set('decls', literal(templateBuilder.getConstCount()));
|
|
// e.g. `vars: 2`
|
|
definitionMap.set('vars', literal(templateBuilder.getVarCount()));
|
|
// Generate `consts` section of ComponentDef:
|
|
// - either as an array:
|
|
// `consts: [['one', 'two'], ['three', 'four']]`
|
|
// - or as a factory function in case additional statements are present (to support i18n):
|
|
// `consts: function() { var i18n_0; if (ngI18nClosureMode) {...} else {...} return [i18n_0]; }`
|
|
var _e = templateBuilder.getConsts(), constExpressions = _e.constExpressions, prepareStatements = _e.prepareStatements;
|
|
if (constExpressions.length > 0) {
|
|
var constsExpr = literalArr(constExpressions);
|
|
// Prepare statements are present - turn `consts` into a function.
|
|
if (prepareStatements.length > 0) {
|
|
constsExpr = fn([], __spreadArray(__spreadArray([], __read(prepareStatements)), [new ReturnStatement(constsExpr)]));
|
|
}
|
|
definitionMap.set('consts', constsExpr);
|
|
}
|
|
definitionMap.set('template', templateFunctionExpression);
|
|
// e.g. `directives: [MyDirective]`
|
|
if (directivesUsed.size) {
|
|
var directivesList = literalArr(Array.from(directivesUsed));
|
|
var directivesExpr = compileDeclarationList(directivesList, meta.declarationListEmitMode);
|
|
definitionMap.set('directives', directivesExpr);
|
|
}
|
|
// e.g. `pipes: [MyPipe]`
|
|
if (pipesUsed.size) {
|
|
var pipesList = literalArr(Array.from(pipesUsed));
|
|
var pipesExpr = compileDeclarationList(pipesList, meta.declarationListEmitMode);
|
|
definitionMap.set('pipes', pipesExpr);
|
|
}
|
|
if (meta.encapsulation === null) {
|
|
meta.encapsulation = ViewEncapsulation.Emulated;
|
|
}
|
|
// e.g. `styles: [str1, str2]`
|
|
if (meta.styles && meta.styles.length) {
|
|
var styleValues = meta.encapsulation == ViewEncapsulation.Emulated ?
|
|
compileStyles(meta.styles, CONTENT_ATTR, HOST_ATTR) :
|
|
meta.styles;
|
|
var strings = styleValues.map(function (str) { return constantPool.getConstLiteral(literal(str)); });
|
|
definitionMap.set('styles', literalArr(strings));
|
|
}
|
|
else if (meta.encapsulation === ViewEncapsulation.Emulated) {
|
|
// If there is no style, don't generate css selectors on elements
|
|
meta.encapsulation = ViewEncapsulation.None;
|
|
}
|
|
// Only set view encapsulation if it's not the default value
|
|
if (meta.encapsulation !== ViewEncapsulation.Emulated) {
|
|
definitionMap.set('encapsulation', literal(meta.encapsulation));
|
|
}
|
|
// e.g. `animation: [trigger('123', [])]`
|
|
if (meta.animations !== null) {
|
|
definitionMap.set('data', literalMap([{ key: 'animation', value: meta.animations, quoted: false }]));
|
|
}
|
|
// Only set the change detection flag if it's defined and it's not the default.
|
|
if (changeDetection != null && changeDetection !== ChangeDetectionStrategy.Default) {
|
|
definitionMap.set('changeDetection', literal(changeDetection));
|
|
}
|
|
var expression = importExpr(Identifiers.defineComponent).callFn([definitionMap.toLiteralMap()], undefined, true);
|
|
var type = createComponentType(meta);
|
|
return { expression: expression, type: type, statements: [] };
|
|
}
|
|
/**
|
|
* Creates the type specification from the component meta. This type is inserted into .d.ts files
|
|
* to be consumed by upstream compilations.
|
|
*/
|
|
function createComponentType(meta) {
|
|
var typeParams = createDirectiveTypeParams(meta);
|
|
typeParams.push(stringArrayAsType(meta.template.ngContentSelectors));
|
|
return expressionType(importExpr(Identifiers.ComponentDeclaration, typeParams));
|
|
}
|
|
/**
|
|
* Compiles the array literal of declarations into an expression according to the provided emit
|
|
* mode.
|
|
*/
|
|
function compileDeclarationList(list, mode) {
|
|
switch (mode) {
|
|
case 0 /* Direct */:
|
|
// directives: [MyDir],
|
|
return list;
|
|
case 1 /* Closure */:
|
|
// directives: function () { return [MyDir]; }
|
|
return fn([], [new ReturnStatement(list)]);
|
|
case 2 /* ClosureResolved */:
|
|
// directives: function () { return [MyDir].map(ng.resolveForwardRef); }
|
|
var resolvedList = list.callMethod('map', [importExpr(Identifiers.resolveForwardRef)]);
|
|
return fn([], [new ReturnStatement(resolvedList)]);
|
|
}
|
|
}
|
|
function prepareQueryParams(query, constantPool) {
|
|
var parameters = [getQueryPredicate(query, constantPool), literal(toQueryFlags(query))];
|
|
if (query.read) {
|
|
parameters.push(query.read);
|
|
}
|
|
return parameters;
|
|
}
|
|
/**
|
|
* Translates query flags into `TQueryFlags` type in packages/core/src/render3/interfaces/query.ts
|
|
* @param query
|
|
*/
|
|
function toQueryFlags(query) {
|
|
return (query.descendants ? 1 /* descendants */ : 0 /* none */) |
|
|
(query.static ? 2 /* isStatic */ : 0 /* none */) |
|
|
(query.emitDistinctChangesOnly ? 4 /* emitDistinctChangesOnly */ : 0 /* none */);
|
|
}
|
|
function convertAttributesToExpressions(attributes) {
|
|
var e_2, _a;
|
|
var values = [];
|
|
try {
|
|
for (var _b = __values(Object.getOwnPropertyNames(attributes)), _c = _b.next(); !_c.done; _c = _b.next()) {
|
|
var key = _c.value;
|
|
var value = attributes[key];
|
|
values.push(literal(key), value);
|
|
}
|
|
}
|
|
catch (e_2_1) { e_2 = { error: e_2_1 }; }
|
|
finally {
|
|
try {
|
|
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
|
|
}
|
|
finally { if (e_2) throw e_2.error; }
|
|
}
|
|
return values;
|
|
}
|
|
// Define and update any content queries
|
|
function createContentQueriesFunction(queries, constantPool, name) {
|
|
var e_3, _a;
|
|
var createStatements = [];
|
|
var updateStatements = [];
|
|
var tempAllocator = temporaryAllocator(updateStatements, TEMPORARY_NAME);
|
|
try {
|
|
for (var queries_1 = __values(queries), queries_1_1 = queries_1.next(); !queries_1_1.done; queries_1_1 = queries_1.next()) {
|
|
var query = queries_1_1.value;
|
|
// creation, e.g. r3.contentQuery(dirIndex, somePredicate, true, null);
|
|
createStatements.push(importExpr(Identifiers.contentQuery)
|
|
.callFn(__spreadArray([variable('dirIndex')], __read(prepareQueryParams(query, constantPool))))
|
|
.toStmt());
|
|
// update, e.g. (r3.queryRefresh(tmp = r3.loadQuery()) && (ctx.someDir = tmp));
|
|
var temporary = tempAllocator();
|
|
var getQueryList = importExpr(Identifiers.loadQuery).callFn([]);
|
|
var refresh = importExpr(Identifiers.queryRefresh).callFn([temporary.set(getQueryList)]);
|
|
var updateDirective = variable(CONTEXT_NAME)
|
|
.prop(query.propertyName)
|
|
.set(query.first ? temporary.prop('first') : temporary);
|
|
updateStatements.push(refresh.and(updateDirective).toStmt());
|
|
}
|
|
}
|
|
catch (e_3_1) { e_3 = { error: e_3_1 }; }
|
|
finally {
|
|
try {
|
|
if (queries_1_1 && !queries_1_1.done && (_a = queries_1.return)) _a.call(queries_1);
|
|
}
|
|
finally { if (e_3) throw e_3.error; }
|
|
}
|
|
var contentQueriesFnName = name ? name + "_ContentQueries" : null;
|
|
return fn([
|
|
new FnParam(RENDER_FLAGS, NUMBER_TYPE), new FnParam(CONTEXT_NAME, null),
|
|
new FnParam('dirIndex', null)
|
|
], [
|
|
renderFlagCheckIfStmt(1 /* Create */, createStatements),
|
|
renderFlagCheckIfStmt(2 /* Update */, updateStatements)
|
|
], INFERRED_TYPE, null, contentQueriesFnName);
|
|
}
|
|
function stringAsType(str) {
|
|
return expressionType(literal(str));
|
|
}
|
|
function stringMapAsType(map) {
|
|
var mapValues = Object.keys(map).map(function (key) {
|
|
var value = Array.isArray(map[key]) ? map[key][0] : map[key];
|
|
return {
|
|
key: key,
|
|
value: literal(value),
|
|
quoted: true,
|
|
};
|
|
});
|
|
return expressionType(literalMap(mapValues));
|
|
}
|
|
function stringArrayAsType(arr) {
|
|
return arr.length > 0 ? expressionType(literalArr(arr.map(function (value) { return literal(value); }))) :
|
|
NONE_TYPE;
|
|
}
|
|
function createDirectiveTypeParams(meta) {
|
|
// On the type side, remove newlines from the selector as it will need to fit into a TypeScript
|
|
// string literal, which must be on one line.
|
|
var selectorForType = meta.selector !== null ? meta.selector.replace(/\n/g, '') : null;
|
|
return [
|
|
typeWithParameters(meta.type.type, meta.typeArgumentCount),
|
|
selectorForType !== null ? stringAsType(selectorForType) : NONE_TYPE,
|
|
meta.exportAs !== null ? stringArrayAsType(meta.exportAs) : NONE_TYPE,
|
|
stringMapAsType(meta.inputs),
|
|
stringMapAsType(meta.outputs),
|
|
stringArrayAsType(meta.queries.map(function (q) { return q.propertyName; })),
|
|
];
|
|
}
|
|
/**
|
|
* Creates the type specification from the directive meta. This type is inserted into .d.ts files
|
|
* to be consumed by upstream compilations.
|
|
*/
|
|
function createDirectiveType(meta) {
|
|
var typeParams = createDirectiveTypeParams(meta);
|
|
return expressionType(importExpr(Identifiers.DirectiveDeclaration, typeParams));
|
|
}
|
|
// Define and update any view queries
|
|
function createViewQueriesFunction(viewQueries, constantPool, name) {
|
|
var createStatements = [];
|
|
var updateStatements = [];
|
|
var tempAllocator = temporaryAllocator(updateStatements, TEMPORARY_NAME);
|
|
viewQueries.forEach(function (query) {
|
|
// creation, e.g. r3.viewQuery(somePredicate, true);
|
|
var queryDefinition = importExpr(Identifiers.viewQuery).callFn(prepareQueryParams(query, constantPool));
|
|
createStatements.push(queryDefinition.toStmt());
|
|
// update, e.g. (r3.queryRefresh(tmp = r3.loadQuery()) && (ctx.someDir = tmp));
|
|
var temporary = tempAllocator();
|
|
var getQueryList = importExpr(Identifiers.loadQuery).callFn([]);
|
|
var refresh = importExpr(Identifiers.queryRefresh).callFn([temporary.set(getQueryList)]);
|
|
var updateDirective = variable(CONTEXT_NAME)
|
|
.prop(query.propertyName)
|
|
.set(query.first ? temporary.prop('first') : temporary);
|
|
updateStatements.push(refresh.and(updateDirective).toStmt());
|
|
});
|
|
var viewQueryFnName = name ? name + "_Query" : null;
|
|
return fn([new FnParam(RENDER_FLAGS, NUMBER_TYPE), new FnParam(CONTEXT_NAME, null)], [
|
|
renderFlagCheckIfStmt(1 /* Create */, createStatements),
|
|
renderFlagCheckIfStmt(2 /* Update */, updateStatements)
|
|
], INFERRED_TYPE, null, viewQueryFnName);
|
|
}
|
|
// Return a host binding function or null if one is not necessary.
|
|
function createHostBindingsFunction(hostBindingsMetadata, typeSourceSpan, bindingParser, constantPool, selector, name, definitionMap) {
|
|
var bindingContext = variable(CONTEXT_NAME);
|
|
var styleBuilder = new StylingBuilder(bindingContext);
|
|
var _a = hostBindingsMetadata.specialAttributes, styleAttr = _a.styleAttr, classAttr = _a.classAttr;
|
|
if (styleAttr !== undefined) {
|
|
styleBuilder.registerStyleAttr(styleAttr);
|
|
}
|
|
if (classAttr !== undefined) {
|
|
styleBuilder.registerClassAttr(classAttr);
|
|
}
|
|
var createStatements = [];
|
|
var updateStatements = [];
|
|
var hostBindingSourceSpan = typeSourceSpan;
|
|
var directiveSummary = metadataAsSummary(hostBindingsMetadata);
|
|
// Calculate host event bindings
|
|
var eventBindings = bindingParser.createDirectiveHostEventAsts(directiveSummary, hostBindingSourceSpan);
|
|
if (eventBindings && eventBindings.length) {
|
|
var listeners = createHostListeners(eventBindings, name);
|
|
createStatements.push.apply(createStatements, __spreadArray([], __read(listeners)));
|
|
}
|
|
// Calculate the host property bindings
|
|
var bindings = bindingParser.createBoundHostProperties(directiveSummary, hostBindingSourceSpan);
|
|
var allOtherBindings = [];
|
|
// We need to calculate the total amount of binding slots required by
|
|
// all the instructions together before any value conversions happen.
|
|
// Value conversions may require additional slots for interpolation and
|
|
// bindings with pipes. These calculates happen after this block.
|
|
var totalHostVarsCount = 0;
|
|
bindings && bindings.forEach(function (binding) {
|
|
var stylingInputWasSet = styleBuilder.registerInputBasedOnName(binding.name, binding.expression, hostBindingSourceSpan);
|
|
if (stylingInputWasSet) {
|
|
totalHostVarsCount += MIN_STYLING_BINDING_SLOTS_REQUIRED;
|
|
}
|
|
else {
|
|
allOtherBindings.push(binding);
|
|
totalHostVarsCount++;
|
|
}
|
|
});
|
|
var valueConverter;
|
|
var getValueConverter = function () {
|
|
if (!valueConverter) {
|
|
var hostVarsCountFn = function (numSlots) {
|
|
var originalVarsCount = totalHostVarsCount;
|
|
totalHostVarsCount += numSlots;
|
|
return originalVarsCount;
|
|
};
|
|
valueConverter = new ValueConverter(constantPool, function () { return error('Unexpected node'); }, // new nodes are illegal here
|
|
hostVarsCountFn, function () { return error('Unexpected pipe'); }); // pipes are illegal here
|
|
}
|
|
return valueConverter;
|
|
};
|
|
var propertyBindings = [];
|
|
var attributeBindings = [];
|
|
var syntheticHostBindings = [];
|
|
allOtherBindings.forEach(function (binding) {
|
|
// resolve literal arrays and literal objects
|
|
var value = binding.expression.visit(getValueConverter());
|
|
var bindingExpr = bindingFn(bindingContext, value);
|
|
var _a = getBindingNameAndInstruction(binding), bindingName = _a.bindingName, instruction = _a.instruction, isAttribute = _a.isAttribute;
|
|
var securityContexts = bindingParser.calcPossibleSecurityContexts(selector, bindingName, isAttribute)
|
|
.filter(function (context) { return context !== SecurityContext.NONE; });
|
|
var sanitizerFn = null;
|
|
if (securityContexts.length) {
|
|
if (securityContexts.length === 2 &&
|
|
securityContexts.indexOf(SecurityContext.URL) > -1 &&
|
|
securityContexts.indexOf(SecurityContext.RESOURCE_URL) > -1) {
|
|
// Special case for some URL attributes (such as "src" and "href") that may be a part
|
|
// of different security contexts. In this case we use special sanitization function and
|
|
// select the actual sanitizer at runtime based on a tag name that is provided while
|
|
// invoking sanitization function.
|
|
sanitizerFn = importExpr(Identifiers.sanitizeUrlOrResourceUrl);
|
|
}
|
|
else {
|
|
sanitizerFn = resolveSanitizationFn(securityContexts[0], isAttribute);
|
|
}
|
|
}
|
|
var instructionParams = [literal(bindingName), bindingExpr.currValExpr];
|
|
if (sanitizerFn) {
|
|
instructionParams.push(sanitizerFn);
|
|
}
|
|
updateStatements.push.apply(updateStatements, __spreadArray([], __read(bindingExpr.stmts)));
|
|
if (instruction === Identifiers.hostProperty) {
|
|
propertyBindings.push(instructionParams);
|
|
}
|
|
else if (instruction === Identifiers.attribute) {
|
|
attributeBindings.push(instructionParams);
|
|
}
|
|
else if (instruction === Identifiers.syntheticHostProperty) {
|
|
syntheticHostBindings.push(instructionParams);
|
|
}
|
|
else {
|
|
updateStatements.push(importExpr(instruction).callFn(instructionParams).toStmt());
|
|
}
|
|
});
|
|
if (propertyBindings.length > 0) {
|
|
updateStatements.push(chainedInstruction(Identifiers.hostProperty, propertyBindings).toStmt());
|
|
}
|
|
if (attributeBindings.length > 0) {
|
|
updateStatements.push(chainedInstruction(Identifiers.attribute, attributeBindings).toStmt());
|
|
}
|
|
if (syntheticHostBindings.length > 0) {
|
|
updateStatements.push(chainedInstruction(Identifiers.syntheticHostProperty, syntheticHostBindings).toStmt());
|
|
}
|
|
// since we're dealing with directives/components and both have hostBinding
|
|
// functions, we need to generate a special hostAttrs instruction that deals
|
|
// with both the assignment of styling as well as static attributes to the host
|
|
// element. The instruction below will instruct all initial styling (styling
|
|
// that is inside of a host binding within a directive/component) to be attached
|
|
// to the host element alongside any of the provided host attributes that were
|
|
// collected earlier.
|
|
var hostAttrs = convertAttributesToExpressions(hostBindingsMetadata.attributes);
|
|
styleBuilder.assignHostAttrs(hostAttrs, definitionMap);
|
|
if (styleBuilder.hasBindings) {
|
|
// finally each binding that was registered in the statement above will need to be added to
|
|
// the update block of a component/directive templateFn/hostBindingsFn so that the bindings
|
|
// are evaluated and updated for the element.
|
|
styleBuilder.buildUpdateLevelInstructions(getValueConverter()).forEach(function (instruction) {
|
|
if (instruction.calls.length > 0) {
|
|
var calls_1 = [];
|
|
instruction.calls.forEach(function (call) {
|
|
// we subtract a value of `1` here because the binding slot was already allocated
|
|
// at the top of this method when all the input bindings were counted.
|
|
totalHostVarsCount +=
|
|
Math.max(call.allocateBindingSlots - MIN_STYLING_BINDING_SLOTS_REQUIRED, 0);
|
|
calls_1.push(convertStylingCall(call, bindingContext, bindingFn));
|
|
});
|
|
updateStatements.push(chainedInstruction(instruction.reference, calls_1).toStmt());
|
|
}
|
|
});
|
|
}
|
|
if (totalHostVarsCount) {
|
|
definitionMap.set('hostVars', literal(totalHostVarsCount));
|
|
}
|
|
if (createStatements.length > 0 || updateStatements.length > 0) {
|
|
var hostBindingsFnName = name ? name + "_HostBindings" : null;
|
|
var statements = [];
|
|
if (createStatements.length > 0) {
|
|
statements.push(renderFlagCheckIfStmt(1 /* Create */, createStatements));
|
|
}
|
|
if (updateStatements.length > 0) {
|
|
statements.push(renderFlagCheckIfStmt(2 /* Update */, updateStatements));
|
|
}
|
|
return fn([new FnParam(RENDER_FLAGS, NUMBER_TYPE), new FnParam(CONTEXT_NAME, null)], statements, INFERRED_TYPE, null, hostBindingsFnName);
|
|
}
|
|
return null;
|
|
}
|
|
function bindingFn(implicit, value) {
|
|
return convertPropertyBinding(null, implicit, value, 'b', BindingForm.Expression, function () { return error('Unexpected interpolation'); });
|
|
}
|
|
function convertStylingCall(call, bindingContext, bindingFn) {
|
|
return call.params(function (value) { return bindingFn(bindingContext, value).currValExpr; });
|
|
}
|
|
function getBindingNameAndInstruction(binding) {
|
|
var bindingName = binding.name;
|
|
var instruction;
|
|
// Check to see if this is an attr binding or a property binding
|
|
var attrMatches = bindingName.match(ATTR_REGEX);
|
|
if (attrMatches) {
|
|
bindingName = attrMatches[1];
|
|
instruction = Identifiers.attribute;
|
|
}
|
|
else {
|
|
if (binding.isAnimation) {
|
|
bindingName = prepareSyntheticPropertyName(bindingName);
|
|
// host bindings that have a synthetic property (e.g. @foo) should always be rendered
|
|
// in the context of the component and not the parent. Therefore there is a special
|
|
// compatibility instruction available for this purpose.
|
|
instruction = Identifiers.syntheticHostProperty;
|
|
}
|
|
else {
|
|
instruction = Identifiers.hostProperty;
|
|
}
|
|
}
|
|
return { bindingName: bindingName, instruction: instruction, isAttribute: !!attrMatches };
|
|
}
|
|
function createHostListeners(eventBindings, name) {
|
|
var listeners = [];
|
|
var syntheticListeners = [];
|
|
var instructions = [];
|
|
eventBindings.forEach(function (binding) {
|
|
var bindingName = binding.name && sanitizeIdentifier(binding.name);
|
|
var bindingFnName = binding.type === 1 /* Animation */ ?
|
|
prepareSyntheticListenerFunctionName(bindingName, binding.targetOrPhase) :
|
|
bindingName;
|
|
var handlerName = name && bindingName ? name + "_" + bindingFnName + "_HostBindingHandler" : null;
|
|
var params = prepareEventListenerParameters(BoundEvent.fromParsedEvent(binding), handlerName);
|
|
if (binding.type == 1 /* Animation */) {
|
|
syntheticListeners.push(params);
|
|
}
|
|
else {
|
|
listeners.push(params);
|
|
}
|
|
});
|
|
if (syntheticListeners.length > 0) {
|
|
instructions.push(chainedInstruction(Identifiers.syntheticHostListener, syntheticListeners).toStmt());
|
|
}
|
|
if (listeners.length > 0) {
|
|
instructions.push(chainedInstruction(Identifiers.listener, listeners).toStmt());
|
|
}
|
|
return instructions;
|
|
}
|
|
function metadataAsSummary(meta) {
|
|
// clang-format off
|
|
return {
|
|
// This is used by the BindingParser, which only deals with listeners and properties. There's no
|
|
// need to pass attributes to it.
|
|
hostAttributes: {},
|
|
hostListeners: meta.listeners,
|
|
hostProperties: meta.properties,
|
|
};
|
|
// clang-format on
|
|
}
|
|
var HOST_REG_EXP$1 = /^(?:\[([^\]]+)\])|(?:\(([^\)]+)\))$/;
|
|
function parseHostBindings(host) {
|
|
var e_4, _a;
|
|
var attributes = {};
|
|
var listeners = {};
|
|
var properties = {};
|
|
var specialAttributes = {};
|
|
try {
|
|
for (var _b = __values(Object.keys(host)), _c = _b.next(); !_c.done; _c = _b.next()) {
|
|
var key = _c.value;
|
|
var value = host[key];
|
|
var matches = key.match(HOST_REG_EXP$1);
|
|
if (matches === null) {
|
|
switch (key) {
|
|
case 'class':
|
|
if (typeof value !== 'string') {
|
|
// TODO(alxhub): make this a diagnostic.
|
|
throw new Error("Class binding must be string");
|
|
}
|
|
specialAttributes.classAttr = value;
|
|
break;
|
|
case 'style':
|
|
if (typeof value !== 'string') {
|
|
// TODO(alxhub): make this a diagnostic.
|
|
throw new Error("Style binding must be string");
|
|
}
|
|
specialAttributes.styleAttr = value;
|
|
break;
|
|
default:
|
|
if (typeof value === 'string') {
|
|
attributes[key] = literal(value);
|
|
}
|
|
else {
|
|
attributes[key] = value;
|
|
}
|
|
}
|
|
}
|
|
else if (matches[1 /* Binding */] != null) {
|
|
if (typeof value !== 'string') {
|
|
// TODO(alxhub): make this a diagnostic.
|
|
throw new Error("Property binding must be string");
|
|
}
|
|
// synthetic properties (the ones that have a `@` as a prefix)
|
|
// are still treated the same as regular properties. Therefore
|
|
// there is no point in storing them in a separate map.
|
|
properties[matches[1 /* Binding */]] = value;
|
|
}
|
|
else if (matches[2 /* Event */] != null) {
|
|
if (typeof value !== 'string') {
|
|
// TODO(alxhub): make this a diagnostic.
|
|
throw new Error("Event binding must be string");
|
|
}
|
|
listeners[matches[2 /* Event */]] = value;
|
|
}
|
|
}
|
|
}
|
|
catch (e_4_1) { e_4 = { error: e_4_1 }; }
|
|
finally {
|
|
try {
|
|
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
|
|
}
|
|
finally { if (e_4) throw e_4.error; }
|
|
}
|
|
return { attributes: attributes, listeners: listeners, properties: properties, specialAttributes: specialAttributes };
|
|
}
|
|
/**
|
|
* Verifies host bindings and returns the list of errors (if any). Empty array indicates that a
|
|
* given set of host bindings has no errors.
|
|
*
|
|
* @param bindings set of host bindings to verify.
|
|
* @param sourceSpan source span where host bindings were defined.
|
|
* @returns array of errors associated with a given set of host bindings.
|
|
*/
|
|
function verifyHostBindings(bindings, sourceSpan) {
|
|
var summary = metadataAsSummary(bindings);
|
|
// TODO: abstract out host bindings verification logic and use it instead of
|
|
// creating events and properties ASTs to detect errors (FW-996)
|
|
var bindingParser = makeBindingParser();
|
|
bindingParser.createDirectiveHostEventAsts(summary, sourceSpan);
|
|
bindingParser.createBoundHostProperties(summary, sourceSpan);
|
|
return bindingParser.errors;
|
|
}
|
|
function compileStyles(styles, selector, hostSelector) {
|
|
var shadowCss = new ShadowCss();
|
|
return styles.map(function (style) {
|
|
return shadowCss.shimCssText(style, selector, hostSelector);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* @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
|
|
*/
|
|
/**
|
|
* An interface for retrieving documents by URL that the compiler uses to
|
|
* load templates.
|
|
*
|
|
* This is an abstract class, rather than an interface, so that it can be used
|
|
* as injection token.
|
|
*/
|
|
var ResourceLoader = /** @class */ (function () {
|
|
function ResourceLoader() {
|
|
}
|
|
return ResourceLoader;
|
|
}());
|
|
|
|
var CompilerFacadeImpl = /** @class */ (function () {
|
|
function CompilerFacadeImpl(jitEvaluator) {
|
|
if (jitEvaluator === void 0) { jitEvaluator = new JitEvaluator(); }
|
|
this.jitEvaluator = jitEvaluator;
|
|
this.FactoryTarget = exports.FactoryTarget;
|
|
this.ResourceLoader = ResourceLoader;
|
|
this.elementSchemaRegistry = new DomElementSchemaRegistry();
|
|
}
|
|
CompilerFacadeImpl.prototype.compilePipe = function (angularCoreEnv, sourceMapUrl, facade) {
|
|
var metadata = {
|
|
name: facade.name,
|
|
type: wrapReference(facade.type),
|
|
internalType: new WrappedNodeExpr(facade.type),
|
|
typeArgumentCount: 0,
|
|
deps: null,
|
|
pipeName: facade.pipeName,
|
|
pure: facade.pure,
|
|
};
|
|
var res = compilePipeFromMetadata(metadata);
|
|
return this.jitExpression(res.expression, angularCoreEnv, sourceMapUrl, []);
|
|
};
|
|
CompilerFacadeImpl.prototype.compilePipeDeclaration = function (angularCoreEnv, sourceMapUrl, declaration) {
|
|
var meta = convertDeclarePipeFacadeToMetadata(declaration);
|
|
var res = compilePipeFromMetadata(meta);
|
|
return this.jitExpression(res.expression, angularCoreEnv, sourceMapUrl, []);
|
|
};
|
|
CompilerFacadeImpl.prototype.compileInjectable = function (angularCoreEnv, sourceMapUrl, facade) {
|
|
var _a;
|
|
var _j = compileInjectable({
|
|
name: facade.name,
|
|
type: wrapReference(facade.type),
|
|
internalType: new WrappedNodeExpr(facade.type),
|
|
typeArgumentCount: facade.typeArgumentCount,
|
|
providedIn: computeProvidedIn(facade.providedIn),
|
|
useClass: convertToProviderExpression(facade, USE_CLASS),
|
|
useFactory: wrapExpression(facade, USE_FACTORY),
|
|
useValue: convertToProviderExpression(facade, USE_VALUE),
|
|
useExisting: convertToProviderExpression(facade, USE_EXISTING),
|
|
deps: (_a = facade.deps) === null || _a === void 0 ? void 0 : _a.map(convertR3DependencyMetadata),
|
|
},
|
|
/* resolveForwardRefs */ true), expression = _j.expression, statements = _j.statements;
|
|
return this.jitExpression(expression, angularCoreEnv, sourceMapUrl, statements);
|
|
};
|
|
CompilerFacadeImpl.prototype.compileInjectableDeclaration = function (angularCoreEnv, sourceMapUrl, facade) {
|
|
var _a;
|
|
var _j = compileInjectable({
|
|
name: facade.type.name,
|
|
type: wrapReference(facade.type),
|
|
internalType: new WrappedNodeExpr(facade.type),
|
|
typeArgumentCount: 0,
|
|
providedIn: computeProvidedIn(facade.providedIn),
|
|
useClass: convertToProviderExpression(facade, USE_CLASS),
|
|
useFactory: wrapExpression(facade, USE_FACTORY),
|
|
useValue: convertToProviderExpression(facade, USE_VALUE),
|
|
useExisting: convertToProviderExpression(facade, USE_EXISTING),
|
|
deps: (_a = facade.deps) === null || _a === void 0 ? void 0 : _a.map(convertR3DeclareDependencyMetadata),
|
|
},
|
|
/* resolveForwardRefs */ true), expression = _j.expression, statements = _j.statements;
|
|
return this.jitExpression(expression, angularCoreEnv, sourceMapUrl, statements);
|
|
};
|
|
CompilerFacadeImpl.prototype.compileInjector = function (angularCoreEnv, sourceMapUrl, facade) {
|
|
var meta = {
|
|
name: facade.name,
|
|
type: wrapReference(facade.type),
|
|
internalType: new WrappedNodeExpr(facade.type),
|
|
providers: new WrappedNodeExpr(facade.providers),
|
|
imports: facade.imports.map(function (i) { return new WrappedNodeExpr(i); }),
|
|
};
|
|
var res = compileInjector(meta);
|
|
return this.jitExpression(res.expression, angularCoreEnv, sourceMapUrl, []);
|
|
};
|
|
CompilerFacadeImpl.prototype.compileInjectorDeclaration = function (angularCoreEnv, sourceMapUrl, declaration) {
|
|
var meta = convertDeclareInjectorFacadeToMetadata(declaration);
|
|
var res = compileInjector(meta);
|
|
return this.jitExpression(res.expression, angularCoreEnv, sourceMapUrl, []);
|
|
};
|
|
CompilerFacadeImpl.prototype.compileNgModule = function (angularCoreEnv, sourceMapUrl, facade) {
|
|
var meta = {
|
|
type: wrapReference(facade.type),
|
|
internalType: new WrappedNodeExpr(facade.type),
|
|
adjacentType: new WrappedNodeExpr(facade.type),
|
|
bootstrap: facade.bootstrap.map(wrapReference),
|
|
declarations: facade.declarations.map(wrapReference),
|
|
imports: facade.imports.map(wrapReference),
|
|
exports: facade.exports.map(wrapReference),
|
|
emitInline: true,
|
|
containsForwardDecls: false,
|
|
schemas: facade.schemas ? facade.schemas.map(wrapReference) : null,
|
|
id: facade.id ? new WrappedNodeExpr(facade.id) : null,
|
|
};
|
|
var res = compileNgModule(meta);
|
|
return this.jitExpression(res.expression, angularCoreEnv, sourceMapUrl, []);
|
|
};
|
|
CompilerFacadeImpl.prototype.compileNgModuleDeclaration = function (angularCoreEnv, sourceMapUrl, declaration) {
|
|
var expression = compileNgModuleDeclarationExpression(declaration);
|
|
return this.jitExpression(expression, angularCoreEnv, sourceMapUrl, []);
|
|
};
|
|
CompilerFacadeImpl.prototype.compileDirective = function (angularCoreEnv, sourceMapUrl, facade) {
|
|
var meta = convertDirectiveFacadeToMetadata(facade);
|
|
return this.compileDirectiveFromMeta(angularCoreEnv, sourceMapUrl, meta);
|
|
};
|
|
CompilerFacadeImpl.prototype.compileDirectiveDeclaration = function (angularCoreEnv, sourceMapUrl, declaration) {
|
|
var typeSourceSpan = this.createParseSourceSpan('Directive', declaration.type.name, sourceMapUrl);
|
|
var meta = convertDeclareDirectiveFacadeToMetadata(declaration, typeSourceSpan);
|
|
return this.compileDirectiveFromMeta(angularCoreEnv, sourceMapUrl, meta);
|
|
};
|
|
CompilerFacadeImpl.prototype.compileDirectiveFromMeta = function (angularCoreEnv, sourceMapUrl, meta) {
|
|
var constantPool = new ConstantPool();
|
|
var bindingParser = makeBindingParser();
|
|
var res = compileDirectiveFromMetadata(meta, constantPool, bindingParser);
|
|
return this.jitExpression(res.expression, angularCoreEnv, sourceMapUrl, constantPool.statements);
|
|
};
|
|
CompilerFacadeImpl.prototype.compileComponent = function (angularCoreEnv, sourceMapUrl, facade) {
|
|
// Parse the template and check for errors.
|
|
var _j = parseJitTemplate(facade.template, facade.name, sourceMapUrl, facade.preserveWhitespaces, facade.interpolation), template = _j.template, interpolation = _j.interpolation;
|
|
// Compile the component metadata, including template, into an expression.
|
|
var meta = Object.assign(Object.assign(Object.assign({}, facade), convertDirectiveFacadeToMetadata(facade)), { selector: facade.selector || this.elementSchemaRegistry.getDefaultComponentElementName(), template: template, declarationListEmitMode: 0 /* Direct */, styles: __spreadArray(__spreadArray([], __read(facade.styles)), __read(template.styles)), encapsulation: facade.encapsulation, interpolation: interpolation, changeDetection: facade.changeDetection, animations: facade.animations != null ? new WrappedNodeExpr(facade.animations) : null, viewProviders: facade.viewProviders != null ? new WrappedNodeExpr(facade.viewProviders) :
|
|
null, relativeContextFilePath: '', i18nUseExternalIds: true });
|
|
var jitExpressionSourceMap = "ng:///" + facade.name + ".js";
|
|
return this.compileComponentFromMeta(angularCoreEnv, jitExpressionSourceMap, meta);
|
|
};
|
|
CompilerFacadeImpl.prototype.compileComponentDeclaration = function (angularCoreEnv, sourceMapUrl, declaration) {
|
|
var typeSourceSpan = this.createParseSourceSpan('Component', declaration.type.name, sourceMapUrl);
|
|
var meta = convertDeclareComponentFacadeToMetadata(declaration, typeSourceSpan, sourceMapUrl);
|
|
return this.compileComponentFromMeta(angularCoreEnv, sourceMapUrl, meta);
|
|
};
|
|
CompilerFacadeImpl.prototype.compileComponentFromMeta = function (angularCoreEnv, sourceMapUrl, meta) {
|
|
var constantPool = new ConstantPool();
|
|
var bindingParser = makeBindingParser(meta.interpolation);
|
|
var res = compileComponentFromMetadata(meta, constantPool, bindingParser);
|
|
return this.jitExpression(res.expression, angularCoreEnv, sourceMapUrl, constantPool.statements);
|
|
};
|
|
CompilerFacadeImpl.prototype.compileFactory = function (angularCoreEnv, sourceMapUrl, meta) {
|
|
var factoryRes = compileFactoryFunction({
|
|
name: meta.name,
|
|
type: wrapReference(meta.type),
|
|
internalType: new WrappedNodeExpr(meta.type),
|
|
typeArgumentCount: meta.typeArgumentCount,
|
|
deps: convertR3DependencyMetadataArray(meta.deps),
|
|
target: meta.target,
|
|
});
|
|
return this.jitExpression(factoryRes.expression, angularCoreEnv, sourceMapUrl, factoryRes.statements);
|
|
};
|
|
CompilerFacadeImpl.prototype.compileFactoryDeclaration = function (angularCoreEnv, sourceMapUrl, meta) {
|
|
var factoryRes = compileFactoryFunction({
|
|
name: meta.type.name,
|
|
type: wrapReference(meta.type),
|
|
internalType: new WrappedNodeExpr(meta.type),
|
|
typeArgumentCount: 0,
|
|
deps: Array.isArray(meta.deps) ? meta.deps.map(convertR3DeclareDependencyMetadata) :
|
|
meta.deps,
|
|
target: meta.target,
|
|
});
|
|
return this.jitExpression(factoryRes.expression, angularCoreEnv, sourceMapUrl, factoryRes.statements);
|
|
};
|
|
CompilerFacadeImpl.prototype.createParseSourceSpan = function (kind, typeName, sourceUrl) {
|
|
return r3JitTypeSourceSpan(kind, typeName, sourceUrl);
|
|
};
|
|
/**
|
|
* JIT compiles an expression and returns the result of executing that expression.
|
|
*
|
|
* @param def the definition which will be compiled and executed to get the value to patch
|
|
* @param context an object map of @angular/core symbol names to symbols which will be available
|
|
* in the context of the compiled expression
|
|
* @param sourceUrl a URL to use for the source map of the compiled expression
|
|
* @param preStatements a collection of statements that should be evaluated before the expression.
|
|
*/
|
|
CompilerFacadeImpl.prototype.jitExpression = function (def, context, sourceUrl, preStatements) {
|
|
// The ConstantPool may contain Statements which declare variables used in the final expression.
|
|
// Therefore, its statements need to precede the actual JIT operation. The final statement is a
|
|
// declaration of $def which is set to the expression being compiled.
|
|
var statements = __spreadArray(__spreadArray([], __read(preStatements)), [
|
|
new DeclareVarStmt('$def', def, undefined, [exports.StmtModifier.Exported]),
|
|
]);
|
|
var res = this.jitEvaluator.evaluateStatements(sourceUrl, statements, new R3JitReflector(context), /* enableSourceMaps */ true);
|
|
return res['$def'];
|
|
};
|
|
return CompilerFacadeImpl;
|
|
}());
|
|
var USE_CLASS = Object.keys({ useClass: null })[0];
|
|
var USE_FACTORY = Object.keys({ useFactory: null })[0];
|
|
var USE_VALUE = Object.keys({ useValue: null })[0];
|
|
var USE_EXISTING = Object.keys({ useExisting: null })[0];
|
|
function convertToR3QueryMetadata(facade) {
|
|
return Object.assign(Object.assign({}, facade), { predicate: convertQueryPredicate(facade.predicate), read: facade.read ? new WrappedNodeExpr(facade.read) : null, static: facade.static, emitDistinctChangesOnly: facade.emitDistinctChangesOnly });
|
|
}
|
|
function convertQueryDeclarationToMetadata(declaration) {
|
|
var _a, _b, _c, _d;
|
|
return {
|
|
propertyName: declaration.propertyName,
|
|
first: (_a = declaration.first) !== null && _a !== void 0 ? _a : false,
|
|
predicate: convertQueryPredicate(declaration.predicate),
|
|
descendants: (_b = declaration.descendants) !== null && _b !== void 0 ? _b : false,
|
|
read: declaration.read ? new WrappedNodeExpr(declaration.read) : null,
|
|
static: (_c = declaration.static) !== null && _c !== void 0 ? _c : false,
|
|
emitDistinctChangesOnly: (_d = declaration.emitDistinctChangesOnly) !== null && _d !== void 0 ? _d : true,
|
|
};
|
|
}
|
|
function convertQueryPredicate(predicate) {
|
|
return Array.isArray(predicate) ?
|
|
// The predicate is an array of strings so pass it through.
|
|
predicate :
|
|
// The predicate is a type - assume that we will need to unwrap any `forwardRef()` calls.
|
|
createMayBeForwardRefExpression(new WrappedNodeExpr(predicate), 1 /* Wrapped */);
|
|
}
|
|
function convertDirectiveFacadeToMetadata(facade) {
|
|
var inputsFromMetadata = parseInputOutputs(facade.inputs || []);
|
|
var outputsFromMetadata = parseInputOutputs(facade.outputs || []);
|
|
var propMetadata = facade.propMetadata;
|
|
var inputsFromType = {};
|
|
var outputsFromType = {};
|
|
var _loop_1 = function (field) {
|
|
if (propMetadata.hasOwnProperty(field)) {
|
|
propMetadata[field].forEach(function (ann) {
|
|
if (isInput(ann)) {
|
|
inputsFromType[field] =
|
|
ann.bindingPropertyName ? [ann.bindingPropertyName, field] : field;
|
|
}
|
|
else if (isOutput(ann)) {
|
|
outputsFromType[field] = ann.bindingPropertyName || field;
|
|
}
|
|
});
|
|
}
|
|
};
|
|
for (var field in propMetadata) {
|
|
_loop_1(field);
|
|
}
|
|
return Object.assign(Object.assign({}, facade), { typeArgumentCount: 0, typeSourceSpan: facade.typeSourceSpan, type: wrapReference(facade.type), internalType: new WrappedNodeExpr(facade.type), deps: null, host: extractHostBindings(facade.propMetadata, facade.typeSourceSpan, facade.host), inputs: Object.assign(Object.assign({}, inputsFromMetadata), inputsFromType), outputs: Object.assign(Object.assign({}, outputsFromMetadata), outputsFromType), queries: facade.queries.map(convertToR3QueryMetadata), providers: facade.providers != null ? new WrappedNodeExpr(facade.providers) : null, viewQueries: facade.viewQueries.map(convertToR3QueryMetadata), fullInheritance: false });
|
|
}
|
|
function convertDeclareDirectiveFacadeToMetadata(declaration, typeSourceSpan) {
|
|
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
return {
|
|
name: declaration.type.name,
|
|
type: wrapReference(declaration.type),
|
|
typeSourceSpan: typeSourceSpan,
|
|
internalType: new WrappedNodeExpr(declaration.type),
|
|
selector: (_a = declaration.selector) !== null && _a !== void 0 ? _a : null,
|
|
inputs: (_b = declaration.inputs) !== null && _b !== void 0 ? _b : {},
|
|
outputs: (_c = declaration.outputs) !== null && _c !== void 0 ? _c : {},
|
|
host: convertHostDeclarationToMetadata(declaration.host),
|
|
queries: ((_d = declaration.queries) !== null && _d !== void 0 ? _d : []).map(convertQueryDeclarationToMetadata),
|
|
viewQueries: ((_e = declaration.viewQueries) !== null && _e !== void 0 ? _e : []).map(convertQueryDeclarationToMetadata),
|
|
providers: declaration.providers !== undefined ? new WrappedNodeExpr(declaration.providers) :
|
|
null,
|
|
exportAs: (_f = declaration.exportAs) !== null && _f !== void 0 ? _f : null,
|
|
usesInheritance: (_g = declaration.usesInheritance) !== null && _g !== void 0 ? _g : false,
|
|
lifecycle: { usesOnChanges: (_h = declaration.usesOnChanges) !== null && _h !== void 0 ? _h : false },
|
|
deps: null,
|
|
typeArgumentCount: 0,
|
|
fullInheritance: false,
|
|
};
|
|
}
|
|
function convertHostDeclarationToMetadata(host) {
|
|
if (host === void 0) { host = {}; }
|
|
var _a, _b, _c;
|
|
return {
|
|
attributes: convertOpaqueValuesToExpressions((_a = host.attributes) !== null && _a !== void 0 ? _a : {}),
|
|
listeners: (_b = host.listeners) !== null && _b !== void 0 ? _b : {},
|
|
properties: (_c = host.properties) !== null && _c !== void 0 ? _c : {},
|
|
specialAttributes: {
|
|
classAttr: host.classAttribute,
|
|
styleAttr: host.styleAttribute,
|
|
},
|
|
};
|
|
}
|
|
function convertOpaqueValuesToExpressions(obj) {
|
|
var e_1, _j;
|
|
var result = {};
|
|
try {
|
|
for (var _k = __values(Object.keys(obj)), _l = _k.next(); !_l.done; _l = _k.next()) {
|
|
var key = _l.value;
|
|
result[key] = new WrappedNodeExpr(obj[key]);
|
|
}
|
|
}
|
|
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
finally {
|
|
try {
|
|
if (_l && !_l.done && (_j = _k.return)) _j.call(_k);
|
|
}
|
|
finally { if (e_1) throw e_1.error; }
|
|
}
|
|
return result;
|
|
}
|
|
function convertDeclareComponentFacadeToMetadata(declaration, typeSourceSpan, sourceMapUrl) {
|
|
var _a, _b, _c, _d, _e, _f;
|
|
var _j = parseJitTemplate(declaration.template, declaration.type.name, sourceMapUrl, (_a = declaration.preserveWhitespaces) !== null && _a !== void 0 ? _a : false, declaration.interpolation), template = _j.template, interpolation = _j.interpolation;
|
|
return Object.assign(Object.assign({}, convertDeclareDirectiveFacadeToMetadata(declaration, typeSourceSpan)), { template: template, styles: (_b = declaration.styles) !== null && _b !== void 0 ? _b : [], directives: ((_c = declaration.components) !== null && _c !== void 0 ? _c : [])
|
|
.concat((_d = declaration.directives) !== null && _d !== void 0 ? _d : [])
|
|
.map(convertUsedDirectiveDeclarationToMetadata), pipes: convertUsedPipesToMetadata(declaration.pipes), viewProviders: declaration.viewProviders !== undefined ?
|
|
new WrappedNodeExpr(declaration.viewProviders) :
|
|
null, animations: declaration.animations !== undefined ? new WrappedNodeExpr(declaration.animations) :
|
|
null, changeDetection: (_e = declaration.changeDetection) !== null && _e !== void 0 ? _e : ChangeDetectionStrategy.Default, encapsulation: (_f = declaration.encapsulation) !== null && _f !== void 0 ? _f : ViewEncapsulation.Emulated, interpolation: interpolation, declarationListEmitMode: 2 /* ClosureResolved */, relativeContextFilePath: '', i18nUseExternalIds: true });
|
|
}
|
|
function convertUsedDirectiveDeclarationToMetadata(declaration) {
|
|
var _a, _b, _c;
|
|
return {
|
|
selector: declaration.selector,
|
|
type: new WrappedNodeExpr(declaration.type),
|
|
inputs: (_a = declaration.inputs) !== null && _a !== void 0 ? _a : [],
|
|
outputs: (_b = declaration.outputs) !== null && _b !== void 0 ? _b : [],
|
|
exportAs: (_c = declaration.exportAs) !== null && _c !== void 0 ? _c : null,
|
|
};
|
|
}
|
|
function convertUsedPipesToMetadata(declaredPipes) {
|
|
var e_2, _j;
|
|
var pipes = new Map();
|
|
if (declaredPipes === undefined) {
|
|
return pipes;
|
|
}
|
|
try {
|
|
for (var _k = __values(Object.keys(declaredPipes)), _l = _k.next(); !_l.done; _l = _k.next()) {
|
|
var pipeName = _l.value;
|
|
var pipeType = declaredPipes[pipeName];
|
|
pipes.set(pipeName, new WrappedNodeExpr(pipeType));
|
|
}
|
|
}
|
|
catch (e_2_1) { e_2 = { error: e_2_1 }; }
|
|
finally {
|
|
try {
|
|
if (_l && !_l.done && (_j = _k.return)) _j.call(_k);
|
|
}
|
|
finally { if (e_2) throw e_2.error; }
|
|
}
|
|
return pipes;
|
|
}
|
|
function parseJitTemplate(template, typeName, sourceMapUrl, preserveWhitespaces, interpolation) {
|
|
var interpolationConfig = interpolation ? InterpolationConfig.fromArray(interpolation) : DEFAULT_INTERPOLATION_CONFIG;
|
|
// Parse the template and check for errors.
|
|
var parsed = parseTemplate(template, sourceMapUrl, { preserveWhitespaces: preserveWhitespaces, interpolationConfig: interpolationConfig });
|
|
if (parsed.errors !== null) {
|
|
var errors = parsed.errors.map(function (err) { return err.toString(); }).join(', ');
|
|
throw new Error("Errors during JIT compilation of template for " + typeName + ": " + errors);
|
|
}
|
|
return { template: parsed, interpolation: interpolationConfig };
|
|
}
|
|
/**
|
|
* Convert the expression, if present to an `R3ProviderExpression`.
|
|
*
|
|
* In JIT mode we do not want the compiler to wrap the expression in a `forwardRef()` call because,
|
|
* if it is referencing a type that has not yet been defined, it will have already been wrapped in
|
|
* a `forwardRef()` - either by the application developer or during partial-compilation. Thus we can
|
|
* use `ForwardRefHandling.None`.
|
|
*/
|
|
function convertToProviderExpression(obj, property) {
|
|
if (obj.hasOwnProperty(property)) {
|
|
return createMayBeForwardRefExpression(new WrappedNodeExpr(obj[property]), 0 /* None */);
|
|
}
|
|
else {
|
|
return undefined;
|
|
}
|
|
}
|
|
function wrapExpression(obj, property) {
|
|
if (obj.hasOwnProperty(property)) {
|
|
return new WrappedNodeExpr(obj[property]);
|
|
}
|
|
else {
|
|
return undefined;
|
|
}
|
|
}
|
|
function computeProvidedIn(providedIn) {
|
|
var expression = (providedIn == null || typeof providedIn === 'string') ?
|
|
new LiteralExpr(providedIn !== null && providedIn !== void 0 ? providedIn : null) :
|
|
new WrappedNodeExpr(providedIn);
|
|
// See `convertToProviderExpression()` for why `isForwardRef` is false.
|
|
return createMayBeForwardRefExpression(expression, 0 /* None */);
|
|
}
|
|
function convertR3DependencyMetadataArray(facades) {
|
|
return facades == null ? null : facades.map(convertR3DependencyMetadata);
|
|
}
|
|
function convertR3DependencyMetadata(facade) {
|
|
var isAttributeDep = facade.attribute != null; // both `null` and `undefined`
|
|
var rawToken = facade.token === null ? null : new WrappedNodeExpr(facade.token);
|
|
// In JIT mode, if the dep is an `@Attribute()` then we use the attribute name given in
|
|
// `attribute` rather than the `token`.
|
|
var token = isAttributeDep ? new WrappedNodeExpr(facade.attribute) : rawToken;
|
|
return createR3DependencyMetadata(token, isAttributeDep, facade.host, facade.optional, facade.self, facade.skipSelf);
|
|
}
|
|
function convertR3DeclareDependencyMetadata(facade) {
|
|
var _a, _b, _c, _d, _e;
|
|
var isAttributeDep = (_a = facade.attribute) !== null && _a !== void 0 ? _a : false;
|
|
var token = facade.token === null ? null : new WrappedNodeExpr(facade.token);
|
|
return createR3DependencyMetadata(token, isAttributeDep, (_b = facade.host) !== null && _b !== void 0 ? _b : false, (_c = facade.optional) !== null && _c !== void 0 ? _c : false, (_d = facade.self) !== null && _d !== void 0 ? _d : false, (_e = facade.skipSelf) !== null && _e !== void 0 ? _e : false);
|
|
}
|
|
function createR3DependencyMetadata(token, isAttributeDep, host, optional, self, skipSelf) {
|
|
// If the dep is an `@Attribute()` the `attributeNameType` ought to be the `unknown` type.
|
|
// But types are not available at runtime so we just use a literal `"<unknown>"` string as a dummy
|
|
// marker.
|
|
var attributeNameType = isAttributeDep ? literal('unknown') : null;
|
|
return { token: token, attributeNameType: attributeNameType, host: host, optional: optional, self: self, skipSelf: skipSelf };
|
|
}
|
|
function extractHostBindings(propMetadata, sourceSpan, host) {
|
|
// First parse the declarations from the metadata.
|
|
var bindings = parseHostBindings(host || {});
|
|
// After that check host bindings for errors
|
|
var errors = verifyHostBindings(bindings, sourceSpan);
|
|
if (errors.length) {
|
|
throw new Error(errors.map(function (error) { return error.msg; }).join('\n'));
|
|
}
|
|
var _loop_2 = function (field) {
|
|
if (propMetadata.hasOwnProperty(field)) {
|
|
propMetadata[field].forEach(function (ann) {
|
|
if (isHostBinding(ann)) {
|
|
// Since this is a decorator, we know that the value is a class member. Always access it
|
|
// through `this` so that further down the line it can't be confused for a literal value
|
|
// (e.g. if there's a property called `true`).
|
|
bindings.properties[ann.hostPropertyName || field] =
|
|
getSafePropertyAccessString('this', field);
|
|
}
|
|
else if (isHostListener(ann)) {
|
|
bindings.listeners[ann.eventName || field] = field + "(" + (ann.args || []).join(',') + ")";
|
|
}
|
|
});
|
|
}
|
|
};
|
|
// Next, loop over the properties of the object, looking for @HostBinding and @HostListener.
|
|
for (var field in propMetadata) {
|
|
_loop_2(field);
|
|
}
|
|
return bindings;
|
|
}
|
|
function isHostBinding(value) {
|
|
return value.ngMetadataName === 'HostBinding';
|
|
}
|
|
function isHostListener(value) {
|
|
return value.ngMetadataName === 'HostListener';
|
|
}
|
|
function isInput(value) {
|
|
return value.ngMetadataName === 'Input';
|
|
}
|
|
function isOutput(value) {
|
|
return value.ngMetadataName === 'Output';
|
|
}
|
|
function parseInputOutputs(values) {
|
|
return values.reduce(function (map, value) {
|
|
var _j = __read(value.split(',').map(function (piece) { return piece.trim(); }), 2), field = _j[0], property = _j[1];
|
|
map[field] = property || field;
|
|
return map;
|
|
}, {});
|
|
}
|
|
function convertDeclarePipeFacadeToMetadata(declaration) {
|
|
var _a;
|
|
return {
|
|
name: declaration.type.name,
|
|
type: wrapReference(declaration.type),
|
|
internalType: new WrappedNodeExpr(declaration.type),
|
|
typeArgumentCount: 0,
|
|
pipeName: declaration.name,
|
|
deps: null,
|
|
pure: (_a = declaration.pure) !== null && _a !== void 0 ? _a : true,
|
|
};
|
|
}
|
|
function convertDeclareInjectorFacadeToMetadata(declaration) {
|
|
return {
|
|
name: declaration.type.name,
|
|
type: wrapReference(declaration.type),
|
|
internalType: new WrappedNodeExpr(declaration.type),
|
|
providers: declaration.providers !== undefined ? new WrappedNodeExpr(declaration.providers) :
|
|
null,
|
|
imports: declaration.imports !== undefined ?
|
|
declaration.imports.map(function (i) { return new WrappedNodeExpr(i); }) :
|
|
[],
|
|
};
|
|
}
|
|
function publishFacade(global) {
|
|
var ng = global.ng || (global.ng = {});
|
|
ng.ɵcompilerFacade = new CompilerFacadeImpl();
|
|
}
|
|
|
|
/**
|
|
* @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 VERSION$1 = new Version('12.2.16');
|
|
|
|
/**
|
|
* @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 CompilerConfig = /** @class */ (function () {
|
|
function CompilerConfig(_a) {
|
|
var _b = _a === void 0 ? {} : _a, _c = _b.defaultEncapsulation, defaultEncapsulation = _c === void 0 ? ViewEncapsulation.Emulated : _c, _d = _b.useJit, useJit = _d === void 0 ? true : _d, _e = _b.jitDevMode, jitDevMode = _e === void 0 ? false : _e, _f = _b.missingTranslation, missingTranslation = _f === void 0 ? null : _f, preserveWhitespaces = _b.preserveWhitespaces, strictInjectionParameters = _b.strictInjectionParameters;
|
|
this.defaultEncapsulation = defaultEncapsulation;
|
|
this.useJit = !!useJit;
|
|
this.jitDevMode = !!jitDevMode;
|
|
this.missingTranslation = missingTranslation;
|
|
this.preserveWhitespaces = preserveWhitespacesDefault(noUndefined(preserveWhitespaces));
|
|
this.strictInjectionParameters = strictInjectionParameters === true;
|
|
}
|
|
return CompilerConfig;
|
|
}());
|
|
function preserveWhitespacesDefault(preserveWhitespacesOption, defaultSetting) {
|
|
if (defaultSetting === void 0) { defaultSetting = false; }
|
|
return preserveWhitespacesOption === null ? defaultSetting : preserveWhitespacesOption;
|
|
}
|
|
|
|
var DirectiveNormalizer = /** @class */ (function () {
|
|
function DirectiveNormalizer(_resourceLoader, _urlResolver, _htmlParser, _config) {
|
|
this._resourceLoader = _resourceLoader;
|
|
this._urlResolver = _urlResolver;
|
|
this._htmlParser = _htmlParser;
|
|
this._config = _config;
|
|
this._resourceLoaderCache = new Map();
|
|
}
|
|
DirectiveNormalizer.prototype.clearCache = function () {
|
|
this._resourceLoaderCache.clear();
|
|
};
|
|
DirectiveNormalizer.prototype.clearCacheFor = function (normalizedDirective) {
|
|
var _this = this;
|
|
if (!normalizedDirective.isComponent) {
|
|
return;
|
|
}
|
|
var template = normalizedDirective.template;
|
|
this._resourceLoaderCache.delete(template.templateUrl);
|
|
template.externalStylesheets.forEach(function (stylesheet) {
|
|
_this._resourceLoaderCache.delete(stylesheet.moduleUrl);
|
|
});
|
|
};
|
|
DirectiveNormalizer.prototype._fetch = function (url) {
|
|
var result = this._resourceLoaderCache.get(url);
|
|
if (!result) {
|
|
result = this._resourceLoader.get(url);
|
|
this._resourceLoaderCache.set(url, result);
|
|
}
|
|
return result;
|
|
};
|
|
DirectiveNormalizer.prototype.normalizeTemplate = function (prenormData) {
|
|
var _this = this;
|
|
if (isDefined(prenormData.template)) {
|
|
if (isDefined(prenormData.templateUrl)) {
|
|
throw syntaxError("'" + stringify(prenormData
|
|
.componentType) + "' component cannot define both template and templateUrl");
|
|
}
|
|
if (typeof prenormData.template !== 'string') {
|
|
throw syntaxError("The template specified for component " + stringify(prenormData.componentType) + " is not a string");
|
|
}
|
|
}
|
|
else if (isDefined(prenormData.templateUrl)) {
|
|
if (typeof prenormData.templateUrl !== 'string') {
|
|
throw syntaxError("The templateUrl specified for component " + stringify(prenormData.componentType) + " is not a string");
|
|
}
|
|
}
|
|
else {
|
|
throw syntaxError("No template specified for component " + stringify(prenormData.componentType));
|
|
}
|
|
if (isDefined(prenormData.preserveWhitespaces) &&
|
|
typeof prenormData.preserveWhitespaces !== 'boolean') {
|
|
throw syntaxError("The preserveWhitespaces option for component " + stringify(prenormData.componentType) + " must be a boolean");
|
|
}
|
|
return SyncAsync.then(this._preParseTemplate(prenormData), function (preparsedTemplate) { return _this._normalizeTemplateMetadata(prenormData, preparsedTemplate); });
|
|
};
|
|
DirectiveNormalizer.prototype._preParseTemplate = function (prenomData) {
|
|
var _this = this;
|
|
var template;
|
|
var templateUrl;
|
|
if (prenomData.template != null) {
|
|
template = prenomData.template;
|
|
templateUrl = prenomData.moduleUrl;
|
|
}
|
|
else {
|
|
templateUrl = this._urlResolver.resolve(prenomData.moduleUrl, prenomData.templateUrl);
|
|
template = this._fetch(templateUrl);
|
|
}
|
|
return SyncAsync.then(template, function (template) { return _this._preparseLoadedTemplate(prenomData, template, templateUrl); });
|
|
};
|
|
DirectiveNormalizer.prototype._preparseLoadedTemplate = function (prenormData, template, templateAbsUrl) {
|
|
var isInline = !!prenormData.template;
|
|
var interpolationConfig = InterpolationConfig.fromArray(prenormData.interpolation);
|
|
var templateUrl = templateSourceUrl({ reference: prenormData.ngModuleType }, { type: { reference: prenormData.componentType } }, { isInline: isInline, templateUrl: templateAbsUrl });
|
|
var rootNodesAndErrors = this._htmlParser.parse(template, templateUrl, { tokenizeExpansionForms: true, interpolationConfig: interpolationConfig });
|
|
if (rootNodesAndErrors.errors.length > 0) {
|
|
var errorString = rootNodesAndErrors.errors.join('\n');
|
|
throw syntaxError("Template parse errors:\n" + errorString);
|
|
}
|
|
var templateMetadataStyles = this._normalizeStylesheet(new CompileStylesheetMetadata({ styles: prenormData.styles, moduleUrl: prenormData.moduleUrl }));
|
|
var visitor = new TemplatePreparseVisitor();
|
|
visitAll$1(visitor, rootNodesAndErrors.rootNodes);
|
|
var templateStyles = this._normalizeStylesheet(new CompileStylesheetMetadata({ styles: visitor.styles, styleUrls: visitor.styleUrls, moduleUrl: templateAbsUrl }));
|
|
var styles = templateMetadataStyles.styles.concat(templateStyles.styles);
|
|
var inlineStyleUrls = templateMetadataStyles.styleUrls.concat(templateStyles.styleUrls);
|
|
var styleUrls = this
|
|
._normalizeStylesheet(new CompileStylesheetMetadata({ styleUrls: prenormData.styleUrls, moduleUrl: prenormData.moduleUrl }))
|
|
.styleUrls;
|
|
return {
|
|
template: template,
|
|
templateUrl: templateAbsUrl,
|
|
isInline: isInline,
|
|
htmlAst: rootNodesAndErrors,
|
|
styles: styles,
|
|
inlineStyleUrls: inlineStyleUrls,
|
|
styleUrls: styleUrls,
|
|
ngContentSelectors: visitor.ngContentSelectors,
|
|
};
|
|
};
|
|
DirectiveNormalizer.prototype._normalizeTemplateMetadata = function (prenormData, preparsedTemplate) {
|
|
var _this = this;
|
|
return SyncAsync.then(this._loadMissingExternalStylesheets(preparsedTemplate.styleUrls.concat(preparsedTemplate.inlineStyleUrls)), function (externalStylesheets) { return _this._normalizeLoadedTemplateMetadata(prenormData, preparsedTemplate, externalStylesheets); });
|
|
};
|
|
DirectiveNormalizer.prototype._normalizeLoadedTemplateMetadata = function (prenormData, preparsedTemplate, stylesheets) {
|
|
var _this = this;
|
|
// Algorithm:
|
|
// - produce exactly 1 entry per original styleUrl in
|
|
// CompileTemplateMetadata.externalStylesheets with all styles inlined
|
|
// - inline all styles that are referenced by the template into CompileTemplateMetadata.styles.
|
|
// Reason: be able to determine how many stylesheets there are even without loading
|
|
// the template nor the stylesheets, so we can create a stub for TypeScript always synchronously
|
|
// (as resource loading may be async)
|
|
var styles = __spreadArray([], __read(preparsedTemplate.styles));
|
|
this._inlineStyles(preparsedTemplate.inlineStyleUrls, stylesheets, styles);
|
|
var styleUrls = preparsedTemplate.styleUrls;
|
|
var externalStylesheets = styleUrls.map(function (styleUrl) {
|
|
var stylesheet = stylesheets.get(styleUrl);
|
|
var styles = __spreadArray([], __read(stylesheet.styles));
|
|
_this._inlineStyles(stylesheet.styleUrls, stylesheets, styles);
|
|
return new CompileStylesheetMetadata({ moduleUrl: styleUrl, styles: styles });
|
|
});
|
|
var encapsulation = prenormData.encapsulation;
|
|
if (encapsulation == null) {
|
|
encapsulation = this._config.defaultEncapsulation;
|
|
}
|
|
if (encapsulation === ViewEncapsulation.Emulated && styles.length === 0 &&
|
|
styleUrls.length === 0) {
|
|
encapsulation = ViewEncapsulation.None;
|
|
}
|
|
return new CompileTemplateMetadata({
|
|
encapsulation: encapsulation,
|
|
template: preparsedTemplate.template,
|
|
templateUrl: preparsedTemplate.templateUrl,
|
|
htmlAst: preparsedTemplate.htmlAst,
|
|
styles: styles,
|
|
styleUrls: styleUrls,
|
|
ngContentSelectors: preparsedTemplate.ngContentSelectors,
|
|
animations: prenormData.animations,
|
|
interpolation: prenormData.interpolation,
|
|
isInline: preparsedTemplate.isInline,
|
|
externalStylesheets: externalStylesheets,
|
|
preserveWhitespaces: preserveWhitespacesDefault(prenormData.preserveWhitespaces, this._config.preserveWhitespaces),
|
|
});
|
|
};
|
|
DirectiveNormalizer.prototype._inlineStyles = function (styleUrls, stylesheets, targetStyles) {
|
|
var _this = this;
|
|
styleUrls.forEach(function (styleUrl) {
|
|
var stylesheet = stylesheets.get(styleUrl);
|
|
stylesheet.styles.forEach(function (style) { return targetStyles.push(style); });
|
|
_this._inlineStyles(stylesheet.styleUrls, stylesheets, targetStyles);
|
|
});
|
|
};
|
|
DirectiveNormalizer.prototype._loadMissingExternalStylesheets = function (styleUrls, loadedStylesheets) {
|
|
var _this = this;
|
|
if (loadedStylesheets === void 0) { loadedStylesheets = new Map(); }
|
|
return SyncAsync.then(SyncAsync.all(styleUrls.filter(function (styleUrl) { return !loadedStylesheets.has(styleUrl); })
|
|
.map(function (styleUrl) { return SyncAsync.then(_this._fetch(styleUrl), function (loadedStyle) {
|
|
var stylesheet = _this._normalizeStylesheet(new CompileStylesheetMetadata({ styles: [loadedStyle], moduleUrl: styleUrl }));
|
|
loadedStylesheets.set(styleUrl, stylesheet);
|
|
return _this._loadMissingExternalStylesheets(stylesheet.styleUrls, loadedStylesheets);
|
|
}); })), function (_) { return loadedStylesheets; });
|
|
};
|
|
DirectiveNormalizer.prototype._normalizeStylesheet = function (stylesheet) {
|
|
var _this = this;
|
|
var moduleUrl = stylesheet.moduleUrl;
|
|
var allStyleUrls = stylesheet.styleUrls.filter(isStyleUrlResolvable)
|
|
.map(function (url) { return _this._urlResolver.resolve(moduleUrl, url); });
|
|
var allStyles = stylesheet.styles.map(function (style) {
|
|
var styleWithImports = extractStyleUrls(_this._urlResolver, moduleUrl, style);
|
|
allStyleUrls.push.apply(allStyleUrls, __spreadArray([], __read(styleWithImports.styleUrls)));
|
|
return styleWithImports.style;
|
|
});
|
|
return new CompileStylesheetMetadata({ styles: allStyles, styleUrls: allStyleUrls, moduleUrl: moduleUrl });
|
|
};
|
|
return DirectiveNormalizer;
|
|
}());
|
|
var TemplatePreparseVisitor = /** @class */ (function () {
|
|
function TemplatePreparseVisitor() {
|
|
this.ngContentSelectors = [];
|
|
this.styles = [];
|
|
this.styleUrls = [];
|
|
this.ngNonBindableStackCount = 0;
|
|
}
|
|
TemplatePreparseVisitor.prototype.visitElement = function (ast, context) {
|
|
var preparsedElement = preparseElement(ast);
|
|
switch (preparsedElement.type) {
|
|
case PreparsedElementType.NG_CONTENT:
|
|
if (this.ngNonBindableStackCount === 0) {
|
|
this.ngContentSelectors.push(preparsedElement.selectAttr);
|
|
}
|
|
break;
|
|
case PreparsedElementType.STYLE:
|
|
var textContent_1 = '';
|
|
ast.children.forEach(function (child) {
|
|
if (child instanceof Text$3) {
|
|
textContent_1 += child.value;
|
|
}
|
|
});
|
|
this.styles.push(textContent_1);
|
|
break;
|
|
case PreparsedElementType.STYLESHEET:
|
|
this.styleUrls.push(preparsedElement.hrefAttr);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
if (preparsedElement.nonBindable) {
|
|
this.ngNonBindableStackCount++;
|
|
}
|
|
visitAll$1(this, ast.children);
|
|
if (preparsedElement.nonBindable) {
|
|
this.ngNonBindableStackCount--;
|
|
}
|
|
return null;
|
|
};
|
|
TemplatePreparseVisitor.prototype.visitExpansion = function (ast, context) {
|
|
visitAll$1(this, ast.cases);
|
|
};
|
|
TemplatePreparseVisitor.prototype.visitExpansionCase = function (ast, context) {
|
|
visitAll$1(this, ast.expression);
|
|
};
|
|
TemplatePreparseVisitor.prototype.visitComment = function (ast, context) {
|
|
return null;
|
|
};
|
|
TemplatePreparseVisitor.prototype.visitAttribute = function (ast, context) {
|
|
return null;
|
|
};
|
|
TemplatePreparseVisitor.prototype.visitText = function (ast, context) {
|
|
return null;
|
|
};
|
|
return TemplatePreparseVisitor;
|
|
}());
|
|
|
|
/**
|
|
* @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 QUERY_METADATA_IDENTIFIERS = [
|
|
createViewChild,
|
|
createViewChildren,
|
|
createContentChild,
|
|
createContentChildren,
|
|
];
|
|
/*
|
|
* Resolve a `Type` for {@link Directive}.
|
|
*
|
|
* This interface can be overridden by the application developer to create custom behavior.
|
|
*
|
|
* See {@link Compiler}
|
|
*/
|
|
var DirectiveResolver = /** @class */ (function () {
|
|
function DirectiveResolver(_reflector) {
|
|
this._reflector = _reflector;
|
|
}
|
|
DirectiveResolver.prototype.isDirective = function (type) {
|
|
var typeMetadata = this._reflector.annotations(resolveForwardRef(type));
|
|
return typeMetadata && typeMetadata.some(isDirectiveMetadata);
|
|
};
|
|
DirectiveResolver.prototype.resolve = function (type, throwIfNotFound) {
|
|
if (throwIfNotFound === void 0) { throwIfNotFound = true; }
|
|
var typeMetadata = this._reflector.annotations(resolveForwardRef(type));
|
|
if (typeMetadata) {
|
|
var metadata = findLast(typeMetadata, isDirectiveMetadata);
|
|
if (metadata) {
|
|
var propertyMetadata = this._reflector.propMetadata(type);
|
|
var guards = this._reflector.guards(type);
|
|
return this._mergeWithPropertyMetadata(metadata, propertyMetadata, guards, type);
|
|
}
|
|
}
|
|
if (throwIfNotFound) {
|
|
throw new Error("No Directive annotation found on " + stringify(type));
|
|
}
|
|
return null;
|
|
};
|
|
DirectiveResolver.prototype._mergeWithPropertyMetadata = function (dm, propertyMetadata, guards, directiveType) {
|
|
var inputs = [];
|
|
var outputs = [];
|
|
var host = {};
|
|
var queries = {};
|
|
Object.keys(propertyMetadata).forEach(function (propName) {
|
|
var input = findLast(propertyMetadata[propName], function (a) { return createInput.isTypeOf(a); });
|
|
if (input) {
|
|
if (input.bindingPropertyName) {
|
|
inputs.push(propName + ": " + input.bindingPropertyName);
|
|
}
|
|
else {
|
|
inputs.push(propName);
|
|
}
|
|
}
|
|
var output = findLast(propertyMetadata[propName], function (a) { return createOutput.isTypeOf(a); });
|
|
if (output) {
|
|
if (output.bindingPropertyName) {
|
|
outputs.push(propName + ": " + output.bindingPropertyName);
|
|
}
|
|
else {
|
|
outputs.push(propName);
|
|
}
|
|
}
|
|
var hostBindings = propertyMetadata[propName].filter(function (a) { return createHostBinding.isTypeOf(a); });
|
|
hostBindings.forEach(function (hostBinding) {
|
|
if (hostBinding.hostPropertyName) {
|
|
var startWith = hostBinding.hostPropertyName[0];
|
|
if (startWith === '(') {
|
|
throw new Error("@HostBinding can not bind to events. Use @HostListener instead.");
|
|
}
|
|
else if (startWith === '[') {
|
|
throw new Error("@HostBinding parameter should be a property name, 'class.<name>', or 'attr.<name>'.");
|
|
}
|
|
host["[" + hostBinding.hostPropertyName + "]"] = propName;
|
|
}
|
|
else {
|
|
host["[" + propName + "]"] = propName;
|
|
}
|
|
});
|
|
var hostListeners = propertyMetadata[propName].filter(function (a) { return createHostListener.isTypeOf(a); });
|
|
hostListeners.forEach(function (hostListener) {
|
|
var args = hostListener.args || [];
|
|
host["(" + hostListener.eventName + ")"] = propName + "(" + args.join(',') + ")";
|
|
});
|
|
var query = findLast(propertyMetadata[propName], function (a) { return QUERY_METADATA_IDENTIFIERS.some(function (i) { return i.isTypeOf(a); }); });
|
|
if (query) {
|
|
queries[propName] = query;
|
|
}
|
|
});
|
|
return this._merge(dm, inputs, outputs, host, queries, guards, directiveType);
|
|
};
|
|
DirectiveResolver.prototype._extractPublicName = function (def) {
|
|
return splitAtColon(def, [null, def])[1].trim();
|
|
};
|
|
DirectiveResolver.prototype._dedupeBindings = function (bindings) {
|
|
var names = new Set();
|
|
var publicNames = new Set();
|
|
var reversedResult = [];
|
|
// go last to first to allow later entries to overwrite previous entries
|
|
for (var i = bindings.length - 1; i >= 0; i--) {
|
|
var binding = bindings[i];
|
|
var name = this._extractPublicName(binding);
|
|
publicNames.add(name);
|
|
if (!names.has(name)) {
|
|
names.add(name);
|
|
reversedResult.push(binding);
|
|
}
|
|
}
|
|
return reversedResult.reverse();
|
|
};
|
|
DirectiveResolver.prototype._merge = function (directive, inputs, outputs, host, queries, guards, directiveType) {
|
|
var mergedInputs = this._dedupeBindings(directive.inputs ? directive.inputs.concat(inputs) : inputs);
|
|
var mergedOutputs = this._dedupeBindings(directive.outputs ? directive.outputs.concat(outputs) : outputs);
|
|
var mergedHost = directive.host ? Object.assign(Object.assign({}, directive.host), host) : host;
|
|
var mergedQueries = directive.queries ? Object.assign(Object.assign({}, directive.queries), queries) : queries;
|
|
if (createComponent.isTypeOf(directive)) {
|
|
var comp = directive;
|
|
return createComponent({
|
|
selector: comp.selector,
|
|
inputs: mergedInputs,
|
|
outputs: mergedOutputs,
|
|
host: mergedHost,
|
|
exportAs: comp.exportAs,
|
|
moduleId: comp.moduleId,
|
|
queries: mergedQueries,
|
|
changeDetection: comp.changeDetection,
|
|
providers: comp.providers,
|
|
viewProviders: comp.viewProviders,
|
|
entryComponents: comp.entryComponents,
|
|
template: comp.template,
|
|
templateUrl: comp.templateUrl,
|
|
styles: comp.styles,
|
|
styleUrls: comp.styleUrls,
|
|
encapsulation: comp.encapsulation,
|
|
animations: comp.animations,
|
|
interpolation: comp.interpolation,
|
|
preserveWhitespaces: directive.preserveWhitespaces,
|
|
});
|
|
}
|
|
else {
|
|
return createDirective({
|
|
selector: directive.selector,
|
|
inputs: mergedInputs,
|
|
outputs: mergedOutputs,
|
|
host: mergedHost,
|
|
exportAs: directive.exportAs,
|
|
queries: mergedQueries,
|
|
providers: directive.providers,
|
|
guards: guards
|
|
});
|
|
}
|
|
};
|
|
return DirectiveResolver;
|
|
}());
|
|
function isDirectiveMetadata(type) {
|
|
return createDirective.isTypeOf(type) || createComponent.isTypeOf(type);
|
|
}
|
|
function findLast(arr, condition) {
|
|
for (var i = arr.length - 1; i >= 0; i--) {
|
|
if (condition(arr[i])) {
|
|
return arr[i];
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
var _I18N_ATTR = 'i18n';
|
|
var _I18N_ATTR_PREFIX = 'i18n-';
|
|
var _I18N_COMMENT_PREFIX_REGEXP = /^i18n:?/;
|
|
var MEANING_SEPARATOR = '|';
|
|
var ID_SEPARATOR = '@@';
|
|
var i18nCommentsWarned = false;
|
|
/**
|
|
* Extract translatable messages from an html AST
|
|
*/
|
|
function extractMessages(nodes, interpolationConfig, implicitTags, implicitAttrs) {
|
|
var visitor = new _Visitor$2(implicitTags, implicitAttrs);
|
|
return visitor.extract(nodes, interpolationConfig);
|
|
}
|
|
function mergeTranslations(nodes, translations, interpolationConfig, implicitTags, implicitAttrs) {
|
|
var visitor = new _Visitor$2(implicitTags, implicitAttrs);
|
|
return visitor.merge(nodes, translations, interpolationConfig);
|
|
}
|
|
var ExtractionResult = /** @class */ (function () {
|
|
function ExtractionResult(messages, errors) {
|
|
this.messages = messages;
|
|
this.errors = errors;
|
|
}
|
|
return ExtractionResult;
|
|
}());
|
|
var _VisitorMode;
|
|
(function (_VisitorMode) {
|
|
_VisitorMode[_VisitorMode["Extract"] = 0] = "Extract";
|
|
_VisitorMode[_VisitorMode["Merge"] = 1] = "Merge";
|
|
})(_VisitorMode || (_VisitorMode = {}));
|
|
/**
|
|
* This Visitor is used:
|
|
* 1. to extract all the translatable strings from an html AST (see `extract()`),
|
|
* 2. to replace the translatable strings with the actual translations (see `merge()`)
|
|
*
|
|
* @internal
|
|
*/
|
|
var _Visitor$2 = /** @class */ (function () {
|
|
function _Visitor(_implicitTags, _implicitAttrs) {
|
|
this._implicitTags = _implicitTags;
|
|
this._implicitAttrs = _implicitAttrs;
|
|
}
|
|
/**
|
|
* Extracts the messages from the tree
|
|
*/
|
|
_Visitor.prototype.extract = function (nodes, interpolationConfig) {
|
|
var _this = this;
|
|
this._init(_VisitorMode.Extract, interpolationConfig);
|
|
nodes.forEach(function (node) { return node.visit(_this, null); });
|
|
if (this._inI18nBlock) {
|
|
this._reportError(nodes[nodes.length - 1], 'Unclosed block');
|
|
}
|
|
return new ExtractionResult(this._messages, this._errors);
|
|
};
|
|
/**
|
|
* Returns a tree where all translatable nodes are translated
|
|
*/
|
|
_Visitor.prototype.merge = function (nodes, translations, interpolationConfig) {
|
|
this._init(_VisitorMode.Merge, interpolationConfig);
|
|
this._translations = translations;
|
|
// Construct a single fake root element
|
|
var wrapper = new Element$1('wrapper', [], nodes, undefined, undefined, undefined);
|
|
var translatedNode = wrapper.visit(this, null);
|
|
if (this._inI18nBlock) {
|
|
this._reportError(nodes[nodes.length - 1], 'Unclosed block');
|
|
}
|
|
return new ParseTreeResult(translatedNode.children, this._errors);
|
|
};
|
|
_Visitor.prototype.visitExpansionCase = function (icuCase, context) {
|
|
// Parse cases for translatable html attributes
|
|
var expression = visitAll$1(this, icuCase.expression, context);
|
|
if (this._mode === _VisitorMode.Merge) {
|
|
return new ExpansionCase(icuCase.value, expression, icuCase.sourceSpan, icuCase.valueSourceSpan, icuCase.expSourceSpan);
|
|
}
|
|
};
|
|
_Visitor.prototype.visitExpansion = function (icu, context) {
|
|
this._mayBeAddBlockChildren(icu);
|
|
var wasInIcu = this._inIcu;
|
|
if (!this._inIcu) {
|
|
// nested ICU messages should not be extracted but top-level translated as a whole
|
|
if (this._isInTranslatableSection) {
|
|
this._addMessage([icu]);
|
|
}
|
|
this._inIcu = true;
|
|
}
|
|
var cases = visitAll$1(this, icu.cases, context);
|
|
if (this._mode === _VisitorMode.Merge) {
|
|
icu = new Expansion(icu.switchValue, icu.type, cases, icu.sourceSpan, icu.switchValueSourceSpan);
|
|
}
|
|
this._inIcu = wasInIcu;
|
|
return icu;
|
|
};
|
|
_Visitor.prototype.visitComment = function (comment, context) {
|
|
var isOpening = _isOpeningComment(comment);
|
|
if (isOpening && this._isInTranslatableSection) {
|
|
this._reportError(comment, 'Could not start a block inside a translatable section');
|
|
return;
|
|
}
|
|
var isClosing = _isClosingComment(comment);
|
|
if (isClosing && !this._inI18nBlock) {
|
|
this._reportError(comment, 'Trying to close an unopened block');
|
|
return;
|
|
}
|
|
if (!this._inI18nNode && !this._inIcu) {
|
|
if (!this._inI18nBlock) {
|
|
if (isOpening) {
|
|
// deprecated from v5 you should use <ng-container i18n> instead of i18n comments
|
|
if (!i18nCommentsWarned && console && console.warn) {
|
|
i18nCommentsWarned = true;
|
|
var details = comment.sourceSpan.details ? ", " + comment.sourceSpan.details : '';
|
|
// TODO(ocombe): use a log service once there is a public one available
|
|
console.warn("I18n comments are deprecated, use an <ng-container> element instead (" + comment.sourceSpan.start + details + ")");
|
|
}
|
|
this._inI18nBlock = true;
|
|
this._blockStartDepth = this._depth;
|
|
this._blockChildren = [];
|
|
this._blockMeaningAndDesc =
|
|
comment.value.replace(_I18N_COMMENT_PREFIX_REGEXP, '').trim();
|
|
this._openTranslatableSection(comment);
|
|
}
|
|
}
|
|
else {
|
|
if (isClosing) {
|
|
if (this._depth == this._blockStartDepth) {
|
|
this._closeTranslatableSection(comment, this._blockChildren);
|
|
this._inI18nBlock = false;
|
|
var message = this._addMessage(this._blockChildren, this._blockMeaningAndDesc);
|
|
// merge attributes in sections
|
|
var nodes = this._translateMessage(comment, message);
|
|
return visitAll$1(this, nodes);
|
|
}
|
|
else {
|
|
this._reportError(comment, 'I18N blocks should not cross element boundaries');
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
_Visitor.prototype.visitText = function (text, context) {
|
|
if (this._isInTranslatableSection) {
|
|
this._mayBeAddBlockChildren(text);
|
|
}
|
|
return text;
|
|
};
|
|
_Visitor.prototype.visitElement = function (el, context) {
|
|
var _this = this;
|
|
this._mayBeAddBlockChildren(el);
|
|
this._depth++;
|
|
var wasInI18nNode = this._inI18nNode;
|
|
var wasInImplicitNode = this._inImplicitNode;
|
|
var childNodes = [];
|
|
var translatedChildNodes = undefined;
|
|
// Extract:
|
|
// - top level nodes with the (implicit) "i18n" attribute if not already in a section
|
|
// - ICU messages
|
|
var i18nAttr = _getI18nAttr(el);
|
|
var i18nMeta = i18nAttr ? i18nAttr.value : '';
|
|
var isImplicit = this._implicitTags.some(function (tag) { return el.name === tag; }) && !this._inIcu &&
|
|
!this._isInTranslatableSection;
|
|
var isTopLevelImplicit = !wasInImplicitNode && isImplicit;
|
|
this._inImplicitNode = wasInImplicitNode || isImplicit;
|
|
if (!this._isInTranslatableSection && !this._inIcu) {
|
|
if (i18nAttr || isTopLevelImplicit) {
|
|
this._inI18nNode = true;
|
|
var message = this._addMessage(el.children, i18nMeta);
|
|
translatedChildNodes = this._translateMessage(el, message);
|
|
}
|
|
if (this._mode == _VisitorMode.Extract) {
|
|
var isTranslatable = i18nAttr || isTopLevelImplicit;
|
|
if (isTranslatable)
|
|
this._openTranslatableSection(el);
|
|
visitAll$1(this, el.children);
|
|
if (isTranslatable)
|
|
this._closeTranslatableSection(el, el.children);
|
|
}
|
|
}
|
|
else {
|
|
if (i18nAttr || isTopLevelImplicit) {
|
|
this._reportError(el, 'Could not mark an element as translatable inside a translatable section');
|
|
}
|
|
if (this._mode == _VisitorMode.Extract) {
|
|
// Descend into child nodes for extraction
|
|
visitAll$1(this, el.children);
|
|
}
|
|
}
|
|
if (this._mode === _VisitorMode.Merge) {
|
|
var visitNodes = translatedChildNodes || el.children;
|
|
visitNodes.forEach(function (child) {
|
|
var visited = child.visit(_this, context);
|
|
if (visited && !_this._isInTranslatableSection) {
|
|
// Do not add the children from translatable sections (= i18n blocks here)
|
|
// They will be added later in this loop when the block closes (i.e. on `<!-- /i18n -->`)
|
|
childNodes = childNodes.concat(visited);
|
|
}
|
|
});
|
|
}
|
|
this._visitAttributesOf(el);
|
|
this._depth--;
|
|
this._inI18nNode = wasInI18nNode;
|
|
this._inImplicitNode = wasInImplicitNode;
|
|
if (this._mode === _VisitorMode.Merge) {
|
|
var translatedAttrs = this._translateAttributes(el);
|
|
return new Element$1(el.name, translatedAttrs, childNodes, el.sourceSpan, el.startSourceSpan, el.endSourceSpan);
|
|
}
|
|
return null;
|
|
};
|
|
_Visitor.prototype.visitAttribute = function (attribute, context) {
|
|
throw new Error('unreachable code');
|
|
};
|
|
_Visitor.prototype._init = function (mode, interpolationConfig) {
|
|
this._mode = mode;
|
|
this._inI18nBlock = false;
|
|
this._inI18nNode = false;
|
|
this._depth = 0;
|
|
this._inIcu = false;
|
|
this._msgCountAtSectionStart = undefined;
|
|
this._errors = [];
|
|
this._messages = [];
|
|
this._inImplicitNode = false;
|
|
this._createI18nMessage = createI18nMessageFactory(interpolationConfig);
|
|
};
|
|
// looks for translatable attributes
|
|
_Visitor.prototype._visitAttributesOf = function (el) {
|
|
var _this = this;
|
|
var explicitAttrNameToValue = {};
|
|
var implicitAttrNames = this._implicitAttrs[el.name] || [];
|
|
el.attrs.filter(function (attr) { return attr.name.startsWith(_I18N_ATTR_PREFIX); })
|
|
.forEach(function (attr) { return explicitAttrNameToValue[attr.name.slice(_I18N_ATTR_PREFIX.length)] =
|
|
attr.value; });
|
|
el.attrs.forEach(function (attr) {
|
|
if (attr.name in explicitAttrNameToValue) {
|
|
_this._addMessage([attr], explicitAttrNameToValue[attr.name]);
|
|
}
|
|
else if (implicitAttrNames.some(function (name) { return attr.name === name; })) {
|
|
_this._addMessage([attr]);
|
|
}
|
|
});
|
|
};
|
|
// add a translatable message
|
|
_Visitor.prototype._addMessage = function (ast, msgMeta) {
|
|
if (ast.length == 0 ||
|
|
ast.length == 1 && ast[0] instanceof Attribute && !ast[0].value) {
|
|
// Do not create empty messages
|
|
return null;
|
|
}
|
|
var _a = _parseMessageMeta(msgMeta), meaning = _a.meaning, description = _a.description, id = _a.id;
|
|
var message = this._createI18nMessage(ast, meaning, description, id);
|
|
this._messages.push(message);
|
|
return message;
|
|
};
|
|
// Translates the given message given the `TranslationBundle`
|
|
// This is used for translating elements / blocks - see `_translateAttributes` for attributes
|
|
// no-op when called in extraction mode (returns [])
|
|
_Visitor.prototype._translateMessage = function (el, message) {
|
|
if (message && this._mode === _VisitorMode.Merge) {
|
|
var nodes = this._translations.get(message);
|
|
if (nodes) {
|
|
return nodes;
|
|
}
|
|
this._reportError(el, "Translation unavailable for message id=\"" + this._translations.digest(message) + "\"");
|
|
}
|
|
return [];
|
|
};
|
|
// translate the attributes of an element and remove i18n specific attributes
|
|
_Visitor.prototype._translateAttributes = function (el) {
|
|
var _this = this;
|
|
var attributes = el.attrs;
|
|
var i18nParsedMessageMeta = {};
|
|
attributes.forEach(function (attr) {
|
|
if (attr.name.startsWith(_I18N_ATTR_PREFIX)) {
|
|
i18nParsedMessageMeta[attr.name.slice(_I18N_ATTR_PREFIX.length)] =
|
|
_parseMessageMeta(attr.value);
|
|
}
|
|
});
|
|
var translatedAttributes = [];
|
|
attributes.forEach(function (attr) {
|
|
if (attr.name === _I18N_ATTR || attr.name.startsWith(_I18N_ATTR_PREFIX)) {
|
|
// strip i18n specific attributes
|
|
return;
|
|
}
|
|
if (attr.value && attr.value != '' && i18nParsedMessageMeta.hasOwnProperty(attr.name)) {
|
|
var _a = i18nParsedMessageMeta[attr.name], meaning = _a.meaning, description = _a.description, id = _a.id;
|
|
var message = _this._createI18nMessage([attr], meaning, description, id);
|
|
var nodes = _this._translations.get(message);
|
|
if (nodes) {
|
|
if (nodes.length == 0) {
|
|
translatedAttributes.push(new Attribute(attr.name, '', attr.sourceSpan, undefined /* keySpan */, undefined /* valueSpan */, undefined /* valueTokens */, undefined /* i18n */));
|
|
}
|
|
else if (nodes[0] instanceof Text$3) {
|
|
var value = nodes[0].value;
|
|
translatedAttributes.push(new Attribute(attr.name, value, attr.sourceSpan, undefined /* keySpan */, undefined /* valueSpan */, undefined /* valueTokens */, undefined /* i18n */));
|
|
}
|
|
else {
|
|
_this._reportError(el, "Unexpected translation for attribute \"" + attr.name + "\" (id=\"" + (id || _this._translations.digest(message)) + "\")");
|
|
}
|
|
}
|
|
else {
|
|
_this._reportError(el, "Translation unavailable for attribute \"" + attr.name + "\" (id=\"" + (id || _this._translations.digest(message)) + "\")");
|
|
}
|
|
}
|
|
else {
|
|
translatedAttributes.push(attr);
|
|
}
|
|
});
|
|
return translatedAttributes;
|
|
};
|
|
/**
|
|
* Add the node as a child of the block when:
|
|
* - we are in a block,
|
|
* - we are not inside a ICU message (those are handled separately),
|
|
* - the node is a "direct child" of the block
|
|
*/
|
|
_Visitor.prototype._mayBeAddBlockChildren = function (node) {
|
|
if (this._inI18nBlock && !this._inIcu && this._depth == this._blockStartDepth) {
|
|
this._blockChildren.push(node);
|
|
}
|
|
};
|
|
/**
|
|
* Marks the start of a section, see `_closeTranslatableSection`
|
|
*/
|
|
_Visitor.prototype._openTranslatableSection = function (node) {
|
|
if (this._isInTranslatableSection) {
|
|
this._reportError(node, 'Unexpected section start');
|
|
}
|
|
else {
|
|
this._msgCountAtSectionStart = this._messages.length;
|
|
}
|
|
};
|
|
Object.defineProperty(_Visitor.prototype, "_isInTranslatableSection", {
|
|
/**
|
|
* A translatable section could be:
|
|
* - the content of translatable element,
|
|
* - nodes between `<!-- i18n -->` and `<!-- /i18n -->` comments
|
|
*/
|
|
get: function () {
|
|
return this._msgCountAtSectionStart !== void 0;
|
|
},
|
|
enumerable: false,
|
|
configurable: true
|
|
});
|
|
/**
|
|
* Terminates a section.
|
|
*
|
|
* If a section has only one significant children (comments not significant) then we should not
|
|
* keep the message from this children:
|
|
*
|
|
* `<p i18n="meaning|description">{ICU message}</p>` would produce two messages:
|
|
* - one for the <p> content with meaning and description,
|
|
* - another one for the ICU message.
|
|
*
|
|
* In this case the last message is discarded as it contains less information (the AST is
|
|
* otherwise identical).
|
|
*
|
|
* Note that we should still keep messages extracted from attributes inside the section (ie in the
|
|
* ICU message here)
|
|
*/
|
|
_Visitor.prototype._closeTranslatableSection = function (node, directChildren) {
|
|
if (!this._isInTranslatableSection) {
|
|
this._reportError(node, 'Unexpected section end');
|
|
return;
|
|
}
|
|
var startIndex = this._msgCountAtSectionStart;
|
|
var significantChildren = directChildren.reduce(function (count, node) { return count + (node instanceof Comment$1 ? 0 : 1); }, 0);
|
|
if (significantChildren == 1) {
|
|
for (var i = this._messages.length - 1; i >= startIndex; i--) {
|
|
var ast = this._messages[i].nodes;
|
|
if (!(ast.length == 1 && ast[0] instanceof Text$1)) {
|
|
this._messages.splice(i, 1);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
this._msgCountAtSectionStart = undefined;
|
|
};
|
|
_Visitor.prototype._reportError = function (node, msg) {
|
|
this._errors.push(new I18nError(node.sourceSpan, msg));
|
|
};
|
|
return _Visitor;
|
|
}());
|
|
function _isOpeningComment(n) {
|
|
return !!(n instanceof Comment$1 && n.value && n.value.startsWith('i18n'));
|
|
}
|
|
function _isClosingComment(n) {
|
|
return !!(n instanceof Comment$1 && n.value && n.value === '/i18n');
|
|
}
|
|
function _getI18nAttr(p) {
|
|
return p.attrs.find(function (attr) { return attr.name === _I18N_ATTR; }) || null;
|
|
}
|
|
function _parseMessageMeta(i18n) {
|
|
if (!i18n)
|
|
return { meaning: '', description: '', id: '' };
|
|
var idIndex = i18n.indexOf(ID_SEPARATOR);
|
|
var descIndex = i18n.indexOf(MEANING_SEPARATOR);
|
|
var _a = __read((idIndex > -1) ? [i18n.slice(0, idIndex), i18n.slice(idIndex + 2)] : [i18n, ''], 2), meaningAndDesc = _a[0], id = _a[1];
|
|
var _b = __read((descIndex > -1) ?
|
|
[meaningAndDesc.slice(0, descIndex), meaningAndDesc.slice(descIndex + 1)] :
|
|
['', meaningAndDesc], 2), meaning = _b[0], description = _b[1];
|
|
return { meaning: meaning, description: description, id: id.trim() };
|
|
}
|
|
|
|
/**
|
|
* @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 XmlTagDefinition = /** @class */ (function () {
|
|
function XmlTagDefinition() {
|
|
this.closedByParent = false;
|
|
this.isVoid = false;
|
|
this.ignoreFirstLf = false;
|
|
this.canSelfClose = true;
|
|
this.preventNamespaceInheritance = false;
|
|
}
|
|
XmlTagDefinition.prototype.requireExtraParent = function (currentParent) {
|
|
return false;
|
|
};
|
|
XmlTagDefinition.prototype.isClosedByChild = function (name) {
|
|
return false;
|
|
};
|
|
XmlTagDefinition.prototype.getContentType = function () {
|
|
return exports.TagContentType.PARSABLE_DATA;
|
|
};
|
|
return XmlTagDefinition;
|
|
}());
|
|
var _TAG_DEFINITION = new XmlTagDefinition();
|
|
function getXmlTagDefinition(tagName) {
|
|
return _TAG_DEFINITION;
|
|
}
|
|
|
|
var XmlParser = /** @class */ (function (_super) {
|
|
__extends(XmlParser, _super);
|
|
function XmlParser() {
|
|
return _super.call(this, getXmlTagDefinition) || this;
|
|
}
|
|
XmlParser.prototype.parse = function (source, url, options) {
|
|
return _super.prototype.parse.call(this, source, url, options);
|
|
};
|
|
return XmlParser;
|
|
}(Parser));
|
|
|
|
var _VERSION = '1.2';
|
|
var _XMLNS = 'urn:oasis:names:tc:xliff:document:1.2';
|
|
// TODO(vicb): make this a param (s/_/-/)
|
|
var _DEFAULT_SOURCE_LANG = 'en';
|
|
var _PLACEHOLDER_TAG$1 = 'x';
|
|
var _MARKER_TAG = 'mrk';
|
|
var _FILE_TAG = 'file';
|
|
var _SOURCE_TAG$1 = 'source';
|
|
var _SEGMENT_SOURCE_TAG = 'seg-source';
|
|
var _ALT_TRANS_TAG = 'alt-trans';
|
|
var _TARGET_TAG = 'target';
|
|
var _UNIT_TAG = 'trans-unit';
|
|
var _CONTEXT_GROUP_TAG = 'context-group';
|
|
var _CONTEXT_TAG = 'context';
|
|
// https://docs.oasis-open.org/xliff/v1.2/os/xliff-core.html
|
|
// https://docs.oasis-open.org/xliff/v1.2/xliff-profile-html/xliff-profile-html-1.2.html
|
|
var Xliff = /** @class */ (function (_super) {
|
|
__extends(Xliff, _super);
|
|
function Xliff() {
|
|
return _super !== null && _super.apply(this, arguments) || this;
|
|
}
|
|
Xliff.prototype.write = function (messages, locale) {
|
|
var visitor = new _WriteVisitor();
|
|
var transUnits = [];
|
|
messages.forEach(function (message) {
|
|
var _a;
|
|
var contextTags = [];
|
|
message.sources.forEach(function (source) {
|
|
var contextGroupTag = new Tag(_CONTEXT_GROUP_TAG, { purpose: 'location' });
|
|
contextGroupTag.children.push(new CR(10), new Tag(_CONTEXT_TAG, { 'context-type': 'sourcefile' }, [new Text$2(source.filePath)]), new CR(10), new Tag(_CONTEXT_TAG, { 'context-type': 'linenumber' }, [new Text$2("" + source.startLine)]), new CR(8));
|
|
contextTags.push(new CR(8), contextGroupTag);
|
|
});
|
|
var transUnit = new Tag(_UNIT_TAG, { id: message.id, datatype: 'html' });
|
|
(_a = transUnit.children).push.apply(_a, __spreadArray([new CR(8), new Tag(_SOURCE_TAG$1, {}, visitor.serialize(message.nodes))], __read(contextTags)));
|
|
if (message.description) {
|
|
transUnit.children.push(new CR(8), new Tag('note', { priority: '1', from: 'description' }, [new Text$2(message.description)]));
|
|
}
|
|
if (message.meaning) {
|
|
transUnit.children.push(new CR(8), new Tag('note', { priority: '1', from: 'meaning' }, [new Text$2(message.meaning)]));
|
|
}
|
|
transUnit.children.push(new CR(6));
|
|
transUnits.push(new CR(6), transUnit);
|
|
});
|
|
var body = new Tag('body', {}, __spreadArray(__spreadArray([], __read(transUnits)), [new CR(4)]));
|
|
var file = new Tag('file', {
|
|
'source-language': locale || _DEFAULT_SOURCE_LANG,
|
|
datatype: 'plaintext',
|
|
original: 'ng2.template',
|
|
}, [new CR(4), body, new CR(2)]);
|
|
var xliff = new Tag('xliff', { version: _VERSION, xmlns: _XMLNS }, [new CR(2), file, new CR()]);
|
|
return serialize([
|
|
new Declaration({ version: '1.0', encoding: 'UTF-8' }), new CR(), xliff, new CR()
|
|
]);
|
|
};
|
|
Xliff.prototype.load = function (content, url) {
|
|
// xliff to xml nodes
|
|
var xliffParser = new XliffParser();
|
|
var _a = xliffParser.parse(content, url), locale = _a.locale, msgIdToHtml = _a.msgIdToHtml, errors = _a.errors;
|
|
// xml nodes to i18n nodes
|
|
var i18nNodesByMsgId = {};
|
|
var converter = new XmlToI18n();
|
|
Object.keys(msgIdToHtml).forEach(function (msgId) {
|
|
var _a = converter.convert(msgIdToHtml[msgId], url), i18nNodes = _a.i18nNodes, e = _a.errors;
|
|
errors.push.apply(errors, __spreadArray([], __read(e)));
|
|
i18nNodesByMsgId[msgId] = i18nNodes;
|
|
});
|
|
if (errors.length) {
|
|
throw new Error("xliff parse errors:\n" + errors.join('\n'));
|
|
}
|
|
return { locale: locale, i18nNodesByMsgId: i18nNodesByMsgId };
|
|
};
|
|
Xliff.prototype.digest = function (message) {
|
|
return digest(message);
|
|
};
|
|
return Xliff;
|
|
}(Serializer));
|
|
var _WriteVisitor = /** @class */ (function () {
|
|
function _WriteVisitor() {
|
|
}
|
|
_WriteVisitor.prototype.visitText = function (text, context) {
|
|
return [new Text$2(text.value)];
|
|
};
|
|
_WriteVisitor.prototype.visitContainer = function (container, context) {
|
|
var _this = this;
|
|
var nodes = [];
|
|
container.children.forEach(function (node) { return nodes.push.apply(nodes, __spreadArray([], __read(node.visit(_this)))); });
|
|
return nodes;
|
|
};
|
|
_WriteVisitor.prototype.visitIcu = function (icu, context) {
|
|
var _this = this;
|
|
var nodes = [new Text$2("{" + icu.expressionPlaceholder + ", " + icu.type + ", ")];
|
|
Object.keys(icu.cases).forEach(function (c) {
|
|
nodes.push.apply(nodes, __spreadArray(__spreadArray([new Text$2(c + " {")], __read(icu.cases[c].visit(_this))), [new Text$2("} ")]));
|
|
});
|
|
nodes.push(new Text$2("}"));
|
|
return nodes;
|
|
};
|
|
_WriteVisitor.prototype.visitTagPlaceholder = function (ph, context) {
|
|
var ctype = getCtypeForTag(ph.tag);
|
|
if (ph.isVoid) {
|
|
// void tags have no children nor closing tags
|
|
return [new Tag(_PLACEHOLDER_TAG$1, { id: ph.startName, ctype: ctype, 'equiv-text': "<" + ph.tag + "/>" })];
|
|
}
|
|
var startTagPh = new Tag(_PLACEHOLDER_TAG$1, { id: ph.startName, ctype: ctype, 'equiv-text': "<" + ph.tag + ">" });
|
|
var closeTagPh = new Tag(_PLACEHOLDER_TAG$1, { id: ph.closeName, ctype: ctype, 'equiv-text': "</" + ph.tag + ">" });
|
|
return __spreadArray(__spreadArray([startTagPh], __read(this.serialize(ph.children))), [closeTagPh]);
|
|
};
|
|
_WriteVisitor.prototype.visitPlaceholder = function (ph, context) {
|
|
return [new Tag(_PLACEHOLDER_TAG$1, { id: ph.name, 'equiv-text': "{{" + ph.value + "}}" })];
|
|
};
|
|
_WriteVisitor.prototype.visitIcuPlaceholder = function (ph, context) {
|
|
var equivText = "{" + ph.value.expression + ", " + ph.value.type + ", " + Object.keys(ph.value.cases).map(function (value) { return value + ' {...}'; }).join(' ') + "}";
|
|
return [new Tag(_PLACEHOLDER_TAG$1, { id: ph.name, 'equiv-text': equivText })];
|
|
};
|
|
_WriteVisitor.prototype.serialize = function (nodes) {
|
|
var _this = this;
|
|
return [].concat.apply([], __spreadArray([], __read(nodes.map(function (node) { return node.visit(_this); }))));
|
|
};
|
|
return _WriteVisitor;
|
|
}());
|
|
// TODO(vicb): add error management (structure)
|
|
// Extract messages as xml nodes from the xliff file
|
|
var XliffParser = /** @class */ (function () {
|
|
function XliffParser() {
|
|
this._locale = null;
|
|
}
|
|
XliffParser.prototype.parse = function (xliff, url) {
|
|
this._unitMlString = null;
|
|
this._msgIdToHtml = {};
|
|
var xml = new XmlParser().parse(xliff, url);
|
|
this._errors = xml.errors;
|
|
visitAll$1(this, xml.rootNodes, null);
|
|
return {
|
|
msgIdToHtml: this._msgIdToHtml,
|
|
errors: this._errors,
|
|
locale: this._locale,
|
|
};
|
|
};
|
|
XliffParser.prototype.visitElement = function (element, context) {
|
|
switch (element.name) {
|
|
case _UNIT_TAG:
|
|
this._unitMlString = null;
|
|
var idAttr = element.attrs.find(function (attr) { return attr.name === 'id'; });
|
|
if (!idAttr) {
|
|
this._addError(element, "<" + _UNIT_TAG + "> misses the \"id\" attribute");
|
|
}
|
|
else {
|
|
var id = idAttr.value;
|
|
if (this._msgIdToHtml.hasOwnProperty(id)) {
|
|
this._addError(element, "Duplicated translations for msg " + id);
|
|
}
|
|
else {
|
|
visitAll$1(this, element.children, null);
|
|
if (typeof this._unitMlString === 'string') {
|
|
this._msgIdToHtml[id] = this._unitMlString;
|
|
}
|
|
else {
|
|
this._addError(element, "Message " + id + " misses a translation");
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
// ignore those tags
|
|
case _SOURCE_TAG$1:
|
|
case _SEGMENT_SOURCE_TAG:
|
|
case _ALT_TRANS_TAG:
|
|
break;
|
|
case _TARGET_TAG:
|
|
var innerTextStart = element.startSourceSpan.end.offset;
|
|
var innerTextEnd = element.endSourceSpan.start.offset;
|
|
var content = element.startSourceSpan.start.file.content;
|
|
var innerText = content.slice(innerTextStart, innerTextEnd);
|
|
this._unitMlString = innerText;
|
|
break;
|
|
case _FILE_TAG:
|
|
var localeAttr = element.attrs.find(function (attr) { return attr.name === 'target-language'; });
|
|
if (localeAttr) {
|
|
this._locale = localeAttr.value;
|
|
}
|
|
visitAll$1(this, element.children, null);
|
|
break;
|
|
default:
|
|
// TODO(vicb): assert file structure, xliff version
|
|
// For now only recurse on unhandled nodes
|
|
visitAll$1(this, element.children, null);
|
|
}
|
|
};
|
|
XliffParser.prototype.visitAttribute = function (attribute, context) { };
|
|
XliffParser.prototype.visitText = function (text, context) { };
|
|
XliffParser.prototype.visitComment = function (comment, context) { };
|
|
XliffParser.prototype.visitExpansion = function (expansion, context) { };
|
|
XliffParser.prototype.visitExpansionCase = function (expansionCase, context) { };
|
|
XliffParser.prototype._addError = function (node, message) {
|
|
this._errors.push(new I18nError(node.sourceSpan, message));
|
|
};
|
|
return XliffParser;
|
|
}());
|
|
// Convert ml nodes (xliff syntax) to i18n nodes
|
|
var XmlToI18n = /** @class */ (function () {
|
|
function XmlToI18n() {
|
|
}
|
|
XmlToI18n.prototype.convert = function (message, url) {
|
|
var xmlIcu = new XmlParser().parse(message, url, { tokenizeExpansionForms: true });
|
|
this._errors = xmlIcu.errors;
|
|
var i18nNodes = this._errors.length > 0 || xmlIcu.rootNodes.length == 0 ?
|
|
[] : [].concat.apply([], __spreadArray([], __read(visitAll$1(this, xmlIcu.rootNodes))));
|
|
return {
|
|
i18nNodes: i18nNodes,
|
|
errors: this._errors,
|
|
};
|
|
};
|
|
XmlToI18n.prototype.visitText = function (text, context) {
|
|
return new Text$1(text.value, text.sourceSpan);
|
|
};
|
|
XmlToI18n.prototype.visitElement = function (el, context) {
|
|
if (el.name === _PLACEHOLDER_TAG$1) {
|
|
var nameAttr = el.attrs.find(function (attr) { return attr.name === 'id'; });
|
|
if (nameAttr) {
|
|
return new Placeholder('', nameAttr.value, el.sourceSpan);
|
|
}
|
|
this._addError(el, "<" + _PLACEHOLDER_TAG$1 + "> misses the \"id\" attribute");
|
|
return null;
|
|
}
|
|
if (el.name === _MARKER_TAG) {
|
|
return [].concat.apply([], __spreadArray([], __read(visitAll$1(this, el.children))));
|
|
}
|
|
this._addError(el, "Unexpected tag");
|
|
return null;
|
|
};
|
|
XmlToI18n.prototype.visitExpansion = function (icu, context) {
|
|
var caseMap = {};
|
|
visitAll$1(this, icu.cases).forEach(function (c) {
|
|
caseMap[c.value] = new Container(c.nodes, icu.sourceSpan);
|
|
});
|
|
return new Icu$1(icu.switchValue, icu.type, caseMap, icu.sourceSpan);
|
|
};
|
|
XmlToI18n.prototype.visitExpansionCase = function (icuCase, context) {
|
|
return {
|
|
value: icuCase.value,
|
|
nodes: visitAll$1(this, icuCase.expression),
|
|
};
|
|
};
|
|
XmlToI18n.prototype.visitComment = function (comment, context) { };
|
|
XmlToI18n.prototype.visitAttribute = function (attribute, context) { };
|
|
XmlToI18n.prototype._addError = function (node, message) {
|
|
this._errors.push(new I18nError(node.sourceSpan, message));
|
|
};
|
|
return XmlToI18n;
|
|
}());
|
|
function getCtypeForTag(tag) {
|
|
switch (tag.toLowerCase()) {
|
|
case 'br':
|
|
return 'lb';
|
|
case 'img':
|
|
return 'image';
|
|
default:
|
|
return "x-" + tag;
|
|
}
|
|
}
|
|
|
|
var _VERSION$1 = '2.0';
|
|
var _XMLNS$1 = 'urn:oasis:names:tc:xliff:document:2.0';
|
|
// TODO(vicb): make this a param (s/_/-/)
|
|
var _DEFAULT_SOURCE_LANG$1 = 'en';
|
|
var _PLACEHOLDER_TAG$2 = 'ph';
|
|
var _PLACEHOLDER_SPANNING_TAG = 'pc';
|
|
var _MARKER_TAG$1 = 'mrk';
|
|
var _XLIFF_TAG = 'xliff';
|
|
var _SOURCE_TAG$2 = 'source';
|
|
var _TARGET_TAG$1 = 'target';
|
|
var _UNIT_TAG$1 = 'unit';
|
|
// https://docs.oasis-open.org/xliff/xliff-core/v2.0/os/xliff-core-v2.0-os.html
|
|
var Xliff2 = /** @class */ (function (_super) {
|
|
__extends(Xliff2, _super);
|
|
function Xliff2() {
|
|
return _super !== null && _super.apply(this, arguments) || this;
|
|
}
|
|
Xliff2.prototype.write = function (messages, locale) {
|
|
var visitor = new _WriteVisitor$1();
|
|
var units = [];
|
|
messages.forEach(function (message) {
|
|
var unit = new Tag(_UNIT_TAG$1, { id: message.id });
|
|
var notes = new Tag('notes');
|
|
if (message.description || message.meaning) {
|
|
if (message.description) {
|
|
notes.children.push(new CR(8), new Tag('note', { category: 'description' }, [new Text$2(message.description)]));
|
|
}
|
|
if (message.meaning) {
|
|
notes.children.push(new CR(8), new Tag('note', { category: 'meaning' }, [new Text$2(message.meaning)]));
|
|
}
|
|
}
|
|
message.sources.forEach(function (source) {
|
|
notes.children.push(new CR(8), new Tag('note', { category: 'location' }, [
|
|
new Text$2(source.filePath + ":" + source.startLine + (source.endLine !== source.startLine ? ',' + source.endLine : ''))
|
|
]));
|
|
});
|
|
notes.children.push(new CR(6));
|
|
unit.children.push(new CR(6), notes);
|
|
var segment = new Tag('segment');
|
|
segment.children.push(new CR(8), new Tag(_SOURCE_TAG$2, {}, visitor.serialize(message.nodes)), new CR(6));
|
|
unit.children.push(new CR(6), segment, new CR(4));
|
|
units.push(new CR(4), unit);
|
|
});
|
|
var file = new Tag('file', { 'original': 'ng.template', id: 'ngi18n' }, __spreadArray(__spreadArray([], __read(units)), [new CR(2)]));
|
|
var xliff = new Tag(_XLIFF_TAG, { version: _VERSION$1, xmlns: _XMLNS$1, srcLang: locale || _DEFAULT_SOURCE_LANG$1 }, [new CR(2), file, new CR()]);
|
|
return serialize([
|
|
new Declaration({ version: '1.0', encoding: 'UTF-8' }), new CR(), xliff, new CR()
|
|
]);
|
|
};
|
|
Xliff2.prototype.load = function (content, url) {
|
|
// xliff to xml nodes
|
|
var xliff2Parser = new Xliff2Parser();
|
|
var _a = xliff2Parser.parse(content, url), locale = _a.locale, msgIdToHtml = _a.msgIdToHtml, errors = _a.errors;
|
|
// xml nodes to i18n nodes
|
|
var i18nNodesByMsgId = {};
|
|
var converter = new XmlToI18n$1();
|
|
Object.keys(msgIdToHtml).forEach(function (msgId) {
|
|
var _a = converter.convert(msgIdToHtml[msgId], url), i18nNodes = _a.i18nNodes, e = _a.errors;
|
|
errors.push.apply(errors, __spreadArray([], __read(e)));
|
|
i18nNodesByMsgId[msgId] = i18nNodes;
|
|
});
|
|
if (errors.length) {
|
|
throw new Error("xliff2 parse errors:\n" + errors.join('\n'));
|
|
}
|
|
return { locale: locale, i18nNodesByMsgId: i18nNodesByMsgId };
|
|
};
|
|
Xliff2.prototype.digest = function (message) {
|
|
return decimalDigest(message);
|
|
};
|
|
return Xliff2;
|
|
}(Serializer));
|
|
var _WriteVisitor$1 = /** @class */ (function () {
|
|
function _WriteVisitor() {
|
|
}
|
|
_WriteVisitor.prototype.visitText = function (text, context) {
|
|
return [new Text$2(text.value)];
|
|
};
|
|
_WriteVisitor.prototype.visitContainer = function (container, context) {
|
|
var _this = this;
|
|
var nodes = [];
|
|
container.children.forEach(function (node) { return nodes.push.apply(nodes, __spreadArray([], __read(node.visit(_this)))); });
|
|
return nodes;
|
|
};
|
|
_WriteVisitor.prototype.visitIcu = function (icu, context) {
|
|
var _this = this;
|
|
var nodes = [new Text$2("{" + icu.expressionPlaceholder + ", " + icu.type + ", ")];
|
|
Object.keys(icu.cases).forEach(function (c) {
|
|
nodes.push.apply(nodes, __spreadArray(__spreadArray([new Text$2(c + " {")], __read(icu.cases[c].visit(_this))), [new Text$2("} ")]));
|
|
});
|
|
nodes.push(new Text$2("}"));
|
|
return nodes;
|
|
};
|
|
_WriteVisitor.prototype.visitTagPlaceholder = function (ph, context) {
|
|
var _this = this;
|
|
var type = getTypeForTag(ph.tag);
|
|
if (ph.isVoid) {
|
|
var tagPh = new Tag(_PLACEHOLDER_TAG$2, {
|
|
id: (this._nextPlaceholderId++).toString(),
|
|
equiv: ph.startName,
|
|
type: type,
|
|
disp: "<" + ph.tag + "/>",
|
|
});
|
|
return [tagPh];
|
|
}
|
|
var tagPc = new Tag(_PLACEHOLDER_SPANNING_TAG, {
|
|
id: (this._nextPlaceholderId++).toString(),
|
|
equivStart: ph.startName,
|
|
equivEnd: ph.closeName,
|
|
type: type,
|
|
dispStart: "<" + ph.tag + ">",
|
|
dispEnd: "</" + ph.tag + ">",
|
|
});
|
|
var nodes = [].concat.apply([], __spreadArray([], __read(ph.children.map(function (node) { return node.visit(_this); }))));
|
|
if (nodes.length) {
|
|
nodes.forEach(function (node) { return tagPc.children.push(node); });
|
|
}
|
|
else {
|
|
tagPc.children.push(new Text$2(''));
|
|
}
|
|
return [tagPc];
|
|
};
|
|
_WriteVisitor.prototype.visitPlaceholder = function (ph, context) {
|
|
var idStr = (this._nextPlaceholderId++).toString();
|
|
return [new Tag(_PLACEHOLDER_TAG$2, {
|
|
id: idStr,
|
|
equiv: ph.name,
|
|
disp: "{{" + ph.value + "}}",
|
|
})];
|
|
};
|
|
_WriteVisitor.prototype.visitIcuPlaceholder = function (ph, context) {
|
|
var cases = Object.keys(ph.value.cases).map(function (value) { return value + ' {...}'; }).join(' ');
|
|
var idStr = (this._nextPlaceholderId++).toString();
|
|
return [new Tag(_PLACEHOLDER_TAG$2, { id: idStr, equiv: ph.name, disp: "{" + ph.value.expression + ", " + ph.value.type + ", " + cases + "}" })];
|
|
};
|
|
_WriteVisitor.prototype.serialize = function (nodes) {
|
|
var _this = this;
|
|
this._nextPlaceholderId = 0;
|
|
return [].concat.apply([], __spreadArray([], __read(nodes.map(function (node) { return node.visit(_this); }))));
|
|
};
|
|
return _WriteVisitor;
|
|
}());
|
|
// Extract messages as xml nodes from the xliff file
|
|
var Xliff2Parser = /** @class */ (function () {
|
|
function Xliff2Parser() {
|
|
this._locale = null;
|
|
}
|
|
Xliff2Parser.prototype.parse = function (xliff, url) {
|
|
this._unitMlString = null;
|
|
this._msgIdToHtml = {};
|
|
var xml = new XmlParser().parse(xliff, url);
|
|
this._errors = xml.errors;
|
|
visitAll$1(this, xml.rootNodes, null);
|
|
return {
|
|
msgIdToHtml: this._msgIdToHtml,
|
|
errors: this._errors,
|
|
locale: this._locale,
|
|
};
|
|
};
|
|
Xliff2Parser.prototype.visitElement = function (element, context) {
|
|
switch (element.name) {
|
|
case _UNIT_TAG$1:
|
|
this._unitMlString = null;
|
|
var idAttr = element.attrs.find(function (attr) { return attr.name === 'id'; });
|
|
if (!idAttr) {
|
|
this._addError(element, "<" + _UNIT_TAG$1 + "> misses the \"id\" attribute");
|
|
}
|
|
else {
|
|
var id = idAttr.value;
|
|
if (this._msgIdToHtml.hasOwnProperty(id)) {
|
|
this._addError(element, "Duplicated translations for msg " + id);
|
|
}
|
|
else {
|
|
visitAll$1(this, element.children, null);
|
|
if (typeof this._unitMlString === 'string') {
|
|
this._msgIdToHtml[id] = this._unitMlString;
|
|
}
|
|
else {
|
|
this._addError(element, "Message " + id + " misses a translation");
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case _SOURCE_TAG$2:
|
|
// ignore source message
|
|
break;
|
|
case _TARGET_TAG$1:
|
|
var innerTextStart = element.startSourceSpan.end.offset;
|
|
var innerTextEnd = element.endSourceSpan.start.offset;
|
|
var content = element.startSourceSpan.start.file.content;
|
|
var innerText = content.slice(innerTextStart, innerTextEnd);
|
|
this._unitMlString = innerText;
|
|
break;
|
|
case _XLIFF_TAG:
|
|
var localeAttr = element.attrs.find(function (attr) { return attr.name === 'trgLang'; });
|
|
if (localeAttr) {
|
|
this._locale = localeAttr.value;
|
|
}
|
|
var versionAttr = element.attrs.find(function (attr) { return attr.name === 'version'; });
|
|
if (versionAttr) {
|
|
var version = versionAttr.value;
|
|
if (version !== '2.0') {
|
|
this._addError(element, "The XLIFF file version " + version + " is not compatible with XLIFF 2.0 serializer");
|
|
}
|
|
else {
|
|
visitAll$1(this, element.children, null);
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
visitAll$1(this, element.children, null);
|
|
}
|
|
};
|
|
Xliff2Parser.prototype.visitAttribute = function (attribute, context) { };
|
|
Xliff2Parser.prototype.visitText = function (text, context) { };
|
|
Xliff2Parser.prototype.visitComment = function (comment, context) { };
|
|
Xliff2Parser.prototype.visitExpansion = function (expansion, context) { };
|
|
Xliff2Parser.prototype.visitExpansionCase = function (expansionCase, context) { };
|
|
Xliff2Parser.prototype._addError = function (node, message) {
|
|
this._errors.push(new I18nError(node.sourceSpan, message));
|
|
};
|
|
return Xliff2Parser;
|
|
}());
|
|
// Convert ml nodes (xliff syntax) to i18n nodes
|
|
var XmlToI18n$1 = /** @class */ (function () {
|
|
function XmlToI18n() {
|
|
}
|
|
XmlToI18n.prototype.convert = function (message, url) {
|
|
var xmlIcu = new XmlParser().parse(message, url, { tokenizeExpansionForms: true });
|
|
this._errors = xmlIcu.errors;
|
|
var i18nNodes = this._errors.length > 0 || xmlIcu.rootNodes.length == 0 ?
|
|
[] : [].concat.apply([], __spreadArray([], __read(visitAll$1(this, xmlIcu.rootNodes))));
|
|
return {
|
|
i18nNodes: i18nNodes,
|
|
errors: this._errors,
|
|
};
|
|
};
|
|
XmlToI18n.prototype.visitText = function (text, context) {
|
|
return new Text$1(text.value, text.sourceSpan);
|
|
};
|
|
XmlToI18n.prototype.visitElement = function (el, context) {
|
|
var _this = this;
|
|
switch (el.name) {
|
|
case _PLACEHOLDER_TAG$2:
|
|
var nameAttr = el.attrs.find(function (attr) { return attr.name === 'equiv'; });
|
|
if (nameAttr) {
|
|
return [new Placeholder('', nameAttr.value, el.sourceSpan)];
|
|
}
|
|
this._addError(el, "<" + _PLACEHOLDER_TAG$2 + "> misses the \"equiv\" attribute");
|
|
break;
|
|
case _PLACEHOLDER_SPANNING_TAG:
|
|
var startAttr = el.attrs.find(function (attr) { return attr.name === 'equivStart'; });
|
|
var endAttr = el.attrs.find(function (attr) { return attr.name === 'equivEnd'; });
|
|
if (!startAttr) {
|
|
this._addError(el, "<" + _PLACEHOLDER_TAG$2 + "> misses the \"equivStart\" attribute");
|
|
}
|
|
else if (!endAttr) {
|
|
this._addError(el, "<" + _PLACEHOLDER_TAG$2 + "> misses the \"equivEnd\" attribute");
|
|
}
|
|
else {
|
|
var startId = startAttr.value;
|
|
var endId = endAttr.value;
|
|
var nodes = [];
|
|
return nodes.concat.apply(nodes, __spreadArray(__spreadArray([new Placeholder('', startId, el.sourceSpan)], __read(el.children.map(function (node) { return node.visit(_this, null); }))), [new Placeholder('', endId, el.sourceSpan)]));
|
|
}
|
|
break;
|
|
case _MARKER_TAG$1:
|
|
return [].concat.apply([], __spreadArray([], __read(visitAll$1(this, el.children))));
|
|
default:
|
|
this._addError(el, "Unexpected tag");
|
|
}
|
|
return null;
|
|
};
|
|
XmlToI18n.prototype.visitExpansion = function (icu, context) {
|
|
var caseMap = {};
|
|
visitAll$1(this, icu.cases).forEach(function (c) {
|
|
caseMap[c.value] = new Container(c.nodes, icu.sourceSpan);
|
|
});
|
|
return new Icu$1(icu.switchValue, icu.type, caseMap, icu.sourceSpan);
|
|
};
|
|
XmlToI18n.prototype.visitExpansionCase = function (icuCase, context) {
|
|
return {
|
|
value: icuCase.value,
|
|
nodes: [].concat.apply([], __spreadArray([], __read(visitAll$1(this, icuCase.expression)))),
|
|
};
|
|
};
|
|
XmlToI18n.prototype.visitComment = function (comment, context) { };
|
|
XmlToI18n.prototype.visitAttribute = function (attribute, context) { };
|
|
XmlToI18n.prototype._addError = function (node, message) {
|
|
this._errors.push(new I18nError(node.sourceSpan, message));
|
|
};
|
|
return XmlToI18n;
|
|
}());
|
|
function getTypeForTag(tag) {
|
|
switch (tag.toLowerCase()) {
|
|
case 'br':
|
|
case 'b':
|
|
case 'i':
|
|
case 'u':
|
|
return 'fmt';
|
|
case 'img':
|
|
return 'image';
|
|
case 'a':
|
|
return 'link';
|
|
default:
|
|
return 'other';
|
|
}
|
|
}
|
|
|
|
var _TRANSLATIONS_TAG = 'translationbundle';
|
|
var _TRANSLATION_TAG = 'translation';
|
|
var _PLACEHOLDER_TAG$3 = 'ph';
|
|
var Xtb = /** @class */ (function (_super) {
|
|
__extends(Xtb, _super);
|
|
function Xtb() {
|
|
return _super !== null && _super.apply(this, arguments) || this;
|
|
}
|
|
Xtb.prototype.write = function (messages, locale) {
|
|
throw new Error('Unsupported');
|
|
};
|
|
Xtb.prototype.load = function (content, url) {
|
|
// xtb to xml nodes
|
|
var xtbParser = new XtbParser();
|
|
var _a = xtbParser.parse(content, url), locale = _a.locale, msgIdToHtml = _a.msgIdToHtml, errors = _a.errors;
|
|
// xml nodes to i18n nodes
|
|
var i18nNodesByMsgId = {};
|
|
var converter = new XmlToI18n$2();
|
|
// Because we should be able to load xtb files that rely on features not supported by angular,
|
|
// we need to delay the conversion of html to i18n nodes so that non angular messages are not
|
|
// converted
|
|
Object.keys(msgIdToHtml).forEach(function (msgId) {
|
|
var valueFn = function () {
|
|
var _a = converter.convert(msgIdToHtml[msgId], url), i18nNodes = _a.i18nNodes, errors = _a.errors;
|
|
if (errors.length) {
|
|
throw new Error("xtb parse errors:\n" + errors.join('\n'));
|
|
}
|
|
return i18nNodes;
|
|
};
|
|
createLazyProperty(i18nNodesByMsgId, msgId, valueFn);
|
|
});
|
|
if (errors.length) {
|
|
throw new Error("xtb parse errors:\n" + errors.join('\n'));
|
|
}
|
|
return { locale: locale, i18nNodesByMsgId: i18nNodesByMsgId };
|
|
};
|
|
Xtb.prototype.digest = function (message) {
|
|
return digest$1(message);
|
|
};
|
|
Xtb.prototype.createNameMapper = function (message) {
|
|
return new SimplePlaceholderMapper(message, toPublicName);
|
|
};
|
|
return Xtb;
|
|
}(Serializer));
|
|
function createLazyProperty(messages, id, valueFn) {
|
|
Object.defineProperty(messages, id, {
|
|
configurable: true,
|
|
enumerable: true,
|
|
get: function () {
|
|
var value = valueFn();
|
|
Object.defineProperty(messages, id, { enumerable: true, value: value });
|
|
return value;
|
|
},
|
|
set: function (_) {
|
|
throw new Error('Could not overwrite an XTB translation');
|
|
},
|
|
});
|
|
}
|
|
// Extract messages as xml nodes from the xtb file
|
|
var XtbParser = /** @class */ (function () {
|
|
function XtbParser() {
|
|
this._locale = null;
|
|
}
|
|
XtbParser.prototype.parse = function (xtb, url) {
|
|
this._bundleDepth = 0;
|
|
this._msgIdToHtml = {};
|
|
// We can not parse the ICU messages at this point as some messages might not originate
|
|
// from Angular that could not be lex'd.
|
|
var xml = new XmlParser().parse(xtb, url);
|
|
this._errors = xml.errors;
|
|
visitAll$1(this, xml.rootNodes);
|
|
return {
|
|
msgIdToHtml: this._msgIdToHtml,
|
|
errors: this._errors,
|
|
locale: this._locale,
|
|
};
|
|
};
|
|
XtbParser.prototype.visitElement = function (element, context) {
|
|
switch (element.name) {
|
|
case _TRANSLATIONS_TAG:
|
|
this._bundleDepth++;
|
|
if (this._bundleDepth > 1) {
|
|
this._addError(element, "<" + _TRANSLATIONS_TAG + "> elements can not be nested");
|
|
}
|
|
var langAttr = element.attrs.find(function (attr) { return attr.name === 'lang'; });
|
|
if (langAttr) {
|
|
this._locale = langAttr.value;
|
|
}
|
|
visitAll$1(this, element.children, null);
|
|
this._bundleDepth--;
|
|
break;
|
|
case _TRANSLATION_TAG:
|
|
var idAttr = element.attrs.find(function (attr) { return attr.name === 'id'; });
|
|
if (!idAttr) {
|
|
this._addError(element, "<" + _TRANSLATION_TAG + "> misses the \"id\" attribute");
|
|
}
|
|
else {
|
|
var id = idAttr.value;
|
|
if (this._msgIdToHtml.hasOwnProperty(id)) {
|
|
this._addError(element, "Duplicated translations for msg " + id);
|
|
}
|
|
else {
|
|
var innerTextStart = element.startSourceSpan.end.offset;
|
|
var innerTextEnd = element.endSourceSpan.start.offset;
|
|
var content = element.startSourceSpan.start.file.content;
|
|
var innerText = content.slice(innerTextStart, innerTextEnd);
|
|
this._msgIdToHtml[id] = innerText;
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
this._addError(element, 'Unexpected tag');
|
|
}
|
|
};
|
|
XtbParser.prototype.visitAttribute = function (attribute, context) { };
|
|
XtbParser.prototype.visitText = function (text, context) { };
|
|
XtbParser.prototype.visitComment = function (comment, context) { };
|
|
XtbParser.prototype.visitExpansion = function (expansion, context) { };
|
|
XtbParser.prototype.visitExpansionCase = function (expansionCase, context) { };
|
|
XtbParser.prototype._addError = function (node, message) {
|
|
this._errors.push(new I18nError(node.sourceSpan, message));
|
|
};
|
|
return XtbParser;
|
|
}());
|
|
// Convert ml nodes (xtb syntax) to i18n nodes
|
|
var XmlToI18n$2 = /** @class */ (function () {
|
|
function XmlToI18n() {
|
|
}
|
|
XmlToI18n.prototype.convert = function (message, url) {
|
|
var xmlIcu = new XmlParser().parse(message, url, { tokenizeExpansionForms: true });
|
|
this._errors = xmlIcu.errors;
|
|
var i18nNodes = this._errors.length > 0 || xmlIcu.rootNodes.length == 0 ?
|
|
[] :
|
|
visitAll$1(this, xmlIcu.rootNodes);
|
|
return {
|
|
i18nNodes: i18nNodes,
|
|
errors: this._errors,
|
|
};
|
|
};
|
|
XmlToI18n.prototype.visitText = function (text, context) {
|
|
return new Text$1(text.value, text.sourceSpan);
|
|
};
|
|
XmlToI18n.prototype.visitExpansion = function (icu, context) {
|
|
var caseMap = {};
|
|
visitAll$1(this, icu.cases).forEach(function (c) {
|
|
caseMap[c.value] = new Container(c.nodes, icu.sourceSpan);
|
|
});
|
|
return new Icu$1(icu.switchValue, icu.type, caseMap, icu.sourceSpan);
|
|
};
|
|
XmlToI18n.prototype.visitExpansionCase = function (icuCase, context) {
|
|
return {
|
|
value: icuCase.value,
|
|
nodes: visitAll$1(this, icuCase.expression),
|
|
};
|
|
};
|
|
XmlToI18n.prototype.visitElement = function (el, context) {
|
|
if (el.name === _PLACEHOLDER_TAG$3) {
|
|
var nameAttr = el.attrs.find(function (attr) { return attr.name === 'name'; });
|
|
if (nameAttr) {
|
|
return new Placeholder('', nameAttr.value, el.sourceSpan);
|
|
}
|
|
this._addError(el, "<" + _PLACEHOLDER_TAG$3 + "> misses the \"name\" attribute");
|
|
}
|
|
else {
|
|
this._addError(el, "Unexpected tag");
|
|
}
|
|
return null;
|
|
};
|
|
XmlToI18n.prototype.visitComment = function (comment, context) { };
|
|
XmlToI18n.prototype.visitAttribute = function (attribute, context) { };
|
|
XmlToI18n.prototype._addError = function (node, message) {
|
|
this._errors.push(new I18nError(node.sourceSpan, message));
|
|
};
|
|
return XmlToI18n;
|
|
}());
|
|
|
|
/**
|
|
* A container for translated messages
|
|
*/
|
|
var TranslationBundle = /** @class */ (function () {
|
|
function TranslationBundle(_i18nNodesByMsgId, locale, digest, mapperFactory, missingTranslationStrategy, console) {
|
|
if (_i18nNodesByMsgId === void 0) { _i18nNodesByMsgId = {}; }
|
|
if (missingTranslationStrategy === void 0) { missingTranslationStrategy = MissingTranslationStrategy.Warning; }
|
|
this._i18nNodesByMsgId = _i18nNodesByMsgId;
|
|
this.digest = digest;
|
|
this.mapperFactory = mapperFactory;
|
|
this._i18nToHtml = new I18nToHtmlVisitor(_i18nNodesByMsgId, locale, digest, mapperFactory, missingTranslationStrategy, console);
|
|
}
|
|
// Creates a `TranslationBundle` by parsing the given `content` with the `serializer`.
|
|
TranslationBundle.load = function (content, url, serializer, missingTranslationStrategy, console) {
|
|
var _a = serializer.load(content, url), locale = _a.locale, i18nNodesByMsgId = _a.i18nNodesByMsgId;
|
|
var digestFn = function (m) { return serializer.digest(m); };
|
|
var mapperFactory = function (m) { return serializer.createNameMapper(m); };
|
|
return new TranslationBundle(i18nNodesByMsgId, locale, digestFn, mapperFactory, missingTranslationStrategy, console);
|
|
};
|
|
// Returns the translation as HTML nodes from the given source message.
|
|
TranslationBundle.prototype.get = function (srcMsg) {
|
|
var html = this._i18nToHtml.convert(srcMsg);
|
|
if (html.errors.length) {
|
|
throw new Error(html.errors.join('\n'));
|
|
}
|
|
return html.nodes;
|
|
};
|
|
TranslationBundle.prototype.has = function (srcMsg) {
|
|
return this.digest(srcMsg) in this._i18nNodesByMsgId;
|
|
};
|
|
return TranslationBundle;
|
|
}());
|
|
var I18nToHtmlVisitor = /** @class */ (function () {
|
|
function I18nToHtmlVisitor(_i18nNodesByMsgId, _locale, _digest, _mapperFactory, _missingTranslationStrategy, _console) {
|
|
if (_i18nNodesByMsgId === void 0) { _i18nNodesByMsgId = {}; }
|
|
this._i18nNodesByMsgId = _i18nNodesByMsgId;
|
|
this._locale = _locale;
|
|
this._digest = _digest;
|
|
this._mapperFactory = _mapperFactory;
|
|
this._missingTranslationStrategy = _missingTranslationStrategy;
|
|
this._console = _console;
|
|
this._contextStack = [];
|
|
this._errors = [];
|
|
}
|
|
I18nToHtmlVisitor.prototype.convert = function (srcMsg) {
|
|
this._contextStack.length = 0;
|
|
this._errors.length = 0;
|
|
// i18n to text
|
|
var text = this._convertToText(srcMsg);
|
|
// text to html
|
|
var url = srcMsg.nodes[0].sourceSpan.start.file.url;
|
|
var html = new HtmlParser().parse(text, url, { tokenizeExpansionForms: true });
|
|
return {
|
|
nodes: html.rootNodes,
|
|
errors: __spreadArray(__spreadArray([], __read(this._errors)), __read(html.errors)),
|
|
};
|
|
};
|
|
I18nToHtmlVisitor.prototype.visitText = function (text, context) {
|
|
// `convert()` uses an `HtmlParser` to return `html.Node`s
|
|
// we should then make sure that any special characters are escaped
|
|
return escapeXml(text.value);
|
|
};
|
|
I18nToHtmlVisitor.prototype.visitContainer = function (container, context) {
|
|
var _this = this;
|
|
return container.children.map(function (n) { return n.visit(_this); }).join('');
|
|
};
|
|
I18nToHtmlVisitor.prototype.visitIcu = function (icu, context) {
|
|
var _this = this;
|
|
var cases = Object.keys(icu.cases).map(function (k) { return k + " {" + icu.cases[k].visit(_this) + "}"; });
|
|
// TODO(vicb): Once all format switch to using expression placeholders
|
|
// we should throw when the placeholder is not in the source message
|
|
var exp = this._srcMsg.placeholders.hasOwnProperty(icu.expression) ?
|
|
this._srcMsg.placeholders[icu.expression].text :
|
|
icu.expression;
|
|
return "{" + exp + ", " + icu.type + ", " + cases.join(' ') + "}";
|
|
};
|
|
I18nToHtmlVisitor.prototype.visitPlaceholder = function (ph, context) {
|
|
var phName = this._mapper(ph.name);
|
|
if (this._srcMsg.placeholders.hasOwnProperty(phName)) {
|
|
return this._srcMsg.placeholders[phName].text;
|
|
}
|
|
if (this._srcMsg.placeholderToMessage.hasOwnProperty(phName)) {
|
|
return this._convertToText(this._srcMsg.placeholderToMessage[phName]);
|
|
}
|
|
this._addError(ph, "Unknown placeholder \"" + ph.name + "\"");
|
|
return '';
|
|
};
|
|
// Loaded message contains only placeholders (vs tag and icu placeholders).
|
|
// However when a translation can not be found, we need to serialize the source message
|
|
// which can contain tag placeholders
|
|
I18nToHtmlVisitor.prototype.visitTagPlaceholder = function (ph, context) {
|
|
var _this = this;
|
|
var tag = "" + ph.tag;
|
|
var attrs = Object.keys(ph.attrs).map(function (name) { return name + "=\"" + ph.attrs[name] + "\""; }).join(' ');
|
|
if (ph.isVoid) {
|
|
return "<" + tag + " " + attrs + "/>";
|
|
}
|
|
var children = ph.children.map(function (c) { return c.visit(_this); }).join('');
|
|
return "<" + tag + " " + attrs + ">" + children + "</" + tag + ">";
|
|
};
|
|
// Loaded message contains only placeholders (vs tag and icu placeholders).
|
|
// However when a translation can not be found, we need to serialize the source message
|
|
// which can contain tag placeholders
|
|
I18nToHtmlVisitor.prototype.visitIcuPlaceholder = function (ph, context) {
|
|
// An ICU placeholder references the source message to be serialized
|
|
return this._convertToText(this._srcMsg.placeholderToMessage[ph.name]);
|
|
};
|
|
/**
|
|
* Convert a source message to a translated text string:
|
|
* - text nodes are replaced with their translation,
|
|
* - placeholders are replaced with their content,
|
|
* - ICU nodes are converted to ICU expressions.
|
|
*/
|
|
I18nToHtmlVisitor.prototype._convertToText = function (srcMsg) {
|
|
var _this = this;
|
|
var id = this._digest(srcMsg);
|
|
var mapper = this._mapperFactory ? this._mapperFactory(srcMsg) : null;
|
|
var nodes;
|
|
this._contextStack.push({ msg: this._srcMsg, mapper: this._mapper });
|
|
this._srcMsg = srcMsg;
|
|
if (this._i18nNodesByMsgId.hasOwnProperty(id)) {
|
|
// When there is a translation use its nodes as the source
|
|
// And create a mapper to convert serialized placeholder names to internal names
|
|
nodes = this._i18nNodesByMsgId[id];
|
|
this._mapper = function (name) { return mapper ? mapper.toInternalName(name) : name; };
|
|
}
|
|
else {
|
|
// When no translation has been found
|
|
// - report an error / a warning / nothing,
|
|
// - use the nodes from the original message
|
|
// - placeholders are already internal and need no mapper
|
|
if (this._missingTranslationStrategy === MissingTranslationStrategy.Error) {
|
|
var ctx = this._locale ? " for locale \"" + this._locale + "\"" : '';
|
|
this._addError(srcMsg.nodes[0], "Missing translation for message \"" + id + "\"" + ctx);
|
|
}
|
|
else if (this._console &&
|
|
this._missingTranslationStrategy === MissingTranslationStrategy.Warning) {
|
|
var ctx = this._locale ? " for locale \"" + this._locale + "\"" : '';
|
|
this._console.warn("Missing translation for message \"" + id + "\"" + ctx);
|
|
}
|
|
nodes = srcMsg.nodes;
|
|
this._mapper = function (name) { return name; };
|
|
}
|
|
var text = nodes.map(function (node) { return node.visit(_this); }).join('');
|
|
var context = this._contextStack.pop();
|
|
this._srcMsg = context.msg;
|
|
this._mapper = context.mapper;
|
|
return text;
|
|
};
|
|
I18nToHtmlVisitor.prototype._addError = function (el, msg) {
|
|
this._errors.push(new I18nError(el.sourceSpan, msg));
|
|
};
|
|
return I18nToHtmlVisitor;
|
|
}());
|
|
|
|
/**
|
|
* @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 I18NHtmlParser = /** @class */ (function () {
|
|
function I18NHtmlParser(_htmlParser, translations, translationsFormat, missingTranslation, console) {
|
|
if (missingTranslation === void 0) { missingTranslation = MissingTranslationStrategy.Warning; }
|
|
this._htmlParser = _htmlParser;
|
|
if (translations) {
|
|
var serializer = createSerializer(translationsFormat);
|
|
this._translationBundle =
|
|
TranslationBundle.load(translations, 'i18n', serializer, missingTranslation, console);
|
|
}
|
|
else {
|
|
this._translationBundle =
|
|
new TranslationBundle({}, null, digest, undefined, missingTranslation, console);
|
|
}
|
|
}
|
|
I18NHtmlParser.prototype.parse = function (source, url, options) {
|
|
if (options === void 0) { options = {}; }
|
|
var interpolationConfig = options.interpolationConfig || DEFAULT_INTERPOLATION_CONFIG;
|
|
var parseResult = this._htmlParser.parse(source, url, Object.assign({ interpolationConfig: interpolationConfig }, options));
|
|
if (parseResult.errors.length) {
|
|
return new ParseTreeResult(parseResult.rootNodes, parseResult.errors);
|
|
}
|
|
return mergeTranslations(parseResult.rootNodes, this._translationBundle, interpolationConfig, [], {});
|
|
};
|
|
return I18NHtmlParser;
|
|
}());
|
|
function createSerializer(format) {
|
|
format = (format || 'xlf').toLowerCase();
|
|
switch (format) {
|
|
case 'xmb':
|
|
return new Xmb();
|
|
case 'xtb':
|
|
return new Xtb();
|
|
case 'xliff2':
|
|
case 'xlf2':
|
|
return new Xliff2();
|
|
case 'xliff':
|
|
case 'xlf':
|
|
default:
|
|
return new Xliff();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @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 QUOTED_KEYS = '$quoted$';
|
|
function convertValueToOutputAst(ctx, value, type) {
|
|
if (type === void 0) { type = null; }
|
|
return visitValue(value, new _ValueOutputAstTransformer(ctx), type);
|
|
}
|
|
var _ValueOutputAstTransformer = /** @class */ (function () {
|
|
function _ValueOutputAstTransformer(ctx) {
|
|
this.ctx = ctx;
|
|
}
|
|
_ValueOutputAstTransformer.prototype.visitArray = function (arr, type) {
|
|
var values = [];
|
|
// Note Array.map() must not be used to convert the values because it will
|
|
// skip over empty elements in arrays constructed using `new Array(length)`,
|
|
// resulting in `undefined` elements. This breaks the type guarantee that
|
|
// all values in `o.LiteralArrayExpr` are of type `o.Expression`.
|
|
// See test case in `value_util_spec.ts`.
|
|
for (var i = 0; i < arr.length; ++i) {
|
|
values.push(visitValue(arr[i], this, null /* context */));
|
|
}
|
|
return literalArr(values, type);
|
|
};
|
|
_ValueOutputAstTransformer.prototype.visitStringMap = function (map, type) {
|
|
var _this = this;
|
|
var entries = [];
|
|
var quotedSet = new Set(map && map[QUOTED_KEYS]);
|
|
Object.keys(map).forEach(function (key) {
|
|
entries.push(new LiteralMapEntry(key, visitValue(map[key], _this, null), quotedSet.has(key)));
|
|
});
|
|
return new LiteralMapExpr(entries, type);
|
|
};
|
|
_ValueOutputAstTransformer.prototype.visitPrimitive = function (value, type) {
|
|
return literal(value, type);
|
|
};
|
|
_ValueOutputAstTransformer.prototype.visitOther = function (value, type) {
|
|
if (value instanceof Expression) {
|
|
return value;
|
|
}
|
|
else {
|
|
return this.ctx.importExpr(value);
|
|
}
|
|
};
|
|
return _ValueOutputAstTransformer;
|
|
}());
|
|
|
|
/**
|
|
* @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 mapEntry$1(key, value) {
|
|
return { key: key, value: value, quoted: false };
|
|
}
|
|
var InjectableCompiler = /** @class */ (function () {
|
|
function InjectableCompiler(reflector, alwaysGenerateDef) {
|
|
this.reflector = reflector;
|
|
this.alwaysGenerateDef = alwaysGenerateDef;
|
|
this.tokenInjector = reflector.resolveExternalReference(Identifiers$1.Injector);
|
|
}
|
|
InjectableCompiler.prototype.depsArray = function (deps, ctx) {
|
|
var _this = this;
|
|
return deps.map(function (dep) {
|
|
var token = dep;
|
|
var args = [token];
|
|
var flags = 0 /* Default */;
|
|
if (Array.isArray(dep)) {
|
|
for (var i = 0; i < dep.length; i++) {
|
|
var v = dep[i];
|
|
if (v) {
|
|
if (v.ngMetadataName === 'Optional') {
|
|
flags |= 8 /* Optional */;
|
|
}
|
|
else if (v.ngMetadataName === 'SkipSelf') {
|
|
flags |= 4 /* SkipSelf */;
|
|
}
|
|
else if (v.ngMetadataName === 'Self') {
|
|
flags |= 2 /* Self */;
|
|
}
|
|
else if (v.ngMetadataName === 'Inject') {
|
|
token = v.token;
|
|
}
|
|
else {
|
|
token = v;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
var tokenExpr;
|
|
if (typeof token === 'string') {
|
|
tokenExpr = literal(token);
|
|
}
|
|
else if (token === _this.tokenInjector) {
|
|
tokenExpr = importExpr(Identifiers$1.INJECTOR);
|
|
}
|
|
else {
|
|
tokenExpr = ctx.importExpr(token);
|
|
}
|
|
if (flags !== 0 /* Default */) {
|
|
args = [tokenExpr, literal(flags)];
|
|
}
|
|
else {
|
|
args = [tokenExpr];
|
|
}
|
|
return importExpr(Identifiers$1.inject).callFn(args);
|
|
});
|
|
};
|
|
InjectableCompiler.prototype.factoryFor = function (injectable, ctx) {
|
|
var retValue;
|
|
if (injectable.useExisting) {
|
|
retValue = importExpr(Identifiers$1.inject).callFn([ctx.importExpr(injectable.useExisting)]);
|
|
}
|
|
else if (injectable.useFactory) {
|
|
var deps = injectable.deps || [];
|
|
if (deps.length > 0) {
|
|
retValue = ctx.importExpr(injectable.useFactory).callFn(this.depsArray(deps, ctx));
|
|
}
|
|
else {
|
|
return ctx.importExpr(injectable.useFactory);
|
|
}
|
|
}
|
|
else if (injectable.useValue) {
|
|
retValue = convertValueToOutputAst(ctx, injectable.useValue);
|
|
}
|
|
else {
|
|
var clazz = injectable.useClass || injectable.symbol;
|
|
var depArgs = this.depsArray(this.reflector.parameters(clazz), ctx);
|
|
retValue = new InstantiateExpr(ctx.importExpr(clazz), depArgs);
|
|
}
|
|
return fn([], [new ReturnStatement(retValue)], undefined, undefined, injectable.symbol.name + '_Factory');
|
|
};
|
|
InjectableCompiler.prototype.injectableDef = function (injectable, ctx) {
|
|
var providedIn = NULL_EXPR;
|
|
if (injectable.providedIn !== undefined) {
|
|
if (injectable.providedIn === null) {
|
|
providedIn = NULL_EXPR;
|
|
}
|
|
else if (typeof injectable.providedIn === 'string') {
|
|
providedIn = literal(injectable.providedIn);
|
|
}
|
|
else {
|
|
providedIn = ctx.importExpr(injectable.providedIn);
|
|
}
|
|
}
|
|
var def = [
|
|
mapEntry$1('factory', this.factoryFor(injectable, ctx)),
|
|
mapEntry$1('token', ctx.importExpr(injectable.type.reference)),
|
|
mapEntry$1('providedIn', providedIn),
|
|
];
|
|
return importExpr(Identifiers.ɵɵdefineInjectable).callFn([literalMap(def)], undefined, true);
|
|
};
|
|
InjectableCompiler.prototype.compile = function (injectable, ctx) {
|
|
if (this.alwaysGenerateDef || injectable.providedIn !== undefined) {
|
|
var className = identifierName(injectable.type);
|
|
var clazz = new ClassStmt(className, null, [
|
|
new ClassField('ɵprov', INFERRED_TYPE, [exports.StmtModifier.Static], this.injectableDef(injectable, ctx)),
|
|
], [], new ClassMethod(null, [], []), []);
|
|
ctx.statements.push(clazz);
|
|
}
|
|
};
|
|
return InjectableCompiler;
|
|
}());
|
|
|
|
/**
|
|
* @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 STRIP_SRC_FILE_SUFFIXES = /(\.ts|\.d\.ts|\.js|\.jsx|\.tsx)$/;
|
|
var GENERATED_FILE = /\.ngfactory\.|\.ngsummary\./;
|
|
var JIT_SUMMARY_FILE = /\.ngsummary\./;
|
|
var JIT_SUMMARY_NAME = /NgSummary$/;
|
|
function ngfactoryFilePath(filePath, forceSourceFile) {
|
|
if (forceSourceFile === void 0) { forceSourceFile = false; }
|
|
var urlWithSuffix = splitTypescriptSuffix(filePath, forceSourceFile);
|
|
return urlWithSuffix[0] + ".ngfactory" + normalizeGenFileSuffix(urlWithSuffix[1]);
|
|
}
|
|
function stripGeneratedFileSuffix(filePath) {
|
|
return filePath.replace(GENERATED_FILE, '.');
|
|
}
|
|
function isGeneratedFile(filePath) {
|
|
return GENERATED_FILE.test(filePath);
|
|
}
|
|
function splitTypescriptSuffix(path, forceSourceFile) {
|
|
if (forceSourceFile === void 0) { forceSourceFile = false; }
|
|
if (path.endsWith('.d.ts')) {
|
|
return [path.slice(0, -5), forceSourceFile ? '.ts' : '.d.ts'];
|
|
}
|
|
var lastDot = path.lastIndexOf('.');
|
|
if (lastDot !== -1) {
|
|
return [path.substring(0, lastDot), path.substring(lastDot)];
|
|
}
|
|
return [path, ''];
|
|
}
|
|
function normalizeGenFileSuffix(srcFileSuffix) {
|
|
return srcFileSuffix === '.tsx' ? '.ts' : srcFileSuffix;
|
|
}
|
|
function summaryFileName(fileName) {
|
|
var fileNameWithoutSuffix = fileName.replace(STRIP_SRC_FILE_SUFFIXES, '');
|
|
return fileNameWithoutSuffix + ".ngsummary.json";
|
|
}
|
|
function summaryForJitFileName(fileName, forceSourceFile) {
|
|
if (forceSourceFile === void 0) { forceSourceFile = false; }
|
|
var urlWithSuffix = splitTypescriptSuffix(stripGeneratedFileSuffix(fileName), forceSourceFile);
|
|
return urlWithSuffix[0] + ".ngsummary" + urlWithSuffix[1];
|
|
}
|
|
function stripSummaryForJitFileSuffix(filePath) {
|
|
return filePath.replace(JIT_SUMMARY_FILE, '.');
|
|
}
|
|
function summaryForJitName(symbolName) {
|
|
return symbolName + "NgSummary";
|
|
}
|
|
function stripSummaryForJitNameSuffix(symbolName) {
|
|
return symbolName.replace(JIT_SUMMARY_NAME, '');
|
|
}
|
|
var LOWERED_SYMBOL = /\u0275\d+/;
|
|
function isLoweredSymbol(name) {
|
|
return LOWERED_SYMBOL.test(name);
|
|
}
|
|
function createLoweredSymbol(id) {
|
|
return "\u0275" + id;
|
|
}
|
|
|
|
/**
|
|
* @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 LifecycleHooks;
|
|
(function (LifecycleHooks) {
|
|
LifecycleHooks[LifecycleHooks["OnInit"] = 0] = "OnInit";
|
|
LifecycleHooks[LifecycleHooks["OnDestroy"] = 1] = "OnDestroy";
|
|
LifecycleHooks[LifecycleHooks["DoCheck"] = 2] = "DoCheck";
|
|
LifecycleHooks[LifecycleHooks["OnChanges"] = 3] = "OnChanges";
|
|
LifecycleHooks[LifecycleHooks["AfterContentInit"] = 4] = "AfterContentInit";
|
|
LifecycleHooks[LifecycleHooks["AfterContentChecked"] = 5] = "AfterContentChecked";
|
|
LifecycleHooks[LifecycleHooks["AfterViewInit"] = 6] = "AfterViewInit";
|
|
LifecycleHooks[LifecycleHooks["AfterViewChecked"] = 7] = "AfterViewChecked";
|
|
})(LifecycleHooks || (LifecycleHooks = {}));
|
|
var LIFECYCLE_HOOKS_VALUES = [
|
|
LifecycleHooks.OnInit, LifecycleHooks.OnDestroy, LifecycleHooks.DoCheck, LifecycleHooks.OnChanges,
|
|
LifecycleHooks.AfterContentInit, LifecycleHooks.AfterContentChecked, LifecycleHooks.AfterViewInit,
|
|
LifecycleHooks.AfterViewChecked
|
|
];
|
|
function hasLifecycleHook(reflector, hook, token) {
|
|
return reflector.hasLifecycleHook(token, getHookName(hook));
|
|
}
|
|
function getAllLifecycleHooks(reflector, token) {
|
|
return LIFECYCLE_HOOKS_VALUES.filter(function (hook) { return hasLifecycleHook(reflector, hook, token); });
|
|
}
|
|
function getHookName(hook) {
|
|
switch (hook) {
|
|
case LifecycleHooks.OnInit:
|
|
return 'ngOnInit';
|
|
case LifecycleHooks.OnDestroy:
|
|
return 'ngOnDestroy';
|
|
case LifecycleHooks.DoCheck:
|
|
return 'ngDoCheck';
|
|
case LifecycleHooks.OnChanges:
|
|
return 'ngOnChanges';
|
|
case LifecycleHooks.AfterContentInit:
|
|
return 'ngAfterContentInit';
|
|
case LifecycleHooks.AfterContentChecked:
|
|
return 'ngAfterContentChecked';
|
|
case LifecycleHooks.AfterViewInit:
|
|
return 'ngAfterViewInit';
|
|
case LifecycleHooks.AfterViewChecked:
|
|
return 'ngAfterViewChecked';
|
|
default:
|
|
// This default case is not needed by TypeScript compiler, as the switch is exhaustive.
|
|
// However Closure Compiler does not understand that and reports an error in typed mode.
|
|
// The `throw new Error` below works around the problem, and the unexpected: never variable
|
|
// makes sure tsc still checks this code is unreachable.
|
|
var unexpected = hook;
|
|
throw new Error("unexpected " + unexpected);
|
|
}
|
|
}
|
|
|
|
var ERROR_COMPONENT_TYPE = 'ngComponentType';
|
|
var MISSING_NG_MODULE_METADATA_ERROR_DATA = 'ngMissingNgModuleMetadataErrorData';
|
|
function getMissingNgModuleMetadataErrorData(error) {
|
|
var _a;
|
|
return (_a = error[MISSING_NG_MODULE_METADATA_ERROR_DATA]) !== null && _a !== void 0 ? _a : null;
|
|
}
|
|
// Design notes:
|
|
// - don't lazily create metadata:
|
|
// For some metadata, we need to do async work sometimes,
|
|
// so the user has to kick off this loading.
|
|
// But we want to report errors even when the async work is
|
|
// not required to check that the user would have been able
|
|
// to wait correctly.
|
|
var CompileMetadataResolver = /** @class */ (function () {
|
|
function CompileMetadataResolver(_config, _htmlParser, _ngModuleResolver, _directiveResolver, _pipeResolver, _summaryResolver, _schemaRegistry, _directiveNormalizer, _console, _staticSymbolCache, _reflector, _errorCollector) {
|
|
this._config = _config;
|
|
this._htmlParser = _htmlParser;
|
|
this._ngModuleResolver = _ngModuleResolver;
|
|
this._directiveResolver = _directiveResolver;
|
|
this._pipeResolver = _pipeResolver;
|
|
this._summaryResolver = _summaryResolver;
|
|
this._schemaRegistry = _schemaRegistry;
|
|
this._directiveNormalizer = _directiveNormalizer;
|
|
this._console = _console;
|
|
this._staticSymbolCache = _staticSymbolCache;
|
|
this._reflector = _reflector;
|
|
this._errorCollector = _errorCollector;
|
|
this._nonNormalizedDirectiveCache = new Map();
|
|
this._directiveCache = new Map();
|
|
this._summaryCache = new Map();
|
|
this._pipeCache = new Map();
|
|
this._ngModuleCache = new Map();
|
|
this._ngModuleOfTypes = new Map();
|
|
this._shallowModuleCache = new Map();
|
|
}
|
|
CompileMetadataResolver.prototype.getReflector = function () {
|
|
return this._reflector;
|
|
};
|
|
CompileMetadataResolver.prototype.clearCacheFor = function (type) {
|
|
var dirMeta = this._directiveCache.get(type);
|
|
this._directiveCache.delete(type);
|
|
this._nonNormalizedDirectiveCache.delete(type);
|
|
this._summaryCache.delete(type);
|
|
this._pipeCache.delete(type);
|
|
this._ngModuleOfTypes.delete(type);
|
|
// Clear all of the NgModule as they contain transitive information!
|
|
this._ngModuleCache.clear();
|
|
if (dirMeta) {
|
|
this._directiveNormalizer.clearCacheFor(dirMeta);
|
|
}
|
|
};
|
|
CompileMetadataResolver.prototype.clearCache = function () {
|
|
this._directiveCache.clear();
|
|
this._nonNormalizedDirectiveCache.clear();
|
|
this._summaryCache.clear();
|
|
this._pipeCache.clear();
|
|
this._ngModuleCache.clear();
|
|
this._ngModuleOfTypes.clear();
|
|
this._directiveNormalizer.clearCache();
|
|
};
|
|
CompileMetadataResolver.prototype._createProxyClass = function (baseType, name) {
|
|
var delegate = null;
|
|
var proxyClass = function () {
|
|
if (!delegate) {
|
|
throw new Error("Illegal state: Class " + name + " for type " + stringify(baseType) + " is not compiled yet!");
|
|
}
|
|
return delegate.apply(this, arguments);
|
|
};
|
|
proxyClass.setDelegate = function (d) {
|
|
delegate = d;
|
|
proxyClass.prototype = d.prototype;
|
|
};
|
|
// Make stringify work correctly
|
|
proxyClass.overriddenName = name;
|
|
return proxyClass;
|
|
};
|
|
CompileMetadataResolver.prototype.getGeneratedClass = function (dirType, name) {
|
|
if (dirType instanceof StaticSymbol) {
|
|
return this._staticSymbolCache.get(ngfactoryFilePath(dirType.filePath), name);
|
|
}
|
|
else {
|
|
return this._createProxyClass(dirType, name);
|
|
}
|
|
};
|
|
CompileMetadataResolver.prototype.getComponentViewClass = function (dirType) {
|
|
return this.getGeneratedClass(dirType, viewClassName(dirType, 0));
|
|
};
|
|
CompileMetadataResolver.prototype.getHostComponentViewClass = function (dirType) {
|
|
return this.getGeneratedClass(dirType, hostViewClassName(dirType));
|
|
};
|
|
CompileMetadataResolver.prototype.getHostComponentType = function (dirType) {
|
|
var name = identifierName({ reference: dirType }) + "_Host";
|
|
if (dirType instanceof StaticSymbol) {
|
|
return this._staticSymbolCache.get(dirType.filePath, name);
|
|
}
|
|
return this._createProxyClass(dirType, name);
|
|
};
|
|
CompileMetadataResolver.prototype.getRendererType = function (dirType) {
|
|
if (dirType instanceof StaticSymbol) {
|
|
return this._staticSymbolCache.get(ngfactoryFilePath(dirType.filePath), rendererTypeName(dirType));
|
|
}
|
|
else {
|
|
// returning an object as proxy,
|
|
// that we fill later during runtime compilation.
|
|
return {};
|
|
}
|
|
};
|
|
CompileMetadataResolver.prototype.getComponentFactory = function (selector, dirType, inputs, outputs) {
|
|
if (dirType instanceof StaticSymbol) {
|
|
return this._staticSymbolCache.get(ngfactoryFilePath(dirType.filePath), componentFactoryName(dirType));
|
|
}
|
|
else {
|
|
var hostView = this.getHostComponentViewClass(dirType);
|
|
// Note: ngContentSelectors will be filled later once the template is
|
|
// loaded.
|
|
var createComponentFactory = this._reflector.resolveExternalReference(Identifiers$1.createComponentFactory);
|
|
return createComponentFactory(selector, dirType, hostView, inputs, outputs, []);
|
|
}
|
|
};
|
|
CompileMetadataResolver.prototype.initComponentFactory = function (factory, ngContentSelectors) {
|
|
var _b;
|
|
if (!(factory instanceof StaticSymbol)) {
|
|
(_b = factory.ngContentSelectors).push.apply(_b, __spreadArray([], __read(ngContentSelectors)));
|
|
}
|
|
};
|
|
CompileMetadataResolver.prototype._loadSummary = function (type, kind) {
|
|
var typeSummary = this._summaryCache.get(type);
|
|
if (!typeSummary) {
|
|
var summary = this._summaryResolver.resolveSummary(type);
|
|
typeSummary = summary ? summary.type : null;
|
|
this._summaryCache.set(type, typeSummary || null);
|
|
}
|
|
return typeSummary && typeSummary.summaryKind === kind ? typeSummary : null;
|
|
};
|
|
CompileMetadataResolver.prototype.getHostComponentMetadata = function (compMeta, hostViewType) {
|
|
var hostType = this.getHostComponentType(compMeta.type.reference);
|
|
if (!hostViewType) {
|
|
hostViewType = this.getHostComponentViewClass(hostType);
|
|
}
|
|
// Note: ! is ok here as this method should only be called with normalized directive
|
|
// metadata, which always fills in the selector.
|
|
var template = CssSelector.parse(compMeta.selector)[0].getMatchingElementTemplate();
|
|
var templateUrl = '';
|
|
var htmlAst = this._htmlParser.parse(template, templateUrl);
|
|
return CompileDirectiveMetadata.create({
|
|
isHost: true,
|
|
type: { reference: hostType, diDeps: [], lifecycleHooks: [] },
|
|
template: new CompileTemplateMetadata({
|
|
encapsulation: ViewEncapsulation.None,
|
|
template: template,
|
|
templateUrl: templateUrl,
|
|
htmlAst: htmlAst,
|
|
styles: [],
|
|
styleUrls: [],
|
|
ngContentSelectors: [],
|
|
animations: [],
|
|
isInline: true,
|
|
externalStylesheets: [],
|
|
interpolation: null,
|
|
preserveWhitespaces: false,
|
|
}),
|
|
exportAs: null,
|
|
changeDetection: ChangeDetectionStrategy.Default,
|
|
inputs: [],
|
|
outputs: [],
|
|
host: {},
|
|
isComponent: true,
|
|
selector: '*',
|
|
providers: [],
|
|
viewProviders: [],
|
|
queries: [],
|
|
guards: {},
|
|
viewQueries: [],
|
|
componentViewType: hostViewType,
|
|
rendererType: { id: '__Host__', encapsulation: ViewEncapsulation.None, styles: [], data: {} },
|
|
entryComponents: [],
|
|
componentFactory: null
|
|
});
|
|
};
|
|
CompileMetadataResolver.prototype.loadDirectiveMetadata = function (ngModuleType, directiveType, isSync) {
|
|
var _this = this;
|
|
if (this._directiveCache.has(directiveType)) {
|
|
return null;
|
|
}
|
|
directiveType = resolveForwardRef(directiveType);
|
|
var _b = this.getNonNormalizedDirectiveMetadata(directiveType), annotation = _b.annotation, metadata = _b.metadata;
|
|
var createDirectiveMetadata = function (templateMetadata) {
|
|
var normalizedDirMeta = new CompileDirectiveMetadata({
|
|
isHost: false,
|
|
type: metadata.type,
|
|
isComponent: metadata.isComponent,
|
|
selector: metadata.selector,
|
|
exportAs: metadata.exportAs,
|
|
changeDetection: metadata.changeDetection,
|
|
inputs: metadata.inputs,
|
|
outputs: metadata.outputs,
|
|
hostListeners: metadata.hostListeners,
|
|
hostProperties: metadata.hostProperties,
|
|
hostAttributes: metadata.hostAttributes,
|
|
providers: metadata.providers,
|
|
viewProviders: metadata.viewProviders,
|
|
queries: metadata.queries,
|
|
guards: metadata.guards,
|
|
viewQueries: metadata.viewQueries,
|
|
entryComponents: metadata.entryComponents,
|
|
componentViewType: metadata.componentViewType,
|
|
rendererType: metadata.rendererType,
|
|
componentFactory: metadata.componentFactory,
|
|
template: templateMetadata
|
|
});
|
|
if (templateMetadata) {
|
|
_this.initComponentFactory(metadata.componentFactory, templateMetadata.ngContentSelectors);
|
|
}
|
|
_this._directiveCache.set(directiveType, normalizedDirMeta);
|
|
_this._summaryCache.set(directiveType, normalizedDirMeta.toSummary());
|
|
return null;
|
|
};
|
|
if (metadata.isComponent) {
|
|
var template = metadata.template;
|
|
var templateMeta = this._directiveNormalizer.normalizeTemplate({
|
|
ngModuleType: ngModuleType,
|
|
componentType: directiveType,
|
|
moduleUrl: this._reflector.componentModuleUrl(directiveType, annotation),
|
|
encapsulation: template.encapsulation,
|
|
template: template.template,
|
|
templateUrl: template.templateUrl,
|
|
styles: template.styles,
|
|
styleUrls: template.styleUrls,
|
|
animations: template.animations,
|
|
interpolation: template.interpolation,
|
|
preserveWhitespaces: template.preserveWhitespaces
|
|
});
|
|
if (isPromise(templateMeta) && isSync) {
|
|
this._reportError(componentStillLoadingError(directiveType), directiveType);
|
|
return null;
|
|
}
|
|
return SyncAsync.then(templateMeta, createDirectiveMetadata);
|
|
}
|
|
else {
|
|
// directive
|
|
createDirectiveMetadata(null);
|
|
return null;
|
|
}
|
|
};
|
|
CompileMetadataResolver.prototype.getNonNormalizedDirectiveMetadata = function (directiveType) {
|
|
var _this = this;
|
|
directiveType = resolveForwardRef(directiveType);
|
|
if (!directiveType) {
|
|
return null;
|
|
}
|
|
var cacheEntry = this._nonNormalizedDirectiveCache.get(directiveType);
|
|
if (cacheEntry) {
|
|
return cacheEntry;
|
|
}
|
|
var dirMeta = this._directiveResolver.resolve(directiveType, false);
|
|
if (!dirMeta) {
|
|
return null;
|
|
}
|
|
var nonNormalizedTemplateMetadata = undefined;
|
|
if (createComponent.isTypeOf(dirMeta)) {
|
|
// component
|
|
var compMeta = dirMeta;
|
|
assertArrayOfStrings('styles', compMeta.styles);
|
|
assertArrayOfStrings('styleUrls', compMeta.styleUrls);
|
|
assertInterpolationSymbols('interpolation', compMeta.interpolation);
|
|
var animations = compMeta.animations;
|
|
nonNormalizedTemplateMetadata = new CompileTemplateMetadata({
|
|
encapsulation: noUndefined(compMeta.encapsulation),
|
|
template: noUndefined(compMeta.template),
|
|
templateUrl: noUndefined(compMeta.templateUrl),
|
|
htmlAst: null,
|
|
styles: compMeta.styles || [],
|
|
styleUrls: compMeta.styleUrls || [],
|
|
animations: animations || [],
|
|
interpolation: noUndefined(compMeta.interpolation),
|
|
isInline: !!compMeta.template,
|
|
externalStylesheets: [],
|
|
ngContentSelectors: [],
|
|
preserveWhitespaces: noUndefined(dirMeta.preserveWhitespaces),
|
|
});
|
|
}
|
|
var changeDetectionStrategy = null;
|
|
var viewProviders = [];
|
|
var entryComponentMetadata = [];
|
|
var selector = dirMeta.selector;
|
|
if (createComponent.isTypeOf(dirMeta)) {
|
|
// Component
|
|
var compMeta = dirMeta;
|
|
changeDetectionStrategy = compMeta.changeDetection;
|
|
if (compMeta.viewProviders) {
|
|
viewProviders = this._getProvidersMetadata(compMeta.viewProviders, entryComponentMetadata, "viewProviders for \"" + stringifyType(directiveType) + "\"", [], directiveType);
|
|
}
|
|
if (compMeta.entryComponents) {
|
|
entryComponentMetadata = flattenAndDedupeArray(compMeta.entryComponents)
|
|
.map(function (type) { return _this._getEntryComponentMetadata(type); })
|
|
.concat(entryComponentMetadata);
|
|
}
|
|
if (!selector) {
|
|
selector = this._schemaRegistry.getDefaultComponentElementName();
|
|
}
|
|
}
|
|
else {
|
|
// Directive
|
|
if (!selector) {
|
|
selector = null;
|
|
}
|
|
}
|
|
var providers = [];
|
|
if (dirMeta.providers != null) {
|
|
providers = this._getProvidersMetadata(dirMeta.providers, entryComponentMetadata, "providers for \"" + stringifyType(directiveType) + "\"", [], directiveType);
|
|
}
|
|
var queries = [];
|
|
var viewQueries = [];
|
|
if (dirMeta.queries != null) {
|
|
queries = this._getQueriesMetadata(dirMeta.queries, false, directiveType);
|
|
viewQueries = this._getQueriesMetadata(dirMeta.queries, true, directiveType);
|
|
}
|
|
var metadata = CompileDirectiveMetadata.create({
|
|
isHost: false,
|
|
selector: selector,
|
|
exportAs: noUndefined(dirMeta.exportAs),
|
|
isComponent: !!nonNormalizedTemplateMetadata,
|
|
type: this._getTypeMetadata(directiveType),
|
|
template: nonNormalizedTemplateMetadata,
|
|
changeDetection: changeDetectionStrategy,
|
|
inputs: dirMeta.inputs || [],
|
|
outputs: dirMeta.outputs || [],
|
|
host: dirMeta.host || {},
|
|
providers: providers || [],
|
|
viewProviders: viewProviders || [],
|
|
queries: queries || [],
|
|
guards: dirMeta.guards || {},
|
|
viewQueries: viewQueries || [],
|
|
entryComponents: entryComponentMetadata,
|
|
componentViewType: nonNormalizedTemplateMetadata ? this.getComponentViewClass(directiveType) :
|
|
null,
|
|
rendererType: nonNormalizedTemplateMetadata ? this.getRendererType(directiveType) : null,
|
|
componentFactory: null
|
|
});
|
|
if (nonNormalizedTemplateMetadata) {
|
|
metadata.componentFactory =
|
|
this.getComponentFactory(selector, directiveType, metadata.inputs, metadata.outputs);
|
|
}
|
|
cacheEntry = { metadata: metadata, annotation: dirMeta };
|
|
this._nonNormalizedDirectiveCache.set(directiveType, cacheEntry);
|
|
return cacheEntry;
|
|
};
|
|
/**
|
|
* Gets the metadata for the given directive.
|
|
* This assumes `loadNgModuleDirectiveAndPipeMetadata` has been called first.
|
|
*/
|
|
CompileMetadataResolver.prototype.getDirectiveMetadata = function (directiveType) {
|
|
var dirMeta = this._directiveCache.get(directiveType);
|
|
if (!dirMeta) {
|
|
this._reportError(syntaxError("Illegal state: getDirectiveMetadata can only be called after loadNgModuleDirectiveAndPipeMetadata for a module that declares it. Directive " + stringifyType(directiveType) + "."), directiveType);
|
|
}
|
|
return dirMeta;
|
|
};
|
|
CompileMetadataResolver.prototype.getDirectiveSummary = function (dirType) {
|
|
var dirSummary = this._loadSummary(dirType, exports.CompileSummaryKind.Directive);
|
|
if (!dirSummary) {
|
|
this._reportError(syntaxError("Illegal state: Could not load the summary for directive " + stringifyType(dirType) + "."), dirType);
|
|
}
|
|
return dirSummary;
|
|
};
|
|
CompileMetadataResolver.prototype.isDirective = function (type) {
|
|
return !!this._loadSummary(type, exports.CompileSummaryKind.Directive) ||
|
|
this._directiveResolver.isDirective(type);
|
|
};
|
|
CompileMetadataResolver.prototype.isAbstractDirective = function (type) {
|
|
var summary = this._loadSummary(type, exports.CompileSummaryKind.Directive);
|
|
if (summary && !summary.isComponent) {
|
|
return !summary.selector;
|
|
}
|
|
var meta = this._directiveResolver.resolve(type, false);
|
|
if (meta && !createComponent.isTypeOf(meta)) {
|
|
return !meta.selector;
|
|
}
|
|
return false;
|
|
};
|
|
CompileMetadataResolver.prototype.isPipe = function (type) {
|
|
return !!this._loadSummary(type, exports.CompileSummaryKind.Pipe) ||
|
|
this._pipeResolver.isPipe(type);
|
|
};
|
|
CompileMetadataResolver.prototype.isNgModule = function (type) {
|
|
return !!this._loadSummary(type, exports.CompileSummaryKind.NgModule) ||
|
|
this._ngModuleResolver.isNgModule(type);
|
|
};
|
|
CompileMetadataResolver.prototype.getNgModuleSummary = function (moduleType, alreadyCollecting) {
|
|
if (alreadyCollecting === void 0) { alreadyCollecting = null; }
|
|
var moduleSummary = this._loadSummary(moduleType, exports.CompileSummaryKind.NgModule);
|
|
if (!moduleSummary) {
|
|
var moduleMeta = this.getNgModuleMetadata(moduleType, false, alreadyCollecting);
|
|
moduleSummary = moduleMeta ? moduleMeta.toSummary() : null;
|
|
if (moduleSummary) {
|
|
this._summaryCache.set(moduleType, moduleSummary);
|
|
}
|
|
}
|
|
return moduleSummary;
|
|
};
|
|
/**
|
|
* Loads the declared directives and pipes of an NgModule.
|
|
*/
|
|
CompileMetadataResolver.prototype.loadNgModuleDirectiveAndPipeMetadata = function (moduleType, isSync, throwIfNotFound) {
|
|
var _this = this;
|
|
if (throwIfNotFound === void 0) { throwIfNotFound = true; }
|
|
var ngModule = this.getNgModuleMetadata(moduleType, throwIfNotFound);
|
|
var loading = [];
|
|
if (ngModule) {
|
|
ngModule.declaredDirectives.forEach(function (id) {
|
|
var promise = _this.loadDirectiveMetadata(moduleType, id.reference, isSync);
|
|
if (promise) {
|
|
loading.push(promise);
|
|
}
|
|
});
|
|
ngModule.declaredPipes.forEach(function (id) { return _this._loadPipeMetadata(id.reference); });
|
|
}
|
|
return Promise.all(loading);
|
|
};
|
|
CompileMetadataResolver.prototype.getShallowModuleMetadata = function (moduleType) {
|
|
var compileMeta = this._shallowModuleCache.get(moduleType);
|
|
if (compileMeta) {
|
|
return compileMeta;
|
|
}
|
|
var ngModuleMeta = findLast(this._reflector.shallowAnnotations(moduleType), createNgModule.isTypeOf);
|
|
compileMeta = {
|
|
type: this._getTypeMetadata(moduleType),
|
|
rawExports: ngModuleMeta.exports,
|
|
rawImports: ngModuleMeta.imports,
|
|
rawProviders: ngModuleMeta.providers,
|
|
};
|
|
this._shallowModuleCache.set(moduleType, compileMeta);
|
|
return compileMeta;
|
|
};
|
|
CompileMetadataResolver.prototype.getNgModuleMetadata = function (moduleType, throwIfNotFound, alreadyCollecting) {
|
|
var _this = this;
|
|
if (throwIfNotFound === void 0) { throwIfNotFound = true; }
|
|
if (alreadyCollecting === void 0) { alreadyCollecting = null; }
|
|
moduleType = resolveForwardRef(moduleType);
|
|
var compileMeta = this._ngModuleCache.get(moduleType);
|
|
if (compileMeta) {
|
|
return compileMeta;
|
|
}
|
|
var meta = this._ngModuleResolver.resolve(moduleType, throwIfNotFound);
|
|
if (!meta) {
|
|
return null;
|
|
}
|
|
var declaredDirectives = [];
|
|
var exportedNonModuleIdentifiers = [];
|
|
var declaredPipes = [];
|
|
var importedModules = [];
|
|
var exportedModules = [];
|
|
var providers = [];
|
|
var entryComponents = [];
|
|
var bootstrapComponents = [];
|
|
var schemas = [];
|
|
if (meta.imports) {
|
|
flattenAndDedupeArray(meta.imports).forEach(function (importedType) {
|
|
var importedModuleType = undefined;
|
|
if (isValidType(importedType)) {
|
|
importedModuleType = importedType;
|
|
}
|
|
else if (importedType && importedType.ngModule) {
|
|
var moduleWithProviders = importedType;
|
|
importedModuleType = moduleWithProviders.ngModule;
|
|
if (moduleWithProviders.providers) {
|
|
providers.push.apply(providers, __spreadArray([], __read(_this._getProvidersMetadata(moduleWithProviders.providers, entryComponents, "provider for the NgModule '" + stringifyType(importedModuleType) + "'", [], importedType))));
|
|
}
|
|
}
|
|
if (importedModuleType) {
|
|
if (_this._checkSelfImport(moduleType, importedModuleType))
|
|
return;
|
|
if (!alreadyCollecting)
|
|
alreadyCollecting = new Set();
|
|
if (alreadyCollecting.has(importedModuleType)) {
|
|
_this._reportError(syntaxError(_this._getTypeDescriptor(importedModuleType) + " '" + stringifyType(importedType) + "' is imported recursively by the module '" + stringifyType(moduleType) + "'."), moduleType);
|
|
return;
|
|
}
|
|
alreadyCollecting.add(importedModuleType);
|
|
var importedModuleSummary = _this.getNgModuleSummary(importedModuleType, alreadyCollecting);
|
|
alreadyCollecting.delete(importedModuleType);
|
|
if (!importedModuleSummary) {
|
|
var err = syntaxError("Unexpected " + _this._getTypeDescriptor(importedType) + " '" + stringifyType(importedType) + "' imported by the module '" + stringifyType(moduleType) + "'. Please add a @NgModule annotation.");
|
|
// If possible, record additional context for this error to enable more useful
|
|
// diagnostics on the compiler side.
|
|
if (importedType instanceof StaticSymbol) {
|
|
err[MISSING_NG_MODULE_METADATA_ERROR_DATA] = {
|
|
fileName: importedType.filePath,
|
|
className: importedType.name,
|
|
};
|
|
}
|
|
_this._reportError(err, moduleType);
|
|
return;
|
|
}
|
|
importedModules.push(importedModuleSummary);
|
|
}
|
|
else {
|
|
_this._reportError(syntaxError("Unexpected value '" + stringifyType(importedType) + "' imported by the module '" + stringifyType(moduleType) + "'"), moduleType);
|
|
return;
|
|
}
|
|
});
|
|
}
|
|
if (meta.exports) {
|
|
flattenAndDedupeArray(meta.exports).forEach(function (exportedType) {
|
|
if (!isValidType(exportedType)) {
|
|
_this._reportError(syntaxError("Unexpected value '" + stringifyType(exportedType) + "' exported by the module '" + stringifyType(moduleType) + "'"), moduleType);
|
|
return;
|
|
}
|
|
if (!alreadyCollecting)
|
|
alreadyCollecting = new Set();
|
|
if (alreadyCollecting.has(exportedType)) {
|
|
_this._reportError(syntaxError(_this._getTypeDescriptor(exportedType) + " '" + stringify(exportedType) + "' is exported recursively by the module '" + stringifyType(moduleType) + "'"), moduleType);
|
|
return;
|
|
}
|
|
alreadyCollecting.add(exportedType);
|
|
var exportedModuleSummary = _this.getNgModuleSummary(exportedType, alreadyCollecting);
|
|
alreadyCollecting.delete(exportedType);
|
|
if (exportedModuleSummary) {
|
|
exportedModules.push(exportedModuleSummary);
|
|
}
|
|
else {
|
|
exportedNonModuleIdentifiers.push(_this._getIdentifierMetadata(exportedType));
|
|
}
|
|
});
|
|
}
|
|
// Note: This will be modified later, so we rely on
|
|
// getting a new instance every time!
|
|
var transitiveModule = this._getTransitiveNgModuleMetadata(importedModules, exportedModules);
|
|
if (meta.declarations) {
|
|
flattenAndDedupeArray(meta.declarations).forEach(function (declaredType) {
|
|
if (!isValidType(declaredType)) {
|
|
_this._reportError(syntaxError("Unexpected value '" + stringifyType(declaredType) + "' declared by the module '" + stringifyType(moduleType) + "'"), moduleType);
|
|
return;
|
|
}
|
|
var declaredIdentifier = _this._getIdentifierMetadata(declaredType);
|
|
if (_this.isDirective(declaredType)) {
|
|
if (_this.isAbstractDirective(declaredType)) {
|
|
_this._reportError(syntaxError("Directive " + stringifyType(declaredType) + " has no selector, please add it!"), declaredType);
|
|
}
|
|
transitiveModule.addDirective(declaredIdentifier);
|
|
declaredDirectives.push(declaredIdentifier);
|
|
_this._addTypeToModule(declaredType, moduleType);
|
|
}
|
|
else if (_this.isPipe(declaredType)) {
|
|
transitiveModule.addPipe(declaredIdentifier);
|
|
transitiveModule.pipes.push(declaredIdentifier);
|
|
declaredPipes.push(declaredIdentifier);
|
|
_this._addTypeToModule(declaredType, moduleType);
|
|
}
|
|
else {
|
|
_this._reportError(syntaxError("Unexpected " + _this._getTypeDescriptor(declaredType) + " '" + stringifyType(declaredType) + "' declared by the module '" + stringifyType(moduleType) + "'. Please add a @Pipe/@Directive/@Component annotation."), moduleType);
|
|
return;
|
|
}
|
|
});
|
|
}
|
|
var exportedDirectives = [];
|
|
var exportedPipes = [];
|
|
exportedNonModuleIdentifiers.forEach(function (exportedId) {
|
|
if (transitiveModule.directivesSet.has(exportedId.reference)) {
|
|
exportedDirectives.push(exportedId);
|
|
transitiveModule.addExportedDirective(exportedId);
|
|
}
|
|
else if (transitiveModule.pipesSet.has(exportedId.reference)) {
|
|
exportedPipes.push(exportedId);
|
|
transitiveModule.addExportedPipe(exportedId);
|
|
}
|
|
else {
|
|
_this._reportError(syntaxError("Can't export " + _this._getTypeDescriptor(exportedId.reference) + " " + stringifyType(exportedId.reference) + " from " + stringifyType(moduleType) + " as it was neither declared nor imported!"), moduleType);
|
|
return;
|
|
}
|
|
});
|
|
// The providers of the module have to go last
|
|
// so that they overwrite any other provider we already added.
|
|
if (meta.providers) {
|
|
providers.push.apply(providers, __spreadArray([], __read(this._getProvidersMetadata(meta.providers, entryComponents, "provider for the NgModule '" + stringifyType(moduleType) + "'", [], moduleType))));
|
|
}
|
|
if (meta.entryComponents) {
|
|
entryComponents.push.apply(entryComponents, __spreadArray([], __read(flattenAndDedupeArray(meta.entryComponents)
|
|
.map(function (type) { return _this._getEntryComponentMetadata(type); }))));
|
|
}
|
|
if (meta.bootstrap) {
|
|
flattenAndDedupeArray(meta.bootstrap).forEach(function (type) {
|
|
if (!isValidType(type)) {
|
|
_this._reportError(syntaxError("Unexpected value '" + stringifyType(type) + "' used in the bootstrap property of module '" + stringifyType(moduleType) + "'"), moduleType);
|
|
return;
|
|
}
|
|
bootstrapComponents.push(_this._getIdentifierMetadata(type));
|
|
});
|
|
}
|
|
entryComponents.push.apply(entryComponents, __spreadArray([], __read(bootstrapComponents.map(function (type) { return _this._getEntryComponentMetadata(type.reference); }))));
|
|
if (meta.schemas) {
|
|
schemas.push.apply(schemas, __spreadArray([], __read(flattenAndDedupeArray(meta.schemas))));
|
|
}
|
|
compileMeta = new CompileNgModuleMetadata({
|
|
type: this._getTypeMetadata(moduleType),
|
|
providers: providers,
|
|
entryComponents: entryComponents,
|
|
bootstrapComponents: bootstrapComponents,
|
|
schemas: schemas,
|
|
declaredDirectives: declaredDirectives,
|
|
exportedDirectives: exportedDirectives,
|
|
declaredPipes: declaredPipes,
|
|
exportedPipes: exportedPipes,
|
|
importedModules: importedModules,
|
|
exportedModules: exportedModules,
|
|
transitiveModule: transitiveModule,
|
|
id: meta.id || null,
|
|
});
|
|
entryComponents.forEach(function (id) { return transitiveModule.addEntryComponent(id); });
|
|
providers.forEach(function (provider) { return transitiveModule.addProvider(provider, compileMeta.type); });
|
|
transitiveModule.addModule(compileMeta.type);
|
|
this._ngModuleCache.set(moduleType, compileMeta);
|
|
return compileMeta;
|
|
};
|
|
CompileMetadataResolver.prototype._checkSelfImport = function (moduleType, importedModuleType) {
|
|
if (moduleType === importedModuleType) {
|
|
this._reportError(syntaxError("'" + stringifyType(moduleType) + "' module can't import itself"), moduleType);
|
|
return true;
|
|
}
|
|
return false;
|
|
};
|
|
CompileMetadataResolver.prototype._getTypeDescriptor = function (type) {
|
|
if (isValidType(type)) {
|
|
if (this.isDirective(type)) {
|
|
return 'directive';
|
|
}
|
|
if (this.isPipe(type)) {
|
|
return 'pipe';
|
|
}
|
|
if (this.isNgModule(type)) {
|
|
return 'module';
|
|
}
|
|
}
|
|
if (type.provide) {
|
|
return 'provider';
|
|
}
|
|
return 'value';
|
|
};
|
|
CompileMetadataResolver.prototype._addTypeToModule = function (type, moduleType) {
|
|
var oldModule = this._ngModuleOfTypes.get(type);
|
|
if (oldModule && oldModule !== moduleType) {
|
|
this._reportError(syntaxError("Type " + stringifyType(type) + " is part of the declarations of 2 modules: " + stringifyType(oldModule) + " and " + stringifyType(moduleType) + "! " +
|
|
("Please consider moving " + stringifyType(type) + " to a higher module that imports " + stringifyType(oldModule) + " and " + stringifyType(moduleType) + ". ") +
|
|
("You can also create a new NgModule that exports and includes " + stringifyType(type) + " then import that NgModule in " + stringifyType(oldModule) + " and " + stringifyType(moduleType) + ".")), moduleType);
|
|
return;
|
|
}
|
|
this._ngModuleOfTypes.set(type, moduleType);
|
|
};
|
|
CompileMetadataResolver.prototype._getTransitiveNgModuleMetadata = function (importedModules, exportedModules) {
|
|
// collect `providers` / `entryComponents` from all imported and all exported modules
|
|
var result = new TransitiveCompileNgModuleMetadata();
|
|
var modulesByToken = new Map();
|
|
importedModules.concat(exportedModules).forEach(function (modSummary) {
|
|
modSummary.modules.forEach(function (mod) { return result.addModule(mod); });
|
|
modSummary.entryComponents.forEach(function (comp) { return result.addEntryComponent(comp); });
|
|
var addedTokens = new Set();
|
|
modSummary.providers.forEach(function (entry) {
|
|
var tokenRef = tokenReference(entry.provider.token);
|
|
var prevModules = modulesByToken.get(tokenRef);
|
|
if (!prevModules) {
|
|
prevModules = new Set();
|
|
modulesByToken.set(tokenRef, prevModules);
|
|
}
|
|
var moduleRef = entry.module.reference;
|
|
// Note: the providers of one module may still contain multiple providers
|
|
// per token (e.g. for multi providers), and we need to preserve these.
|
|
if (addedTokens.has(tokenRef) || !prevModules.has(moduleRef)) {
|
|
prevModules.add(moduleRef);
|
|
addedTokens.add(tokenRef);
|
|
result.addProvider(entry.provider, entry.module);
|
|
}
|
|
});
|
|
});
|
|
exportedModules.forEach(function (modSummary) {
|
|
modSummary.exportedDirectives.forEach(function (id) { return result.addExportedDirective(id); });
|
|
modSummary.exportedPipes.forEach(function (id) { return result.addExportedPipe(id); });
|
|
});
|
|
importedModules.forEach(function (modSummary) {
|
|
modSummary.exportedDirectives.forEach(function (id) { return result.addDirective(id); });
|
|
modSummary.exportedPipes.forEach(function (id) { return result.addPipe(id); });
|
|
});
|
|
return result;
|
|
};
|
|
CompileMetadataResolver.prototype._getIdentifierMetadata = function (type) {
|
|
type = resolveForwardRef(type);
|
|
return { reference: type };
|
|
};
|
|
CompileMetadataResolver.prototype.isInjectable = function (type) {
|
|
var annotations = this._reflector.tryAnnotations(type);
|
|
return annotations.some(function (ann) { return createInjectable.isTypeOf(ann); });
|
|
};
|
|
CompileMetadataResolver.prototype.getInjectableSummary = function (type) {
|
|
return {
|
|
summaryKind: exports.CompileSummaryKind.Injectable,
|
|
type: this._getTypeMetadata(type, null, false)
|
|
};
|
|
};
|
|
CompileMetadataResolver.prototype.getInjectableMetadata = function (type, dependencies, throwOnUnknownDeps) {
|
|
if (dependencies === void 0) { dependencies = null; }
|
|
if (throwOnUnknownDeps === void 0) { throwOnUnknownDeps = true; }
|
|
var typeSummary = this._loadSummary(type, exports.CompileSummaryKind.Injectable);
|
|
var typeMetadata = typeSummary ?
|
|
typeSummary.type :
|
|
this._getTypeMetadata(type, dependencies, throwOnUnknownDeps);
|
|
var annotations = this._reflector.annotations(type).filter(function (ann) { return createInjectable.isTypeOf(ann); });
|
|
if (annotations.length === 0) {
|
|
return null;
|
|
}
|
|
var meta = annotations[annotations.length - 1];
|
|
return {
|
|
symbol: type,
|
|
type: typeMetadata,
|
|
providedIn: meta.providedIn,
|
|
useValue: meta.useValue,
|
|
useClass: meta.useClass,
|
|
useExisting: meta.useExisting,
|
|
useFactory: meta.useFactory,
|
|
deps: meta.deps,
|
|
};
|
|
};
|
|
CompileMetadataResolver.prototype._getTypeMetadata = function (type, dependencies, throwOnUnknownDeps) {
|
|
if (dependencies === void 0) { dependencies = null; }
|
|
if (throwOnUnknownDeps === void 0) { throwOnUnknownDeps = true; }
|
|
var identifier = this._getIdentifierMetadata(type);
|
|
return {
|
|
reference: identifier.reference,
|
|
diDeps: this._getDependenciesMetadata(identifier.reference, dependencies, throwOnUnknownDeps),
|
|
lifecycleHooks: getAllLifecycleHooks(this._reflector, identifier.reference),
|
|
};
|
|
};
|
|
CompileMetadataResolver.prototype._getFactoryMetadata = function (factory, dependencies) {
|
|
if (dependencies === void 0) { dependencies = null; }
|
|
factory = resolveForwardRef(factory);
|
|
return { reference: factory, diDeps: this._getDependenciesMetadata(factory, dependencies) };
|
|
};
|
|
/**
|
|
* Gets the metadata for the given pipe.
|
|
* This assumes `loadNgModuleDirectiveAndPipeMetadata` has been called first.
|
|
*/
|
|
CompileMetadataResolver.prototype.getPipeMetadata = function (pipeType) {
|
|
var pipeMeta = this._pipeCache.get(pipeType);
|
|
if (!pipeMeta) {
|
|
this._reportError(syntaxError("Illegal state: getPipeMetadata can only be called after loadNgModuleDirectiveAndPipeMetadata for a module that declares it. Pipe " + stringifyType(pipeType) + "."), pipeType);
|
|
}
|
|
return pipeMeta || null;
|
|
};
|
|
CompileMetadataResolver.prototype.getPipeSummary = function (pipeType) {
|
|
var pipeSummary = this._loadSummary(pipeType, exports.CompileSummaryKind.Pipe);
|
|
if (!pipeSummary) {
|
|
this._reportError(syntaxError("Illegal state: Could not load the summary for pipe " + stringifyType(pipeType) + "."), pipeType);
|
|
}
|
|
return pipeSummary;
|
|
};
|
|
CompileMetadataResolver.prototype.getOrLoadPipeMetadata = function (pipeType) {
|
|
var pipeMeta = this._pipeCache.get(pipeType);
|
|
if (!pipeMeta) {
|
|
pipeMeta = this._loadPipeMetadata(pipeType);
|
|
}
|
|
return pipeMeta;
|
|
};
|
|
CompileMetadataResolver.prototype._loadPipeMetadata = function (pipeType) {
|
|
pipeType = resolveForwardRef(pipeType);
|
|
var pipeAnnotation = this._pipeResolver.resolve(pipeType);
|
|
var pipeMeta = new CompilePipeMetadata({
|
|
type: this._getTypeMetadata(pipeType),
|
|
name: pipeAnnotation.name,
|
|
pure: !!pipeAnnotation.pure
|
|
});
|
|
this._pipeCache.set(pipeType, pipeMeta);
|
|
this._summaryCache.set(pipeType, pipeMeta.toSummary());
|
|
return pipeMeta;
|
|
};
|
|
CompileMetadataResolver.prototype._getDependenciesMetadata = function (typeOrFunc, dependencies, throwOnUnknownDeps) {
|
|
var _this = this;
|
|
if (throwOnUnknownDeps === void 0) { throwOnUnknownDeps = true; }
|
|
var hasUnknownDeps = false;
|
|
var params = dependencies || this._reflector.parameters(typeOrFunc) || [];
|
|
var dependenciesMetadata = params.map(function (param) {
|
|
var isAttribute = false;
|
|
var isHost = false;
|
|
var isSelf = false;
|
|
var isSkipSelf = false;
|
|
var isOptional = false;
|
|
var token = null;
|
|
if (Array.isArray(param)) {
|
|
param.forEach(function (paramEntry) {
|
|
if (createHost.isTypeOf(paramEntry)) {
|
|
isHost = true;
|
|
}
|
|
else if (createSelf.isTypeOf(paramEntry)) {
|
|
isSelf = true;
|
|
}
|
|
else if (createSkipSelf.isTypeOf(paramEntry)) {
|
|
isSkipSelf = true;
|
|
}
|
|
else if (createOptional.isTypeOf(paramEntry)) {
|
|
isOptional = true;
|
|
}
|
|
else if (createAttribute.isTypeOf(paramEntry)) {
|
|
isAttribute = true;
|
|
token = paramEntry.attributeName;
|
|
}
|
|
else if (createInject.isTypeOf(paramEntry)) {
|
|
token = paramEntry.token;
|
|
}
|
|
else if (createInjectionToken.isTypeOf(paramEntry) ||
|
|
paramEntry instanceof StaticSymbol) {
|
|
token = paramEntry;
|
|
}
|
|
else if (isValidType(paramEntry) && token == null) {
|
|
token = paramEntry;
|
|
}
|
|
});
|
|
}
|
|
else {
|
|
token = param;
|
|
}
|
|
if (token == null) {
|
|
hasUnknownDeps = true;
|
|
return {};
|
|
}
|
|
return {
|
|
isAttribute: isAttribute,
|
|
isHost: isHost,
|
|
isSelf: isSelf,
|
|
isSkipSelf: isSkipSelf,
|
|
isOptional: isOptional,
|
|
token: _this._getTokenMetadata(token)
|
|
};
|
|
});
|
|
if (hasUnknownDeps) {
|
|
var depsTokens = dependenciesMetadata.map(function (dep) { return dep.token ? stringifyType(dep.token) : '?'; }).join(', ');
|
|
var message = "Can't resolve all parameters for " + stringifyType(typeOrFunc) + ": (" + depsTokens + ").";
|
|
if (throwOnUnknownDeps || this._config.strictInjectionParameters) {
|
|
this._reportError(syntaxError(message), typeOrFunc);
|
|
}
|
|
}
|
|
return dependenciesMetadata;
|
|
};
|
|
CompileMetadataResolver.prototype._getTokenMetadata = function (token) {
|
|
token = resolveForwardRef(token);
|
|
var compileToken;
|
|
if (typeof token === 'string') {
|
|
compileToken = { value: token };
|
|
}
|
|
else {
|
|
compileToken = { identifier: { reference: token } };
|
|
}
|
|
return compileToken;
|
|
};
|
|
CompileMetadataResolver.prototype._getProvidersMetadata = function (providers, targetEntryComponents, debugInfo, compileProviders, type) {
|
|
var _this = this;
|
|
if (compileProviders === void 0) { compileProviders = []; }
|
|
providers.forEach(function (provider, providerIdx) {
|
|
if (Array.isArray(provider)) {
|
|
_this._getProvidersMetadata(provider, targetEntryComponents, debugInfo, compileProviders);
|
|
}
|
|
else {
|
|
provider = resolveForwardRef(provider);
|
|
var providerMeta = undefined;
|
|
if (provider && typeof provider === 'object' && provider.hasOwnProperty('provide')) {
|
|
_this._validateProvider(provider);
|
|
providerMeta = new ProviderMeta(provider.provide, provider);
|
|
}
|
|
else if (isValidType(provider)) {
|
|
providerMeta = new ProviderMeta(provider, { useClass: provider });
|
|
}
|
|
else if (provider === void 0) {
|
|
_this._reportError(syntaxError("Encountered undefined provider! Usually this means you have a circular dependencies. This might be caused by using 'barrel' index.ts files."));
|
|
return;
|
|
}
|
|
else {
|
|
var providersInfo = providers
|
|
.reduce(function (soFar, seenProvider, seenProviderIdx) {
|
|
if (seenProviderIdx < providerIdx) {
|
|
soFar.push("" + stringifyType(seenProvider));
|
|
}
|
|
else if (seenProviderIdx == providerIdx) {
|
|
soFar.push("?" + stringifyType(seenProvider) + "?");
|
|
}
|
|
else if (seenProviderIdx == providerIdx + 1) {
|
|
soFar.push('...');
|
|
}
|
|
return soFar;
|
|
}, [])
|
|
.join(', ');
|
|
_this._reportError(syntaxError("Invalid " + (debugInfo ?
|
|
debugInfo :
|
|
'provider') + " - only instances of Provider and Type are allowed, got: [" + providersInfo + "]"), type);
|
|
return;
|
|
}
|
|
if (providerMeta.token ===
|
|
_this._reflector.resolveExternalReference(Identifiers$1.ANALYZE_FOR_ENTRY_COMPONENTS)) {
|
|
targetEntryComponents.push.apply(targetEntryComponents, __spreadArray([], __read(_this._getEntryComponentsFromProvider(providerMeta, type))));
|
|
}
|
|
else {
|
|
compileProviders.push(_this.getProviderMetadata(providerMeta));
|
|
}
|
|
}
|
|
});
|
|
return compileProviders;
|
|
};
|
|
CompileMetadataResolver.prototype._validateProvider = function (provider) {
|
|
if (provider.hasOwnProperty('useClass') && provider.useClass == null) {
|
|
this._reportError(syntaxError("Invalid provider for " + stringifyType(provider.provide) + ". useClass cannot be " + provider.useClass + ".\n Usually it happens when:\n 1. There's a circular dependency (might be caused by using index.ts (barrel) files).\n 2. Class was used before it was declared. Use forwardRef in this case."));
|
|
}
|
|
};
|
|
CompileMetadataResolver.prototype._getEntryComponentsFromProvider = function (provider, type) {
|
|
var _this = this;
|
|
var components = [];
|
|
var collectedIdentifiers = [];
|
|
if (provider.useFactory || provider.useExisting || provider.useClass) {
|
|
this._reportError(syntaxError("The ANALYZE_FOR_ENTRY_COMPONENTS token only supports useValue!"), type);
|
|
return [];
|
|
}
|
|
if (!provider.multi) {
|
|
this._reportError(syntaxError("The ANALYZE_FOR_ENTRY_COMPONENTS token only supports 'multi = true'!"), type);
|
|
return [];
|
|
}
|
|
extractIdentifiers(provider.useValue, collectedIdentifiers);
|
|
collectedIdentifiers.forEach(function (identifier) {
|
|
var entry = _this._getEntryComponentMetadata(identifier.reference, false);
|
|
if (entry) {
|
|
components.push(entry);
|
|
}
|
|
});
|
|
return components;
|
|
};
|
|
CompileMetadataResolver.prototype._getEntryComponentMetadata = function (dirType, throwIfNotFound) {
|
|
if (throwIfNotFound === void 0) { throwIfNotFound = true; }
|
|
var dirMeta = this.getNonNormalizedDirectiveMetadata(dirType);
|
|
if (dirMeta && dirMeta.metadata.isComponent) {
|
|
return { componentType: dirType, componentFactory: dirMeta.metadata.componentFactory };
|
|
}
|
|
var dirSummary = this._loadSummary(dirType, exports.CompileSummaryKind.Directive);
|
|
if (dirSummary && dirSummary.isComponent) {
|
|
return { componentType: dirType, componentFactory: dirSummary.componentFactory };
|
|
}
|
|
if (throwIfNotFound) {
|
|
throw syntaxError(dirType.name + " cannot be used as an entry component.");
|
|
}
|
|
return null;
|
|
};
|
|
CompileMetadataResolver.prototype._getInjectableTypeMetadata = function (type, dependencies) {
|
|
if (dependencies === void 0) { dependencies = null; }
|
|
var typeSummary = this._loadSummary(type, exports.CompileSummaryKind.Injectable);
|
|
if (typeSummary) {
|
|
return typeSummary.type;
|
|
}
|
|
return this._getTypeMetadata(type, dependencies);
|
|
};
|
|
CompileMetadataResolver.prototype.getProviderMetadata = function (provider) {
|
|
var compileDeps = undefined;
|
|
var compileTypeMetadata = null;
|
|
var compileFactoryMetadata = null;
|
|
var token = this._getTokenMetadata(provider.token);
|
|
if (provider.useClass) {
|
|
compileTypeMetadata =
|
|
this._getInjectableTypeMetadata(provider.useClass, provider.dependencies);
|
|
compileDeps = compileTypeMetadata.diDeps;
|
|
if (provider.token === provider.useClass) {
|
|
// use the compileTypeMetadata as it contains information about lifecycleHooks...
|
|
token = { identifier: compileTypeMetadata };
|
|
}
|
|
}
|
|
else if (provider.useFactory) {
|
|
compileFactoryMetadata = this._getFactoryMetadata(provider.useFactory, provider.dependencies);
|
|
compileDeps = compileFactoryMetadata.diDeps;
|
|
}
|
|
return {
|
|
token: token,
|
|
useClass: compileTypeMetadata,
|
|
useValue: provider.useValue,
|
|
useFactory: compileFactoryMetadata,
|
|
useExisting: provider.useExisting ? this._getTokenMetadata(provider.useExisting) : undefined,
|
|
deps: compileDeps,
|
|
multi: provider.multi
|
|
};
|
|
};
|
|
CompileMetadataResolver.prototype._getQueriesMetadata = function (queries, isViewQuery, directiveType) {
|
|
var _this = this;
|
|
var res = [];
|
|
Object.keys(queries).forEach(function (propertyName) {
|
|
var query = queries[propertyName];
|
|
if (query.isViewQuery === isViewQuery) {
|
|
res.push(_this._getQueryMetadata(query, propertyName, directiveType));
|
|
}
|
|
});
|
|
return res;
|
|
};
|
|
CompileMetadataResolver.prototype._queryVarBindings = function (selector) {
|
|
return selector.split(/\s*,\s*/);
|
|
};
|
|
CompileMetadataResolver.prototype._getQueryMetadata = function (q, propertyName, typeOrFunc) {
|
|
var _this = this;
|
|
var selectors;
|
|
if (typeof q.selector === 'string') {
|
|
selectors =
|
|
this._queryVarBindings(q.selector).map(function (varName) { return _this._getTokenMetadata(varName); });
|
|
}
|
|
else {
|
|
if (!q.selector) {
|
|
this._reportError(syntaxError("Can't construct a query for the property \"" + propertyName + "\" of \"" + stringifyType(typeOrFunc) + "\" since the query selector wasn't defined."), typeOrFunc);
|
|
selectors = [];
|
|
}
|
|
else {
|
|
selectors = [this._getTokenMetadata(q.selector)];
|
|
}
|
|
}
|
|
return {
|
|
selectors: selectors,
|
|
first: q.first,
|
|
descendants: q.descendants,
|
|
emitDistinctChangesOnly: q.emitDistinctChangesOnly,
|
|
propertyName: propertyName,
|
|
read: q.read ? this._getTokenMetadata(q.read) : null,
|
|
static: q.static
|
|
};
|
|
};
|
|
CompileMetadataResolver.prototype._reportError = function (error, type, otherType) {
|
|
if (this._errorCollector) {
|
|
this._errorCollector(error, type);
|
|
if (otherType) {
|
|
this._errorCollector(error, otherType);
|
|
}
|
|
}
|
|
else {
|
|
throw error;
|
|
}
|
|
};
|
|
return CompileMetadataResolver;
|
|
}());
|
|
function flattenArray(tree, out) {
|
|
if (out === void 0) { out = []; }
|
|
if (tree) {
|
|
for (var i = 0; i < tree.length; i++) {
|
|
var item = resolveForwardRef(tree[i]);
|
|
if (Array.isArray(item)) {
|
|
flattenArray(item, out);
|
|
}
|
|
else {
|
|
out.push(item);
|
|
}
|
|
}
|
|
}
|
|
return out;
|
|
}
|
|
function dedupeArray(array) {
|
|
if (array) {
|
|
return Array.from(new Set(array));
|
|
}
|
|
return [];
|
|
}
|
|
function flattenAndDedupeArray(tree) {
|
|
return dedupeArray(flattenArray(tree));
|
|
}
|
|
function isValidType(value) {
|
|
return (value instanceof StaticSymbol) || (value instanceof Type);
|
|
}
|
|
function extractIdentifiers(value, targetIdentifiers) {
|
|
visitValue(value, new _CompileValueConverter(), targetIdentifiers);
|
|
}
|
|
var _CompileValueConverter = /** @class */ (function (_super) {
|
|
__extends(_CompileValueConverter, _super);
|
|
function _CompileValueConverter() {
|
|
return _super !== null && _super.apply(this, arguments) || this;
|
|
}
|
|
_CompileValueConverter.prototype.visitOther = function (value, targetIdentifiers) {
|
|
targetIdentifiers.push({ reference: value });
|
|
};
|
|
return _CompileValueConverter;
|
|
}(ValueTransformer));
|
|
function stringifyType(type) {
|
|
if (type instanceof StaticSymbol) {
|
|
return type.name + " in " + type.filePath;
|
|
}
|
|
else {
|
|
return stringify(type);
|
|
}
|
|
}
|
|
/**
|
|
* Indicates that a component is still being loaded in a synchronous compile.
|
|
*/
|
|
function componentStillLoadingError(compType) {
|
|
var error = Error("Can't compile synchronously as " + stringify(compType) + " is still being loaded!");
|
|
error[ERROR_COMPONENT_TYPE] = compType;
|
|
return error;
|
|
}
|
|
|
|
/**
|
|
* @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 providerDef(ctx, providerAst) {
|
|
var flags = 0 /* None */;
|
|
if (!providerAst.eager) {
|
|
flags |= 4096 /* LazyProvider */;
|
|
}
|
|
if (providerAst.providerType === exports.ProviderAstType.PrivateService) {
|
|
flags |= 8192 /* PrivateProvider */;
|
|
}
|
|
if (providerAst.isModule) {
|
|
flags |= 1073741824 /* TypeModuleProvider */;
|
|
}
|
|
providerAst.lifecycleHooks.forEach(function (lifecycleHook) {
|
|
// for regular providers, we only support ngOnDestroy
|
|
if (lifecycleHook === LifecycleHooks.OnDestroy ||
|
|
providerAst.providerType === exports.ProviderAstType.Directive ||
|
|
providerAst.providerType === exports.ProviderAstType.Component) {
|
|
flags |= lifecycleHookToNodeFlag(lifecycleHook);
|
|
}
|
|
});
|
|
var _a = providerAst.multiProvider ?
|
|
multiProviderDef(ctx, flags, providerAst.providers) :
|
|
singleProviderDef(ctx, flags, providerAst.providerType, providerAst.providers[0]), providerExpr = _a.providerExpr, providerFlags = _a.flags, depsExpr = _a.depsExpr;
|
|
return {
|
|
providerExpr: providerExpr,
|
|
flags: providerFlags,
|
|
depsExpr: depsExpr,
|
|
tokenExpr: tokenExpr(ctx, providerAst.token),
|
|
};
|
|
}
|
|
function multiProviderDef(ctx, flags, providers) {
|
|
var allDepDefs = [];
|
|
var allParams = [];
|
|
var exprs = providers.map(function (provider, providerIndex) {
|
|
var expr;
|
|
if (provider.useClass) {
|
|
var depExprs = convertDeps(providerIndex, provider.deps || provider.useClass.diDeps);
|
|
expr = ctx.importExpr(provider.useClass.reference).instantiate(depExprs);
|
|
}
|
|
else if (provider.useFactory) {
|
|
var depExprs = convertDeps(providerIndex, provider.deps || provider.useFactory.diDeps);
|
|
expr = ctx.importExpr(provider.useFactory.reference).callFn(depExprs);
|
|
}
|
|
else if (provider.useExisting) {
|
|
var depExprs = convertDeps(providerIndex, [{ token: provider.useExisting }]);
|
|
expr = depExprs[0];
|
|
}
|
|
else {
|
|
expr = convertValueToOutputAst(ctx, provider.useValue);
|
|
}
|
|
return expr;
|
|
});
|
|
var providerExpr = fn(allParams, [new ReturnStatement(literalArr(exprs))], INFERRED_TYPE);
|
|
return {
|
|
providerExpr: providerExpr,
|
|
flags: flags | 1024 /* TypeFactoryProvider */,
|
|
depsExpr: literalArr(allDepDefs)
|
|
};
|
|
function convertDeps(providerIndex, deps) {
|
|
return deps.map(function (dep, depIndex) {
|
|
var paramName = "p" + providerIndex + "_" + depIndex;
|
|
allParams.push(new FnParam(paramName, DYNAMIC_TYPE));
|
|
allDepDefs.push(depDef(ctx, dep));
|
|
return variable(paramName);
|
|
});
|
|
}
|
|
}
|
|
function singleProviderDef(ctx, flags, providerType, providerMeta) {
|
|
var providerExpr;
|
|
var deps;
|
|
if (providerType === exports.ProviderAstType.Directive || providerType === exports.ProviderAstType.Component) {
|
|
providerExpr = ctx.importExpr(providerMeta.useClass.reference);
|
|
flags |= 16384 /* TypeDirective */;
|
|
deps = providerMeta.deps || providerMeta.useClass.diDeps;
|
|
}
|
|
else {
|
|
if (providerMeta.useClass) {
|
|
providerExpr = ctx.importExpr(providerMeta.useClass.reference);
|
|
flags |= 512 /* TypeClassProvider */;
|
|
deps = providerMeta.deps || providerMeta.useClass.diDeps;
|
|
}
|
|
else if (providerMeta.useFactory) {
|
|
providerExpr = ctx.importExpr(providerMeta.useFactory.reference);
|
|
flags |= 1024 /* TypeFactoryProvider */;
|
|
deps = providerMeta.deps || providerMeta.useFactory.diDeps;
|
|
}
|
|
else if (providerMeta.useExisting) {
|
|
providerExpr = NULL_EXPR;
|
|
flags |= 2048 /* TypeUseExistingProvider */;
|
|
deps = [{ token: providerMeta.useExisting }];
|
|
}
|
|
else {
|
|
providerExpr = convertValueToOutputAst(ctx, providerMeta.useValue);
|
|
flags |= 256 /* TypeValueProvider */;
|
|
deps = [];
|
|
}
|
|
}
|
|
var depsExpr = literalArr(deps.map(function (dep) { return depDef(ctx, dep); }));
|
|
return { providerExpr: providerExpr, flags: flags, depsExpr: depsExpr };
|
|
}
|
|
function tokenExpr(ctx, tokenMeta) {
|
|
return tokenMeta.identifier ? ctx.importExpr(tokenMeta.identifier.reference) :
|
|
literal(tokenMeta.value);
|
|
}
|
|
function depDef(ctx, dep) {
|
|
// Note: the following fields have already been normalized out by provider_analyzer:
|
|
// - isAttribute, isHost
|
|
var expr = dep.isValue ? convertValueToOutputAst(ctx, dep.value) : tokenExpr(ctx, dep.token);
|
|
var flags = 0 /* None */;
|
|
if (dep.isSkipSelf) {
|
|
flags |= 1 /* SkipSelf */;
|
|
}
|
|
if (dep.isOptional) {
|
|
flags |= 2 /* Optional */;
|
|
}
|
|
if (dep.isSelf) {
|
|
flags |= 4 /* Self */;
|
|
}
|
|
if (dep.isValue) {
|
|
flags |= 8 /* Value */;
|
|
}
|
|
return flags === 0 /* None */ ? expr : literalArr([literal(flags), expr]);
|
|
}
|
|
function lifecycleHookToNodeFlag(lifecycleHook) {
|
|
var nodeFlag = 0 /* None */;
|
|
switch (lifecycleHook) {
|
|
case LifecycleHooks.AfterContentChecked:
|
|
nodeFlag = 2097152 /* AfterContentChecked */;
|
|
break;
|
|
case LifecycleHooks.AfterContentInit:
|
|
nodeFlag = 1048576 /* AfterContentInit */;
|
|
break;
|
|
case LifecycleHooks.AfterViewChecked:
|
|
nodeFlag = 8388608 /* AfterViewChecked */;
|
|
break;
|
|
case LifecycleHooks.AfterViewInit:
|
|
nodeFlag = 4194304 /* AfterViewInit */;
|
|
break;
|
|
case LifecycleHooks.DoCheck:
|
|
nodeFlag = 262144 /* DoCheck */;
|
|
break;
|
|
case LifecycleHooks.OnChanges:
|
|
nodeFlag = 524288 /* OnChanges */;
|
|
break;
|
|
case LifecycleHooks.OnDestroy:
|
|
nodeFlag = 131072 /* OnDestroy */;
|
|
break;
|
|
case LifecycleHooks.OnInit:
|
|
nodeFlag = 65536 /* OnInit */;
|
|
break;
|
|
}
|
|
return nodeFlag;
|
|
}
|
|
function componentFactoryResolverProviderDef(reflector, ctx, flags, entryComponents) {
|
|
var entryComponentFactories = entryComponents.map(function (entryComponent) { return ctx.importExpr(entryComponent.componentFactory); });
|
|
var token = createTokenForExternalReference(reflector, Identifiers$1.ComponentFactoryResolver);
|
|
var classMeta = {
|
|
diDeps: [
|
|
{ isValue: true, value: literalArr(entryComponentFactories) },
|
|
{ token: token, isSkipSelf: true, isOptional: true },
|
|
{ token: createTokenForExternalReference(reflector, Identifiers$1.NgModuleRef) },
|
|
],
|
|
lifecycleHooks: [],
|
|
reference: reflector.resolveExternalReference(Identifiers$1.CodegenComponentFactoryResolver)
|
|
};
|
|
var _a = singleProviderDef(ctx, flags, exports.ProviderAstType.PrivateService, {
|
|
token: token,
|
|
multi: false,
|
|
useClass: classMeta,
|
|
}), providerExpr = _a.providerExpr, providerFlags = _a.flags, depsExpr = _a.depsExpr;
|
|
return { providerExpr: providerExpr, flags: providerFlags, depsExpr: depsExpr, tokenExpr: tokenExpr(ctx, token) };
|
|
}
|
|
|
|
/**
|
|
* @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 NgModuleCompileResult = /** @class */ (function () {
|
|
function NgModuleCompileResult(ngModuleFactoryVar) {
|
|
this.ngModuleFactoryVar = ngModuleFactoryVar;
|
|
}
|
|
return NgModuleCompileResult;
|
|
}());
|
|
var LOG_VAR = variable('_l');
|
|
var NgModuleCompiler = /** @class */ (function () {
|
|
function NgModuleCompiler(reflector) {
|
|
this.reflector = reflector;
|
|
}
|
|
NgModuleCompiler.prototype.compile = function (ctx, ngModuleMeta, extraProviders) {
|
|
var sourceSpan = typeSourceSpan('NgModule', ngModuleMeta.type);
|
|
var entryComponentFactories = ngModuleMeta.transitiveModule.entryComponents;
|
|
var bootstrapComponents = ngModuleMeta.bootstrapComponents;
|
|
var providerParser = new NgModuleProviderAnalyzer(this.reflector, ngModuleMeta, extraProviders, sourceSpan);
|
|
var providerDefs = [componentFactoryResolverProviderDef(this.reflector, ctx, 0 /* None */, entryComponentFactories)]
|
|
.concat(providerParser.parse().map(function (provider) { return providerDef(ctx, provider); }))
|
|
.map(function (_a) {
|
|
var providerExpr = _a.providerExpr, depsExpr = _a.depsExpr, flags = _a.flags, tokenExpr = _a.tokenExpr;
|
|
return importExpr(Identifiers$1.moduleProviderDef).callFn([
|
|
literal(flags), tokenExpr, providerExpr, depsExpr
|
|
]);
|
|
});
|
|
var ngModuleDef = importExpr(Identifiers$1.moduleDef).callFn([literalArr(providerDefs)]);
|
|
var ngModuleDefFactory = fn([new FnParam(LOG_VAR.name)], [new ReturnStatement(ngModuleDef)], INFERRED_TYPE);
|
|
var ngModuleFactoryVar = identifierName(ngModuleMeta.type) + "NgFactory";
|
|
this._createNgModuleFactory(ctx, ngModuleMeta.type.reference, importExpr(Identifiers$1.createModuleFactory).callFn([
|
|
ctx.importExpr(ngModuleMeta.type.reference),
|
|
literalArr(bootstrapComponents.map(function (id) { return ctx.importExpr(id.reference); })),
|
|
ngModuleDefFactory
|
|
]));
|
|
if (ngModuleMeta.id) {
|
|
var id = typeof ngModuleMeta.id === 'string' ? literal(ngModuleMeta.id) :
|
|
ctx.importExpr(ngModuleMeta.id);
|
|
var registerFactoryStmt = importExpr(Identifiers$1.RegisterModuleFactoryFn)
|
|
.callFn([id, variable(ngModuleFactoryVar)])
|
|
.toStmt();
|
|
ctx.statements.push(registerFactoryStmt);
|
|
}
|
|
return new NgModuleCompileResult(ngModuleFactoryVar);
|
|
};
|
|
NgModuleCompiler.prototype.createStub = function (ctx, ngModuleReference) {
|
|
this._createNgModuleFactory(ctx, ngModuleReference, NULL_EXPR);
|
|
};
|
|
NgModuleCompiler.prototype._createNgModuleFactory = function (ctx, reference, value) {
|
|
var ngModuleFactoryVar = identifierName({ reference: reference }) + "NgFactory";
|
|
var ngModuleFactoryStmt = variable(ngModuleFactoryVar)
|
|
.set(value)
|
|
.toDeclStmt(importType(Identifiers$1.NgModuleFactory, [expressionType(ctx.importExpr(reference))], [TypeModifier.Const]), [exports.StmtModifier.Final, exports.StmtModifier.Exported]);
|
|
ctx.statements.push(ngModuleFactoryStmt);
|
|
};
|
|
return NgModuleCompiler;
|
|
}());
|
|
|
|
/**
|
|
* @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
|
|
*/
|
|
/**
|
|
* Resolves types to {@link NgModule}.
|
|
*/
|
|
var NgModuleResolver = /** @class */ (function () {
|
|
function NgModuleResolver(_reflector) {
|
|
this._reflector = _reflector;
|
|
}
|
|
NgModuleResolver.prototype.isNgModule = function (type) {
|
|
return this._reflector.annotations(type).some(createNgModule.isTypeOf);
|
|
};
|
|
NgModuleResolver.prototype.resolve = function (type, throwIfNotFound) {
|
|
if (throwIfNotFound === void 0) { throwIfNotFound = true; }
|
|
var ngModuleMeta = findLast(this._reflector.annotations(type), createNgModule.isTypeOf);
|
|
if (ngModuleMeta) {
|
|
return ngModuleMeta;
|
|
}
|
|
else {
|
|
if (throwIfNotFound) {
|
|
throw new Error("No NgModule metadata found for '" + stringify(type) + "'.");
|
|
}
|
|
return null;
|
|
}
|
|
};
|
|
return NgModuleResolver;
|
|
}());
|
|
|
|
function debugOutputAstAsTypeScript(ast) {
|
|
var converter = new _TsEmitterVisitor();
|
|
var ctx = EmitterVisitorContext.createRoot();
|
|
var asts = Array.isArray(ast) ? ast : [ast];
|
|
asts.forEach(function (ast) {
|
|
if (ast instanceof Statement) {
|
|
ast.visitStatement(converter, ctx);
|
|
}
|
|
else if (ast instanceof Expression) {
|
|
ast.visitExpression(converter, ctx);
|
|
}
|
|
else if (ast instanceof Type$1) {
|
|
ast.visitType(converter, ctx);
|
|
}
|
|
else {
|
|
throw new Error("Don't know how to print debug info for " + ast);
|
|
}
|
|
});
|
|
return ctx.toSource();
|
|
}
|
|
var TypeScriptEmitter = /** @class */ (function () {
|
|
function TypeScriptEmitter() {
|
|
}
|
|
TypeScriptEmitter.prototype.emitStatementsAndContext = function (genFilePath, stmts, preamble, emitSourceMaps, referenceFilter, importFilter) {
|
|
if (preamble === void 0) { preamble = ''; }
|
|
if (emitSourceMaps === void 0) { emitSourceMaps = true; }
|
|
var converter = new _TsEmitterVisitor(referenceFilter, importFilter);
|
|
var ctx = EmitterVisitorContext.createRoot();
|
|
converter.visitAllStatements(stmts, ctx);
|
|
var preambleLines = preamble ? preamble.split('\n') : [];
|
|
converter.reexports.forEach(function (reexports, exportedModuleName) {
|
|
var reexportsCode = reexports.map(function (reexport) { return reexport.name + " as " + reexport.as; }).join(',');
|
|
preambleLines.push("export {" + reexportsCode + "} from '" + exportedModuleName + "';");
|
|
});
|
|
converter.importsWithPrefixes.forEach(function (prefix, importedModuleName) {
|
|
// Note: can't write the real word for import as it screws up system.js auto detection...
|
|
preambleLines.push("imp" +
|
|
("ort * as " + prefix + " from '" + importedModuleName + "';"));
|
|
});
|
|
var sm = emitSourceMaps ?
|
|
ctx.toSourceMapGenerator(genFilePath, preambleLines.length).toJsComment() :
|
|
'';
|
|
var lines = __spreadArray(__spreadArray([], __read(preambleLines)), [ctx.toSource(), sm]);
|
|
if (sm) {
|
|
// always add a newline at the end, as some tools have bugs without it.
|
|
lines.push('');
|
|
}
|
|
ctx.setPreambleLineCount(preambleLines.length);
|
|
return { sourceText: lines.join('\n'), context: ctx };
|
|
};
|
|
TypeScriptEmitter.prototype.emitStatements = function (genFilePath, stmts, preamble) {
|
|
if (preamble === void 0) { preamble = ''; }
|
|
return this.emitStatementsAndContext(genFilePath, stmts, preamble).sourceText;
|
|
};
|
|
return TypeScriptEmitter;
|
|
}());
|
|
var _TsEmitterVisitor = /** @class */ (function (_super) {
|
|
__extends(_TsEmitterVisitor, _super);
|
|
function _TsEmitterVisitor(referenceFilter, importFilter) {
|
|
var _this = _super.call(this, false) || this;
|
|
_this.referenceFilter = referenceFilter;
|
|
_this.importFilter = importFilter;
|
|
_this.typeExpression = 0;
|
|
_this.importsWithPrefixes = new Map();
|
|
_this.reexports = new Map();
|
|
return _this;
|
|
}
|
|
_TsEmitterVisitor.prototype.visitType = function (t, ctx, defaultType) {
|
|
if (defaultType === void 0) { defaultType = 'any'; }
|
|
if (t) {
|
|
this.typeExpression++;
|
|
t.visitType(this, ctx);
|
|
this.typeExpression--;
|
|
}
|
|
else {
|
|
ctx.print(null, defaultType);
|
|
}
|
|
};
|
|
_TsEmitterVisitor.prototype.visitLiteralExpr = function (ast, ctx) {
|
|
var value = ast.value;
|
|
if (value == null && ast.type != INFERRED_TYPE) {
|
|
ctx.print(ast, "(" + value + " as any)");
|
|
return null;
|
|
}
|
|
return _super.prototype.visitLiteralExpr.call(this, ast, ctx);
|
|
};
|
|
// Temporary workaround to support strictNullCheck enabled consumers of ngc emit.
|
|
// In SNC mode, [] have the type never[], so we cast here to any[].
|
|
// TODO: narrow the cast to a more explicit type, or use a pattern that does not
|
|
// start with [].concat. see https://github.com/angular/angular/pull/11846
|
|
_TsEmitterVisitor.prototype.visitLiteralArrayExpr = function (ast, ctx) {
|
|
if (ast.entries.length === 0) {
|
|
ctx.print(ast, '(');
|
|
}
|
|
var result = _super.prototype.visitLiteralArrayExpr.call(this, ast, ctx);
|
|
if (ast.entries.length === 0) {
|
|
ctx.print(ast, ' as any[])');
|
|
}
|
|
return result;
|
|
};
|
|
_TsEmitterVisitor.prototype.visitExternalExpr = function (ast, ctx) {
|
|
this._visitIdentifier(ast.value, ast.typeParams, ctx);
|
|
return null;
|
|
};
|
|
_TsEmitterVisitor.prototype.visitAssertNotNullExpr = function (ast, ctx) {
|
|
var result = _super.prototype.visitAssertNotNullExpr.call(this, ast, ctx);
|
|
ctx.print(ast, '!');
|
|
return result;
|
|
};
|
|
_TsEmitterVisitor.prototype.visitDeclareVarStmt = function (stmt, ctx) {
|
|
if (stmt.hasModifier(exports.StmtModifier.Exported) && stmt.value instanceof ExternalExpr &&
|
|
!stmt.type) {
|
|
// check for a reexport
|
|
var _a = stmt.value.value, name = _a.name, moduleName = _a.moduleName;
|
|
if (moduleName) {
|
|
var reexports = this.reexports.get(moduleName);
|
|
if (!reexports) {
|
|
reexports = [];
|
|
this.reexports.set(moduleName, reexports);
|
|
}
|
|
reexports.push({ name: name, as: stmt.name });
|
|
return null;
|
|
}
|
|
}
|
|
if (stmt.hasModifier(exports.StmtModifier.Exported)) {
|
|
ctx.print(stmt, "export ");
|
|
}
|
|
if (stmt.hasModifier(exports.StmtModifier.Final)) {
|
|
ctx.print(stmt, "const");
|
|
}
|
|
else {
|
|
ctx.print(stmt, "var");
|
|
}
|
|
ctx.print(stmt, " " + stmt.name);
|
|
this._printColonType(stmt.type, ctx);
|
|
if (stmt.value) {
|
|
ctx.print(stmt, " = ");
|
|
stmt.value.visitExpression(this, ctx);
|
|
}
|
|
ctx.println(stmt, ";");
|
|
return null;
|
|
};
|
|
_TsEmitterVisitor.prototype.visitWrappedNodeExpr = function (ast, ctx) {
|
|
throw new Error('Cannot visit a WrappedNodeExpr when outputting Typescript.');
|
|
};
|
|
_TsEmitterVisitor.prototype.visitCastExpr = function (ast, ctx) {
|
|
ctx.print(ast, "(<");
|
|
ast.type.visitType(this, ctx);
|
|
ctx.print(ast, ">");
|
|
ast.value.visitExpression(this, ctx);
|
|
ctx.print(ast, ")");
|
|
return null;
|
|
};
|
|
_TsEmitterVisitor.prototype.visitInstantiateExpr = function (ast, ctx) {
|
|
ctx.print(ast, "new ");
|
|
this.typeExpression++;
|
|
ast.classExpr.visitExpression(this, ctx);
|
|
this.typeExpression--;
|
|
ctx.print(ast, "(");
|
|
this.visitAllExpressions(ast.args, ctx, ',');
|
|
ctx.print(ast, ")");
|
|
return null;
|
|
};
|
|
_TsEmitterVisitor.prototype.visitDeclareClassStmt = function (stmt, ctx) {
|
|
var _this = this;
|
|
ctx.pushClass(stmt);
|
|
if (stmt.hasModifier(exports.StmtModifier.Exported)) {
|
|
ctx.print(stmt, "export ");
|
|
}
|
|
ctx.print(stmt, "class " + stmt.name);
|
|
if (stmt.parent != null) {
|
|
ctx.print(stmt, " extends ");
|
|
this.typeExpression++;
|
|
stmt.parent.visitExpression(this, ctx);
|
|
this.typeExpression--;
|
|
}
|
|
ctx.println(stmt, " {");
|
|
ctx.incIndent();
|
|
stmt.fields.forEach(function (field) { return _this._visitClassField(field, ctx); });
|
|
if (stmt.constructorMethod != null) {
|
|
this._visitClassConstructor(stmt, ctx);
|
|
}
|
|
stmt.getters.forEach(function (getter) { return _this._visitClassGetter(getter, ctx); });
|
|
stmt.methods.forEach(function (method) { return _this._visitClassMethod(method, ctx); });
|
|
ctx.decIndent();
|
|
ctx.println(stmt, "}");
|
|
ctx.popClass();
|
|
return null;
|
|
};
|
|
_TsEmitterVisitor.prototype._visitClassField = function (field, ctx) {
|
|
if (field.hasModifier(exports.StmtModifier.Private)) {
|
|
// comment out as a workaround for #10967
|
|
ctx.print(null, "/*private*/ ");
|
|
}
|
|
if (field.hasModifier(exports.StmtModifier.Static)) {
|
|
ctx.print(null, 'static ');
|
|
}
|
|
ctx.print(null, field.name);
|
|
this._printColonType(field.type, ctx);
|
|
if (field.initializer) {
|
|
ctx.print(null, ' = ');
|
|
field.initializer.visitExpression(this, ctx);
|
|
}
|
|
ctx.println(null, ";");
|
|
};
|
|
_TsEmitterVisitor.prototype._visitClassGetter = function (getter, ctx) {
|
|
if (getter.hasModifier(exports.StmtModifier.Private)) {
|
|
ctx.print(null, "private ");
|
|
}
|
|
ctx.print(null, "get " + getter.name + "()");
|
|
this._printColonType(getter.type, ctx);
|
|
ctx.println(null, " {");
|
|
ctx.incIndent();
|
|
this.visitAllStatements(getter.body, ctx);
|
|
ctx.decIndent();
|
|
ctx.println(null, "}");
|
|
};
|
|
_TsEmitterVisitor.prototype._visitClassConstructor = function (stmt, ctx) {
|
|
ctx.print(stmt, "constructor(");
|
|
this._visitParams(stmt.constructorMethod.params, ctx);
|
|
ctx.println(stmt, ") {");
|
|
ctx.incIndent();
|
|
this.visitAllStatements(stmt.constructorMethod.body, ctx);
|
|
ctx.decIndent();
|
|
ctx.println(stmt, "}");
|
|
};
|
|
_TsEmitterVisitor.prototype._visitClassMethod = function (method, ctx) {
|
|
if (method.hasModifier(exports.StmtModifier.Private)) {
|
|
ctx.print(null, "private ");
|
|
}
|
|
ctx.print(null, method.name + "(");
|
|
this._visitParams(method.params, ctx);
|
|
ctx.print(null, ")");
|
|
this._printColonType(method.type, ctx, 'void');
|
|
ctx.println(null, " {");
|
|
ctx.incIndent();
|
|
this.visitAllStatements(method.body, ctx);
|
|
ctx.decIndent();
|
|
ctx.println(null, "}");
|
|
};
|
|
_TsEmitterVisitor.prototype.visitFunctionExpr = function (ast, ctx) {
|
|
if (ast.name) {
|
|
ctx.print(ast, 'function ');
|
|
ctx.print(ast, ast.name);
|
|
}
|
|
ctx.print(ast, "(");
|
|
this._visitParams(ast.params, ctx);
|
|
ctx.print(ast, ")");
|
|
this._printColonType(ast.type, ctx, 'void');
|
|
if (!ast.name) {
|
|
ctx.print(ast, " => ");
|
|
}
|
|
ctx.println(ast, '{');
|
|
ctx.incIndent();
|
|
this.visitAllStatements(ast.statements, ctx);
|
|
ctx.decIndent();
|
|
ctx.print(ast, "}");
|
|
return null;
|
|
};
|
|
_TsEmitterVisitor.prototype.visitDeclareFunctionStmt = function (stmt, ctx) {
|
|
if (stmt.hasModifier(exports.StmtModifier.Exported)) {
|
|
ctx.print(stmt, "export ");
|
|
}
|
|
ctx.print(stmt, "function " + stmt.name + "(");
|
|
this._visitParams(stmt.params, ctx);
|
|
ctx.print(stmt, ")");
|
|
this._printColonType(stmt.type, ctx, 'void');
|
|
ctx.println(stmt, " {");
|
|
ctx.incIndent();
|
|
this.visitAllStatements(stmt.statements, ctx);
|
|
ctx.decIndent();
|
|
ctx.println(stmt, "}");
|
|
return null;
|
|
};
|
|
_TsEmitterVisitor.prototype.visitTryCatchStmt = function (stmt, ctx) {
|
|
ctx.println(stmt, "try {");
|
|
ctx.incIndent();
|
|
this.visitAllStatements(stmt.bodyStmts, ctx);
|
|
ctx.decIndent();
|
|
ctx.println(stmt, "} catch (" + CATCH_ERROR_VAR$1.name + ") {");
|
|
ctx.incIndent();
|
|
var catchStmts = [CATCH_STACK_VAR$1.set(CATCH_ERROR_VAR$1.prop('stack', null)).toDeclStmt(null, [
|
|
exports.StmtModifier.Final
|
|
])].concat(stmt.catchStmts);
|
|
this.visitAllStatements(catchStmts, ctx);
|
|
ctx.decIndent();
|
|
ctx.println(stmt, "}");
|
|
return null;
|
|
};
|
|
_TsEmitterVisitor.prototype.visitBuiltinType = function (type, ctx) {
|
|
var typeStr;
|
|
switch (type.name) {
|
|
case exports.BuiltinTypeName.Bool:
|
|
typeStr = 'boolean';
|
|
break;
|
|
case exports.BuiltinTypeName.Dynamic:
|
|
typeStr = 'any';
|
|
break;
|
|
case exports.BuiltinTypeName.Function:
|
|
typeStr = 'Function';
|
|
break;
|
|
case exports.BuiltinTypeName.Number:
|
|
typeStr = 'number';
|
|
break;
|
|
case exports.BuiltinTypeName.Int:
|
|
typeStr = 'number';
|
|
break;
|
|
case exports.BuiltinTypeName.String:
|
|
typeStr = 'string';
|
|
break;
|
|
case exports.BuiltinTypeName.None:
|
|
typeStr = 'never';
|
|
break;
|
|
default:
|
|
throw new Error("Unsupported builtin type " + type.name);
|
|
}
|
|
ctx.print(null, typeStr);
|
|
return null;
|
|
};
|
|
_TsEmitterVisitor.prototype.visitExpressionType = function (ast, ctx) {
|
|
var _this = this;
|
|
ast.value.visitExpression(this, ctx);
|
|
if (ast.typeParams !== null) {
|
|
ctx.print(null, '<');
|
|
this.visitAllObjects(function (type) { return _this.visitType(type, ctx); }, ast.typeParams, ctx, ',');
|
|
ctx.print(null, '>');
|
|
}
|
|
return null;
|
|
};
|
|
_TsEmitterVisitor.prototype.visitArrayType = function (type, ctx) {
|
|
this.visitType(type.of, ctx);
|
|
ctx.print(null, "[]");
|
|
return null;
|
|
};
|
|
_TsEmitterVisitor.prototype.visitMapType = function (type, ctx) {
|
|
ctx.print(null, "{[key: string]:");
|
|
this.visitType(type.valueType, ctx);
|
|
ctx.print(null, "}");
|
|
return null;
|
|
};
|
|
_TsEmitterVisitor.prototype.getBuiltinMethodName = function (method) {
|
|
var name;
|
|
switch (method) {
|
|
case exports.BuiltinMethod.ConcatArray:
|
|
name = 'concat';
|
|
break;
|
|
case exports.BuiltinMethod.SubscribeObservable:
|
|
name = 'subscribe';
|
|
break;
|
|
case exports.BuiltinMethod.Bind:
|
|
name = 'bind';
|
|
break;
|
|
default:
|
|
throw new Error("Unknown builtin method: " + method);
|
|
}
|
|
return name;
|
|
};
|
|
_TsEmitterVisitor.prototype._visitParams = function (params, ctx) {
|
|
var _this = this;
|
|
this.visitAllObjects(function (param) {
|
|
ctx.print(null, param.name);
|
|
_this._printColonType(param.type, ctx);
|
|
}, params, ctx, ',');
|
|
};
|
|
_TsEmitterVisitor.prototype._visitIdentifier = function (value, typeParams, ctx) {
|
|
var _this = this;
|
|
var name = value.name, moduleName = value.moduleName;
|
|
if (this.referenceFilter && this.referenceFilter(value)) {
|
|
ctx.print(null, '(null as any)');
|
|
return;
|
|
}
|
|
if (moduleName && (!this.importFilter || !this.importFilter(value))) {
|
|
var prefix = this.importsWithPrefixes.get(moduleName);
|
|
if (prefix == null) {
|
|
prefix = "i" + this.importsWithPrefixes.size;
|
|
this.importsWithPrefixes.set(moduleName, prefix);
|
|
}
|
|
ctx.print(null, prefix + ".");
|
|
}
|
|
ctx.print(null, name);
|
|
if (this.typeExpression > 0) {
|
|
// If we are in a type expression that refers to a generic type then supply
|
|
// the required type parameters. If there were not enough type parameters
|
|
// supplied, supply any as the type. Outside a type expression the reference
|
|
// should not supply type parameters and be treated as a simple value reference
|
|
// to the constructor function itself.
|
|
var suppliedParameters = typeParams || [];
|
|
if (suppliedParameters.length > 0) {
|
|
ctx.print(null, "<");
|
|
this.visitAllObjects(function (type) { return type.visitType(_this, ctx); }, typeParams, ctx, ',');
|
|
ctx.print(null, ">");
|
|
}
|
|
}
|
|
};
|
|
_TsEmitterVisitor.prototype._printColonType = function (type, ctx, defaultType) {
|
|
if (type !== INFERRED_TYPE) {
|
|
ctx.print(null, ':');
|
|
this.visitType(type, ctx, defaultType);
|
|
}
|
|
};
|
|
return _TsEmitterVisitor;
|
|
}(AbstractEmitterVisitor));
|
|
|
|
/**
|
|
* @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
|
|
*/
|
|
/**
|
|
* Resolve a `Type` for {@link Pipe}.
|
|
*
|
|
* This interface can be overridden by the application developer to create custom behavior.
|
|
*
|
|
* See {@link Compiler}
|
|
*/
|
|
var PipeResolver = /** @class */ (function () {
|
|
function PipeResolver(_reflector) {
|
|
this._reflector = _reflector;
|
|
}
|
|
PipeResolver.prototype.isPipe = function (type) {
|
|
var typeMetadata = this._reflector.annotations(resolveForwardRef(type));
|
|
return typeMetadata && typeMetadata.some(createPipe.isTypeOf);
|
|
};
|
|
/**
|
|
* Return {@link Pipe} for a given `Type`.
|
|
*/
|
|
PipeResolver.prototype.resolve = function (type, throwIfNotFound) {
|
|
if (throwIfNotFound === void 0) { throwIfNotFound = true; }
|
|
var metas = this._reflector.annotations(resolveForwardRef(type));
|
|
if (metas) {
|
|
var annotation = findLast(metas, createPipe.isTypeOf);
|
|
if (annotation) {
|
|
return annotation;
|
|
}
|
|
}
|
|
if (throwIfNotFound) {
|
|
throw new Error("No Pipe decorator found on " + stringify(type));
|
|
}
|
|
return null;
|
|
};
|
|
return PipeResolver;
|
|
}());
|
|
|
|
/**
|
|
* Generates code that is used to type check templates.
|
|
*/
|
|
var TypeCheckCompiler = /** @class */ (function () {
|
|
function TypeCheckCompiler(options, reflector) {
|
|
this.options = options;
|
|
this.reflector = reflector;
|
|
}
|
|
/**
|
|
* Important notes:
|
|
* - This must not produce new `import` statements, but only refer to types outside
|
|
* of the file via the variables provided via externalReferenceVars.
|
|
* This allows Typescript to reuse the old program's structure as no imports have changed.
|
|
* - This must not produce any exports, as this would pollute the .d.ts file
|
|
* and also violate the point above.
|
|
*/
|
|
TypeCheckCompiler.prototype.compileComponent = function (componentId, component, template, usedPipes, externalReferenceVars, ctx) {
|
|
var _this = this;
|
|
var pipes = new Map();
|
|
usedPipes.forEach(function (p) { return pipes.set(p.name, p.type.reference); });
|
|
var embeddedViewCount = 0;
|
|
var viewBuilderFactory = function (parent, guards) {
|
|
var embeddedViewIndex = embeddedViewCount++;
|
|
return new ViewBuilder(_this.options, _this.reflector, externalReferenceVars, parent, component.type.reference, component.isHost, embeddedViewIndex, pipes, guards, ctx, viewBuilderFactory);
|
|
};
|
|
var visitor = viewBuilderFactory(null, []);
|
|
visitor.visitAll([], template);
|
|
return visitor.build(componentId);
|
|
};
|
|
return TypeCheckCompiler;
|
|
}());
|
|
var DYNAMIC_VAR_NAME = '_any';
|
|
var TypeCheckLocalResolver = /** @class */ (function () {
|
|
function TypeCheckLocalResolver() {
|
|
}
|
|
TypeCheckLocalResolver.prototype.notifyImplicitReceiverUse = function () { };
|
|
TypeCheckLocalResolver.prototype.maybeRestoreView = function () { };
|
|
TypeCheckLocalResolver.prototype.getLocal = function (name) {
|
|
if (name === EventHandlerVars.event.name) {
|
|
// References to the event should not be type-checked.
|
|
// TODO(chuckj): determine a better type for the event.
|
|
return variable(DYNAMIC_VAR_NAME);
|
|
}
|
|
return null;
|
|
};
|
|
return TypeCheckLocalResolver;
|
|
}());
|
|
var defaultResolver = new TypeCheckLocalResolver();
|
|
var ViewBuilder = /** @class */ (function () {
|
|
function ViewBuilder(options, reflector, externalReferenceVars, parent, component, isHostComponent, embeddedViewIndex, pipes, guards, ctx, viewBuilderFactory) {
|
|
this.options = options;
|
|
this.reflector = reflector;
|
|
this.externalReferenceVars = externalReferenceVars;
|
|
this.parent = parent;
|
|
this.component = component;
|
|
this.isHostComponent = isHostComponent;
|
|
this.embeddedViewIndex = embeddedViewIndex;
|
|
this.pipes = pipes;
|
|
this.guards = guards;
|
|
this.ctx = ctx;
|
|
this.viewBuilderFactory = viewBuilderFactory;
|
|
this.refOutputVars = new Map();
|
|
this.variables = [];
|
|
this.children = [];
|
|
this.updates = [];
|
|
this.actions = [];
|
|
}
|
|
ViewBuilder.prototype.getOutputVar = function (type) {
|
|
var varName;
|
|
if (type === this.component && this.isHostComponent) {
|
|
varName = DYNAMIC_VAR_NAME;
|
|
}
|
|
else if (type instanceof StaticSymbol) {
|
|
varName = this.externalReferenceVars.get(type);
|
|
}
|
|
else {
|
|
varName = DYNAMIC_VAR_NAME;
|
|
}
|
|
if (!varName) {
|
|
throw new Error("Illegal State: referring to a type without a variable " + JSON.stringify(type));
|
|
}
|
|
return varName;
|
|
};
|
|
ViewBuilder.prototype.getTypeGuardExpressions = function (ast) {
|
|
var e_1, _a, e_2, _b;
|
|
var result = __spreadArray([], __read(this.guards));
|
|
try {
|
|
for (var _c = __values(ast.directives), _d = _c.next(); !_d.done; _d = _c.next()) {
|
|
var directive = _d.value;
|
|
try {
|
|
for (var _e = (e_2 = void 0, __values(directive.inputs)), _f = _e.next(); !_f.done; _f = _e.next()) {
|
|
var input = _f.value;
|
|
var guard = directive.directive.guards[input.directiveName];
|
|
if (guard) {
|
|
var useIf = guard === 'UseIf';
|
|
result.push({
|
|
guard: guard,
|
|
useIf: useIf,
|
|
expression: {
|
|
context: this.component,
|
|
value: input.value,
|
|
sourceSpan: input.sourceSpan,
|
|
},
|
|
});
|
|
}
|
|
}
|
|
}
|
|
catch (e_2_1) { e_2 = { error: e_2_1 }; }
|
|
finally {
|
|
try {
|
|
if (_f && !_f.done && (_b = _e.return)) _b.call(_e);
|
|
}
|
|
finally { if (e_2) throw e_2.error; }
|
|
}
|
|
}
|
|
}
|
|
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
finally {
|
|
try {
|
|
if (_d && !_d.done && (_a = _c.return)) _a.call(_c);
|
|
}
|
|
finally { if (e_1) throw e_1.error; }
|
|
}
|
|
return result;
|
|
};
|
|
ViewBuilder.prototype.visitAll = function (variables, astNodes) {
|
|
this.variables = variables;
|
|
templateVisitAll(this, astNodes);
|
|
};
|
|
ViewBuilder.prototype.build = function (componentId, targetStatements) {
|
|
var e_3, _a;
|
|
var _this = this;
|
|
if (targetStatements === void 0) { targetStatements = []; }
|
|
this.children.forEach(function (child) { return child.build(componentId, targetStatements); });
|
|
var viewStmts = [variable(DYNAMIC_VAR_NAME).set(NULL_EXPR).toDeclStmt(DYNAMIC_TYPE)];
|
|
var bindingCount = 0;
|
|
this.updates.forEach(function (expression) {
|
|
var _a = _this.preprocessUpdateExpression(expression), sourceSpan = _a.sourceSpan, context = _a.context, value = _a.value;
|
|
var bindingId = "" + bindingCount++;
|
|
var nameResolver = context === _this.component ? _this : defaultResolver;
|
|
var _b = convertPropertyBinding(nameResolver, variable(_this.getOutputVar(context)), value, bindingId, BindingForm.General), stmts = _b.stmts, currValExpr = _b.currValExpr;
|
|
stmts.push(new ExpressionStatement(currValExpr));
|
|
viewStmts.push.apply(viewStmts, __spreadArray([], __read(stmts.map(function (stmt) { return applySourceSpanToStatementIfNeeded(stmt, sourceSpan); }))));
|
|
});
|
|
this.actions.forEach(function (_a) {
|
|
var sourceSpan = _a.sourceSpan, context = _a.context, value = _a.value;
|
|
var bindingId = "" + bindingCount++;
|
|
var nameResolver = context === _this.component ? _this : defaultResolver;
|
|
var stmts = convertActionBinding(nameResolver, variable(_this.getOutputVar(context)), value, bindingId).stmts;
|
|
viewStmts.push.apply(viewStmts, __spreadArray([], __read(stmts.map(function (stmt) { return applySourceSpanToStatementIfNeeded(stmt, sourceSpan); }))));
|
|
});
|
|
if (this.guards.length) {
|
|
var guardExpression = undefined;
|
|
try {
|
|
for (var _b = __values(this.guards), _c = _b.next(); !_c.done; _c = _b.next()) {
|
|
var guard = _c.value;
|
|
var _d = this.preprocessUpdateExpression(guard.expression), context = _d.context, value = _d.value;
|
|
var bindingId = "" + bindingCount++;
|
|
var nameResolver = context === this.component ? this : defaultResolver;
|
|
// We only support support simple expressions and ignore others as they
|
|
// are unlikely to affect type narrowing.
|
|
var _e = convertPropertyBinding(nameResolver, variable(this.getOutputVar(context)), value, bindingId, BindingForm.TrySimple), stmts = _e.stmts, currValExpr = _e.currValExpr;
|
|
if (stmts.length == 0) {
|
|
var guardClause = guard.useIf ? currValExpr : this.ctx.importExpr(guard.guard).callFn([currValExpr]);
|
|
guardExpression = guardExpression ? guardExpression.and(guardClause) : guardClause;
|
|
}
|
|
}
|
|
}
|
|
catch (e_3_1) { e_3 = { error: e_3_1 }; }
|
|
finally {
|
|
try {
|
|
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
|
|
}
|
|
finally { if (e_3) throw e_3.error; }
|
|
}
|
|
if (guardExpression) {
|
|
viewStmts = [new IfStmt(guardExpression, viewStmts)];
|
|
}
|
|
}
|
|
var viewName = "_View_" + componentId + "_" + this.embeddedViewIndex;
|
|
var viewFactory = new DeclareFunctionStmt(viewName, [], viewStmts);
|
|
targetStatements.push(viewFactory);
|
|
return targetStatements;
|
|
};
|
|
ViewBuilder.prototype.visitBoundText = function (ast, context) {
|
|
var _this = this;
|
|
var astWithSource = ast.value;
|
|
var inter = astWithSource.ast;
|
|
inter.expressions.forEach(function (expr) { return _this.updates.push({ context: _this.component, value: expr, sourceSpan: ast.sourceSpan }); });
|
|
};
|
|
ViewBuilder.prototype.visitEmbeddedTemplate = function (ast, context) {
|
|
this.visitElementOrTemplate(ast);
|
|
// Note: The old view compiler used to use an `any` type
|
|
// for the context in any embedded view.
|
|
// We keep this behaivor behind a flag for now.
|
|
if (this.options.fullTemplateTypeCheck) {
|
|
// Find any applicable type guards. For example, NgIf has a type guard on ngIf
|
|
// (see NgIf.ngIfTypeGuard) that can be used to indicate that a template is only
|
|
// stamped out if ngIf is truthy so any bindings in the template can assume that,
|
|
// if a nullable type is used for ngIf, that expression is not null or undefined.
|
|
var guards = this.getTypeGuardExpressions(ast);
|
|
var childVisitor = this.viewBuilderFactory(this, guards);
|
|
this.children.push(childVisitor);
|
|
childVisitor.visitAll(ast.variables, ast.children);
|
|
}
|
|
};
|
|
ViewBuilder.prototype.visitElement = function (ast, context) {
|
|
var _this = this;
|
|
this.visitElementOrTemplate(ast);
|
|
var inputDefs = [];
|
|
var updateRendererExpressions = [];
|
|
var outputDefs = [];
|
|
ast.inputs.forEach(function (inputAst) {
|
|
_this.updates.push({ context: _this.component, value: inputAst.value, sourceSpan: inputAst.sourceSpan });
|
|
});
|
|
templateVisitAll(this, ast.children);
|
|
};
|
|
ViewBuilder.prototype.visitElementOrTemplate = function (ast) {
|
|
var _this = this;
|
|
ast.directives.forEach(function (dirAst) {
|
|
_this.visitDirective(dirAst);
|
|
});
|
|
ast.references.forEach(function (ref) {
|
|
var outputVarType = null;
|
|
// Note: The old view compiler used to use an `any` type
|
|
// for directives exposed via `exportAs`.
|
|
// We keep this behaivor behind a flag for now.
|
|
if (ref.value && ref.value.identifier && _this.options.fullTemplateTypeCheck) {
|
|
outputVarType = ref.value.identifier.reference;
|
|
}
|
|
else {
|
|
outputVarType = exports.BuiltinTypeName.Dynamic;
|
|
}
|
|
_this.refOutputVars.set(ref.name, outputVarType);
|
|
});
|
|
ast.outputs.forEach(function (outputAst) {
|
|
_this.actions.push({ context: _this.component, value: outputAst.handler, sourceSpan: outputAst.sourceSpan });
|
|
});
|
|
};
|
|
ViewBuilder.prototype.visitDirective = function (dirAst) {
|
|
var _this = this;
|
|
var dirType = dirAst.directive.type.reference;
|
|
dirAst.inputs.forEach(function (input) { return _this.updates.push({ context: _this.component, value: input.value, sourceSpan: input.sourceSpan }); });
|
|
// Note: The old view compiler used to use an `any` type
|
|
// for expressions in host properties / events.
|
|
// We keep this behaivor behind a flag for now.
|
|
if (this.options.fullTemplateTypeCheck) {
|
|
dirAst.hostProperties.forEach(function (inputAst) { return _this.updates.push({ context: dirType, value: inputAst.value, sourceSpan: inputAst.sourceSpan }); });
|
|
dirAst.hostEvents.forEach(function (hostEventAst) { return _this.actions.push({
|
|
context: dirType,
|
|
value: hostEventAst.handler,
|
|
sourceSpan: hostEventAst.sourceSpan
|
|
}); });
|
|
}
|
|
};
|
|
ViewBuilder.prototype.notifyImplicitReceiverUse = function () { };
|
|
ViewBuilder.prototype.maybeRestoreView = function () { };
|
|
ViewBuilder.prototype.getLocal = function (name) {
|
|
if (name == EventHandlerVars.event.name) {
|
|
return variable(this.getOutputVar(exports.BuiltinTypeName.Dynamic));
|
|
}
|
|
for (var currBuilder = this; currBuilder; currBuilder = currBuilder.parent) {
|
|
var outputVarType = void 0;
|
|
// check references
|
|
outputVarType = currBuilder.refOutputVars.get(name);
|
|
if (outputVarType == null) {
|
|
// check variables
|
|
var varAst = currBuilder.variables.find(function (varAst) { return varAst.name === name; });
|
|
if (varAst) {
|
|
outputVarType = exports.BuiltinTypeName.Dynamic;
|
|
}
|
|
}
|
|
if (outputVarType != null) {
|
|
return variable(this.getOutputVar(outputVarType));
|
|
}
|
|
}
|
|
return null;
|
|
};
|
|
ViewBuilder.prototype.pipeOutputVar = function (name) {
|
|
var pipe = this.pipes.get(name);
|
|
if (!pipe) {
|
|
throw new Error("Illegal State: Could not find pipe " + name + " in template of " + this.component);
|
|
}
|
|
return this.getOutputVar(pipe);
|
|
};
|
|
ViewBuilder.prototype.preprocessUpdateExpression = function (expression) {
|
|
var _this = this;
|
|
return {
|
|
sourceSpan: expression.sourceSpan,
|
|
context: expression.context,
|
|
value: convertPropertyBindingBuiltins({
|
|
createLiteralArrayConverter: function (argCount) { return function (args) {
|
|
var arr = literalArr(args);
|
|
// Note: The old view compiler used to use an `any` type
|
|
// for arrays.
|
|
return _this.options.fullTemplateTypeCheck ? arr : arr.cast(DYNAMIC_TYPE);
|
|
}; },
|
|
createLiteralMapConverter: function (keys) { return function (values) {
|
|
var entries = keys.map(function (k, i) { return ({
|
|
key: k.key,
|
|
value: values[i],
|
|
quoted: k.quoted,
|
|
}); });
|
|
var map = literalMap(entries);
|
|
// Note: The old view compiler used to use an `any` type
|
|
// for maps.
|
|
return _this.options.fullTemplateTypeCheck ? map : map.cast(DYNAMIC_TYPE);
|
|
}; },
|
|
createPipeConverter: function (name, argCount) { return function (args) {
|
|
// Note: The old view compiler used to use an `any` type
|
|
// for pipes.
|
|
var pipeExpr = _this.options.fullTemplateTypeCheck ?
|
|
variable(_this.pipeOutputVar(name)) :
|
|
variable(_this.getOutputVar(exports.BuiltinTypeName.Dynamic));
|
|
return pipeExpr.callMethod('transform', args);
|
|
}; },
|
|
}, expression.value)
|
|
};
|
|
};
|
|
ViewBuilder.prototype.visitNgContent = function (ast, context) { };
|
|
ViewBuilder.prototype.visitText = function (ast, context) { };
|
|
ViewBuilder.prototype.visitDirectiveProperty = function (ast, context) { };
|
|
ViewBuilder.prototype.visitReference = function (ast, context) { };
|
|
ViewBuilder.prototype.visitVariable = function (ast, context) { };
|
|
ViewBuilder.prototype.visitEvent = function (ast, context) { };
|
|
ViewBuilder.prototype.visitElementProperty = function (ast, context) { };
|
|
ViewBuilder.prototype.visitAttr = function (ast, context) { };
|
|
return ViewBuilder;
|
|
}());
|
|
|
|
var CLASS_ATTR$1 = 'class';
|
|
var STYLE_ATTR = 'style';
|
|
var IMPLICIT_TEMPLATE_VAR = '$implicit';
|
|
var ViewCompileResult = /** @class */ (function () {
|
|
function ViewCompileResult(viewClassVar, rendererTypeVar) {
|
|
this.viewClassVar = viewClassVar;
|
|
this.rendererTypeVar = rendererTypeVar;
|
|
}
|
|
return ViewCompileResult;
|
|
}());
|
|
var ViewCompiler = /** @class */ (function () {
|
|
function ViewCompiler(_reflector) {
|
|
this._reflector = _reflector;
|
|
}
|
|
ViewCompiler.prototype.compileComponent = function (outputCtx, component, template, styles, usedPipes) {
|
|
var _a;
|
|
var _this = this;
|
|
var embeddedViewCount = 0;
|
|
var renderComponentVarName = undefined;
|
|
if (!component.isHost) {
|
|
var template_1 = component.template;
|
|
var customRenderData = [];
|
|
if (template_1.animations && template_1.animations.length) {
|
|
customRenderData.push(new LiteralMapEntry('animation', convertValueToOutputAst(outputCtx, template_1.animations), true));
|
|
}
|
|
var renderComponentVar = variable(rendererTypeName(component.type.reference));
|
|
renderComponentVarName = renderComponentVar.name;
|
|
outputCtx.statements.push(renderComponentVar
|
|
.set(importExpr(Identifiers$1.createRendererType2).callFn([new LiteralMapExpr([
|
|
new LiteralMapEntry('encapsulation', literal(template_1.encapsulation), false),
|
|
new LiteralMapEntry('styles', styles, false),
|
|
new LiteralMapEntry('data', new LiteralMapExpr(customRenderData), false)
|
|
])]))
|
|
.toDeclStmt(importType(Identifiers$1.RendererType2), [exports.StmtModifier.Final, exports.StmtModifier.Exported]));
|
|
}
|
|
var viewBuilderFactory = function (parent) {
|
|
var embeddedViewIndex = embeddedViewCount++;
|
|
return new ViewBuilder$1(_this._reflector, outputCtx, parent, component, embeddedViewIndex, usedPipes, viewBuilderFactory);
|
|
};
|
|
var visitor = viewBuilderFactory(null);
|
|
visitor.visitAll([], template);
|
|
(_a = outputCtx.statements).push.apply(_a, __spreadArray([], __read(visitor.build())));
|
|
return new ViewCompileResult(visitor.viewName, renderComponentVarName);
|
|
};
|
|
return ViewCompiler;
|
|
}());
|
|
var LOG_VAR$1 = variable('_l');
|
|
var VIEW_VAR = variable('_v');
|
|
var CHECK_VAR = variable('_ck');
|
|
var COMP_VAR = variable('_co');
|
|
var EVENT_NAME_VAR = variable('en');
|
|
var ALLOW_DEFAULT_VAR = variable("ad");
|
|
var ViewBuilder$1 = /** @class */ (function () {
|
|
function ViewBuilder(reflector, outputCtx, parent, component, embeddedViewIndex, usedPipes, viewBuilderFactory) {
|
|
this.reflector = reflector;
|
|
this.outputCtx = outputCtx;
|
|
this.parent = parent;
|
|
this.component = component;
|
|
this.embeddedViewIndex = embeddedViewIndex;
|
|
this.usedPipes = usedPipes;
|
|
this.viewBuilderFactory = viewBuilderFactory;
|
|
this.nodes = [];
|
|
this.purePipeNodeIndices = Object.create(null);
|
|
// Need Object.create so that we don't have builtin values...
|
|
this.refNodeIndices = Object.create(null);
|
|
this.variables = [];
|
|
this.children = [];
|
|
// TODO(tbosch): The old view compiler used to use an `any` type
|
|
// for the context in any embedded view. We keep this behaivor for now
|
|
// to be able to introduce the new view compiler without too many errors.
|
|
this.compType = this.embeddedViewIndex > 0 ?
|
|
DYNAMIC_TYPE :
|
|
expressionType(outputCtx.importExpr(this.component.type.reference));
|
|
this.viewName = viewClassName(this.component.type.reference, this.embeddedViewIndex);
|
|
}
|
|
ViewBuilder.prototype.visitAll = function (variables, astNodes) {
|
|
var _this = this;
|
|
this.variables = variables;
|
|
// create the pipes for the pure pipes immediately, so that we know their indices.
|
|
if (!this.parent) {
|
|
this.usedPipes.forEach(function (pipe) {
|
|
if (pipe.pure) {
|
|
_this.purePipeNodeIndices[pipe.name] = _this._createPipe(null, pipe);
|
|
}
|
|
});
|
|
}
|
|
if (!this.parent) {
|
|
this.component.viewQueries.forEach(function (query, queryIndex) {
|
|
// Note: queries start with id 1 so we can use the number in a Bloom filter!
|
|
var queryId = queryIndex + 1;
|
|
var bindingType = query.first ? 0 /* First */ : 1 /* All */;
|
|
var flags = 134217728 /* TypeViewQuery */ | calcQueryFlags(query);
|
|
_this.nodes.push(function () { return ({
|
|
sourceSpan: null,
|
|
nodeFlags: flags,
|
|
nodeDef: importExpr(Identifiers$1.queryDef).callFn([
|
|
literal(flags), literal(queryId),
|
|
new LiteralMapExpr([new LiteralMapEntry(query.propertyName, literal(bindingType), false)])
|
|
])
|
|
}); });
|
|
});
|
|
}
|
|
templateVisitAll(this, astNodes);
|
|
if (this.parent && (astNodes.length === 0 || needsAdditionalRootNode(astNodes))) {
|
|
// if the view is an embedded view, then we need to add an additional root node in some cases
|
|
this.nodes.push(function () { return ({
|
|
sourceSpan: null,
|
|
nodeFlags: 1 /* TypeElement */,
|
|
nodeDef: importExpr(Identifiers$1.anchorDef).callFn([
|
|
literal(0 /* None */), NULL_EXPR, NULL_EXPR, literal(0)
|
|
])
|
|
}); });
|
|
}
|
|
};
|
|
ViewBuilder.prototype.build = function (targetStatements) {
|
|
if (targetStatements === void 0) { targetStatements = []; }
|
|
this.children.forEach(function (child) { return child.build(targetStatements); });
|
|
var _a = this._createNodeExpressions(), updateRendererStmts = _a.updateRendererStmts, updateDirectivesStmts = _a.updateDirectivesStmts, nodeDefExprs = _a.nodeDefExprs;
|
|
var updateRendererFn = this._createUpdateFn(updateRendererStmts);
|
|
var updateDirectivesFn = this._createUpdateFn(updateDirectivesStmts);
|
|
var viewFlags = 0 /* None */;
|
|
if (!this.parent && this.component.changeDetection === ChangeDetectionStrategy.OnPush) {
|
|
viewFlags |= 2 /* OnPush */;
|
|
}
|
|
var viewFactory = new DeclareFunctionStmt(this.viewName, [new FnParam(LOG_VAR$1.name)], [new ReturnStatement(importExpr(Identifiers$1.viewDef).callFn([
|
|
literal(viewFlags),
|
|
literalArr(nodeDefExprs),
|
|
updateDirectivesFn,
|
|
updateRendererFn,
|
|
]))], importType(Identifiers$1.ViewDefinition), this.embeddedViewIndex === 0 ? [exports.StmtModifier.Exported] : []);
|
|
targetStatements.push(viewFactory);
|
|
return targetStatements;
|
|
};
|
|
ViewBuilder.prototype._createUpdateFn = function (updateStmts) {
|
|
var updateFn;
|
|
if (updateStmts.length > 0) {
|
|
var preStmts = [];
|
|
if (!this.component.isHost && findReadVarNames(updateStmts).has(COMP_VAR.name)) {
|
|
preStmts.push(COMP_VAR.set(VIEW_VAR.prop('component')).toDeclStmt(this.compType));
|
|
}
|
|
updateFn = fn([
|
|
new FnParam(CHECK_VAR.name, INFERRED_TYPE),
|
|
new FnParam(VIEW_VAR.name, INFERRED_TYPE)
|
|
], __spreadArray(__spreadArray([], __read(preStmts)), __read(updateStmts)), INFERRED_TYPE);
|
|
}
|
|
else {
|
|
updateFn = NULL_EXPR;
|
|
}
|
|
return updateFn;
|
|
};
|
|
ViewBuilder.prototype.visitNgContent = function (ast, context) {
|
|
// ngContentDef(ngContentIndex: number, index: number): NodeDef;
|
|
this.nodes.push(function () { return ({
|
|
sourceSpan: ast.sourceSpan,
|
|
nodeFlags: 8 /* TypeNgContent */,
|
|
nodeDef: importExpr(Identifiers$1.ngContentDef)
|
|
.callFn([literal(ast.ngContentIndex), literal(ast.index)])
|
|
}); });
|
|
};
|
|
ViewBuilder.prototype.visitText = function (ast, context) {
|
|
// Static text nodes have no check function
|
|
var checkIndex = -1;
|
|
this.nodes.push(function () { return ({
|
|
sourceSpan: ast.sourceSpan,
|
|
nodeFlags: 2 /* TypeText */,
|
|
nodeDef: importExpr(Identifiers$1.textDef).callFn([
|
|
literal(checkIndex),
|
|
literal(ast.ngContentIndex),
|
|
literalArr([literal(ast.value)]),
|
|
])
|
|
}); });
|
|
};
|
|
ViewBuilder.prototype.visitBoundText = function (ast, context) {
|
|
var _this = this;
|
|
var nodeIndex = this.nodes.length;
|
|
// reserve the space in the nodeDefs array
|
|
this.nodes.push(null);
|
|
var astWithSource = ast.value;
|
|
var inter = astWithSource.ast;
|
|
var updateRendererExpressions = inter.expressions.map(function (expr, bindingIndex) { return _this._preprocessUpdateExpression({ nodeIndex: nodeIndex, bindingIndex: bindingIndex, sourceSpan: ast.sourceSpan, context: COMP_VAR, value: expr }); });
|
|
// Check index is the same as the node index during compilation
|
|
// They might only differ at runtime
|
|
var checkIndex = nodeIndex;
|
|
this.nodes[nodeIndex] = function () { return ({
|
|
sourceSpan: ast.sourceSpan,
|
|
nodeFlags: 2 /* TypeText */,
|
|
nodeDef: importExpr(Identifiers$1.textDef).callFn([
|
|
literal(checkIndex),
|
|
literal(ast.ngContentIndex),
|
|
literalArr(inter.strings.map(function (s) { return literal(s); })),
|
|
]),
|
|
updateRenderer: updateRendererExpressions
|
|
}); };
|
|
};
|
|
ViewBuilder.prototype.visitEmbeddedTemplate = function (ast, context) {
|
|
var _this = this;
|
|
var nodeIndex = this.nodes.length;
|
|
// reserve the space in the nodeDefs array
|
|
this.nodes.push(null);
|
|
var _a = this._visitElementOrTemplate(nodeIndex, ast), flags = _a.flags, queryMatchesExpr = _a.queryMatchesExpr, hostEvents = _a.hostEvents;
|
|
var childVisitor = this.viewBuilderFactory(this);
|
|
this.children.push(childVisitor);
|
|
childVisitor.visitAll(ast.variables, ast.children);
|
|
var childCount = this.nodes.length - nodeIndex - 1;
|
|
// anchorDef(
|
|
// flags: NodeFlags, matchedQueries: [string, QueryValueType][], ngContentIndex: number,
|
|
// childCount: number, handleEventFn?: ElementHandleEventFn, templateFactory?:
|
|
// ViewDefinitionFactory): NodeDef;
|
|
this.nodes[nodeIndex] = function () { return ({
|
|
sourceSpan: ast.sourceSpan,
|
|
nodeFlags: 1 /* TypeElement */ | flags,
|
|
nodeDef: importExpr(Identifiers$1.anchorDef).callFn([
|
|
literal(flags),
|
|
queryMatchesExpr,
|
|
literal(ast.ngContentIndex),
|
|
literal(childCount),
|
|
_this._createElementHandleEventFn(nodeIndex, hostEvents),
|
|
variable(childVisitor.viewName),
|
|
])
|
|
}); };
|
|
};
|
|
ViewBuilder.prototype.visitElement = function (ast, context) {
|
|
var _this = this;
|
|
var nodeIndex = this.nodes.length;
|
|
// reserve the space in the nodeDefs array so we can add children
|
|
this.nodes.push(null);
|
|
// Using a null element name creates an anchor.
|
|
var elName = isNgContainer(ast.name) ? null : ast.name;
|
|
var _a = this._visitElementOrTemplate(nodeIndex, ast), flags = _a.flags, usedEvents = _a.usedEvents, queryMatchesExpr = _a.queryMatchesExpr, dirHostBindings = _a.hostBindings, hostEvents = _a.hostEvents;
|
|
var inputDefs = [];
|
|
var updateRendererExpressions = [];
|
|
var outputDefs = [];
|
|
if (elName) {
|
|
var hostBindings = ast.inputs
|
|
.map(function (inputAst) { return ({
|
|
context: COMP_VAR,
|
|
inputAst: inputAst,
|
|
dirAst: null,
|
|
}); })
|
|
.concat(dirHostBindings);
|
|
if (hostBindings.length) {
|
|
updateRendererExpressions =
|
|
hostBindings.map(function (hostBinding, bindingIndex) { return _this._preprocessUpdateExpression({
|
|
context: hostBinding.context,
|
|
nodeIndex: nodeIndex,
|
|
bindingIndex: bindingIndex,
|
|
sourceSpan: hostBinding.inputAst.sourceSpan,
|
|
value: hostBinding.inputAst.value
|
|
}); });
|
|
inputDefs = hostBindings.map(function (hostBinding) { return elementBindingDef(hostBinding.inputAst, hostBinding.dirAst); });
|
|
}
|
|
outputDefs = usedEvents.map(function (_a) {
|
|
var _b = __read(_a, 2), target = _b[0], eventName = _b[1];
|
|
return literalArr([literal(target), literal(eventName)]);
|
|
});
|
|
}
|
|
templateVisitAll(this, ast.children);
|
|
var childCount = this.nodes.length - nodeIndex - 1;
|
|
var compAst = ast.directives.find(function (dirAst) { return dirAst.directive.isComponent; });
|
|
var compRendererType = NULL_EXPR;
|
|
var compView = NULL_EXPR;
|
|
if (compAst) {
|
|
compView = this.outputCtx.importExpr(compAst.directive.componentViewType);
|
|
compRendererType = this.outputCtx.importExpr(compAst.directive.rendererType);
|
|
}
|
|
// Check index is the same as the node index during compilation
|
|
// They might only differ at runtime
|
|
var checkIndex = nodeIndex;
|
|
this.nodes[nodeIndex] = function () { return ({
|
|
sourceSpan: ast.sourceSpan,
|
|
nodeFlags: 1 /* TypeElement */ | flags,
|
|
nodeDef: importExpr(Identifiers$1.elementDef).callFn([
|
|
literal(checkIndex),
|
|
literal(flags),
|
|
queryMatchesExpr,
|
|
literal(ast.ngContentIndex),
|
|
literal(childCount),
|
|
literal(elName),
|
|
elName ? fixedAttrsDef(ast) : NULL_EXPR,
|
|
inputDefs.length ? literalArr(inputDefs) : NULL_EXPR,
|
|
outputDefs.length ? literalArr(outputDefs) : NULL_EXPR,
|
|
_this._createElementHandleEventFn(nodeIndex, hostEvents),
|
|
compView,
|
|
compRendererType,
|
|
]),
|
|
updateRenderer: updateRendererExpressions
|
|
}); };
|
|
};
|
|
ViewBuilder.prototype._visitElementOrTemplate = function (nodeIndex, ast) {
|
|
var _this = this;
|
|
var flags = 0 /* None */;
|
|
if (ast.hasViewContainer) {
|
|
flags |= 16777216 /* EmbeddedViews */;
|
|
}
|
|
var usedEvents = new Map();
|
|
ast.outputs.forEach(function (event) {
|
|
var _a = elementEventNameAndTarget(event, null), name = _a.name, target = _a.target;
|
|
usedEvents.set(elementEventFullName(target, name), [target, name]);
|
|
});
|
|
ast.directives.forEach(function (dirAst) {
|
|
dirAst.hostEvents.forEach(function (event) {
|
|
var _a = elementEventNameAndTarget(event, dirAst), name = _a.name, target = _a.target;
|
|
usedEvents.set(elementEventFullName(target, name), [target, name]);
|
|
});
|
|
});
|
|
var hostBindings = [];
|
|
var hostEvents = [];
|
|
this._visitComponentFactoryResolverProvider(ast.directives);
|
|
ast.providers.forEach(function (providerAst) {
|
|
var dirAst = undefined;
|
|
ast.directives.forEach(function (localDirAst) {
|
|
if (localDirAst.directive.type.reference === tokenReference(providerAst.token)) {
|
|
dirAst = localDirAst;
|
|
}
|
|
});
|
|
if (dirAst) {
|
|
var _a = _this._visitDirective(providerAst, dirAst, ast.references, ast.queryMatches, usedEvents), dirHostBindings = _a.hostBindings, dirHostEvents = _a.hostEvents;
|
|
hostBindings.push.apply(hostBindings, __spreadArray([], __read(dirHostBindings)));
|
|
hostEvents.push.apply(hostEvents, __spreadArray([], __read(dirHostEvents)));
|
|
}
|
|
else {
|
|
_this._visitProvider(providerAst, ast.queryMatches);
|
|
}
|
|
});
|
|
var queryMatchExprs = [];
|
|
ast.queryMatches.forEach(function (match) {
|
|
var valueType = undefined;
|
|
if (tokenReference(match.value) ===
|
|
_this.reflector.resolveExternalReference(Identifiers$1.ElementRef)) {
|
|
valueType = 0 /* ElementRef */;
|
|
}
|
|
else if (tokenReference(match.value) ===
|
|
_this.reflector.resolveExternalReference(Identifiers$1.ViewContainerRef)) {
|
|
valueType = 3 /* ViewContainerRef */;
|
|
}
|
|
else if (tokenReference(match.value) ===
|
|
_this.reflector.resolveExternalReference(Identifiers$1.TemplateRef)) {
|
|
valueType = 2 /* TemplateRef */;
|
|
}
|
|
if (valueType != null) {
|
|
queryMatchExprs.push(literalArr([literal(match.queryId), literal(valueType)]));
|
|
}
|
|
});
|
|
ast.references.forEach(function (ref) {
|
|
var valueType = undefined;
|
|
if (!ref.value) {
|
|
valueType = 1 /* RenderElement */;
|
|
}
|
|
else if (tokenReference(ref.value) ===
|
|
_this.reflector.resolveExternalReference(Identifiers$1.TemplateRef)) {
|
|
valueType = 2 /* TemplateRef */;
|
|
}
|
|
if (valueType != null) {
|
|
_this.refNodeIndices[ref.name] = nodeIndex;
|
|
queryMatchExprs.push(literalArr([literal(ref.name), literal(valueType)]));
|
|
}
|
|
});
|
|
ast.outputs.forEach(function (outputAst) {
|
|
hostEvents.push({ context: COMP_VAR, eventAst: outputAst, dirAst: null });
|
|
});
|
|
return {
|
|
flags: flags,
|
|
usedEvents: Array.from(usedEvents.values()),
|
|
queryMatchesExpr: queryMatchExprs.length ? literalArr(queryMatchExprs) : NULL_EXPR,
|
|
hostBindings: hostBindings,
|
|
hostEvents: hostEvents
|
|
};
|
|
};
|
|
ViewBuilder.prototype._visitDirective = function (providerAst, dirAst, refs, queryMatches, usedEvents) {
|
|
var _this = this;
|
|
var nodeIndex = this.nodes.length;
|
|
// reserve the space in the nodeDefs array so we can add children
|
|
this.nodes.push(null);
|
|
dirAst.directive.queries.forEach(function (query, queryIndex) {
|
|
var queryId = dirAst.contentQueryStartId + queryIndex;
|
|
var flags = 67108864 /* TypeContentQuery */ | calcQueryFlags(query);
|
|
var bindingType = query.first ? 0 /* First */ : 1 /* All */;
|
|
_this.nodes.push(function () { return ({
|
|
sourceSpan: dirAst.sourceSpan,
|
|
nodeFlags: flags,
|
|
nodeDef: importExpr(Identifiers$1.queryDef).callFn([
|
|
literal(flags), literal(queryId),
|
|
new LiteralMapExpr([new LiteralMapEntry(query.propertyName, literal(bindingType), false)])
|
|
]),
|
|
}); });
|
|
});
|
|
// Note: the operation below might also create new nodeDefs,
|
|
// but we don't want them to be a child of a directive,
|
|
// as they might be a provider/pipe on their own.
|
|
// I.e. we only allow queries as children of directives nodes.
|
|
var childCount = this.nodes.length - nodeIndex - 1;
|
|
var _a = this._visitProviderOrDirective(providerAst, queryMatches), flags = _a.flags, queryMatchExprs = _a.queryMatchExprs, providerExpr = _a.providerExpr, depsExpr = _a.depsExpr;
|
|
refs.forEach(function (ref) {
|
|
if (ref.value && tokenReference(ref.value) === tokenReference(providerAst.token)) {
|
|
_this.refNodeIndices[ref.name] = nodeIndex;
|
|
queryMatchExprs.push(literalArr([literal(ref.name), literal(4 /* Provider */)]));
|
|
}
|
|
});
|
|
if (dirAst.directive.isComponent) {
|
|
flags |= 32768 /* Component */;
|
|
}
|
|
var inputDefs = dirAst.inputs.map(function (inputAst, inputIndex) {
|
|
var mapValue = literalArr([literal(inputIndex), literal(inputAst.directiveName)]);
|
|
// Note: it's important to not quote the key so that we can capture renames by minifiers!
|
|
return new LiteralMapEntry(inputAst.directiveName, mapValue, false);
|
|
});
|
|
var outputDefs = [];
|
|
var dirMeta = dirAst.directive;
|
|
Object.keys(dirMeta.outputs).forEach(function (propName) {
|
|
var eventName = dirMeta.outputs[propName];
|
|
if (usedEvents.has(eventName)) {
|
|
// Note: it's important to not quote the key so that we can capture renames by minifiers!
|
|
outputDefs.push(new LiteralMapEntry(propName, literal(eventName), false));
|
|
}
|
|
});
|
|
var updateDirectiveExpressions = [];
|
|
if (dirAst.inputs.length || (flags & (262144 /* DoCheck */ | 65536 /* OnInit */)) > 0) {
|
|
updateDirectiveExpressions =
|
|
dirAst.inputs.map(function (input, bindingIndex) { return _this._preprocessUpdateExpression({
|
|
nodeIndex: nodeIndex,
|
|
bindingIndex: bindingIndex,
|
|
sourceSpan: input.sourceSpan,
|
|
context: COMP_VAR,
|
|
value: input.value
|
|
}); });
|
|
}
|
|
var dirContextExpr = importExpr(Identifiers$1.nodeValue).callFn([VIEW_VAR, literal(nodeIndex)]);
|
|
var hostBindings = dirAst.hostProperties.map(function (inputAst) { return ({
|
|
context: dirContextExpr,
|
|
dirAst: dirAst,
|
|
inputAst: inputAst,
|
|
}); });
|
|
var hostEvents = dirAst.hostEvents.map(function (hostEventAst) { return ({
|
|
context: dirContextExpr,
|
|
eventAst: hostEventAst,
|
|
dirAst: dirAst,
|
|
}); });
|
|
// Check index is the same as the node index during compilation
|
|
// They might only differ at runtime
|
|
var checkIndex = nodeIndex;
|
|
this.nodes[nodeIndex] = function () { return ({
|
|
sourceSpan: dirAst.sourceSpan,
|
|
nodeFlags: 16384 /* TypeDirective */ | flags,
|
|
nodeDef: importExpr(Identifiers$1.directiveDef).callFn([
|
|
literal(checkIndex),
|
|
literal(flags),
|
|
queryMatchExprs.length ? literalArr(queryMatchExprs) : NULL_EXPR,
|
|
literal(childCount),
|
|
providerExpr,
|
|
depsExpr,
|
|
inputDefs.length ? new LiteralMapExpr(inputDefs) : NULL_EXPR,
|
|
outputDefs.length ? new LiteralMapExpr(outputDefs) : NULL_EXPR,
|
|
]),
|
|
updateDirectives: updateDirectiveExpressions,
|
|
directive: dirAst.directive.type,
|
|
}); };
|
|
return { hostBindings: hostBindings, hostEvents: hostEvents };
|
|
};
|
|
ViewBuilder.prototype._visitProvider = function (providerAst, queryMatches) {
|
|
this._addProviderNode(this._visitProviderOrDirective(providerAst, queryMatches));
|
|
};
|
|
ViewBuilder.prototype._visitComponentFactoryResolverProvider = function (directives) {
|
|
var componentDirMeta = directives.find(function (dirAst) { return dirAst.directive.isComponent; });
|
|
if (componentDirMeta && componentDirMeta.directive.entryComponents.length) {
|
|
var _a = componentFactoryResolverProviderDef(this.reflector, this.outputCtx, 8192 /* PrivateProvider */, componentDirMeta.directive.entryComponents), providerExpr = _a.providerExpr, depsExpr = _a.depsExpr, flags = _a.flags, tokenExpr = _a.tokenExpr;
|
|
this._addProviderNode({
|
|
providerExpr: providerExpr,
|
|
depsExpr: depsExpr,
|
|
flags: flags,
|
|
tokenExpr: tokenExpr,
|
|
queryMatchExprs: [],
|
|
sourceSpan: componentDirMeta.sourceSpan
|
|
});
|
|
}
|
|
};
|
|
ViewBuilder.prototype._addProviderNode = function (data) {
|
|
// providerDef(
|
|
// flags: NodeFlags, matchedQueries: [string, QueryValueType][], token:any,
|
|
// value: any, deps: ([DepFlags, any] | any)[]): NodeDef;
|
|
this.nodes.push(function () { return ({
|
|
sourceSpan: data.sourceSpan,
|
|
nodeFlags: data.flags,
|
|
nodeDef: importExpr(Identifiers$1.providerDef).callFn([
|
|
literal(data.flags),
|
|
data.queryMatchExprs.length ? literalArr(data.queryMatchExprs) : NULL_EXPR,
|
|
data.tokenExpr, data.providerExpr, data.depsExpr
|
|
])
|
|
}); });
|
|
};
|
|
ViewBuilder.prototype._visitProviderOrDirective = function (providerAst, queryMatches) {
|
|
var flags = 0 /* None */;
|
|
var queryMatchExprs = [];
|
|
queryMatches.forEach(function (match) {
|
|
if (tokenReference(match.value) === tokenReference(providerAst.token)) {
|
|
queryMatchExprs.push(literalArr([literal(match.queryId), literal(4 /* Provider */)]));
|
|
}
|
|
});
|
|
var _a = providerDef(this.outputCtx, providerAst), providerExpr = _a.providerExpr, depsExpr = _a.depsExpr, providerFlags = _a.flags, tokenExpr = _a.tokenExpr;
|
|
return {
|
|
flags: flags | providerFlags,
|
|
queryMatchExprs: queryMatchExprs,
|
|
providerExpr: providerExpr,
|
|
depsExpr: depsExpr,
|
|
tokenExpr: tokenExpr,
|
|
sourceSpan: providerAst.sourceSpan
|
|
};
|
|
};
|
|
ViewBuilder.prototype.getLocal = function (name) {
|
|
if (name == EventHandlerVars.event.name) {
|
|
return EventHandlerVars.event;
|
|
}
|
|
var currViewExpr = VIEW_VAR;
|
|
for (var currBuilder = this; currBuilder; currBuilder = currBuilder.parent,
|
|
currViewExpr = currViewExpr.prop('parent').cast(DYNAMIC_TYPE)) {
|
|
// check references
|
|
var refNodeIndex = currBuilder.refNodeIndices[name];
|
|
if (refNodeIndex != null) {
|
|
return importExpr(Identifiers$1.nodeValue).callFn([currViewExpr, literal(refNodeIndex)]);
|
|
}
|
|
// check variables
|
|
var varAst = currBuilder.variables.find(function (varAst) { return varAst.name === name; });
|
|
if (varAst) {
|
|
var varValue = varAst.value || IMPLICIT_TEMPLATE_VAR;
|
|
return currViewExpr.prop('context').prop(varValue);
|
|
}
|
|
}
|
|
return null;
|
|
};
|
|
ViewBuilder.prototype.notifyImplicitReceiverUse = function () {
|
|
// Not needed in ViewEngine as ViewEngine walks through the generated
|
|
// expressions to figure out if the implicit receiver is used and needs
|
|
// to be generated as part of the pre-update statements.
|
|
};
|
|
ViewBuilder.prototype.maybeRestoreView = function () {
|
|
// Not necessary in ViewEngine, because view restoration is an Ivy concept.
|
|
};
|
|
ViewBuilder.prototype._createLiteralArrayConverter = function (sourceSpan, argCount) {
|
|
if (argCount === 0) {
|
|
var valueExpr_1 = importExpr(Identifiers$1.EMPTY_ARRAY);
|
|
return function () { return valueExpr_1; };
|
|
}
|
|
var checkIndex = this.nodes.length;
|
|
this.nodes.push(function () { return ({
|
|
sourceSpan: sourceSpan,
|
|
nodeFlags: 32 /* TypePureArray */,
|
|
nodeDef: importExpr(Identifiers$1.pureArrayDef).callFn([
|
|
literal(checkIndex),
|
|
literal(argCount),
|
|
])
|
|
}); });
|
|
return function (args) { return callCheckStmt(checkIndex, args); };
|
|
};
|
|
ViewBuilder.prototype._createLiteralMapConverter = function (sourceSpan, keys) {
|
|
if (keys.length === 0) {
|
|
var valueExpr_2 = importExpr(Identifiers$1.EMPTY_MAP);
|
|
return function () { return valueExpr_2; };
|
|
}
|
|
var map = literalMap(keys.map(function (e, i) { return (Object.assign(Object.assign({}, e), { value: literal(i) })); }));
|
|
var checkIndex = this.nodes.length;
|
|
this.nodes.push(function () { return ({
|
|
sourceSpan: sourceSpan,
|
|
nodeFlags: 64 /* TypePureObject */,
|
|
nodeDef: importExpr(Identifiers$1.pureObjectDef).callFn([
|
|
literal(checkIndex),
|
|
map,
|
|
])
|
|
}); });
|
|
return function (args) { return callCheckStmt(checkIndex, args); };
|
|
};
|
|
ViewBuilder.prototype._createPipeConverter = function (expression, name, argCount) {
|
|
var pipe = this.usedPipes.find(function (pipeSummary) { return pipeSummary.name === name; });
|
|
if (pipe.pure) {
|
|
var checkIndex_1 = this.nodes.length;
|
|
this.nodes.push(function () { return ({
|
|
sourceSpan: expression.sourceSpan,
|
|
nodeFlags: 128 /* TypePurePipe */,
|
|
nodeDef: importExpr(Identifiers$1.purePipeDef).callFn([
|
|
literal(checkIndex_1),
|
|
literal(argCount),
|
|
])
|
|
}); });
|
|
// find underlying pipe in the component view
|
|
var compViewExpr = VIEW_VAR;
|
|
var compBuilder = this;
|
|
while (compBuilder.parent) {
|
|
compBuilder = compBuilder.parent;
|
|
compViewExpr = compViewExpr.prop('parent').cast(DYNAMIC_TYPE);
|
|
}
|
|
var pipeNodeIndex = compBuilder.purePipeNodeIndices[name];
|
|
var pipeValueExpr_1 = importExpr(Identifiers$1.nodeValue).callFn([compViewExpr, literal(pipeNodeIndex)]);
|
|
return function (args) { return callUnwrapValue(expression.nodeIndex, expression.bindingIndex, callCheckStmt(checkIndex_1, [pipeValueExpr_1].concat(args))); };
|
|
}
|
|
else {
|
|
var nodeIndex = this._createPipe(expression.sourceSpan, pipe);
|
|
var nodeValueExpr_1 = importExpr(Identifiers$1.nodeValue).callFn([VIEW_VAR, literal(nodeIndex)]);
|
|
return function (args) { return callUnwrapValue(expression.nodeIndex, expression.bindingIndex, nodeValueExpr_1.callMethod('transform', args)); };
|
|
}
|
|
};
|
|
ViewBuilder.prototype._createPipe = function (sourceSpan, pipe) {
|
|
var _this = this;
|
|
var nodeIndex = this.nodes.length;
|
|
var flags = 0 /* None */;
|
|
pipe.type.lifecycleHooks.forEach(function (lifecycleHook) {
|
|
// for pipes, we only support ngOnDestroy
|
|
if (lifecycleHook === LifecycleHooks.OnDestroy) {
|
|
flags |= lifecycleHookToNodeFlag(lifecycleHook);
|
|
}
|
|
});
|
|
var depExprs = pipe.type.diDeps.map(function (diDep) { return depDef(_this.outputCtx, diDep); });
|
|
// function pipeDef(
|
|
// flags: NodeFlags, ctor: any, deps: ([DepFlags, any] | any)[]): NodeDef
|
|
this.nodes.push(function () { return ({
|
|
sourceSpan: sourceSpan,
|
|
nodeFlags: 16 /* TypePipe */,
|
|
nodeDef: importExpr(Identifiers$1.pipeDef).callFn([
|
|
literal(flags), _this.outputCtx.importExpr(pipe.type.reference), literalArr(depExprs)
|
|
])
|
|
}); });
|
|
return nodeIndex;
|
|
};
|
|
/**
|
|
* For the AST in `UpdateExpression.value`:
|
|
* - create nodes for pipes, literal arrays and, literal maps,
|
|
* - update the AST to replace pipes, literal arrays and, literal maps with calls to check fn.
|
|
*
|
|
* WARNING: This might create new nodeDefs (for pipes and literal arrays and literal maps)!
|
|
*/
|
|
ViewBuilder.prototype._preprocessUpdateExpression = function (expression) {
|
|
var _this = this;
|
|
return {
|
|
nodeIndex: expression.nodeIndex,
|
|
bindingIndex: expression.bindingIndex,
|
|
sourceSpan: expression.sourceSpan,
|
|
context: expression.context,
|
|
value: convertPropertyBindingBuiltins({
|
|
createLiteralArrayConverter: function (argCount) { return _this._createLiteralArrayConverter(expression.sourceSpan, argCount); },
|
|
createLiteralMapConverter: function (keys) { return _this._createLiteralMapConverter(expression.sourceSpan, keys); },
|
|
createPipeConverter: function (name, argCount) { return _this._createPipeConverter(expression, name, argCount); }
|
|
}, expression.value)
|
|
};
|
|
};
|
|
ViewBuilder.prototype._createNodeExpressions = function () {
|
|
var self = this;
|
|
var updateBindingCount = 0;
|
|
var updateRendererStmts = [];
|
|
var updateDirectivesStmts = [];
|
|
var nodeDefExprs = this.nodes.map(function (factory, nodeIndex) {
|
|
var _a = factory(), nodeDef = _a.nodeDef, nodeFlags = _a.nodeFlags, updateDirectives = _a.updateDirectives, updateRenderer = _a.updateRenderer, sourceSpan = _a.sourceSpan;
|
|
if (updateRenderer) {
|
|
updateRendererStmts.push.apply(updateRendererStmts, __spreadArray([], __read(createUpdateStatements(nodeIndex, sourceSpan, updateRenderer, false))));
|
|
}
|
|
if (updateDirectives) {
|
|
updateDirectivesStmts.push.apply(updateDirectivesStmts, __spreadArray([], __read(createUpdateStatements(nodeIndex, sourceSpan, updateDirectives, (nodeFlags & (262144 /* DoCheck */ | 65536 /* OnInit */)) > 0))));
|
|
}
|
|
// We use a comma expression to call the log function before
|
|
// the nodeDef function, but still use the result of the nodeDef function
|
|
// as the value.
|
|
// Note: We only add the logger to elements / text nodes,
|
|
// so we don't generate too much code.
|
|
var logWithNodeDef = nodeFlags & 3 /* CatRenderNode */ ?
|
|
new CommaExpr([LOG_VAR$1.callFn([]).callFn([]), nodeDef]) :
|
|
nodeDef;
|
|
return applySourceSpanToExpressionIfNeeded(logWithNodeDef, sourceSpan);
|
|
});
|
|
return { updateRendererStmts: updateRendererStmts, updateDirectivesStmts: updateDirectivesStmts, nodeDefExprs: nodeDefExprs };
|
|
function createUpdateStatements(nodeIndex, sourceSpan, expressions, allowEmptyExprs) {
|
|
var updateStmts = [];
|
|
var exprs = expressions.map(function (_a) {
|
|
var sourceSpan = _a.sourceSpan, context = _a.context, value = _a.value;
|
|
var bindingId = "" + updateBindingCount++;
|
|
var nameResolver = context === COMP_VAR ? self : null;
|
|
var _b = convertPropertyBinding(nameResolver, context, value, bindingId, BindingForm.General), stmts = _b.stmts, currValExpr = _b.currValExpr;
|
|
updateStmts.push.apply(updateStmts, __spreadArray([], __read(stmts.map(function (stmt) { return applySourceSpanToStatementIfNeeded(stmt, sourceSpan); }))));
|
|
return applySourceSpanToExpressionIfNeeded(currValExpr, sourceSpan);
|
|
});
|
|
if (expressions.length || allowEmptyExprs) {
|
|
updateStmts.push(applySourceSpanToStatementIfNeeded(callCheckStmt(nodeIndex, exprs).toStmt(), sourceSpan));
|
|
}
|
|
return updateStmts;
|
|
}
|
|
};
|
|
ViewBuilder.prototype._createElementHandleEventFn = function (nodeIndex, handlers) {
|
|
var _this = this;
|
|
var handleEventStmts = [];
|
|
var handleEventBindingCount = 0;
|
|
handlers.forEach(function (_a) {
|
|
var context = _a.context, eventAst = _a.eventAst, dirAst = _a.dirAst;
|
|
var bindingId = "" + handleEventBindingCount++;
|
|
var nameResolver = context === COMP_VAR ? _this : null;
|
|
var _b = convertActionBinding(nameResolver, context, eventAst.handler, bindingId), stmts = _b.stmts, allowDefault = _b.allowDefault;
|
|
var trueStmts = stmts;
|
|
if (allowDefault) {
|
|
trueStmts.push(ALLOW_DEFAULT_VAR.set(allowDefault.and(ALLOW_DEFAULT_VAR)).toStmt());
|
|
}
|
|
var _c = elementEventNameAndTarget(eventAst, dirAst), eventTarget = _c.target, eventName = _c.name;
|
|
var fullEventName = elementEventFullName(eventTarget, eventName);
|
|
handleEventStmts.push(applySourceSpanToStatementIfNeeded(new IfStmt(literal(fullEventName).identical(EVENT_NAME_VAR), trueStmts), eventAst.sourceSpan));
|
|
});
|
|
var handleEventFn;
|
|
if (handleEventStmts.length > 0) {
|
|
var preStmts = [ALLOW_DEFAULT_VAR.set(literal(true)).toDeclStmt(BOOL_TYPE)];
|
|
if (!this.component.isHost && findReadVarNames(handleEventStmts).has(COMP_VAR.name)) {
|
|
preStmts.push(COMP_VAR.set(VIEW_VAR.prop('component')).toDeclStmt(this.compType));
|
|
}
|
|
handleEventFn = fn([
|
|
new FnParam(VIEW_VAR.name, INFERRED_TYPE),
|
|
new FnParam(EVENT_NAME_VAR.name, INFERRED_TYPE),
|
|
new FnParam(EventHandlerVars.event.name, INFERRED_TYPE)
|
|
], __spreadArray(__spreadArray(__spreadArray([], __read(preStmts)), __read(handleEventStmts)), [new ReturnStatement(ALLOW_DEFAULT_VAR)]), INFERRED_TYPE);
|
|
}
|
|
else {
|
|
handleEventFn = NULL_EXPR;
|
|
}
|
|
return handleEventFn;
|
|
};
|
|
ViewBuilder.prototype.visitDirective = function (ast, context) { };
|
|
ViewBuilder.prototype.visitDirectiveProperty = function (ast, context) { };
|
|
ViewBuilder.prototype.visitReference = function (ast, context) { };
|
|
ViewBuilder.prototype.visitVariable = function (ast, context) { };
|
|
ViewBuilder.prototype.visitEvent = function (ast, context) { };
|
|
ViewBuilder.prototype.visitElementProperty = function (ast, context) { };
|
|
ViewBuilder.prototype.visitAttr = function (ast, context) { };
|
|
return ViewBuilder;
|
|
}());
|
|
function needsAdditionalRootNode(astNodes) {
|
|
var lastAstNode = astNodes[astNodes.length - 1];
|
|
if (lastAstNode instanceof EmbeddedTemplateAst) {
|
|
return lastAstNode.hasViewContainer;
|
|
}
|
|
if (lastAstNode instanceof ElementAst) {
|
|
if (isNgContainer(lastAstNode.name) && lastAstNode.children.length) {
|
|
return needsAdditionalRootNode(lastAstNode.children);
|
|
}
|
|
return lastAstNode.hasViewContainer;
|
|
}
|
|
return lastAstNode instanceof NgContentAst;
|
|
}
|
|
function elementBindingDef(inputAst, dirAst) {
|
|
var inputType = inputAst.type;
|
|
switch (inputType) {
|
|
case 1 /* Attribute */:
|
|
return literalArr([
|
|
literal(1 /* TypeElementAttribute */), literal(inputAst.name),
|
|
literal(inputAst.securityContext)
|
|
]);
|
|
case 0 /* Property */:
|
|
return literalArr([
|
|
literal(8 /* TypeProperty */), literal(inputAst.name),
|
|
literal(inputAst.securityContext)
|
|
]);
|
|
case 4 /* Animation */:
|
|
var bindingType = 8 /* TypeProperty */ |
|
|
(dirAst && dirAst.directive.isComponent ? 32 /* SyntheticHostProperty */ :
|
|
16 /* SyntheticProperty */);
|
|
return literalArr([
|
|
literal(bindingType), literal('@' + inputAst.name), literal(inputAst.securityContext)
|
|
]);
|
|
case 2 /* Class */:
|
|
return literalArr([literal(2 /* TypeElementClass */), literal(inputAst.name), NULL_EXPR]);
|
|
case 3 /* Style */:
|
|
return literalArr([
|
|
literal(4 /* TypeElementStyle */), literal(inputAst.name), literal(inputAst.unit)
|
|
]);
|
|
default:
|
|
// This default case is not needed by TypeScript compiler, as the switch is exhaustive.
|
|
// However Closure Compiler does not understand that and reports an error in typed mode.
|
|
// The `throw new Error` below works around the problem, and the unexpected: never variable
|
|
// makes sure tsc still checks this code is unreachable.
|
|
var unexpected = inputType;
|
|
throw new Error("unexpected " + unexpected);
|
|
}
|
|
}
|
|
function fixedAttrsDef(elementAst) {
|
|
var mapResult = Object.create(null);
|
|
elementAst.attrs.forEach(function (attrAst) {
|
|
mapResult[attrAst.name] = attrAst.value;
|
|
});
|
|
elementAst.directives.forEach(function (dirAst) {
|
|
Object.keys(dirAst.directive.hostAttributes).forEach(function (name) {
|
|
var value = dirAst.directive.hostAttributes[name];
|
|
var prevValue = mapResult[name];
|
|
mapResult[name] = prevValue != null ? mergeAttributeValue(name, prevValue, value) : value;
|
|
});
|
|
});
|
|
// Note: We need to sort to get a defined output order
|
|
// for tests and for caching generated artifacts...
|
|
return literalArr(Object.keys(mapResult).sort().map(function (attrName) { return literalArr([literal(attrName), literal(mapResult[attrName])]); }));
|
|
}
|
|
function mergeAttributeValue(attrName, attrValue1, attrValue2) {
|
|
if (attrName == CLASS_ATTR$1 || attrName == STYLE_ATTR) {
|
|
return attrValue1 + " " + attrValue2;
|
|
}
|
|
else {
|
|
return attrValue2;
|
|
}
|
|
}
|
|
function callCheckStmt(nodeIndex, exprs) {
|
|
if (exprs.length > 10) {
|
|
return CHECK_VAR.callFn([VIEW_VAR, literal(nodeIndex), literal(1 /* Dynamic */), literalArr(exprs)]);
|
|
}
|
|
else {
|
|
return CHECK_VAR.callFn(__spreadArray([VIEW_VAR, literal(nodeIndex), literal(0 /* Inline */)], __read(exprs)));
|
|
}
|
|
}
|
|
function callUnwrapValue(nodeIndex, bindingIdx, expr) {
|
|
return importExpr(Identifiers$1.unwrapValue).callFn([
|
|
VIEW_VAR, literal(nodeIndex), literal(bindingIdx), expr
|
|
]);
|
|
}
|
|
function elementEventNameAndTarget(eventAst, dirAst) {
|
|
if (eventAst.isAnimation) {
|
|
return {
|
|
name: "@" + eventAst.name + "." + eventAst.phase,
|
|
target: dirAst && dirAst.directive.isComponent ? 'component' : null
|
|
};
|
|
}
|
|
else {
|
|
return eventAst;
|
|
}
|
|
}
|
|
function calcQueryFlags(query) {
|
|
var flags = 0 /* None */;
|
|
// Note: We only make queries static that query for a single item and the user specifically
|
|
// set the to be static. This is because of backwards compatibility with the old view compiler...
|
|
if (query.first && query.static) {
|
|
flags |= 268435456 /* StaticQuery */;
|
|
}
|
|
else {
|
|
flags |= 536870912 /* DynamicQuery */;
|
|
}
|
|
if (query.emitDistinctChangesOnly) {
|
|
flags |= -2147483648 /* EmitDistinctChangesOnly */;
|
|
}
|
|
return flags;
|
|
}
|
|
function elementEventFullName(target, name) {
|
|
return target ? target + ":" + name : name;
|
|
}
|
|
|
|
/**
|
|
* A container for message extracted from the templates.
|
|
*/
|
|
var MessageBundle = /** @class */ (function () {
|
|
function MessageBundle(_htmlParser, _implicitTags, _implicitAttrs, _locale) {
|
|
if (_locale === void 0) { _locale = null; }
|
|
this._htmlParser = _htmlParser;
|
|
this._implicitTags = _implicitTags;
|
|
this._implicitAttrs = _implicitAttrs;
|
|
this._locale = _locale;
|
|
this._messages = [];
|
|
}
|
|
MessageBundle.prototype.updateFromTemplate = function (html, url, interpolationConfig) {
|
|
var _a;
|
|
var htmlParserResult = this._htmlParser.parse(html, url, { tokenizeExpansionForms: true, interpolationConfig: interpolationConfig });
|
|
if (htmlParserResult.errors.length) {
|
|
return htmlParserResult.errors;
|
|
}
|
|
var i18nParserResult = extractMessages(htmlParserResult.rootNodes, interpolationConfig, this._implicitTags, this._implicitAttrs);
|
|
if (i18nParserResult.errors.length) {
|
|
return i18nParserResult.errors;
|
|
}
|
|
(_a = this._messages).push.apply(_a, __spreadArray([], __read(i18nParserResult.messages)));
|
|
return [];
|
|
};
|
|
// Return the message in the internal format
|
|
// The public (serialized) format might be different, see the `write` method.
|
|
MessageBundle.prototype.getMessages = function () {
|
|
return this._messages;
|
|
};
|
|
MessageBundle.prototype.write = function (serializer, filterSources) {
|
|
var messages = {};
|
|
var mapperVisitor = new MapPlaceholderNames();
|
|
// Deduplicate messages based on their ID
|
|
this._messages.forEach(function (message) {
|
|
var _a;
|
|
var id = serializer.digest(message);
|
|
if (!messages.hasOwnProperty(id)) {
|
|
messages[id] = message;
|
|
}
|
|
else {
|
|
(_a = messages[id].sources).push.apply(_a, __spreadArray([], __read(message.sources)));
|
|
}
|
|
});
|
|
// Transform placeholder names using the serializer mapping
|
|
var msgList = Object.keys(messages).map(function (id) {
|
|
var mapper = serializer.createNameMapper(messages[id]);
|
|
var src = messages[id];
|
|
var nodes = mapper ? mapperVisitor.convert(src.nodes, mapper) : src.nodes;
|
|
var transformedMessage = new Message(nodes, {}, {}, src.meaning, src.description, id);
|
|
transformedMessage.sources = src.sources;
|
|
if (filterSources) {
|
|
transformedMessage.sources.forEach(function (source) { return source.filePath = filterSources(source.filePath); });
|
|
}
|
|
return transformedMessage;
|
|
});
|
|
return serializer.write(msgList, this._locale);
|
|
};
|
|
return MessageBundle;
|
|
}());
|
|
// Transform an i18n AST by renaming the placeholder nodes with the given mapper
|
|
var MapPlaceholderNames = /** @class */ (function (_super) {
|
|
__extends(MapPlaceholderNames, _super);
|
|
function MapPlaceholderNames() {
|
|
return _super !== null && _super.apply(this, arguments) || this;
|
|
}
|
|
MapPlaceholderNames.prototype.convert = function (nodes, mapper) {
|
|
var _this = this;
|
|
return mapper ? nodes.map(function (n) { return n.visit(_this, mapper); }) : nodes;
|
|
};
|
|
MapPlaceholderNames.prototype.visitTagPlaceholder = function (ph, mapper) {
|
|
var _this = this;
|
|
var startName = mapper.toPublicName(ph.startName);
|
|
var closeName = ph.closeName ? mapper.toPublicName(ph.closeName) : ph.closeName;
|
|
var children = ph.children.map(function (n) { return n.visit(_this, mapper); });
|
|
return new TagPlaceholder(ph.tag, ph.attrs, startName, closeName, children, ph.isVoid, ph.sourceSpan, ph.startSourceSpan, ph.endSourceSpan);
|
|
};
|
|
MapPlaceholderNames.prototype.visitPlaceholder = function (ph, mapper) {
|
|
return new Placeholder(ph.value, mapper.toPublicName(ph.name), ph.sourceSpan);
|
|
};
|
|
MapPlaceholderNames.prototype.visitIcuPlaceholder = function (ph, mapper) {
|
|
return new IcuPlaceholder(ph.value, mapper.toPublicName(ph.name), ph.sourceSpan);
|
|
};
|
|
return MapPlaceholderNames;
|
|
}(CloneVisitor));
|
|
|
|
/**
|
|
* @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 GeneratedFile = /** @class */ (function () {
|
|
function GeneratedFile(srcFileUrl, genFileUrl, sourceOrStmts) {
|
|
this.srcFileUrl = srcFileUrl;
|
|
this.genFileUrl = genFileUrl;
|
|
if (typeof sourceOrStmts === 'string') {
|
|
this.source = sourceOrStmts;
|
|
this.stmts = null;
|
|
}
|
|
else {
|
|
this.source = null;
|
|
this.stmts = sourceOrStmts;
|
|
}
|
|
}
|
|
GeneratedFile.prototype.isEquivalent = function (other) {
|
|
if (this.genFileUrl !== other.genFileUrl) {
|
|
return false;
|
|
}
|
|
if (this.source) {
|
|
return this.source === other.source;
|
|
}
|
|
if (other.stmts == null) {
|
|
return false;
|
|
}
|
|
// Note: the constructor guarantees that if this.source is not filled,
|
|
// then this.stmts is.
|
|
return areAllEquivalent(this.stmts, other.stmts);
|
|
};
|
|
return GeneratedFile;
|
|
}());
|
|
function toTypeScript(file, preamble) {
|
|
if (preamble === void 0) { preamble = ''; }
|
|
if (!file.stmts) {
|
|
throw new Error("Illegal state: No stmts present on GeneratedFile " + file.genFileUrl);
|
|
}
|
|
return new TypeScriptEmitter().emitStatements(file.genFileUrl, file.stmts, preamble);
|
|
}
|
|
|
|
function listLazyRoutes(moduleMeta, reflector) {
|
|
var e_1, _a, e_2, _b;
|
|
var allLazyRoutes = [];
|
|
try {
|
|
for (var _c = __values(moduleMeta.transitiveModule.providers), _d = _c.next(); !_d.done; _d = _c.next()) {
|
|
var _e = _d.value, provider = _e.provider, module = _e.module;
|
|
if (tokenReference(provider.token) === reflector.ROUTES) {
|
|
var loadChildren = _collectLoadChildren(provider.useValue);
|
|
try {
|
|
for (var loadChildren_1 = (e_2 = void 0, __values(loadChildren)), loadChildren_1_1 = loadChildren_1.next(); !loadChildren_1_1.done; loadChildren_1_1 = loadChildren_1.next()) {
|
|
var route = loadChildren_1_1.value;
|
|
allLazyRoutes.push(parseLazyRoute(route, reflector, module.reference));
|
|
}
|
|
}
|
|
catch (e_2_1) { e_2 = { error: e_2_1 }; }
|
|
finally {
|
|
try {
|
|
if (loadChildren_1_1 && !loadChildren_1_1.done && (_b = loadChildren_1.return)) _b.call(loadChildren_1);
|
|
}
|
|
finally { if (e_2) throw e_2.error; }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
finally {
|
|
try {
|
|
if (_d && !_d.done && (_a = _c.return)) _a.call(_c);
|
|
}
|
|
finally { if (e_1) throw e_1.error; }
|
|
}
|
|
return allLazyRoutes;
|
|
}
|
|
function _collectLoadChildren(routes, target) {
|
|
var e_3, _a;
|
|
if (target === void 0) { target = []; }
|
|
if (typeof routes === 'string') {
|
|
target.push(routes);
|
|
}
|
|
else if (Array.isArray(routes)) {
|
|
try {
|
|
for (var routes_1 = __values(routes), routes_1_1 = routes_1.next(); !routes_1_1.done; routes_1_1 = routes_1.next()) {
|
|
var route = routes_1_1.value;
|
|
_collectLoadChildren(route, target);
|
|
}
|
|
}
|
|
catch (e_3_1) { e_3 = { error: e_3_1 }; }
|
|
finally {
|
|
try {
|
|
if (routes_1_1 && !routes_1_1.done && (_a = routes_1.return)) _a.call(routes_1);
|
|
}
|
|
finally { if (e_3) throw e_3.error; }
|
|
}
|
|
}
|
|
else if (routes.loadChildren) {
|
|
_collectLoadChildren(routes.loadChildren, target);
|
|
}
|
|
else if (routes.children) {
|
|
_collectLoadChildren(routes.children, target);
|
|
}
|
|
return target;
|
|
}
|
|
function parseLazyRoute(route, reflector, module) {
|
|
var _a = __read(route.split('#'), 2), routePath = _a[0], routeName = _a[1];
|
|
var referencedModule = reflector.resolveExternalReference({
|
|
moduleName: routePath,
|
|
name: routeName,
|
|
}, module ? module.filePath : undefined);
|
|
return { route: route, module: module || referencedModule, referencedModule: referencedModule };
|
|
}
|
|
|
|
var TS = /^(?!.*\.d\.ts$).*\.ts$/;
|
|
var ResolvedStaticSymbol = /** @class */ (function () {
|
|
function ResolvedStaticSymbol(symbol, metadata) {
|
|
this.symbol = symbol;
|
|
this.metadata = metadata;
|
|
}
|
|
return ResolvedStaticSymbol;
|
|
}());
|
|
var SUPPORTED_SCHEMA_VERSION = 4;
|
|
/**
|
|
* This class is responsible for loading metadata per symbol,
|
|
* and normalizing references between symbols.
|
|
*
|
|
* Internally, it only uses symbols without members,
|
|
* and deduces the values for symbols with members based
|
|
* on these symbols.
|
|
*/
|
|
var StaticSymbolResolver = /** @class */ (function () {
|
|
function StaticSymbolResolver(host, staticSymbolCache, summaryResolver, errorRecorder) {
|
|
this.host = host;
|
|
this.staticSymbolCache = staticSymbolCache;
|
|
this.summaryResolver = summaryResolver;
|
|
this.errorRecorder = errorRecorder;
|
|
this.metadataCache = new Map();
|
|
// Note: this will only contain StaticSymbols without members!
|
|
this.resolvedSymbols = new Map();
|
|
// Note: this will only contain StaticSymbols without members!
|
|
this.importAs = new Map();
|
|
this.symbolResourcePaths = new Map();
|
|
this.symbolFromFile = new Map();
|
|
this.knownFileNameToModuleNames = new Map();
|
|
}
|
|
StaticSymbolResolver.prototype.resolveSymbol = function (staticSymbol) {
|
|
if (staticSymbol.members.length > 0) {
|
|
return this._resolveSymbolMembers(staticSymbol);
|
|
}
|
|
// Note: always ask for a summary first,
|
|
// as we might have read shallow metadata via a .d.ts file
|
|
// for the symbol.
|
|
var resultFromSummary = this._resolveSymbolFromSummary(staticSymbol);
|
|
if (resultFromSummary) {
|
|
return resultFromSummary;
|
|
}
|
|
var resultFromCache = this.resolvedSymbols.get(staticSymbol);
|
|
if (resultFromCache) {
|
|
return resultFromCache;
|
|
}
|
|
// Note: Some users use libraries that were not compiled with ngc, i.e. they don't
|
|
// have summaries, only .d.ts files. So we always need to check both, the summary
|
|
// and metadata.
|
|
this._createSymbolsOf(staticSymbol.filePath);
|
|
return this.resolvedSymbols.get(staticSymbol);
|
|
};
|
|
/**
|
|
* getImportAs produces a symbol that can be used to import the given symbol.
|
|
* The import might be different than the symbol if the symbol is exported from
|
|
* a library with a summary; in which case we want to import the symbol from the
|
|
* ngfactory re-export instead of directly to avoid introducing a direct dependency
|
|
* on an otherwise indirect dependency.
|
|
*
|
|
* @param staticSymbol the symbol for which to generate a import symbol
|
|
*/
|
|
StaticSymbolResolver.prototype.getImportAs = function (staticSymbol, useSummaries) {
|
|
if (useSummaries === void 0) { useSummaries = true; }
|
|
if (staticSymbol.members.length) {
|
|
var baseSymbol = this.getStaticSymbol(staticSymbol.filePath, staticSymbol.name);
|
|
var baseImportAs = this.getImportAs(baseSymbol, useSummaries);
|
|
return baseImportAs ?
|
|
this.getStaticSymbol(baseImportAs.filePath, baseImportAs.name, staticSymbol.members) :
|
|
null;
|
|
}
|
|
var summarizedFileName = stripSummaryForJitFileSuffix(staticSymbol.filePath);
|
|
if (summarizedFileName !== staticSymbol.filePath) {
|
|
var summarizedName = stripSummaryForJitNameSuffix(staticSymbol.name);
|
|
var baseSymbol = this.getStaticSymbol(summarizedFileName, summarizedName, staticSymbol.members);
|
|
var baseImportAs = this.getImportAs(baseSymbol, useSummaries);
|
|
return baseImportAs ? this.getStaticSymbol(summaryForJitFileName(baseImportAs.filePath), summaryForJitName(baseImportAs.name), baseSymbol.members) :
|
|
null;
|
|
}
|
|
var result = (useSummaries && this.summaryResolver.getImportAs(staticSymbol)) || null;
|
|
if (!result) {
|
|
result = this.importAs.get(staticSymbol);
|
|
}
|
|
return result;
|
|
};
|
|
/**
|
|
* getResourcePath produces the path to the original location of the symbol and should
|
|
* be used to determine the relative location of resource references recorded in
|
|
* symbol metadata.
|
|
*/
|
|
StaticSymbolResolver.prototype.getResourcePath = function (staticSymbol) {
|
|
return this.symbolResourcePaths.get(staticSymbol) || staticSymbol.filePath;
|
|
};
|
|
/**
|
|
* getTypeArity returns the number of generic type parameters the given symbol
|
|
* has. If the symbol is not a type the result is null.
|
|
*/
|
|
StaticSymbolResolver.prototype.getTypeArity = function (staticSymbol) {
|
|
// If the file is a factory/ngsummary file, don't resolve the symbol as doing so would
|
|
// cause the metadata for an factory/ngsummary file to be loaded which doesn't exist.
|
|
// All references to generated classes must include the correct arity whenever
|
|
// generating code.
|
|
if (isGeneratedFile(staticSymbol.filePath)) {
|
|
return null;
|
|
}
|
|
var resolvedSymbol = unwrapResolvedMetadata(this.resolveSymbol(staticSymbol));
|
|
while (resolvedSymbol && resolvedSymbol.metadata instanceof StaticSymbol) {
|
|
resolvedSymbol = unwrapResolvedMetadata(this.resolveSymbol(resolvedSymbol.metadata));
|
|
}
|
|
return (resolvedSymbol && resolvedSymbol.metadata && resolvedSymbol.metadata.arity) || null;
|
|
};
|
|
StaticSymbolResolver.prototype.getKnownModuleName = function (filePath) {
|
|
return this.knownFileNameToModuleNames.get(filePath) || null;
|
|
};
|
|
StaticSymbolResolver.prototype.recordImportAs = function (sourceSymbol, targetSymbol) {
|
|
sourceSymbol.assertNoMembers();
|
|
targetSymbol.assertNoMembers();
|
|
this.importAs.set(sourceSymbol, targetSymbol);
|
|
};
|
|
StaticSymbolResolver.prototype.recordModuleNameForFileName = function (fileName, moduleName) {
|
|
this.knownFileNameToModuleNames.set(fileName, moduleName);
|
|
};
|
|
/**
|
|
* Invalidate all information derived from the given file and return the
|
|
* static symbols contained in the file.
|
|
*
|
|
* @param fileName the file to invalidate
|
|
*/
|
|
StaticSymbolResolver.prototype.invalidateFile = function (fileName) {
|
|
var e_1, _a;
|
|
this.metadataCache.delete(fileName);
|
|
var symbols = this.symbolFromFile.get(fileName);
|
|
if (!symbols) {
|
|
return [];
|
|
}
|
|
this.symbolFromFile.delete(fileName);
|
|
try {
|
|
for (var symbols_1 = __values(symbols), symbols_1_1 = symbols_1.next(); !symbols_1_1.done; symbols_1_1 = symbols_1.next()) {
|
|
var symbol = symbols_1_1.value;
|
|
this.resolvedSymbols.delete(symbol);
|
|
this.importAs.delete(symbol);
|
|
this.symbolResourcePaths.delete(symbol);
|
|
}
|
|
}
|
|
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
finally {
|
|
try {
|
|
if (symbols_1_1 && !symbols_1_1.done && (_a = symbols_1.return)) _a.call(symbols_1);
|
|
}
|
|
finally { if (e_1) throw e_1.error; }
|
|
}
|
|
return symbols;
|
|
};
|
|
/** @internal */
|
|
StaticSymbolResolver.prototype.ignoreErrorsFor = function (cb) {
|
|
var recorder = this.errorRecorder;
|
|
this.errorRecorder = function () { };
|
|
try {
|
|
return cb();
|
|
}
|
|
finally {
|
|
this.errorRecorder = recorder;
|
|
}
|
|
};
|
|
StaticSymbolResolver.prototype._resolveSymbolMembers = function (staticSymbol) {
|
|
var members = staticSymbol.members;
|
|
var baseResolvedSymbol = this.resolveSymbol(this.getStaticSymbol(staticSymbol.filePath, staticSymbol.name));
|
|
if (!baseResolvedSymbol) {
|
|
return null;
|
|
}
|
|
var baseMetadata = unwrapResolvedMetadata(baseResolvedSymbol.metadata);
|
|
if (baseMetadata instanceof StaticSymbol) {
|
|
return new ResolvedStaticSymbol(staticSymbol, this.getStaticSymbol(baseMetadata.filePath, baseMetadata.name, members));
|
|
}
|
|
else if (baseMetadata && baseMetadata.__symbolic === 'class') {
|
|
if (baseMetadata.statics && members.length === 1) {
|
|
return new ResolvedStaticSymbol(staticSymbol, baseMetadata.statics[members[0]]);
|
|
}
|
|
}
|
|
else {
|
|
var value = baseMetadata;
|
|
for (var i = 0; i < members.length && value; i++) {
|
|
value = value[members[i]];
|
|
}
|
|
return new ResolvedStaticSymbol(staticSymbol, value);
|
|
}
|
|
return null;
|
|
};
|
|
StaticSymbolResolver.prototype._resolveSymbolFromSummary = function (staticSymbol) {
|
|
var summary = this.summaryResolver.resolveSummary(staticSymbol);
|
|
return summary ? new ResolvedStaticSymbol(staticSymbol, summary.metadata) : null;
|
|
};
|
|
/**
|
|
* getStaticSymbol produces a Type whose metadata is known but whose implementation is not loaded.
|
|
* All types passed to the StaticResolver should be pseudo-types returned by this method.
|
|
*
|
|
* @param declarationFile the absolute path of the file where the symbol is declared
|
|
* @param name the name of the type.
|
|
* @param members a symbol for a static member of the named type
|
|
*/
|
|
StaticSymbolResolver.prototype.getStaticSymbol = function (declarationFile, name, members) {
|
|
return this.staticSymbolCache.get(declarationFile, name, members);
|
|
};
|
|
/**
|
|
* hasDecorators checks a file's metadata for the presence of decorators without evaluating the
|
|
* metadata.
|
|
*
|
|
* @param filePath the absolute path to examine for decorators.
|
|
* @returns true if any class in the file has a decorator.
|
|
*/
|
|
StaticSymbolResolver.prototype.hasDecorators = function (filePath) {
|
|
var metadata = this.getModuleMetadata(filePath);
|
|
if (metadata['metadata']) {
|
|
return Object.keys(metadata['metadata']).some(function (metadataKey) {
|
|
var entry = metadata['metadata'][metadataKey];
|
|
return entry && entry.__symbolic === 'class' && entry.decorators;
|
|
});
|
|
}
|
|
return false;
|
|
};
|
|
StaticSymbolResolver.prototype.getSymbolsOf = function (filePath) {
|
|
var summarySymbols = this.summaryResolver.getSymbolsOf(filePath);
|
|
if (summarySymbols) {
|
|
return summarySymbols;
|
|
}
|
|
// Note: Some users use libraries that were not compiled with ngc, i.e. they don't
|
|
// have summaries, only .d.ts files, but `summaryResolver.isLibraryFile` returns true.
|
|
this._createSymbolsOf(filePath);
|
|
return this.symbolFromFile.get(filePath) || [];
|
|
};
|
|
StaticSymbolResolver.prototype._createSymbolsOf = function (filePath) {
|
|
var e_2, _a, e_3, _b;
|
|
var _this = this;
|
|
if (this.symbolFromFile.has(filePath)) {
|
|
return;
|
|
}
|
|
var resolvedSymbols = [];
|
|
var metadata = this.getModuleMetadata(filePath);
|
|
if (metadata['importAs']) {
|
|
// Index bundle indices should use the importAs module name defined
|
|
// in the bundle.
|
|
this.knownFileNameToModuleNames.set(filePath, metadata['importAs']);
|
|
}
|
|
// handle the symbols in one of the re-export location
|
|
if (metadata['exports']) {
|
|
var _loop_1 = function (moduleExport) {
|
|
// handle the symbols in the list of explicitly re-exported symbols.
|
|
if (moduleExport.export) {
|
|
moduleExport.export.forEach(function (exportSymbol) {
|
|
var symbolName;
|
|
if (typeof exportSymbol === 'string') {
|
|
symbolName = exportSymbol;
|
|
}
|
|
else {
|
|
symbolName = exportSymbol.as;
|
|
}
|
|
symbolName = unescapeIdentifier(symbolName);
|
|
var symName = symbolName;
|
|
if (typeof exportSymbol !== 'string') {
|
|
symName = unescapeIdentifier(exportSymbol.name);
|
|
}
|
|
var resolvedModule = _this.resolveModule(moduleExport.from, filePath);
|
|
if (resolvedModule) {
|
|
var targetSymbol = _this.getStaticSymbol(resolvedModule, symName);
|
|
var sourceSymbol = _this.getStaticSymbol(filePath, symbolName);
|
|
resolvedSymbols.push(_this.createExport(sourceSymbol, targetSymbol));
|
|
}
|
|
});
|
|
}
|
|
else {
|
|
// Handle the symbols loaded by 'export *' directives.
|
|
var resolvedModule = this_1.resolveModule(moduleExport.from, filePath);
|
|
if (resolvedModule && resolvedModule !== filePath) {
|
|
var nestedExports = this_1.getSymbolsOf(resolvedModule);
|
|
nestedExports.forEach(function (targetSymbol) {
|
|
var sourceSymbol = _this.getStaticSymbol(filePath, targetSymbol.name);
|
|
resolvedSymbols.push(_this.createExport(sourceSymbol, targetSymbol));
|
|
});
|
|
}
|
|
}
|
|
};
|
|
var this_1 = this;
|
|
try {
|
|
for (var _c = __values(metadata['exports']), _d = _c.next(); !_d.done; _d = _c.next()) {
|
|
var moduleExport = _d.value;
|
|
_loop_1(moduleExport);
|
|
}
|
|
}
|
|
catch (e_2_1) { e_2 = { error: e_2_1 }; }
|
|
finally {
|
|
try {
|
|
if (_d && !_d.done && (_a = _c.return)) _a.call(_c);
|
|
}
|
|
finally { if (e_2) throw e_2.error; }
|
|
}
|
|
}
|
|
// handle the actual metadata. Has to be after the exports
|
|
// as there might be collisions in the names, and we want the symbols
|
|
// of the current module to win ofter reexports.
|
|
if (metadata['metadata']) {
|
|
// handle direct declarations of the symbol
|
|
var topLevelSymbolNames_1 = new Set(Object.keys(metadata['metadata']).map(unescapeIdentifier));
|
|
var origins_1 = metadata['origins'] || {};
|
|
Object.keys(metadata['metadata']).forEach(function (metadataKey) {
|
|
var symbolMeta = metadata['metadata'][metadataKey];
|
|
var name = unescapeIdentifier(metadataKey);
|
|
var symbol = _this.getStaticSymbol(filePath, name);
|
|
var origin = origins_1.hasOwnProperty(metadataKey) && origins_1[metadataKey];
|
|
if (origin) {
|
|
// If the symbol is from a bundled index, use the declaration location of the
|
|
// symbol so relative references (such as './my.html') will be calculated
|
|
// correctly.
|
|
var originFilePath = _this.resolveModule(origin, filePath);
|
|
if (!originFilePath) {
|
|
_this.reportError(new Error("Couldn't resolve original symbol for " + origin + " from " + _this.host.getOutputName(filePath)));
|
|
}
|
|
else {
|
|
_this.symbolResourcePaths.set(symbol, originFilePath);
|
|
}
|
|
}
|
|
resolvedSymbols.push(_this.createResolvedSymbol(symbol, filePath, topLevelSymbolNames_1, symbolMeta));
|
|
});
|
|
}
|
|
var uniqueSymbols = new Set();
|
|
try {
|
|
for (var resolvedSymbols_1 = __values(resolvedSymbols), resolvedSymbols_1_1 = resolvedSymbols_1.next(); !resolvedSymbols_1_1.done; resolvedSymbols_1_1 = resolvedSymbols_1.next()) {
|
|
var resolvedSymbol = resolvedSymbols_1_1.value;
|
|
this.resolvedSymbols.set(resolvedSymbol.symbol, resolvedSymbol);
|
|
uniqueSymbols.add(resolvedSymbol.symbol);
|
|
}
|
|
}
|
|
catch (e_3_1) { e_3 = { error: e_3_1 }; }
|
|
finally {
|
|
try {
|
|
if (resolvedSymbols_1_1 && !resolvedSymbols_1_1.done && (_b = resolvedSymbols_1.return)) _b.call(resolvedSymbols_1);
|
|
}
|
|
finally { if (e_3) throw e_3.error; }
|
|
}
|
|
this.symbolFromFile.set(filePath, Array.from(uniqueSymbols));
|
|
};
|
|
StaticSymbolResolver.prototype.createResolvedSymbol = function (sourceSymbol, topLevelPath, topLevelSymbolNames, metadata) {
|
|
var _this = this;
|
|
// For classes that don't have Angular summaries / metadata,
|
|
// we only keep their arity, but nothing else
|
|
// (e.g. their constructor parameters).
|
|
// We do this to prevent introducing deep imports
|
|
// as we didn't generate .ngfactory.ts files with proper reexports.
|
|
var isTsFile = TS.test(sourceSymbol.filePath);
|
|
if (this.summaryResolver.isLibraryFile(sourceSymbol.filePath) && !isTsFile && metadata &&
|
|
metadata['__symbolic'] === 'class') {
|
|
var transformedMeta_1 = { __symbolic: 'class', arity: metadata.arity };
|
|
return new ResolvedStaticSymbol(sourceSymbol, transformedMeta_1);
|
|
}
|
|
var _originalFileMemo;
|
|
var getOriginalName = function () {
|
|
if (!_originalFileMemo) {
|
|
// Guess what the original file name is from the reference. If it has a `.d.ts` extension
|
|
// replace it with `.ts`. If it already has `.ts` just leave it in place. If it doesn't have
|
|
// .ts or .d.ts, append `.ts'. Also, if it is in `node_modules`, trim the `node_module`
|
|
// location as it is not important to finding the file.
|
|
_originalFileMemo =
|
|
_this.host.getOutputName(topLevelPath.replace(/((\.ts)|(\.d\.ts)|)$/, '.ts')
|
|
.replace(/^.*node_modules[/\\]/, ''));
|
|
}
|
|
return _originalFileMemo;
|
|
};
|
|
var self = this;
|
|
var ReferenceTransformer = /** @class */ (function (_super) {
|
|
__extends(ReferenceTransformer, _super);
|
|
function ReferenceTransformer() {
|
|
return _super !== null && _super.apply(this, arguments) || this;
|
|
}
|
|
ReferenceTransformer.prototype.visitStringMap = function (map, functionParams) {
|
|
var symbolic = map['__symbolic'];
|
|
if (symbolic === 'function') {
|
|
var oldLen = functionParams.length;
|
|
functionParams.push.apply(functionParams, __spreadArray([], __read((map['parameters'] || []))));
|
|
var result = _super.prototype.visitStringMap.call(this, map, functionParams);
|
|
functionParams.length = oldLen;
|
|
return result;
|
|
}
|
|
else if (symbolic === 'reference') {
|
|
var module = map['module'];
|
|
var name = map['name'] ? unescapeIdentifier(map['name']) : map['name'];
|
|
if (!name) {
|
|
return null;
|
|
}
|
|
var filePath = void 0;
|
|
if (module) {
|
|
filePath = self.resolveModule(module, sourceSymbol.filePath);
|
|
if (!filePath) {
|
|
return {
|
|
__symbolic: 'error',
|
|
message: "Could not resolve " + module + " relative to " + self.host.getMetadataFor(sourceSymbol.filePath) + ".",
|
|
line: map['line'],
|
|
character: map['character'],
|
|
fileName: getOriginalName()
|
|
};
|
|
}
|
|
return {
|
|
__symbolic: 'resolved',
|
|
symbol: self.getStaticSymbol(filePath, name),
|
|
line: map['line'],
|
|
character: map['character'],
|
|
fileName: getOriginalName()
|
|
};
|
|
}
|
|
else if (functionParams.indexOf(name) >= 0) {
|
|
// reference to a function parameter
|
|
return { __symbolic: 'reference', name: name };
|
|
}
|
|
else {
|
|
if (topLevelSymbolNames.has(name)) {
|
|
return self.getStaticSymbol(topLevelPath, name);
|
|
}
|
|
// ambient value
|
|
null;
|
|
}
|
|
}
|
|
else if (symbolic === 'error') {
|
|
return Object.assign(Object.assign({}, map), { fileName: getOriginalName() });
|
|
}
|
|
else {
|
|
return _super.prototype.visitStringMap.call(this, map, functionParams);
|
|
}
|
|
};
|
|
return ReferenceTransformer;
|
|
}(ValueTransformer));
|
|
var transformedMeta = visitValue(metadata, new ReferenceTransformer(), []);
|
|
var unwrappedTransformedMeta = unwrapResolvedMetadata(transformedMeta);
|
|
if (unwrappedTransformedMeta instanceof StaticSymbol) {
|
|
return this.createExport(sourceSymbol, unwrappedTransformedMeta);
|
|
}
|
|
return new ResolvedStaticSymbol(sourceSymbol, transformedMeta);
|
|
};
|
|
StaticSymbolResolver.prototype.createExport = function (sourceSymbol, targetSymbol) {
|
|
sourceSymbol.assertNoMembers();
|
|
targetSymbol.assertNoMembers();
|
|
if (this.summaryResolver.isLibraryFile(sourceSymbol.filePath) &&
|
|
this.summaryResolver.isLibraryFile(targetSymbol.filePath)) {
|
|
// This case is for an ng library importing symbols from a plain ts library
|
|
// transitively.
|
|
// Note: We rely on the fact that we discover symbols in the direction
|
|
// from source files to library files
|
|
this.importAs.set(targetSymbol, this.getImportAs(sourceSymbol) || sourceSymbol);
|
|
}
|
|
return new ResolvedStaticSymbol(sourceSymbol, targetSymbol);
|
|
};
|
|
StaticSymbolResolver.prototype.reportError = function (error, context, path) {
|
|
if (this.errorRecorder) {
|
|
this.errorRecorder(error, (context && context.filePath) || path);
|
|
}
|
|
else {
|
|
throw error;
|
|
}
|
|
};
|
|
/**
|
|
* @param module an absolute path to a module file.
|
|
*/
|
|
StaticSymbolResolver.prototype.getModuleMetadata = function (module) {
|
|
var moduleMetadata = this.metadataCache.get(module);
|
|
if (!moduleMetadata) {
|
|
var moduleMetadatas = this.host.getMetadataFor(module);
|
|
if (moduleMetadatas) {
|
|
var maxVersion_1 = -1;
|
|
moduleMetadatas.forEach(function (md) {
|
|
if (md && md['version'] > maxVersion_1) {
|
|
maxVersion_1 = md['version'];
|
|
moduleMetadata = md;
|
|
}
|
|
});
|
|
}
|
|
if (!moduleMetadata) {
|
|
moduleMetadata =
|
|
{ __symbolic: 'module', version: SUPPORTED_SCHEMA_VERSION, module: module, metadata: {} };
|
|
}
|
|
if (moduleMetadata['version'] != SUPPORTED_SCHEMA_VERSION) {
|
|
var errorMessage = moduleMetadata['version'] == 2 ?
|
|
"Unsupported metadata version " + moduleMetadata['version'] + " for module " + module + ". This module should be compiled with a newer version of ngc" :
|
|
"Metadata version mismatch for module " + this.host.getOutputName(module) + ", found version " + moduleMetadata['version'] + ", expected " + SUPPORTED_SCHEMA_VERSION;
|
|
this.reportError(new Error(errorMessage));
|
|
}
|
|
this.metadataCache.set(module, moduleMetadata);
|
|
}
|
|
return moduleMetadata;
|
|
};
|
|
StaticSymbolResolver.prototype.getSymbolByModule = function (module, symbolName, containingFile) {
|
|
var filePath = this.resolveModule(module, containingFile);
|
|
if (!filePath) {
|
|
this.reportError(new Error("Could not resolve module " + module + (containingFile ? ' relative to ' + this.host.getOutputName(containingFile) : '')));
|
|
return this.getStaticSymbol("ERROR:" + module, symbolName);
|
|
}
|
|
return this.getStaticSymbol(filePath, symbolName);
|
|
};
|
|
StaticSymbolResolver.prototype.resolveModule = function (module, containingFile) {
|
|
try {
|
|
return this.host.moduleNameToFileName(module, containingFile);
|
|
}
|
|
catch (e) {
|
|
console.error("Could not resolve module '" + module + "' relative to file " + containingFile);
|
|
this.reportError(e, undefined, containingFile);
|
|
}
|
|
return null;
|
|
};
|
|
return StaticSymbolResolver;
|
|
}());
|
|
// Remove extra underscore from escaped identifier.
|
|
// See https://github.com/Microsoft/TypeScript/blob/master/src/compiler/utilities.ts
|
|
function unescapeIdentifier(identifier) {
|
|
return identifier.startsWith('___') ? identifier.substr(1) : identifier;
|
|
}
|
|
function unwrapResolvedMetadata(metadata) {
|
|
if (metadata && metadata.__symbolic === 'resolved') {
|
|
return metadata.symbol;
|
|
}
|
|
return metadata;
|
|
}
|
|
|
|
function serializeSummaries(srcFileName, forJitCtx, summaryResolver, symbolResolver, symbols, types, createExternalSymbolReexports) {
|
|
if (createExternalSymbolReexports === void 0) { createExternalSymbolReexports = false; }
|
|
var toJsonSerializer = new ToJsonSerializer(symbolResolver, summaryResolver, srcFileName);
|
|
// for symbols, we use everything except for the class metadata itself
|
|
// (we keep the statics though), as the class metadata is contained in the
|
|
// CompileTypeSummary.
|
|
symbols.forEach(function (resolvedSymbol) { return toJsonSerializer.addSummary({ symbol: resolvedSymbol.symbol, metadata: resolvedSymbol.metadata }); });
|
|
// Add type summaries.
|
|
types.forEach(function (_a) {
|
|
var summary = _a.summary, metadata = _a.metadata;
|
|
toJsonSerializer.addSummary({ symbol: summary.type.reference, metadata: undefined, type: summary });
|
|
});
|
|
var _a = toJsonSerializer.serialize(createExternalSymbolReexports), json = _a.json, exportAs = _a.exportAs;
|
|
if (forJitCtx) {
|
|
var forJitSerializer_1 = new ForJitSerializer(forJitCtx, symbolResolver, summaryResolver);
|
|
types.forEach(function (_a) {
|
|
var summary = _a.summary, metadata = _a.metadata;
|
|
forJitSerializer_1.addSourceType(summary, metadata);
|
|
});
|
|
toJsonSerializer.unprocessedSymbolSummariesBySymbol.forEach(function (summary) {
|
|
if (summaryResolver.isLibraryFile(summary.symbol.filePath) && summary.type) {
|
|
forJitSerializer_1.addLibType(summary.type);
|
|
}
|
|
});
|
|
forJitSerializer_1.serialize(exportAs);
|
|
}
|
|
return { json: json, exportAs: exportAs };
|
|
}
|
|
function deserializeSummaries(symbolCache, summaryResolver, libraryFileName, json) {
|
|
var deserializer = new FromJsonDeserializer(symbolCache, summaryResolver);
|
|
return deserializer.deserialize(libraryFileName, json);
|
|
}
|
|
function createForJitStub(outputCtx, reference) {
|
|
return createSummaryForJitFunction(outputCtx, reference, NULL_EXPR);
|
|
}
|
|
function createSummaryForJitFunction(outputCtx, reference, value) {
|
|
var fnName = summaryForJitName(reference.name);
|
|
outputCtx.statements.push(fn([], [new ReturnStatement(value)], new ArrayType(DYNAMIC_TYPE)).toDeclStmt(fnName, [
|
|
exports.StmtModifier.Final, exports.StmtModifier.Exported
|
|
]));
|
|
}
|
|
var ToJsonSerializer = /** @class */ (function (_super) {
|
|
__extends(ToJsonSerializer, _super);
|
|
function ToJsonSerializer(symbolResolver, summaryResolver, srcFileName) {
|
|
var _this = _super.call(this) || this;
|
|
_this.symbolResolver = symbolResolver;
|
|
_this.summaryResolver = summaryResolver;
|
|
_this.srcFileName = srcFileName;
|
|
// Note: This only contains symbols without members.
|
|
_this.symbols = [];
|
|
_this.indexBySymbol = new Map();
|
|
_this.reexportedBy = new Map();
|
|
// This now contains a `__symbol: number` in the place of
|
|
// StaticSymbols, but otherwise has the same shape as the original objects.
|
|
_this.processedSummaryBySymbol = new Map();
|
|
_this.processedSummaries = [];
|
|
_this.unprocessedSymbolSummariesBySymbol = new Map();
|
|
_this.moduleName = symbolResolver.getKnownModuleName(srcFileName);
|
|
return _this;
|
|
}
|
|
ToJsonSerializer.prototype.addSummary = function (summary) {
|
|
var _this = this;
|
|
var unprocessedSummary = this.unprocessedSymbolSummariesBySymbol.get(summary.symbol);
|
|
var processedSummary = this.processedSummaryBySymbol.get(summary.symbol);
|
|
if (!unprocessedSummary) {
|
|
unprocessedSummary = { symbol: summary.symbol, metadata: undefined };
|
|
this.unprocessedSymbolSummariesBySymbol.set(summary.symbol, unprocessedSummary);
|
|
processedSummary = { symbol: this.processValue(summary.symbol, 0 /* None */) };
|
|
this.processedSummaries.push(processedSummary);
|
|
this.processedSummaryBySymbol.set(summary.symbol, processedSummary);
|
|
}
|
|
if (!unprocessedSummary.metadata && summary.metadata) {
|
|
var metadata_1 = summary.metadata || {};
|
|
if (metadata_1.__symbolic === 'class') {
|
|
// For classes, we keep everything except their class decorators.
|
|
// We need to keep e.g. the ctor args, method names, method decorators
|
|
// so that the class can be extended in another compilation unit.
|
|
// We don't keep the class decorators as
|
|
// 1) they refer to data
|
|
// that should not cause a rebuild of downstream compilation units
|
|
// (e.g. inline templates of @Component, or @NgModule.declarations)
|
|
// 2) their data is already captured in TypeSummaries, e.g. DirectiveSummary.
|
|
var clone_1 = {};
|
|
Object.keys(metadata_1).forEach(function (propName) {
|
|
if (propName !== 'decorators') {
|
|
clone_1[propName] = metadata_1[propName];
|
|
}
|
|
});
|
|
metadata_1 = clone_1;
|
|
}
|
|
else if (isCall(metadata_1)) {
|
|
if (!isFunctionCall(metadata_1) && !isMethodCallOnVariable(metadata_1)) {
|
|
// Don't store complex calls as we won't be able to simplify them anyways later on.
|
|
metadata_1 = {
|
|
__symbolic: 'error',
|
|
message: 'Complex function calls are not supported.',
|
|
};
|
|
}
|
|
}
|
|
// Note: We need to keep storing ctor calls for e.g.
|
|
// `export const x = new InjectionToken(...)`
|
|
unprocessedSummary.metadata = metadata_1;
|
|
processedSummary.metadata = this.processValue(metadata_1, 1 /* ResolveValue */);
|
|
if (metadata_1 instanceof StaticSymbol &&
|
|
this.summaryResolver.isLibraryFile(metadata_1.filePath)) {
|
|
var declarationSymbol = this.symbols[this.indexBySymbol.get(metadata_1)];
|
|
if (!isLoweredSymbol(declarationSymbol.name)) {
|
|
// Note: symbols that were introduced during codegen in the user file can have a reexport
|
|
// if a user used `export *`. However, we can't rely on this as tsickle will change
|
|
// `export *` into named exports, using only the information from the typechecker.
|
|
// As we introduce the new symbols after typecheck, Tsickle does not know about them,
|
|
// and omits them when expanding `export *`.
|
|
// So we have to keep reexporting these symbols manually via .ngfactory files.
|
|
this.reexportedBy.set(declarationSymbol, summary.symbol);
|
|
}
|
|
}
|
|
}
|
|
if (!unprocessedSummary.type && summary.type) {
|
|
unprocessedSummary.type = summary.type;
|
|
// Note: We don't add the summaries of all referenced symbols as for the ResolvedSymbols,
|
|
// as the type summaries already contain the transitive data that they require
|
|
// (in a minimal way).
|
|
processedSummary.type = this.processValue(summary.type, 0 /* None */);
|
|
// except for reexported directives / pipes, so we need to store
|
|
// their summaries explicitly.
|
|
if (summary.type.summaryKind === exports.CompileSummaryKind.NgModule) {
|
|
var ngModuleSummary = summary.type;
|
|
ngModuleSummary.exportedDirectives.concat(ngModuleSummary.exportedPipes).forEach(function (id) {
|
|
var symbol = id.reference;
|
|
if (_this.summaryResolver.isLibraryFile(symbol.filePath) &&
|
|
!_this.unprocessedSymbolSummariesBySymbol.has(symbol)) {
|
|
var summary_1 = _this.summaryResolver.resolveSummary(symbol);
|
|
if (summary_1) {
|
|
_this.addSummary(summary_1);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
}
|
|
};
|
|
/**
|
|
* @param createExternalSymbolReexports Whether external static symbols should be re-exported.
|
|
* This can be enabled if external symbols should be re-exported by the current module in
|
|
* order to avoid dynamically generated module dependencies which can break strict dependency
|
|
* enforcements (as in Google3). Read more here: https://github.com/angular/angular/issues/25644
|
|
*/
|
|
ToJsonSerializer.prototype.serialize = function (createExternalSymbolReexports) {
|
|
var _this = this;
|
|
var exportAs = [];
|
|
var json = JSON.stringify({
|
|
moduleName: this.moduleName,
|
|
summaries: this.processedSummaries,
|
|
symbols: this.symbols.map(function (symbol, index) {
|
|
symbol.assertNoMembers();
|
|
var importAs = undefined;
|
|
if (_this.summaryResolver.isLibraryFile(symbol.filePath)) {
|
|
var reexportSymbol = _this.reexportedBy.get(symbol);
|
|
if (reexportSymbol) {
|
|
// In case the given external static symbol is already manually exported by the
|
|
// user, we just proxy the external static symbol reference to the manual export.
|
|
// This ensures that the AOT compiler imports the external symbol through the
|
|
// user export and does not introduce another dependency which is not needed.
|
|
importAs = _this.indexBySymbol.get(reexportSymbol);
|
|
}
|
|
else if (createExternalSymbolReexports) {
|
|
// In this case, the given external static symbol is *not* manually exported by
|
|
// the user, and we manually create a re-export in the factory file so that we
|
|
// don't introduce another module dependency. This is useful when running within
|
|
// Bazel so that the AOT compiler does not introduce any module dependencies
|
|
// which can break the strict dependency enforcement. (e.g. as in Google3)
|
|
// Read more about this here: https://github.com/angular/angular/issues/25644
|
|
var summary = _this.unprocessedSymbolSummariesBySymbol.get(symbol);
|
|
if (!summary || !summary.metadata || summary.metadata.__symbolic !== 'interface') {
|
|
importAs = symbol.name + "_" + index;
|
|
exportAs.push({ symbol: symbol, exportAs: importAs });
|
|
}
|
|
}
|
|
}
|
|
return {
|
|
__symbol: index,
|
|
name: symbol.name,
|
|
filePath: _this.summaryResolver.toSummaryFileName(symbol.filePath, _this.srcFileName),
|
|
importAs: importAs
|
|
};
|
|
})
|
|
});
|
|
return { json: json, exportAs: exportAs };
|
|
};
|
|
ToJsonSerializer.prototype.processValue = function (value, flags) {
|
|
return visitValue(value, this, flags);
|
|
};
|
|
ToJsonSerializer.prototype.visitOther = function (value, context) {
|
|
if (value instanceof StaticSymbol) {
|
|
var baseSymbol = this.symbolResolver.getStaticSymbol(value.filePath, value.name);
|
|
var index = this.visitStaticSymbol(baseSymbol, context);
|
|
return { __symbol: index, members: value.members };
|
|
}
|
|
};
|
|
/**
|
|
* Strip line and character numbers from ngsummaries.
|
|
* Emitting them causes white spaces changes to retrigger upstream
|
|
* recompilations in bazel.
|
|
* TODO: find out a way to have line and character numbers in errors without
|
|
* excessive recompilation in bazel.
|
|
*/
|
|
ToJsonSerializer.prototype.visitStringMap = function (map, context) {
|
|
if (map['__symbolic'] === 'resolved') {
|
|
return visitValue(map['symbol'], this, context);
|
|
}
|
|
if (map['__symbolic'] === 'error') {
|
|
delete map['line'];
|
|
delete map['character'];
|
|
}
|
|
return _super.prototype.visitStringMap.call(this, map, context);
|
|
};
|
|
/**
|
|
* Returns null if the options.resolveValue is true, and the summary for the symbol
|
|
* resolved to a type or could not be resolved.
|
|
*/
|
|
ToJsonSerializer.prototype.visitStaticSymbol = function (baseSymbol, flags) {
|
|
var index = this.indexBySymbol.get(baseSymbol);
|
|
var summary = null;
|
|
if (flags & 1 /* ResolveValue */ &&
|
|
this.summaryResolver.isLibraryFile(baseSymbol.filePath)) {
|
|
if (this.unprocessedSymbolSummariesBySymbol.has(baseSymbol)) {
|
|
// the summary for this symbol was already added
|
|
// -> nothing to do.
|
|
return index;
|
|
}
|
|
summary = this.loadSummary(baseSymbol);
|
|
if (summary && summary.metadata instanceof StaticSymbol) {
|
|
// The summary is a reexport
|
|
index = this.visitStaticSymbol(summary.metadata, flags);
|
|
// reset the summary as it is just a reexport, so we don't want to store it.
|
|
summary = null;
|
|
}
|
|
}
|
|
else if (index != null) {
|
|
// Note: == on purpose to compare with undefined!
|
|
// No summary and the symbol is already added -> nothing to do.
|
|
return index;
|
|
}
|
|
// Note: == on purpose to compare with undefined!
|
|
if (index == null) {
|
|
index = this.symbols.length;
|
|
this.symbols.push(baseSymbol);
|
|
}
|
|
this.indexBySymbol.set(baseSymbol, index);
|
|
if (summary) {
|
|
this.addSummary(summary);
|
|
}
|
|
return index;
|
|
};
|
|
ToJsonSerializer.prototype.loadSummary = function (symbol) {
|
|
var summary = this.summaryResolver.resolveSummary(symbol);
|
|
if (!summary) {
|
|
// some symbols might originate from a plain typescript library
|
|
// that just exported .d.ts and .metadata.json files, i.e. where no summary
|
|
// files were created.
|
|
var resolvedSymbol = this.symbolResolver.resolveSymbol(symbol);
|
|
if (resolvedSymbol) {
|
|
summary = { symbol: resolvedSymbol.symbol, metadata: resolvedSymbol.metadata };
|
|
}
|
|
}
|
|
return summary;
|
|
};
|
|
return ToJsonSerializer;
|
|
}(ValueTransformer));
|
|
var ForJitSerializer = /** @class */ (function () {
|
|
function ForJitSerializer(outputCtx, symbolResolver, summaryResolver) {
|
|
this.outputCtx = outputCtx;
|
|
this.symbolResolver = symbolResolver;
|
|
this.summaryResolver = summaryResolver;
|
|
this.data = [];
|
|
}
|
|
ForJitSerializer.prototype.addSourceType = function (summary, metadata) {
|
|
this.data.push({ summary: summary, metadata: metadata, isLibrary: false });
|
|
};
|
|
ForJitSerializer.prototype.addLibType = function (summary) {
|
|
this.data.push({ summary: summary, metadata: null, isLibrary: true });
|
|
};
|
|
ForJitSerializer.prototype.serialize = function (exportAsArr) {
|
|
var e_1, _a, e_2, _b, e_3, _c;
|
|
var _this = this;
|
|
var exportAsBySymbol = new Map();
|
|
try {
|
|
for (var exportAsArr_1 = __values(exportAsArr), exportAsArr_1_1 = exportAsArr_1.next(); !exportAsArr_1_1.done; exportAsArr_1_1 = exportAsArr_1.next()) {
|
|
var _d = exportAsArr_1_1.value, symbol = _d.symbol, exportAs = _d.exportAs;
|
|
exportAsBySymbol.set(symbol, exportAs);
|
|
}
|
|
}
|
|
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
finally {
|
|
try {
|
|
if (exportAsArr_1_1 && !exportAsArr_1_1.done && (_a = exportAsArr_1.return)) _a.call(exportAsArr_1);
|
|
}
|
|
finally { if (e_1) throw e_1.error; }
|
|
}
|
|
var ngModuleSymbols = new Set();
|
|
try {
|
|
for (var _e = __values(this.data), _f = _e.next(); !_f.done; _f = _e.next()) {
|
|
var _g = _f.value, summary = _g.summary, metadata = _g.metadata, isLibrary = _g.isLibrary;
|
|
if (summary.summaryKind === exports.CompileSummaryKind.NgModule) {
|
|
// collect the symbols that refer to NgModule classes.
|
|
// Note: we can't just rely on `summary.type.summaryKind` to determine this as
|
|
// we don't add the summaries of all referenced symbols when we serialize type summaries.
|
|
// See serializeSummaries for details.
|
|
ngModuleSymbols.add(summary.type.reference);
|
|
var modSummary = summary;
|
|
try {
|
|
for (var _h = (e_3 = void 0, __values(modSummary.modules)), _j = _h.next(); !_j.done; _j = _h.next()) {
|
|
var mod = _j.value;
|
|
ngModuleSymbols.add(mod.reference);
|
|
}
|
|
}
|
|
catch (e_3_1) { e_3 = { error: e_3_1 }; }
|
|
finally {
|
|
try {
|
|
if (_j && !_j.done && (_c = _h.return)) _c.call(_h);
|
|
}
|
|
finally { if (e_3) throw e_3.error; }
|
|
}
|
|
}
|
|
if (!isLibrary) {
|
|
var fnName = summaryForJitName(summary.type.reference.name);
|
|
createSummaryForJitFunction(this.outputCtx, summary.type.reference, this.serializeSummaryWithDeps(summary, metadata));
|
|
}
|
|
}
|
|
}
|
|
catch (e_2_1) { e_2 = { error: e_2_1 }; }
|
|
finally {
|
|
try {
|
|
if (_f && !_f.done && (_b = _e.return)) _b.call(_e);
|
|
}
|
|
finally { if (e_2) throw e_2.error; }
|
|
}
|
|
ngModuleSymbols.forEach(function (ngModuleSymbol) {
|
|
if (_this.summaryResolver.isLibraryFile(ngModuleSymbol.filePath)) {
|
|
var exportAs = exportAsBySymbol.get(ngModuleSymbol) || ngModuleSymbol.name;
|
|
var jitExportAsName = summaryForJitName(exportAs);
|
|
_this.outputCtx.statements.push(variable(jitExportAsName)
|
|
.set(_this.serializeSummaryRef(ngModuleSymbol))
|
|
.toDeclStmt(null, [exports.StmtModifier.Exported]));
|
|
}
|
|
});
|
|
};
|
|
ForJitSerializer.prototype.serializeSummaryWithDeps = function (summary, metadata) {
|
|
var _this = this;
|
|
var expressions = [this.serializeSummary(summary)];
|
|
var providers = [];
|
|
if (metadata instanceof CompileNgModuleMetadata) {
|
|
expressions.push.apply(expressions, __spreadArray([], __read(
|
|
// For directives / pipes, we only add the declared ones,
|
|
// and rely on transitively importing NgModules to get the transitive
|
|
// summaries.
|
|
metadata.declaredDirectives.concat(metadata.declaredPipes)
|
|
.map(function (type) { return type.reference; })
|
|
// For modules,
|
|
// we also add the summaries for modules
|
|
// from libraries.
|
|
// This is ok as we produce reexports for all transitive modules.
|
|
.concat(metadata.transitiveModule.modules.map(function (type) { return type.reference; })
|
|
.filter(function (ref) { return ref !== metadata.type.reference; }))
|
|
.map(function (ref) { return _this.serializeSummaryRef(ref); }))));
|
|
// Note: We don't use `NgModuleSummary.providers`, as that one is transitive,
|
|
// and we already have transitive modules.
|
|
providers = metadata.providers;
|
|
}
|
|
else if (summary.summaryKind === exports.CompileSummaryKind.Directive) {
|
|
var dirSummary = summary;
|
|
providers = dirSummary.providers.concat(dirSummary.viewProviders);
|
|
}
|
|
// Note: We can't just refer to the `ngsummary.ts` files for `useClass` providers (as we do for
|
|
// declaredDirectives / declaredPipes), as we allow
|
|
// providers without ctor arguments to skip the `@Injectable` decorator,
|
|
// i.e. we didn't generate .ngsummary.ts files for these.
|
|
expressions.push.apply(expressions, __spreadArray([], __read(providers.filter(function (provider) { return !!provider.useClass; }).map(function (provider) { return _this.serializeSummary({
|
|
summaryKind: exports.CompileSummaryKind.Injectable,
|
|
type: provider.useClass
|
|
}); }))));
|
|
return literalArr(expressions);
|
|
};
|
|
ForJitSerializer.prototype.serializeSummaryRef = function (typeSymbol) {
|
|
var jitImportedSymbol = this.symbolResolver.getStaticSymbol(summaryForJitFileName(typeSymbol.filePath), summaryForJitName(typeSymbol.name));
|
|
return this.outputCtx.importExpr(jitImportedSymbol);
|
|
};
|
|
ForJitSerializer.prototype.serializeSummary = function (data) {
|
|
var outputCtx = this.outputCtx;
|
|
var Transformer = /** @class */ (function () {
|
|
function Transformer() {
|
|
}
|
|
Transformer.prototype.visitArray = function (arr, context) {
|
|
var _this = this;
|
|
return literalArr(arr.map(function (entry) { return visitValue(entry, _this, context); }));
|
|
};
|
|
Transformer.prototype.visitStringMap = function (map, context) {
|
|
var _this = this;
|
|
return new LiteralMapExpr(Object.keys(map).map(function (key) { return new LiteralMapEntry(key, visitValue(map[key], _this, context), false); }));
|
|
};
|
|
Transformer.prototype.visitPrimitive = function (value, context) {
|
|
return literal(value);
|
|
};
|
|
Transformer.prototype.visitOther = function (value, context) {
|
|
if (value instanceof StaticSymbol) {
|
|
return outputCtx.importExpr(value);
|
|
}
|
|
else {
|
|
throw new Error("Illegal State: Encountered value " + value);
|
|
}
|
|
};
|
|
return Transformer;
|
|
}());
|
|
return visitValue(data, new Transformer(), null);
|
|
};
|
|
return ForJitSerializer;
|
|
}());
|
|
var FromJsonDeserializer = /** @class */ (function (_super) {
|
|
__extends(FromJsonDeserializer, _super);
|
|
function FromJsonDeserializer(symbolCache, summaryResolver) {
|
|
var _this = _super.call(this) || this;
|
|
_this.symbolCache = symbolCache;
|
|
_this.summaryResolver = summaryResolver;
|
|
return _this;
|
|
}
|
|
FromJsonDeserializer.prototype.deserialize = function (libraryFileName, json) {
|
|
var _this = this;
|
|
var data = JSON.parse(json);
|
|
var allImportAs = [];
|
|
this.symbols = data.symbols.map(function (serializedSymbol) { return _this.symbolCache.get(_this.summaryResolver.fromSummaryFileName(serializedSymbol.filePath, libraryFileName), serializedSymbol.name); });
|
|
data.symbols.forEach(function (serializedSymbol, index) {
|
|
var symbol = _this.symbols[index];
|
|
var importAs = serializedSymbol.importAs;
|
|
if (typeof importAs === 'number') {
|
|
allImportAs.push({ symbol: symbol, importAs: _this.symbols[importAs] });
|
|
}
|
|
else if (typeof importAs === 'string') {
|
|
allImportAs.push({ symbol: symbol, importAs: _this.symbolCache.get(ngfactoryFilePath(libraryFileName), importAs) });
|
|
}
|
|
});
|
|
var summaries = visitValue(data.summaries, this, null);
|
|
return { moduleName: data.moduleName, summaries: summaries, importAs: allImportAs };
|
|
};
|
|
FromJsonDeserializer.prototype.visitStringMap = function (map, context) {
|
|
if ('__symbol' in map) {
|
|
var baseSymbol = this.symbols[map['__symbol']];
|
|
var members = map['members'];
|
|
return members.length ? this.symbolCache.get(baseSymbol.filePath, baseSymbol.name, members) :
|
|
baseSymbol;
|
|
}
|
|
else {
|
|
return _super.prototype.visitStringMap.call(this, map, context);
|
|
}
|
|
};
|
|
return FromJsonDeserializer;
|
|
}(ValueTransformer));
|
|
function isCall(metadata) {
|
|
return metadata && metadata.__symbolic === 'call';
|
|
}
|
|
function isFunctionCall(metadata) {
|
|
return isCall(metadata) && unwrapResolvedMetadata(metadata.expression) instanceof StaticSymbol;
|
|
}
|
|
function isMethodCallOnVariable(metadata) {
|
|
return isCall(metadata) && metadata.expression && metadata.expression.__symbolic === 'select' &&
|
|
unwrapResolvedMetadata(metadata.expression.expression) instanceof StaticSymbol;
|
|
}
|
|
|
|
var AotCompiler = /** @class */ (function () {
|
|
function AotCompiler(_config, _options, _host, reflector, _metadataResolver, _templateParser, _styleCompiler, _viewCompiler, _typeCheckCompiler, _ngModuleCompiler, _injectableCompiler, _outputEmitter, _summaryResolver, _symbolResolver) {
|
|
this._config = _config;
|
|
this._options = _options;
|
|
this._host = _host;
|
|
this.reflector = reflector;
|
|
this._metadataResolver = _metadataResolver;
|
|
this._templateParser = _templateParser;
|
|
this._styleCompiler = _styleCompiler;
|
|
this._viewCompiler = _viewCompiler;
|
|
this._typeCheckCompiler = _typeCheckCompiler;
|
|
this._ngModuleCompiler = _ngModuleCompiler;
|
|
this._injectableCompiler = _injectableCompiler;
|
|
this._outputEmitter = _outputEmitter;
|
|
this._summaryResolver = _summaryResolver;
|
|
this._symbolResolver = _symbolResolver;
|
|
this._templateAstCache = new Map();
|
|
this._analyzedFiles = new Map();
|
|
this._analyzedFilesForInjectables = new Map();
|
|
}
|
|
AotCompiler.prototype.clearCache = function () {
|
|
this._metadataResolver.clearCache();
|
|
};
|
|
AotCompiler.prototype.analyzeModulesSync = function (rootFiles) {
|
|
var _this = this;
|
|
var analyzeResult = analyzeAndValidateNgModules(rootFiles, this._host, this._symbolResolver, this._metadataResolver);
|
|
analyzeResult.ngModules.forEach(function (ngModule) { return _this._metadataResolver.loadNgModuleDirectiveAndPipeMetadata(ngModule.type.reference, true); });
|
|
return analyzeResult;
|
|
};
|
|
AotCompiler.prototype.analyzeModulesAsync = function (rootFiles) {
|
|
var _this = this;
|
|
var analyzeResult = analyzeAndValidateNgModules(rootFiles, this._host, this._symbolResolver, this._metadataResolver);
|
|
return Promise
|
|
.all(analyzeResult.ngModules.map(function (ngModule) { return _this._metadataResolver.loadNgModuleDirectiveAndPipeMetadata(ngModule.type.reference, false); }))
|
|
.then(function () { return analyzeResult; });
|
|
};
|
|
AotCompiler.prototype._analyzeFile = function (fileName) {
|
|
var analyzedFile = this._analyzedFiles.get(fileName);
|
|
if (!analyzedFile) {
|
|
analyzedFile =
|
|
analyzeFile(this._host, this._symbolResolver, this._metadataResolver, fileName);
|
|
this._analyzedFiles.set(fileName, analyzedFile);
|
|
}
|
|
return analyzedFile;
|
|
};
|
|
AotCompiler.prototype._analyzeFileForInjectables = function (fileName) {
|
|
var analyzedFile = this._analyzedFilesForInjectables.get(fileName);
|
|
if (!analyzedFile) {
|
|
analyzedFile = analyzeFileForInjectables(this._host, this._symbolResolver, this._metadataResolver, fileName);
|
|
this._analyzedFilesForInjectables.set(fileName, analyzedFile);
|
|
}
|
|
return analyzedFile;
|
|
};
|
|
AotCompiler.prototype.findGeneratedFileNames = function (fileName) {
|
|
var _this = this;
|
|
var genFileNames = [];
|
|
var file = this._analyzeFile(fileName);
|
|
// Make sure we create a .ngfactory if we have a injectable/directive/pipe/NgModule
|
|
// or a reference to a non source file.
|
|
// Note: This is overestimating the required .ngfactory files as the real calculation is harder.
|
|
// Only do this for StubEmitFlags.Basic, as adding a type check block
|
|
// does not change this file (as we generate type check blocks based on NgModules).
|
|
if (this._options.allowEmptyCodegenFiles || file.directives.length || file.pipes.length ||
|
|
file.injectables.length || file.ngModules.length || file.exportsNonSourceFiles) {
|
|
genFileNames.push(ngfactoryFilePath(file.fileName, true));
|
|
if (this._options.enableSummariesForJit) {
|
|
genFileNames.push(summaryForJitFileName(file.fileName, true));
|
|
}
|
|
}
|
|
var fileSuffix = normalizeGenFileSuffix(splitTypescriptSuffix(file.fileName, true)[1]);
|
|
file.directives.forEach(function (dirSymbol) {
|
|
var compMeta = _this._metadataResolver.getNonNormalizedDirectiveMetadata(dirSymbol).metadata;
|
|
if (!compMeta.isComponent) {
|
|
return;
|
|
}
|
|
// Note: compMeta is a component and therefore template is non null.
|
|
compMeta.template.styleUrls.forEach(function (styleUrl) {
|
|
var normalizedUrl = _this._host.resourceNameToFileName(styleUrl, file.fileName);
|
|
if (!normalizedUrl) {
|
|
throw syntaxError("Couldn't resolve resource " + styleUrl + " relative to " + file.fileName);
|
|
}
|
|
var needsShim = (compMeta.template.encapsulation ||
|
|
_this._config.defaultEncapsulation) === ViewEncapsulation.Emulated;
|
|
genFileNames.push(_stylesModuleUrl(normalizedUrl, needsShim, fileSuffix));
|
|
if (_this._options.allowEmptyCodegenFiles) {
|
|
genFileNames.push(_stylesModuleUrl(normalizedUrl, !needsShim, fileSuffix));
|
|
}
|
|
});
|
|
});
|
|
return genFileNames;
|
|
};
|
|
AotCompiler.prototype.emitBasicStub = function (genFileName, originalFileName) {
|
|
var outputCtx = this._createOutputContext(genFileName);
|
|
if (genFileName.endsWith('.ngfactory.ts')) {
|
|
if (!originalFileName) {
|
|
throw new Error("Assertion error: require the original file for .ngfactory.ts stubs. File: " + genFileName);
|
|
}
|
|
var originalFile = this._analyzeFile(originalFileName);
|
|
this._createNgFactoryStub(outputCtx, originalFile, 1 /* Basic */);
|
|
}
|
|
else if (genFileName.endsWith('.ngsummary.ts')) {
|
|
if (this._options.enableSummariesForJit) {
|
|
if (!originalFileName) {
|
|
throw new Error("Assertion error: require the original file for .ngsummary.ts stubs. File: " + genFileName);
|
|
}
|
|
var originalFile = this._analyzeFile(originalFileName);
|
|
_createEmptyStub(outputCtx);
|
|
originalFile.ngModules.forEach(function (ngModule) {
|
|
// create exports that user code can reference
|
|
createForJitStub(outputCtx, ngModule.type.reference);
|
|
});
|
|
}
|
|
}
|
|
else if (genFileName.endsWith('.ngstyle.ts')) {
|
|
_createEmptyStub(outputCtx);
|
|
}
|
|
// Note: for the stubs, we don't need a property srcFileUrl,
|
|
// as later on in emitAllImpls we will create the proper GeneratedFiles with the
|
|
// correct srcFileUrl.
|
|
// This is good as e.g. for .ngstyle.ts files we can't derive
|
|
// the url of components based on the genFileUrl.
|
|
return this._codegenSourceModule('unknown', outputCtx);
|
|
};
|
|
AotCompiler.prototype.emitTypeCheckStub = function (genFileName, originalFileName) {
|
|
var originalFile = this._analyzeFile(originalFileName);
|
|
var outputCtx = this._createOutputContext(genFileName);
|
|
if (genFileName.endsWith('.ngfactory.ts')) {
|
|
this._createNgFactoryStub(outputCtx, originalFile, 2 /* TypeCheck */);
|
|
}
|
|
return outputCtx.statements.length > 0 ?
|
|
this._codegenSourceModule(originalFile.fileName, outputCtx) :
|
|
null;
|
|
};
|
|
AotCompiler.prototype.loadFilesAsync = function (fileNames, tsFiles) {
|
|
var _this = this;
|
|
var files = fileNames.map(function (fileName) { return _this._analyzeFile(fileName); });
|
|
var loadingPromises = [];
|
|
files.forEach(function (file) { return file.ngModules.forEach(function (ngModule) { return loadingPromises.push(_this._metadataResolver.loadNgModuleDirectiveAndPipeMetadata(ngModule.type.reference, false)); }); });
|
|
var analyzedInjectables = tsFiles.map(function (tsFile) { return _this._analyzeFileForInjectables(tsFile); });
|
|
return Promise.all(loadingPromises).then(function (_) { return ({
|
|
analyzedModules: mergeAndValidateNgFiles(files),
|
|
analyzedInjectables: analyzedInjectables,
|
|
}); });
|
|
};
|
|
AotCompiler.prototype.loadFilesSync = function (fileNames, tsFiles) {
|
|
var _this = this;
|
|
var files = fileNames.map(function (fileName) { return _this._analyzeFile(fileName); });
|
|
files.forEach(function (file) { return file.ngModules.forEach(function (ngModule) { return _this._metadataResolver.loadNgModuleDirectiveAndPipeMetadata(ngModule.type.reference, true); }); });
|
|
var analyzedInjectables = tsFiles.map(function (tsFile) { return _this._analyzeFileForInjectables(tsFile); });
|
|
return {
|
|
analyzedModules: mergeAndValidateNgFiles(files),
|
|
analyzedInjectables: analyzedInjectables,
|
|
};
|
|
};
|
|
AotCompiler.prototype._createNgFactoryStub = function (outputCtx, file, emitFlags) {
|
|
var _this = this;
|
|
var componentId = 0;
|
|
file.ngModules.forEach(function (ngModuleMeta, ngModuleIndex) {
|
|
// Note: the code below needs to executed for StubEmitFlags.Basic and StubEmitFlags.TypeCheck,
|
|
// so we don't change the .ngfactory file too much when adding the type-check block.
|
|
// create exports that user code can reference
|
|
_this._ngModuleCompiler.createStub(outputCtx, ngModuleMeta.type.reference);
|
|
// add references to the symbols from the metadata.
|
|
// These can be used by the type check block for components,
|
|
// and they also cause TypeScript to include these files into the program too,
|
|
// which will make them part of the analyzedFiles.
|
|
var externalReferences = __spreadArray(__spreadArray(__spreadArray(__spreadArray(__spreadArray([], __read(ngModuleMeta.transitiveModule.directives.map(function (d) { return d.reference; }))), __read(ngModuleMeta.transitiveModule.pipes.map(function (d) { return d.reference; }))), __read(ngModuleMeta.importedModules.map(function (m) { return m.type.reference; }))), __read(ngModuleMeta.exportedModules.map(function (m) { return m.type.reference; }))), __read(_this._externalIdentifierReferences([Identifiers$1.TemplateRef, Identifiers$1.ElementRef])));
|
|
var externalReferenceVars = new Map();
|
|
externalReferences.forEach(function (ref, typeIndex) {
|
|
externalReferenceVars.set(ref, "_decl" + ngModuleIndex + "_" + typeIndex);
|
|
});
|
|
externalReferenceVars.forEach(function (varName, reference) {
|
|
outputCtx.statements.push(variable(varName)
|
|
.set(NULL_EXPR.cast(DYNAMIC_TYPE))
|
|
.toDeclStmt(expressionType(outputCtx.importExpr(reference, /* typeParams */ null, /* useSummaries */ false))));
|
|
});
|
|
if (emitFlags & 2 /* TypeCheck */) {
|
|
// add the type-check block for all components of the NgModule
|
|
ngModuleMeta.declaredDirectives.forEach(function (dirId) {
|
|
var compMeta = _this._metadataResolver.getDirectiveMetadata(dirId.reference);
|
|
if (!compMeta.isComponent) {
|
|
return;
|
|
}
|
|
componentId++;
|
|
_this._createTypeCheckBlock(outputCtx, compMeta.type.reference.name + "_Host_" + componentId, ngModuleMeta, _this._metadataResolver.getHostComponentMetadata(compMeta), [compMeta.type], externalReferenceVars);
|
|
_this._createTypeCheckBlock(outputCtx, compMeta.type.reference.name + "_" + componentId, ngModuleMeta, compMeta, ngModuleMeta.transitiveModule.directives, externalReferenceVars);
|
|
});
|
|
}
|
|
});
|
|
if (outputCtx.statements.length === 0) {
|
|
_createEmptyStub(outputCtx);
|
|
}
|
|
};
|
|
AotCompiler.prototype._externalIdentifierReferences = function (references) {
|
|
var e_1, _a;
|
|
var result = [];
|
|
try {
|
|
for (var references_1 = __values(references), references_1_1 = references_1.next(); !references_1_1.done; references_1_1 = references_1.next()) {
|
|
var reference = references_1_1.value;
|
|
var token = createTokenForExternalReference(this.reflector, reference);
|
|
if (token.identifier) {
|
|
result.push(token.identifier.reference);
|
|
}
|
|
}
|
|
}
|
|
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
finally {
|
|
try {
|
|
if (references_1_1 && !references_1_1.done && (_a = references_1.return)) _a.call(references_1);
|
|
}
|
|
finally { if (e_1) throw e_1.error; }
|
|
}
|
|
return result;
|
|
};
|
|
AotCompiler.prototype._createTypeCheckBlock = function (ctx, componentId, moduleMeta, compMeta, directives, externalReferenceVars) {
|
|
var _a;
|
|
var _b = this._parseTemplate(compMeta, moduleMeta, directives), parsedTemplate = _b.template, usedPipes = _b.pipes;
|
|
(_a = ctx.statements).push.apply(_a, __spreadArray([], __read(this._typeCheckCompiler.compileComponent(componentId, compMeta, parsedTemplate, usedPipes, externalReferenceVars, ctx))));
|
|
};
|
|
AotCompiler.prototype.emitMessageBundle = function (analyzeResult, locale) {
|
|
var _this = this;
|
|
var errors = [];
|
|
var htmlParser = new HtmlParser();
|
|
// TODO(vicb): implicit tags & attributes
|
|
var messageBundle = new MessageBundle(htmlParser, [], {}, locale);
|
|
analyzeResult.files.forEach(function (file) {
|
|
var compMetas = [];
|
|
file.directives.forEach(function (directiveType) {
|
|
var dirMeta = _this._metadataResolver.getDirectiveMetadata(directiveType);
|
|
if (dirMeta && dirMeta.isComponent) {
|
|
compMetas.push(dirMeta);
|
|
}
|
|
});
|
|
compMetas.forEach(function (compMeta) {
|
|
var html = compMeta.template.template;
|
|
// Template URL points to either an HTML or TS file depending on whether
|
|
// the file is used with `templateUrl:` or `template:`, respectively.
|
|
var templateUrl = compMeta.template.templateUrl;
|
|
var interpolationConfig = InterpolationConfig.fromArray(compMeta.template.interpolation);
|
|
errors.push.apply(errors, __spreadArray([], __read(messageBundle.updateFromTemplate(html, templateUrl, interpolationConfig))));
|
|
});
|
|
});
|
|
if (errors.length) {
|
|
throw new Error(errors.map(function (e) { return e.toString(); }).join('\n'));
|
|
}
|
|
return messageBundle;
|
|
};
|
|
AotCompiler.prototype.emitAllPartialModules2 = function (files) {
|
|
var _this = this;
|
|
// Using reduce like this is a select many pattern (where map is a select pattern)
|
|
return files.reduce(function (r, file) {
|
|
r.push.apply(r, __spreadArray([], __read(_this._emitPartialModule2(file.fileName, file.injectables))));
|
|
return r;
|
|
}, []);
|
|
};
|
|
AotCompiler.prototype._emitPartialModule2 = function (fileName, injectables) {
|
|
var _this = this;
|
|
var context = this._createOutputContext(fileName);
|
|
injectables.forEach(function (injectable) { return _this._injectableCompiler.compile(injectable, context); });
|
|
if (context.statements && context.statements.length > 0) {
|
|
return [{ fileName: fileName, statements: __spreadArray(__spreadArray([], __read(context.constantPool.statements)), __read(context.statements)) }];
|
|
}
|
|
return [];
|
|
};
|
|
AotCompiler.prototype.emitAllImpls = function (analyzeResult) {
|
|
var _this = this;
|
|
var ngModuleByPipeOrDirective = analyzeResult.ngModuleByPipeOrDirective, files = analyzeResult.files;
|
|
var sourceModules = files.map(function (file) { return _this._compileImplFile(file.fileName, ngModuleByPipeOrDirective, file.directives, file.pipes, file.ngModules, file.injectables); });
|
|
return flatten(sourceModules);
|
|
};
|
|
AotCompiler.prototype._compileImplFile = function (srcFileUrl, ngModuleByPipeOrDirective, directives, pipes, ngModules, injectables) {
|
|
var _this = this;
|
|
var fileSuffix = normalizeGenFileSuffix(splitTypescriptSuffix(srcFileUrl, true)[1]);
|
|
var generatedFiles = [];
|
|
var outputCtx = this._createOutputContext(ngfactoryFilePath(srcFileUrl, true));
|
|
generatedFiles.push.apply(generatedFiles, __spreadArray([], __read(this._createSummary(srcFileUrl, directives, pipes, ngModules, injectables, outputCtx))));
|
|
// compile all ng modules
|
|
ngModules.forEach(function (ngModuleMeta) { return _this._compileModule(outputCtx, ngModuleMeta); });
|
|
// compile components
|
|
directives.forEach(function (dirType) {
|
|
var compMeta = _this._metadataResolver.getDirectiveMetadata(dirType);
|
|
if (!compMeta.isComponent) {
|
|
return;
|
|
}
|
|
var ngModule = ngModuleByPipeOrDirective.get(dirType);
|
|
if (!ngModule) {
|
|
throw new Error("Internal Error: cannot determine the module for component " + identifierName(compMeta.type) + "!");
|
|
}
|
|
// compile styles
|
|
var componentStylesheet = _this._styleCompiler.compileComponent(outputCtx, compMeta);
|
|
// Note: compMeta is a component and therefore template is non null.
|
|
compMeta.template.externalStylesheets.forEach(function (stylesheetMeta) {
|
|
// Note: fill non shim and shim style files as they might
|
|
// be shared by component with and without ViewEncapsulation.
|
|
var shim = _this._styleCompiler.needsStyleShim(compMeta);
|
|
generatedFiles.push(_this._codegenStyles(srcFileUrl, compMeta, stylesheetMeta, shim, fileSuffix));
|
|
if (_this._options.allowEmptyCodegenFiles) {
|
|
generatedFiles.push(_this._codegenStyles(srcFileUrl, compMeta, stylesheetMeta, !shim, fileSuffix));
|
|
}
|
|
});
|
|
// compile components
|
|
var compViewVars = _this._compileComponent(outputCtx, compMeta, ngModule, ngModule.transitiveModule.directives, componentStylesheet, fileSuffix);
|
|
_this._compileComponentFactory(outputCtx, compMeta, ngModule, fileSuffix);
|
|
});
|
|
if (outputCtx.statements.length > 0 || this._options.allowEmptyCodegenFiles) {
|
|
var srcModule = this._codegenSourceModule(srcFileUrl, outputCtx);
|
|
generatedFiles.unshift(srcModule);
|
|
}
|
|
return generatedFiles;
|
|
};
|
|
AotCompiler.prototype._createSummary = function (srcFileName, directives, pipes, ngModules, injectables, ngFactoryCtx) {
|
|
var _this = this;
|
|
var symbolSummaries = this._symbolResolver.getSymbolsOf(srcFileName)
|
|
.map(function (symbol) { return _this._symbolResolver.resolveSymbol(symbol); });
|
|
var typeData = __spreadArray(__spreadArray(__spreadArray(__spreadArray([], __read(ngModules.map(function (meta) { return ({
|
|
summary: _this._metadataResolver.getNgModuleSummary(meta.type.reference),
|
|
metadata: _this._metadataResolver.getNgModuleMetadata(meta.type.reference)
|
|
}); }))), __read(directives.map(function (ref) { return ({
|
|
summary: _this._metadataResolver.getDirectiveSummary(ref),
|
|
metadata: _this._metadataResolver.getDirectiveMetadata(ref)
|
|
}); }))), __read(pipes.map(function (ref) { return ({
|
|
summary: _this._metadataResolver.getPipeSummary(ref),
|
|
metadata: _this._metadataResolver.getPipeMetadata(ref)
|
|
}); }))), __read(injectables.map(function (ref) { return ({
|
|
summary: _this._metadataResolver.getInjectableSummary(ref.symbol),
|
|
metadata: _this._metadataResolver.getInjectableSummary(ref.symbol).type
|
|
}); })));
|
|
var forJitOutputCtx = this._options.enableSummariesForJit ?
|
|
this._createOutputContext(summaryForJitFileName(srcFileName, true)) :
|
|
null;
|
|
var _a = serializeSummaries(srcFileName, forJitOutputCtx, this._summaryResolver, this._symbolResolver, symbolSummaries, typeData, this._options.createExternalSymbolFactoryReexports), json = _a.json, exportAs = _a.exportAs;
|
|
exportAs.forEach(function (entry) {
|
|
ngFactoryCtx.statements.push(variable(entry.exportAs).set(ngFactoryCtx.importExpr(entry.symbol)).toDeclStmt(null, [
|
|
exports.StmtModifier.Exported
|
|
]));
|
|
});
|
|
var summaryJson = new GeneratedFile(srcFileName, summaryFileName(srcFileName), json);
|
|
var result = [summaryJson];
|
|
if (forJitOutputCtx) {
|
|
result.push(this._codegenSourceModule(srcFileName, forJitOutputCtx));
|
|
}
|
|
return result;
|
|
};
|
|
AotCompiler.prototype._compileModule = function (outputCtx, ngModule) {
|
|
var providers = [];
|
|
if (this._options.locale) {
|
|
var normalizedLocale = this._options.locale.replace(/_/g, '-');
|
|
providers.push({
|
|
token: createTokenForExternalReference(this.reflector, Identifiers$1.LOCALE_ID),
|
|
useValue: normalizedLocale,
|
|
});
|
|
}
|
|
if (this._options.i18nFormat) {
|
|
providers.push({
|
|
token: createTokenForExternalReference(this.reflector, Identifiers$1.TRANSLATIONS_FORMAT),
|
|
useValue: this._options.i18nFormat
|
|
});
|
|
}
|
|
this._ngModuleCompiler.compile(outputCtx, ngModule, providers);
|
|
};
|
|
AotCompiler.prototype._compileComponentFactory = function (outputCtx, compMeta, ngModule, fileSuffix) {
|
|
var hostMeta = this._metadataResolver.getHostComponentMetadata(compMeta);
|
|
var hostViewFactoryVar = this._compileComponent(outputCtx, hostMeta, ngModule, [compMeta.type], null, fileSuffix)
|
|
.viewClassVar;
|
|
var compFactoryVar = componentFactoryName(compMeta.type.reference);
|
|
var inputsExprs = [];
|
|
for (var propName in compMeta.inputs) {
|
|
var templateName = compMeta.inputs[propName];
|
|
// Don't quote so that the key gets minified...
|
|
inputsExprs.push(new LiteralMapEntry(propName, literal(templateName), false));
|
|
}
|
|
var outputsExprs = [];
|
|
for (var propName in compMeta.outputs) {
|
|
var templateName = compMeta.outputs[propName];
|
|
// Don't quote so that the key gets minified...
|
|
outputsExprs.push(new LiteralMapEntry(propName, literal(templateName), false));
|
|
}
|
|
outputCtx.statements.push(variable(compFactoryVar)
|
|
.set(importExpr(Identifiers$1.createComponentFactory).callFn([
|
|
literal(compMeta.selector), outputCtx.importExpr(compMeta.type.reference),
|
|
variable(hostViewFactoryVar), new LiteralMapExpr(inputsExprs),
|
|
new LiteralMapExpr(outputsExprs),
|
|
literalArr(compMeta.template.ngContentSelectors.map(function (selector) { return literal(selector); }))
|
|
]))
|
|
.toDeclStmt(importType(Identifiers$1.ComponentFactory, [expressionType(outputCtx.importExpr(compMeta.type.reference))], [TypeModifier.Const]), [exports.StmtModifier.Final, exports.StmtModifier.Exported]));
|
|
};
|
|
AotCompiler.prototype._compileComponent = function (outputCtx, compMeta, ngModule, directiveIdentifiers, componentStyles, fileSuffix) {
|
|
var _a = this._parseTemplate(compMeta, ngModule, directiveIdentifiers), parsedTemplate = _a.template, usedPipes = _a.pipes;
|
|
var stylesExpr = componentStyles ? variable(componentStyles.stylesVar) : literalArr([]);
|
|
var viewResult = this._viewCompiler.compileComponent(outputCtx, compMeta, parsedTemplate, stylesExpr, usedPipes);
|
|
if (componentStyles) {
|
|
_resolveStyleStatements(this._symbolResolver, componentStyles, this._styleCompiler.needsStyleShim(compMeta), fileSuffix);
|
|
}
|
|
return viewResult;
|
|
};
|
|
AotCompiler.prototype._parseTemplate = function (compMeta, ngModule, directiveIdentifiers) {
|
|
var _this = this;
|
|
if (this._templateAstCache.has(compMeta.type.reference)) {
|
|
return this._templateAstCache.get(compMeta.type.reference);
|
|
}
|
|
var preserveWhitespaces = compMeta.template.preserveWhitespaces;
|
|
var directives = directiveIdentifiers.map(function (dir) { return _this._metadataResolver.getDirectiveSummary(dir.reference); });
|
|
var pipes = ngModule.transitiveModule.pipes.map(function (pipe) { return _this._metadataResolver.getPipeSummary(pipe.reference); });
|
|
var result = this._templateParser.parse(compMeta, compMeta.template.htmlAst, directives, pipes, ngModule.schemas, templateSourceUrl(ngModule.type, compMeta, compMeta.template), preserveWhitespaces);
|
|
this._templateAstCache.set(compMeta.type.reference, result);
|
|
return result;
|
|
};
|
|
AotCompiler.prototype._createOutputContext = function (genFilePath) {
|
|
var _this = this;
|
|
var importExpr$1 = function (symbol, typeParams, useSummaries) {
|
|
if (typeParams === void 0) { typeParams = null; }
|
|
if (useSummaries === void 0) { useSummaries = true; }
|
|
if (!(symbol instanceof StaticSymbol)) {
|
|
throw new Error("Internal error: unknown identifier " + JSON.stringify(symbol));
|
|
}
|
|
var arity = _this._symbolResolver.getTypeArity(symbol) || 0;
|
|
var _a = _this._symbolResolver.getImportAs(symbol, useSummaries) || symbol, filePath = _a.filePath, name = _a.name, members = _a.members;
|
|
var importModule = _this._fileNameToModuleName(filePath, genFilePath);
|
|
// It should be good enough to compare filePath to genFilePath and if they are equal
|
|
// there is a self reference. However, ngfactory files generate to .ts but their
|
|
// symbols have .d.ts so a simple compare is insufficient. They should be canonical
|
|
// and is tracked by #17705.
|
|
var selfReference = _this._fileNameToModuleName(genFilePath, genFilePath);
|
|
var moduleName = importModule === selfReference ? null : importModule;
|
|
// If we are in a type expression that refers to a generic type then supply
|
|
// the required type parameters. If there were not enough type parameters
|
|
// supplied, supply any as the type. Outside a type expression the reference
|
|
// should not supply type parameters and be treated as a simple value reference
|
|
// to the constructor function itself.
|
|
var suppliedTypeParams = typeParams || [];
|
|
var missingTypeParamsCount = arity - suppliedTypeParams.length;
|
|
var allTypeParams = suppliedTypeParams.concat(newArray(missingTypeParamsCount, DYNAMIC_TYPE));
|
|
return members.reduce(function (expr, memberName) { return expr.prop(memberName); }, importExpr(new ExternalReference(moduleName, name, null), allTypeParams));
|
|
};
|
|
return { statements: [], genFilePath: genFilePath, importExpr: importExpr$1, constantPool: new ConstantPool() };
|
|
};
|
|
AotCompiler.prototype._fileNameToModuleName = function (importedFilePath, containingFilePath) {
|
|
return this._summaryResolver.getKnownModuleName(importedFilePath) ||
|
|
this._symbolResolver.getKnownModuleName(importedFilePath) ||
|
|
this._host.fileNameToModuleName(importedFilePath, containingFilePath);
|
|
};
|
|
AotCompiler.prototype._codegenStyles = function (srcFileUrl, compMeta, stylesheetMetadata, isShimmed, fileSuffix) {
|
|
var outputCtx = this._createOutputContext(_stylesModuleUrl(stylesheetMetadata.moduleUrl, isShimmed, fileSuffix));
|
|
var compiledStylesheet = this._styleCompiler.compileStyles(outputCtx, compMeta, stylesheetMetadata, isShimmed);
|
|
_resolveStyleStatements(this._symbolResolver, compiledStylesheet, isShimmed, fileSuffix);
|
|
return this._codegenSourceModule(srcFileUrl, outputCtx);
|
|
};
|
|
AotCompiler.prototype._codegenSourceModule = function (srcFileUrl, ctx) {
|
|
return new GeneratedFile(srcFileUrl, ctx.genFilePath, ctx.statements);
|
|
};
|
|
AotCompiler.prototype.listLazyRoutes = function (entryRoute, analyzedModules) {
|
|
var e_2, _a, e_3, _b;
|
|
var self = this;
|
|
if (entryRoute) {
|
|
var symbol = parseLazyRoute(entryRoute, this.reflector).referencedModule;
|
|
return visitLazyRoute(symbol);
|
|
}
|
|
else if (analyzedModules) {
|
|
var allLazyRoutes = [];
|
|
try {
|
|
for (var _c = __values(analyzedModules.ngModules), _d = _c.next(); !_d.done; _d = _c.next()) {
|
|
var ngModule = _d.value;
|
|
var lazyRoutes = listLazyRoutes(ngModule, this.reflector);
|
|
try {
|
|
for (var lazyRoutes_1 = (e_3 = void 0, __values(lazyRoutes)), lazyRoutes_1_1 = lazyRoutes_1.next(); !lazyRoutes_1_1.done; lazyRoutes_1_1 = lazyRoutes_1.next()) {
|
|
var lazyRoute = lazyRoutes_1_1.value;
|
|
allLazyRoutes.push(lazyRoute);
|
|
}
|
|
}
|
|
catch (e_3_1) { e_3 = { error: e_3_1 }; }
|
|
finally {
|
|
try {
|
|
if (lazyRoutes_1_1 && !lazyRoutes_1_1.done && (_b = lazyRoutes_1.return)) _b.call(lazyRoutes_1);
|
|
}
|
|
finally { if (e_3) throw e_3.error; }
|
|
}
|
|
}
|
|
}
|
|
catch (e_2_1) { e_2 = { error: e_2_1 }; }
|
|
finally {
|
|
try {
|
|
if (_d && !_d.done && (_a = _c.return)) _a.call(_c);
|
|
}
|
|
finally { if (e_2) throw e_2.error; }
|
|
}
|
|
return allLazyRoutes;
|
|
}
|
|
else {
|
|
throw new Error("Either route or analyzedModules has to be specified!");
|
|
}
|
|
function visitLazyRoute(symbol, seenRoutes, allLazyRoutes) {
|
|
var e_4, _a;
|
|
if (seenRoutes === void 0) { seenRoutes = new Set(); }
|
|
if (allLazyRoutes === void 0) { allLazyRoutes = []; }
|
|
// Support pointing to default exports, but stop recursing there,
|
|
// as the StaticReflector does not yet support default exports.
|
|
if (seenRoutes.has(symbol) || !symbol.name) {
|
|
return allLazyRoutes;
|
|
}
|
|
seenRoutes.add(symbol);
|
|
var lazyRoutes = listLazyRoutes(self._metadataResolver.getNgModuleMetadata(symbol, true), self.reflector);
|
|
try {
|
|
for (var lazyRoutes_2 = __values(lazyRoutes), lazyRoutes_2_1 = lazyRoutes_2.next(); !lazyRoutes_2_1.done; lazyRoutes_2_1 = lazyRoutes_2.next()) {
|
|
var lazyRoute = lazyRoutes_2_1.value;
|
|
allLazyRoutes.push(lazyRoute);
|
|
visitLazyRoute(lazyRoute.referencedModule, seenRoutes, allLazyRoutes);
|
|
}
|
|
}
|
|
catch (e_4_1) { e_4 = { error: e_4_1 }; }
|
|
finally {
|
|
try {
|
|
if (lazyRoutes_2_1 && !lazyRoutes_2_1.done && (_a = lazyRoutes_2.return)) _a.call(lazyRoutes_2);
|
|
}
|
|
finally { if (e_4) throw e_4.error; }
|
|
}
|
|
return allLazyRoutes;
|
|
}
|
|
};
|
|
return AotCompiler;
|
|
}());
|
|
function _createEmptyStub(outputCtx) {
|
|
// Note: We need to produce at least one import statement so that
|
|
// TypeScript knows that the file is an es6 module. Otherwise our generated
|
|
// exports / imports won't be emitted properly by TypeScript.
|
|
outputCtx.statements.push(importExpr(Identifiers$1.ComponentFactory).toStmt());
|
|
}
|
|
function _resolveStyleStatements(symbolResolver, compileResult, needsShim, fileSuffix) {
|
|
compileResult.dependencies.forEach(function (dep) {
|
|
dep.setValue(symbolResolver.getStaticSymbol(_stylesModuleUrl(dep.moduleUrl, needsShim, fileSuffix), dep.name));
|
|
});
|
|
}
|
|
function _stylesModuleUrl(stylesheetUrl, shim, suffix) {
|
|
return "" + stylesheetUrl + (shim ? '.shim' : '') + ".ngstyle" + suffix;
|
|
}
|
|
function analyzeNgModules(fileNames, host, staticSymbolResolver, metadataResolver) {
|
|
var files = _analyzeFilesIncludingNonProgramFiles(fileNames, host, staticSymbolResolver, metadataResolver);
|
|
return mergeAnalyzedFiles(files);
|
|
}
|
|
function analyzeAndValidateNgModules(fileNames, host, staticSymbolResolver, metadataResolver) {
|
|
return validateAnalyzedModules(analyzeNgModules(fileNames, host, staticSymbolResolver, metadataResolver));
|
|
}
|
|
function validateAnalyzedModules(analyzedModules) {
|
|
if (analyzedModules.symbolsMissingModule && analyzedModules.symbolsMissingModule.length) {
|
|
var messages = analyzedModules.symbolsMissingModule.map(function (s) { return "Cannot determine the module for class " + s.name + " in " + s.filePath + "! Add " + s.name + " to the NgModule to fix it."; });
|
|
throw syntaxError(messages.join('\n'));
|
|
}
|
|
return analyzedModules;
|
|
}
|
|
// Analyzes all of the program files,
|
|
// including files that are not part of the program
|
|
// but are referenced by an NgModule.
|
|
function _analyzeFilesIncludingNonProgramFiles(fileNames, host, staticSymbolResolver, metadataResolver) {
|
|
var seenFiles = new Set();
|
|
var files = [];
|
|
var visitFile = function (fileName) {
|
|
if (seenFiles.has(fileName) || !host.isSourceFile(fileName)) {
|
|
return false;
|
|
}
|
|
seenFiles.add(fileName);
|
|
var analyzedFile = analyzeFile(host, staticSymbolResolver, metadataResolver, fileName);
|
|
files.push(analyzedFile);
|
|
analyzedFile.ngModules.forEach(function (ngModule) {
|
|
ngModule.transitiveModule.modules.forEach(function (modMeta) { return visitFile(modMeta.reference.filePath); });
|
|
});
|
|
};
|
|
fileNames.forEach(function (fileName) { return visitFile(fileName); });
|
|
return files;
|
|
}
|
|
function analyzeFile(host, staticSymbolResolver, metadataResolver, fileName) {
|
|
var abstractDirectives = [];
|
|
var directives = [];
|
|
var pipes = [];
|
|
var injectables = [];
|
|
var ngModules = [];
|
|
var hasDecorators = staticSymbolResolver.hasDecorators(fileName);
|
|
var exportsNonSourceFiles = false;
|
|
var isDeclarationFile = fileName.endsWith('.d.ts');
|
|
// Don't analyze .d.ts files that have no decorators as a shortcut
|
|
// to speed up the analysis. This prevents us from
|
|
// resolving the references in these files.
|
|
// Note: exportsNonSourceFiles is only needed when compiling with summaries,
|
|
// which is not the case when .d.ts files are treated as input files.
|
|
if (!isDeclarationFile || hasDecorators) {
|
|
staticSymbolResolver.getSymbolsOf(fileName).forEach(function (symbol) {
|
|
var resolvedSymbol = staticSymbolResolver.resolveSymbol(symbol);
|
|
var symbolMeta = resolvedSymbol.metadata;
|
|
if (!symbolMeta || symbolMeta.__symbolic === 'error') {
|
|
return;
|
|
}
|
|
var isNgSymbol = false;
|
|
if (symbolMeta.__symbolic === 'class') {
|
|
if (metadataResolver.isDirective(symbol)) {
|
|
isNgSymbol = true;
|
|
// This directive either has a selector or doesn't. Selector-less directives get tracked
|
|
// in abstractDirectives, not directives. The compiler doesn't deal with selector-less
|
|
// directives at all, really, other than to persist their metadata. This is done so that
|
|
// apps will have an easier time migrating to Ivy, which requires the selector-less
|
|
// annotations to be applied.
|
|
if (!metadataResolver.isAbstractDirective(symbol)) {
|
|
// The directive is an ordinary directive.
|
|
directives.push(symbol);
|
|
}
|
|
else {
|
|
// The directive has no selector and is an "abstract" directive, so track it
|
|
// accordingly.
|
|
abstractDirectives.push(symbol);
|
|
}
|
|
}
|
|
else if (metadataResolver.isPipe(symbol)) {
|
|
isNgSymbol = true;
|
|
pipes.push(symbol);
|
|
}
|
|
else if (metadataResolver.isNgModule(symbol)) {
|
|
var ngModule = metadataResolver.getNgModuleMetadata(symbol, false);
|
|
if (ngModule) {
|
|
isNgSymbol = true;
|
|
ngModules.push(ngModule);
|
|
}
|
|
}
|
|
else if (metadataResolver.isInjectable(symbol)) {
|
|
isNgSymbol = true;
|
|
var injectable = metadataResolver.getInjectableMetadata(symbol, null, false);
|
|
if (injectable) {
|
|
injectables.push(injectable);
|
|
}
|
|
}
|
|
}
|
|
if (!isNgSymbol) {
|
|
exportsNonSourceFiles =
|
|
exportsNonSourceFiles || isValueExportingNonSourceFile(host, symbolMeta);
|
|
}
|
|
});
|
|
}
|
|
return {
|
|
fileName: fileName,
|
|
directives: directives,
|
|
abstractDirectives: abstractDirectives,
|
|
pipes: pipes,
|
|
ngModules: ngModules,
|
|
injectables: injectables,
|
|
exportsNonSourceFiles: exportsNonSourceFiles,
|
|
};
|
|
}
|
|
function analyzeFileForInjectables(host, staticSymbolResolver, metadataResolver, fileName) {
|
|
var injectables = [];
|
|
var shallowModules = [];
|
|
if (staticSymbolResolver.hasDecorators(fileName)) {
|
|
staticSymbolResolver.getSymbolsOf(fileName).forEach(function (symbol) {
|
|
var resolvedSymbol = staticSymbolResolver.resolveSymbol(symbol);
|
|
var symbolMeta = resolvedSymbol.metadata;
|
|
if (!symbolMeta || symbolMeta.__symbolic === 'error') {
|
|
return;
|
|
}
|
|
if (symbolMeta.__symbolic === 'class') {
|
|
if (metadataResolver.isInjectable(symbol)) {
|
|
var injectable = metadataResolver.getInjectableMetadata(symbol, null, false);
|
|
if (injectable) {
|
|
injectables.push(injectable);
|
|
}
|
|
}
|
|
else if (metadataResolver.isNgModule(symbol)) {
|
|
var module = metadataResolver.getShallowModuleMetadata(symbol);
|
|
if (module) {
|
|
shallowModules.push(module);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
return { fileName: fileName, injectables: injectables, shallowModules: shallowModules };
|
|
}
|
|
function isValueExportingNonSourceFile(host, metadata) {
|
|
var exportsNonSourceFiles = false;
|
|
var Visitor = /** @class */ (function () {
|
|
function Visitor() {
|
|
}
|
|
Visitor.prototype.visitArray = function (arr, context) {
|
|
var _this = this;
|
|
arr.forEach(function (v) { return visitValue(v, _this, context); });
|
|
};
|
|
Visitor.prototype.visitStringMap = function (map, context) {
|
|
var _this = this;
|
|
Object.keys(map).forEach(function (key) { return visitValue(map[key], _this, context); });
|
|
};
|
|
Visitor.prototype.visitPrimitive = function (value, context) { };
|
|
Visitor.prototype.visitOther = function (value, context) {
|
|
if (value instanceof StaticSymbol && !host.isSourceFile(value.filePath)) {
|
|
exportsNonSourceFiles = true;
|
|
}
|
|
};
|
|
return Visitor;
|
|
}());
|
|
visitValue(metadata, new Visitor(), null);
|
|
return exportsNonSourceFiles;
|
|
}
|
|
function mergeAnalyzedFiles(analyzedFiles) {
|
|
var allNgModules = [];
|
|
var ngModuleByPipeOrDirective = new Map();
|
|
var allPipesAndDirectives = new Set();
|
|
analyzedFiles.forEach(function (af) {
|
|
af.ngModules.forEach(function (ngModule) {
|
|
allNgModules.push(ngModule);
|
|
ngModule.declaredDirectives.forEach(function (d) { return ngModuleByPipeOrDirective.set(d.reference, ngModule); });
|
|
ngModule.declaredPipes.forEach(function (p) { return ngModuleByPipeOrDirective.set(p.reference, ngModule); });
|
|
});
|
|
af.directives.forEach(function (d) { return allPipesAndDirectives.add(d); });
|
|
af.pipes.forEach(function (p) { return allPipesAndDirectives.add(p); });
|
|
});
|
|
var symbolsMissingModule = [];
|
|
allPipesAndDirectives.forEach(function (ref) {
|
|
if (!ngModuleByPipeOrDirective.has(ref)) {
|
|
symbolsMissingModule.push(ref);
|
|
}
|
|
});
|
|
return {
|
|
ngModules: allNgModules,
|
|
ngModuleByPipeOrDirective: ngModuleByPipeOrDirective,
|
|
symbolsMissingModule: symbolsMissingModule,
|
|
files: analyzedFiles
|
|
};
|
|
}
|
|
function mergeAndValidateNgFiles(files) {
|
|
return validateAnalyzedModules(mergeAnalyzedFiles(files));
|
|
}
|
|
|
|
var FORMATTED_MESSAGE = 'ngFormattedMessage';
|
|
function indentStr(level) {
|
|
if (level <= 0)
|
|
return '';
|
|
if (level < 6)
|
|
return ['', ' ', ' ', ' ', ' ', ' '][level];
|
|
var half = indentStr(Math.floor(level / 2));
|
|
return half + half + (level % 2 === 1 ? ' ' : '');
|
|
}
|
|
function formatChain(chain, indent) {
|
|
var e_1, _a;
|
|
if (indent === void 0) { indent = 0; }
|
|
if (!chain)
|
|
return '';
|
|
var position = chain.position ?
|
|
chain.position.fileName + "(" + (chain.position.line + 1) + "," + (chain.position.column + 1) + ")" :
|
|
'';
|
|
var prefix = position && indent === 0 ? position + ": " : '';
|
|
var postfix = position && indent !== 0 ? " at " + position : '';
|
|
var message = "" + prefix + chain.message + postfix;
|
|
if (chain.next) {
|
|
try {
|
|
for (var _b = __values(chain.next), _c = _b.next(); !_c.done; _c = _b.next()) {
|
|
var kid = _c.value;
|
|
message += '\n' + formatChain(kid, indent + 2);
|
|
}
|
|
}
|
|
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
finally {
|
|
try {
|
|
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
|
|
}
|
|
finally { if (e_1) throw e_1.error; }
|
|
}
|
|
}
|
|
return "" + indentStr(indent) + message;
|
|
}
|
|
function formattedError(chain) {
|
|
var message = formatChain(chain) + '.';
|
|
var error = syntaxError(message);
|
|
error[FORMATTED_MESSAGE] = true;
|
|
error.chain = chain;
|
|
error.position = chain.position;
|
|
return error;
|
|
}
|
|
function isFormattedError(error) {
|
|
return !!error[FORMATTED_MESSAGE];
|
|
}
|
|
|
|
var ANGULAR_CORE = '@angular/core';
|
|
var ANGULAR_ROUTER = '@angular/router';
|
|
var HIDDEN_KEY = /^\$.*\$$/;
|
|
var IGNORE = {
|
|
__symbolic: 'ignore'
|
|
};
|
|
var USE_VALUE$1 = 'useValue';
|
|
var PROVIDE = 'provide';
|
|
var REFERENCE_SET = new Set([USE_VALUE$1, 'useFactory', 'data', 'id', 'loadChildren']);
|
|
var TYPEGUARD_POSTFIX = 'TypeGuard';
|
|
var USE_IF = 'UseIf';
|
|
function shouldIgnore(value) {
|
|
return value && value.__symbolic == 'ignore';
|
|
}
|
|
/**
|
|
* A static reflector implements enough of the Reflector API that is necessary to compile
|
|
* templates statically.
|
|
*/
|
|
var StaticReflector = /** @class */ (function () {
|
|
function StaticReflector(summaryResolver, symbolResolver, knownMetadataClasses, knownMetadataFunctions, errorRecorder) {
|
|
var _this = this;
|
|
if (knownMetadataClasses === void 0) { knownMetadataClasses = []; }
|
|
if (knownMetadataFunctions === void 0) { knownMetadataFunctions = []; }
|
|
this.summaryResolver = summaryResolver;
|
|
this.symbolResolver = symbolResolver;
|
|
this.errorRecorder = errorRecorder;
|
|
this.annotationCache = new Map();
|
|
this.shallowAnnotationCache = new Map();
|
|
this.propertyCache = new Map();
|
|
this.parameterCache = new Map();
|
|
this.methodCache = new Map();
|
|
this.staticCache = new Map();
|
|
this.conversionMap = new Map();
|
|
this.resolvedExternalReferences = new Map();
|
|
this.annotationForParentClassWithSummaryKind = new Map();
|
|
this.initializeConversionMap();
|
|
knownMetadataClasses.forEach(function (kc) { return _this._registerDecoratorOrConstructor(_this.getStaticSymbol(kc.filePath, kc.name), kc.ctor); });
|
|
knownMetadataFunctions.forEach(function (kf) { return _this._registerFunction(_this.getStaticSymbol(kf.filePath, kf.name), kf.fn); });
|
|
this.annotationForParentClassWithSummaryKind.set(exports.CompileSummaryKind.Directive, [createDirective, createComponent]);
|
|
this.annotationForParentClassWithSummaryKind.set(exports.CompileSummaryKind.Pipe, [createPipe]);
|
|
this.annotationForParentClassWithSummaryKind.set(exports.CompileSummaryKind.NgModule, [createNgModule]);
|
|
this.annotationForParentClassWithSummaryKind.set(exports.CompileSummaryKind.Injectable, [createInjectable, createPipe, createDirective, createComponent, createNgModule]);
|
|
}
|
|
StaticReflector.prototype.componentModuleUrl = function (typeOrFunc) {
|
|
var staticSymbol = this.findSymbolDeclaration(typeOrFunc);
|
|
return this.symbolResolver.getResourcePath(staticSymbol);
|
|
};
|
|
/**
|
|
* Invalidate the specified `symbols` on program change.
|
|
* @param symbols
|
|
*/
|
|
StaticReflector.prototype.invalidateSymbols = function (symbols) {
|
|
var e_1, _a;
|
|
try {
|
|
for (var symbols_1 = __values(symbols), symbols_1_1 = symbols_1.next(); !symbols_1_1.done; symbols_1_1 = symbols_1.next()) {
|
|
var symbol = symbols_1_1.value;
|
|
this.annotationCache.delete(symbol);
|
|
this.shallowAnnotationCache.delete(symbol);
|
|
this.propertyCache.delete(symbol);
|
|
this.parameterCache.delete(symbol);
|
|
this.methodCache.delete(symbol);
|
|
this.staticCache.delete(symbol);
|
|
this.conversionMap.delete(symbol);
|
|
}
|
|
}
|
|
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
finally {
|
|
try {
|
|
if (symbols_1_1 && !symbols_1_1.done && (_a = symbols_1.return)) _a.call(symbols_1);
|
|
}
|
|
finally { if (e_1) throw e_1.error; }
|
|
}
|
|
};
|
|
StaticReflector.prototype.resolveExternalReference = function (ref, containingFile) {
|
|
var key = undefined;
|
|
if (!containingFile) {
|
|
key = ref.moduleName + ":" + ref.name;
|
|
var declarationSymbol_1 = this.resolvedExternalReferences.get(key);
|
|
if (declarationSymbol_1)
|
|
return declarationSymbol_1;
|
|
}
|
|
var refSymbol = this.symbolResolver.getSymbolByModule(ref.moduleName, ref.name, containingFile);
|
|
var declarationSymbol = this.findSymbolDeclaration(refSymbol);
|
|
if (!containingFile) {
|
|
this.symbolResolver.recordModuleNameForFileName(refSymbol.filePath, ref.moduleName);
|
|
this.symbolResolver.recordImportAs(declarationSymbol, refSymbol);
|
|
}
|
|
if (key) {
|
|
this.resolvedExternalReferences.set(key, declarationSymbol);
|
|
}
|
|
return declarationSymbol;
|
|
};
|
|
StaticReflector.prototype.findDeclaration = function (moduleUrl, name, containingFile) {
|
|
return this.findSymbolDeclaration(this.symbolResolver.getSymbolByModule(moduleUrl, name, containingFile));
|
|
};
|
|
StaticReflector.prototype.tryFindDeclaration = function (moduleUrl, name, containingFile) {
|
|
var _this = this;
|
|
return this.symbolResolver.ignoreErrorsFor(function () { return _this.findDeclaration(moduleUrl, name, containingFile); });
|
|
};
|
|
StaticReflector.prototype.findSymbolDeclaration = function (symbol) {
|
|
var resolvedSymbol = this.symbolResolver.resolveSymbol(symbol);
|
|
if (resolvedSymbol) {
|
|
var resolvedMetadata = resolvedSymbol.metadata;
|
|
if (resolvedMetadata && resolvedMetadata.__symbolic === 'resolved') {
|
|
resolvedMetadata = resolvedMetadata.symbol;
|
|
}
|
|
if (resolvedMetadata instanceof StaticSymbol) {
|
|
return this.findSymbolDeclaration(resolvedSymbol.metadata);
|
|
}
|
|
}
|
|
return symbol;
|
|
};
|
|
StaticReflector.prototype.tryAnnotations = function (type) {
|
|
var originalRecorder = this.errorRecorder;
|
|
this.errorRecorder = function (error, fileName) { };
|
|
try {
|
|
return this.annotations(type);
|
|
}
|
|
finally {
|
|
this.errorRecorder = originalRecorder;
|
|
}
|
|
};
|
|
StaticReflector.prototype.annotations = function (type) {
|
|
var _this = this;
|
|
return this._annotations(type, function (type, decorators) { return _this.simplify(type, decorators); }, this.annotationCache);
|
|
};
|
|
StaticReflector.prototype.shallowAnnotations = function (type) {
|
|
var _this = this;
|
|
return this._annotations(type, function (type, decorators) { return _this.simplify(type, decorators, true); }, this.shallowAnnotationCache);
|
|
};
|
|
StaticReflector.prototype._annotations = function (type, simplify, annotationCache) {
|
|
var annotations = annotationCache.get(type);
|
|
if (!annotations) {
|
|
annotations = [];
|
|
var classMetadata = this.getTypeMetadata(type);
|
|
var parentType = this.findParentType(type, classMetadata);
|
|
if (parentType) {
|
|
var parentAnnotations = this.annotations(parentType);
|
|
annotations.push.apply(annotations, __spreadArray([], __read(parentAnnotations)));
|
|
}
|
|
var ownAnnotations_1 = [];
|
|
if (classMetadata['decorators']) {
|
|
ownAnnotations_1 = simplify(type, classMetadata['decorators']);
|
|
if (ownAnnotations_1) {
|
|
annotations.push.apply(annotations, __spreadArray([], __read(ownAnnotations_1)));
|
|
}
|
|
}
|
|
if (parentType && !this.summaryResolver.isLibraryFile(type.filePath) &&
|
|
this.summaryResolver.isLibraryFile(parentType.filePath)) {
|
|
var summary = this.summaryResolver.resolveSummary(parentType);
|
|
if (summary && summary.type) {
|
|
var requiredAnnotationTypes = this.annotationForParentClassWithSummaryKind.get(summary.type.summaryKind);
|
|
var typeHasRequiredAnnotation = requiredAnnotationTypes.some(function (requiredType) { return ownAnnotations_1.some(function (ann) { return requiredType.isTypeOf(ann); }); });
|
|
if (!typeHasRequiredAnnotation) {
|
|
this.reportError(formatMetadataError(metadataError("Class " + type.name + " in " + type.filePath + " extends from a " + exports.CompileSummaryKind[summary.type.summaryKind] + " in another compilation unit without duplicating the decorator",
|
|
/* summary */ undefined, "Please add a " + requiredAnnotationTypes.map(function (type) { return type.ngMetadataName; })
|
|
.join(' or ') + " decorator to the class"), type), type);
|
|
}
|
|
}
|
|
}
|
|
annotationCache.set(type, annotations.filter(function (ann) { return !!ann; }));
|
|
}
|
|
return annotations;
|
|
};
|
|
StaticReflector.prototype.propMetadata = function (type) {
|
|
var _this = this;
|
|
var propMetadata = this.propertyCache.get(type);
|
|
if (!propMetadata) {
|
|
var classMetadata = this.getTypeMetadata(type);
|
|
propMetadata = {};
|
|
var parentType = this.findParentType(type, classMetadata);
|
|
if (parentType) {
|
|
var parentPropMetadata_1 = this.propMetadata(parentType);
|
|
Object.keys(parentPropMetadata_1).forEach(function (parentProp) {
|
|
propMetadata[parentProp] = parentPropMetadata_1[parentProp];
|
|
});
|
|
}
|
|
var members_1 = classMetadata['members'] || {};
|
|
Object.keys(members_1).forEach(function (propName) {
|
|
var propData = members_1[propName];
|
|
var prop = propData
|
|
.find(function (a) { return a['__symbolic'] == 'property' || a['__symbolic'] == 'method'; });
|
|
var decorators = [];
|
|
// hasOwnProperty() is used here to make sure we do not look up methods
|
|
// on `Object.prototype`.
|
|
if (propMetadata === null || propMetadata === void 0 ? void 0 : propMetadata.hasOwnProperty(propName)) {
|
|
decorators.push.apply(decorators, __spreadArray([], __read(propMetadata[propName])));
|
|
}
|
|
propMetadata[propName] = decorators;
|
|
if (prop && prop['decorators']) {
|
|
decorators.push.apply(decorators, __spreadArray([], __read(_this.simplify(type, prop['decorators']))));
|
|
}
|
|
});
|
|
this.propertyCache.set(type, propMetadata);
|
|
}
|
|
return propMetadata;
|
|
};
|
|
StaticReflector.prototype.parameters = function (type) {
|
|
var _this = this;
|
|
if (!(type instanceof StaticSymbol)) {
|
|
this.reportError(new Error("parameters received " + JSON.stringify(type) + " which is not a StaticSymbol"), type);
|
|
return [];
|
|
}
|
|
try {
|
|
var parameters_1 = this.parameterCache.get(type);
|
|
if (!parameters_1) {
|
|
var classMetadata = this.getTypeMetadata(type);
|
|
var parentType = this.findParentType(type, classMetadata);
|
|
var members = classMetadata ? classMetadata['members'] : null;
|
|
var ctorData = members ? members['__ctor__'] : null;
|
|
if (ctorData) {
|
|
var ctor = ctorData.find(function (a) { return a['__symbolic'] == 'constructor'; });
|
|
var rawParameterTypes = ctor['parameters'] || [];
|
|
var parameterDecorators_1 = this.simplify(type, ctor['parameterDecorators'] || []);
|
|
parameters_1 = [];
|
|
rawParameterTypes.forEach(function (rawParamType, index) {
|
|
var nestedResult = [];
|
|
var paramType = _this.trySimplify(type, rawParamType);
|
|
if (paramType)
|
|
nestedResult.push(paramType);
|
|
var decorators = parameterDecorators_1 ? parameterDecorators_1[index] : null;
|
|
if (decorators) {
|
|
nestedResult.push.apply(nestedResult, __spreadArray([], __read(decorators)));
|
|
}
|
|
parameters_1.push(nestedResult);
|
|
});
|
|
}
|
|
else if (parentType) {
|
|
parameters_1 = this.parameters(parentType);
|
|
}
|
|
if (!parameters_1) {
|
|
parameters_1 = [];
|
|
}
|
|
this.parameterCache.set(type, parameters_1);
|
|
}
|
|
return parameters_1;
|
|
}
|
|
catch (e) {
|
|
console.error("Failed on type " + JSON.stringify(type) + " with error " + e);
|
|
throw e;
|
|
}
|
|
};
|
|
StaticReflector.prototype._methodNames = function (type) {
|
|
var methodNames = this.methodCache.get(type);
|
|
if (!methodNames) {
|
|
var classMetadata = this.getTypeMetadata(type);
|
|
methodNames = {};
|
|
var parentType = this.findParentType(type, classMetadata);
|
|
if (parentType) {
|
|
var parentMethodNames_1 = this._methodNames(parentType);
|
|
Object.keys(parentMethodNames_1).forEach(function (parentProp) {
|
|
methodNames[parentProp] = parentMethodNames_1[parentProp];
|
|
});
|
|
}
|
|
var members_2 = classMetadata['members'] || {};
|
|
Object.keys(members_2).forEach(function (propName) {
|
|
var propData = members_2[propName];
|
|
var isMethod = propData.some(function (a) { return a['__symbolic'] == 'method'; });
|
|
methodNames[propName] = methodNames[propName] || isMethod;
|
|
});
|
|
this.methodCache.set(type, methodNames);
|
|
}
|
|
return methodNames;
|
|
};
|
|
StaticReflector.prototype._staticMembers = function (type) {
|
|
var staticMembers = this.staticCache.get(type);
|
|
if (!staticMembers) {
|
|
var classMetadata = this.getTypeMetadata(type);
|
|
var staticMemberData = classMetadata['statics'] || {};
|
|
staticMembers = Object.keys(staticMemberData);
|
|
this.staticCache.set(type, staticMembers);
|
|
}
|
|
return staticMembers;
|
|
};
|
|
StaticReflector.prototype.findParentType = function (type, classMetadata) {
|
|
var parentType = this.trySimplify(type, classMetadata['extends']);
|
|
if (parentType instanceof StaticSymbol) {
|
|
return parentType;
|
|
}
|
|
};
|
|
StaticReflector.prototype.hasLifecycleHook = function (type, lcProperty) {
|
|
if (!(type instanceof StaticSymbol)) {
|
|
this.reportError(new Error("hasLifecycleHook received " + JSON.stringify(type) + " which is not a StaticSymbol"), type);
|
|
}
|
|
try {
|
|
return !!this._methodNames(type)[lcProperty];
|
|
}
|
|
catch (e) {
|
|
console.error("Failed on type " + JSON.stringify(type) + " with error " + e);
|
|
throw e;
|
|
}
|
|
};
|
|
StaticReflector.prototype.guards = function (type) {
|
|
var e_2, _a;
|
|
if (!(type instanceof StaticSymbol)) {
|
|
this.reportError(new Error("guards received " + JSON.stringify(type) + " which is not a StaticSymbol"), type);
|
|
return {};
|
|
}
|
|
var staticMembers = this._staticMembers(type);
|
|
var result = {};
|
|
try {
|
|
for (var staticMembers_1 = __values(staticMembers), staticMembers_1_1 = staticMembers_1.next(); !staticMembers_1_1.done; staticMembers_1_1 = staticMembers_1.next()) {
|
|
var name = staticMembers_1_1.value;
|
|
if (name.endsWith(TYPEGUARD_POSTFIX)) {
|
|
var property = name.substr(0, name.length - TYPEGUARD_POSTFIX.length);
|
|
var value = void 0;
|
|
if (property.endsWith(USE_IF)) {
|
|
property = name.substr(0, property.length - USE_IF.length);
|
|
value = USE_IF;
|
|
}
|
|
else {
|
|
value = this.getStaticSymbol(type.filePath, type.name, [name]);
|
|
}
|
|
result[property] = value;
|
|
}
|
|
}
|
|
}
|
|
catch (e_2_1) { e_2 = { error: e_2_1 }; }
|
|
finally {
|
|
try {
|
|
if (staticMembers_1_1 && !staticMembers_1_1.done && (_a = staticMembers_1.return)) _a.call(staticMembers_1);
|
|
}
|
|
finally { if (e_2) throw e_2.error; }
|
|
}
|
|
return result;
|
|
};
|
|
StaticReflector.prototype._registerDecoratorOrConstructor = function (type, ctor) {
|
|
this.conversionMap.set(type, function (context, args) { return new (ctor.bind.apply(ctor, __spreadArray([void 0], __read(args))))(); });
|
|
};
|
|
StaticReflector.prototype._registerFunction = function (type, fn) {
|
|
this.conversionMap.set(type, function (context, args) { return fn.apply(undefined, args); });
|
|
};
|
|
StaticReflector.prototype.initializeConversionMap = function () {
|
|
this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Injectable'), createInjectable);
|
|
this.injectionToken = this.findDeclaration(ANGULAR_CORE, 'InjectionToken');
|
|
this.opaqueToken = this.findDeclaration(ANGULAR_CORE, 'OpaqueToken');
|
|
this.ROUTES = this.tryFindDeclaration(ANGULAR_ROUTER, 'ROUTES');
|
|
this.ANALYZE_FOR_ENTRY_COMPONENTS =
|
|
this.findDeclaration(ANGULAR_CORE, 'ANALYZE_FOR_ENTRY_COMPONENTS');
|
|
this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Host'), createHost);
|
|
this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Self'), createSelf);
|
|
this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'SkipSelf'), createSkipSelf);
|
|
this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Inject'), createInject);
|
|
this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Optional'), createOptional);
|
|
this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Attribute'), createAttribute);
|
|
this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'ContentChild'), createContentChild);
|
|
this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'ContentChildren'), createContentChildren);
|
|
this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'ViewChild'), createViewChild);
|
|
this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'ViewChildren'), createViewChildren);
|
|
this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Input'), createInput);
|
|
this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Output'), createOutput);
|
|
this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Pipe'), createPipe);
|
|
this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'HostBinding'), createHostBinding);
|
|
this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'HostListener'), createHostListener);
|
|
this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Directive'), createDirective);
|
|
this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Component'), createComponent);
|
|
this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'NgModule'), createNgModule);
|
|
// Note: Some metadata classes can be used directly with Provider.deps.
|
|
this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Host'), createHost);
|
|
this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Self'), createSelf);
|
|
this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'SkipSelf'), createSkipSelf);
|
|
this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Optional'), createOptional);
|
|
};
|
|
/**
|
|
* getStaticSymbol produces a Type whose metadata is known but whose implementation is not loaded.
|
|
* All types passed to the StaticResolver should be pseudo-types returned by this method.
|
|
*
|
|
* @param declarationFile the absolute path of the file where the symbol is declared
|
|
* @param name the name of the type.
|
|
*/
|
|
StaticReflector.prototype.getStaticSymbol = function (declarationFile, name, members) {
|
|
return this.symbolResolver.getStaticSymbol(declarationFile, name, members);
|
|
};
|
|
/**
|
|
* Simplify but discard any errors
|
|
*/
|
|
StaticReflector.prototype.trySimplify = function (context, value) {
|
|
var originalRecorder = this.errorRecorder;
|
|
this.errorRecorder = function (error, fileName) { };
|
|
var result = this.simplify(context, value);
|
|
this.errorRecorder = originalRecorder;
|
|
return result;
|
|
};
|
|
/** @internal */
|
|
StaticReflector.prototype.simplify = function (context, value, lazy) {
|
|
if (lazy === void 0) { lazy = false; }
|
|
var self = this;
|
|
var scope = BindingScope$1.empty;
|
|
var calling = new Map();
|
|
var rootContext = context;
|
|
function simplifyInContext(context, value, depth, references) {
|
|
function resolveReferenceValue(staticSymbol) {
|
|
var resolvedSymbol = self.symbolResolver.resolveSymbol(staticSymbol);
|
|
return resolvedSymbol ? resolvedSymbol.metadata : null;
|
|
}
|
|
function simplifyEagerly(value) {
|
|
return simplifyInContext(context, value, depth, 0);
|
|
}
|
|
function simplifyLazily(value) {
|
|
return simplifyInContext(context, value, depth, references + 1);
|
|
}
|
|
function simplifyNested(nestedContext, value) {
|
|
if (nestedContext === context) {
|
|
// If the context hasn't changed let the exception propagate unmodified.
|
|
return simplifyInContext(nestedContext, value, depth + 1, references);
|
|
}
|
|
try {
|
|
return simplifyInContext(nestedContext, value, depth + 1, references);
|
|
}
|
|
catch (e) {
|
|
if (isMetadataError(e)) {
|
|
// Propagate the message text up but add a message to the chain that explains how we got
|
|
// here.
|
|
// e.chain implies e.symbol
|
|
var summaryMsg = e.chain ? 'references \'' + e.symbol.name + '\'' : errorSummary(e);
|
|
var summary = "'" + nestedContext.name + "' " + summaryMsg;
|
|
var chain = { message: summary, position: e.position, next: e.chain };
|
|
// TODO(chuckj): retrieve the position information indirectly from the collectors node
|
|
// map if the metadata is from a .ts file.
|
|
self.error({
|
|
message: e.message,
|
|
advise: e.advise,
|
|
context: e.context,
|
|
chain: chain,
|
|
symbol: nestedContext
|
|
}, context);
|
|
}
|
|
else {
|
|
// It is probably an internal error.
|
|
throw e;
|
|
}
|
|
}
|
|
}
|
|
function simplifyCall(functionSymbol, targetFunction, args, targetExpression) {
|
|
if (targetFunction && targetFunction['__symbolic'] == 'function') {
|
|
if (calling.get(functionSymbol)) {
|
|
self.error({
|
|
message: 'Recursion is not supported',
|
|
summary: "called '" + functionSymbol.name + "' recursively",
|
|
value: targetFunction
|
|
}, functionSymbol);
|
|
}
|
|
try {
|
|
var value_1 = targetFunction['value'];
|
|
if (value_1 && (depth != 0 || value_1.__symbolic != 'error')) {
|
|
var parameters = targetFunction['parameters'];
|
|
var defaults = targetFunction.defaults;
|
|
args = args.map(function (arg) { return simplifyNested(context, arg); })
|
|
.map(function (arg) { return shouldIgnore(arg) ? undefined : arg; });
|
|
if (defaults && defaults.length > args.length) {
|
|
args.push.apply(args, __spreadArray([], __read(defaults.slice(args.length).map(function (value) { return simplify(value); }))));
|
|
}
|
|
calling.set(functionSymbol, true);
|
|
var functionScope = BindingScope$1.build();
|
|
for (var i = 0; i < parameters.length; i++) {
|
|
functionScope.define(parameters[i], args[i]);
|
|
}
|
|
var oldScope = scope;
|
|
var result_1;
|
|
try {
|
|
scope = functionScope.done();
|
|
result_1 = simplifyNested(functionSymbol, value_1);
|
|
}
|
|
finally {
|
|
scope = oldScope;
|
|
}
|
|
return result_1;
|
|
}
|
|
}
|
|
finally {
|
|
calling.delete(functionSymbol);
|
|
}
|
|
}
|
|
if (depth === 0) {
|
|
// If depth is 0 we are evaluating the top level expression that is describing element
|
|
// decorator. In this case, it is a decorator we don't understand, such as a custom
|
|
// non-angular decorator, and we should just ignore it.
|
|
return IGNORE;
|
|
}
|
|
var position = undefined;
|
|
if (targetExpression && targetExpression.__symbolic == 'resolved') {
|
|
var line = targetExpression.line;
|
|
var character = targetExpression.character;
|
|
var fileName = targetExpression.fileName;
|
|
if (fileName != null && line != null && character != null) {
|
|
position = { fileName: fileName, line: line, column: character };
|
|
}
|
|
}
|
|
self.error({
|
|
message: FUNCTION_CALL_NOT_SUPPORTED,
|
|
context: functionSymbol,
|
|
value: targetFunction,
|
|
position: position
|
|
}, context);
|
|
}
|
|
function simplify(expression) {
|
|
var e_3, _a, e_4, _b;
|
|
if (isPrimitive(expression)) {
|
|
return expression;
|
|
}
|
|
if (Array.isArray(expression)) {
|
|
var result_2 = [];
|
|
try {
|
|
for (var expression_1 = __values(expression), expression_1_1 = expression_1.next(); !expression_1_1.done; expression_1_1 = expression_1.next()) {
|
|
var item = expression_1_1.value;
|
|
// Check for a spread expression
|
|
if (item && item.__symbolic === 'spread') {
|
|
// We call with references as 0 because we require the actual value and cannot
|
|
// tolerate a reference here.
|
|
var spreadArray = simplifyEagerly(item.expression);
|
|
if (Array.isArray(spreadArray)) {
|
|
try {
|
|
for (var spreadArray_1 = (e_4 = void 0, __values(spreadArray)), spreadArray_1_1 = spreadArray_1.next(); !spreadArray_1_1.done; spreadArray_1_1 = spreadArray_1.next()) {
|
|
var spreadItem = spreadArray_1_1.value;
|
|
result_2.push(spreadItem);
|
|
}
|
|
}
|
|
catch (e_4_1) { e_4 = { error: e_4_1 }; }
|
|
finally {
|
|
try {
|
|
if (spreadArray_1_1 && !spreadArray_1_1.done && (_b = spreadArray_1.return)) _b.call(spreadArray_1);
|
|
}
|
|
finally { if (e_4) throw e_4.error; }
|
|
}
|
|
continue;
|
|
}
|
|
}
|
|
var value_2 = simplify(item);
|
|
if (shouldIgnore(value_2)) {
|
|
continue;
|
|
}
|
|
result_2.push(value_2);
|
|
}
|
|
}
|
|
catch (e_3_1) { e_3 = { error: e_3_1 }; }
|
|
finally {
|
|
try {
|
|
if (expression_1_1 && !expression_1_1.done && (_a = expression_1.return)) _a.call(expression_1);
|
|
}
|
|
finally { if (e_3) throw e_3.error; }
|
|
}
|
|
return result_2;
|
|
}
|
|
if (expression instanceof StaticSymbol) {
|
|
// Stop simplification at builtin symbols or if we are in a reference context and
|
|
// the symbol doesn't have members.
|
|
if (expression === self.injectionToken || self.conversionMap.has(expression) ||
|
|
(references > 0 && !expression.members.length)) {
|
|
return expression;
|
|
}
|
|
else {
|
|
var staticSymbol = expression;
|
|
var declarationValue = resolveReferenceValue(staticSymbol);
|
|
if (declarationValue != null) {
|
|
return simplifyNested(staticSymbol, declarationValue);
|
|
}
|
|
else {
|
|
return staticSymbol;
|
|
}
|
|
}
|
|
}
|
|
if (expression) {
|
|
if (expression['__symbolic']) {
|
|
var staticSymbol = void 0;
|
|
switch (expression['__symbolic']) {
|
|
case 'binop':
|
|
var left = simplify(expression['left']);
|
|
if (shouldIgnore(left))
|
|
return left;
|
|
var right = simplify(expression['right']);
|
|
if (shouldIgnore(right))
|
|
return right;
|
|
switch (expression['operator']) {
|
|
case '&&':
|
|
return left && right;
|
|
case '||':
|
|
return left || right;
|
|
case '|':
|
|
return left | right;
|
|
case '^':
|
|
return left ^ right;
|
|
case '&':
|
|
return left & right;
|
|
case '==':
|
|
return left == right;
|
|
case '!=':
|
|
return left != right;
|
|
case '===':
|
|
return left === right;
|
|
case '!==':
|
|
return left !== right;
|
|
case '<':
|
|
return left < right;
|
|
case '>':
|
|
return left > right;
|
|
case '<=':
|
|
return left <= right;
|
|
case '>=':
|
|
return left >= right;
|
|
case '<<':
|
|
return left << right;
|
|
case '>>':
|
|
return left >> right;
|
|
case '+':
|
|
return left + right;
|
|
case '-':
|
|
return left - right;
|
|
case '*':
|
|
return left * right;
|
|
case '/':
|
|
return left / right;
|
|
case '%':
|
|
return left % right;
|
|
case '??':
|
|
return left !== null && left !== void 0 ? left : right;
|
|
}
|
|
return null;
|
|
case 'if':
|
|
var condition = simplify(expression['condition']);
|
|
return condition ? simplify(expression['thenExpression']) :
|
|
simplify(expression['elseExpression']);
|
|
case 'pre':
|
|
var operand = simplify(expression['operand']);
|
|
if (shouldIgnore(operand))
|
|
return operand;
|
|
switch (expression['operator']) {
|
|
case '+':
|
|
return operand;
|
|
case '-':
|
|
return -operand;
|
|
case '!':
|
|
return !operand;
|
|
case '~':
|
|
return ~operand;
|
|
}
|
|
return null;
|
|
case 'index':
|
|
var indexTarget = simplifyEagerly(expression['expression']);
|
|
var index = simplifyEagerly(expression['index']);
|
|
if (indexTarget && isPrimitive(index))
|
|
return indexTarget[index];
|
|
return null;
|
|
case 'select':
|
|
var member = expression['member'];
|
|
var selectContext = context;
|
|
var selectTarget = simplify(expression['expression']);
|
|
if (selectTarget instanceof StaticSymbol) {
|
|
var members = selectTarget.members.concat(member);
|
|
selectContext =
|
|
self.getStaticSymbol(selectTarget.filePath, selectTarget.name, members);
|
|
var declarationValue = resolveReferenceValue(selectContext);
|
|
if (declarationValue != null) {
|
|
return simplifyNested(selectContext, declarationValue);
|
|
}
|
|
else {
|
|
return selectContext;
|
|
}
|
|
}
|
|
if (selectTarget && isPrimitive(member))
|
|
return simplifyNested(selectContext, selectTarget[member]);
|
|
return null;
|
|
case 'reference':
|
|
// Note: This only has to deal with variable references, as symbol references have
|
|
// been converted into 'resolved'
|
|
// in the StaticSymbolResolver.
|
|
var name = expression['name'];
|
|
var localValue = scope.resolve(name);
|
|
if (localValue != BindingScope$1.missing) {
|
|
return localValue;
|
|
}
|
|
break;
|
|
case 'resolved':
|
|
try {
|
|
return simplify(expression.symbol);
|
|
}
|
|
catch (e) {
|
|
// If an error is reported evaluating the symbol record the position of the
|
|
// reference in the error so it can
|
|
// be reported in the error message generated from the exception.
|
|
if (isMetadataError(e) && expression.fileName != null &&
|
|
expression.line != null && expression.character != null) {
|
|
e.position = {
|
|
fileName: expression.fileName,
|
|
line: expression.line,
|
|
column: expression.character
|
|
};
|
|
}
|
|
throw e;
|
|
}
|
|
case 'class':
|
|
return context;
|
|
case 'function':
|
|
return context;
|
|
case 'new':
|
|
case 'call':
|
|
// Determine if the function is a built-in conversion
|
|
staticSymbol = simplifyInContext(context, expression['expression'], depth + 1, /* references */ 0);
|
|
if (staticSymbol instanceof StaticSymbol) {
|
|
if (staticSymbol === self.injectionToken || staticSymbol === self.opaqueToken) {
|
|
// if somebody calls new InjectionToken, don't create an InjectionToken,
|
|
// but rather return the symbol to which the InjectionToken is assigned to.
|
|
// OpaqueToken is supported too as it is required by the language service to
|
|
// support v4 and prior versions of Angular.
|
|
return context;
|
|
}
|
|
var argExpressions = expression['arguments'] || [];
|
|
var converter = self.conversionMap.get(staticSymbol);
|
|
if (converter) {
|
|
var args = argExpressions.map(function (arg) { return simplifyNested(context, arg); })
|
|
.map(function (arg) { return shouldIgnore(arg) ? undefined : arg; });
|
|
return converter(context, args);
|
|
}
|
|
else {
|
|
// Determine if the function is one we can simplify.
|
|
var targetFunction = resolveReferenceValue(staticSymbol);
|
|
return simplifyCall(staticSymbol, targetFunction, argExpressions, expression['expression']);
|
|
}
|
|
}
|
|
return IGNORE;
|
|
case 'error':
|
|
var message = expression.message;
|
|
if (expression['line'] != null) {
|
|
self.error({
|
|
message: message,
|
|
context: expression.context,
|
|
value: expression,
|
|
position: {
|
|
fileName: expression['fileName'],
|
|
line: expression['line'],
|
|
column: expression['character']
|
|
}
|
|
}, context);
|
|
}
|
|
else {
|
|
self.error({ message: message, context: expression.context }, context);
|
|
}
|
|
return IGNORE;
|
|
case 'ignore':
|
|
return expression;
|
|
}
|
|
return null;
|
|
}
|
|
return mapStringMap(expression, function (value, name) {
|
|
if (REFERENCE_SET.has(name)) {
|
|
if (name === USE_VALUE$1 && PROVIDE in expression) {
|
|
// If this is a provider expression, check for special tokens that need the value
|
|
// during analysis.
|
|
var provide = simplify(expression.provide);
|
|
if (provide === self.ROUTES || provide == self.ANALYZE_FOR_ENTRY_COMPONENTS) {
|
|
return simplify(value);
|
|
}
|
|
}
|
|
return simplifyLazily(value);
|
|
}
|
|
return simplify(value);
|
|
});
|
|
}
|
|
return IGNORE;
|
|
}
|
|
return simplify(value);
|
|
}
|
|
var result;
|
|
try {
|
|
result = simplifyInContext(context, value, 0, lazy ? 1 : 0);
|
|
}
|
|
catch (e) {
|
|
if (this.errorRecorder) {
|
|
this.reportError(e, context);
|
|
}
|
|
else {
|
|
throw formatMetadataError(e, context);
|
|
}
|
|
}
|
|
if (shouldIgnore(result)) {
|
|
return undefined;
|
|
}
|
|
return result;
|
|
};
|
|
StaticReflector.prototype.getTypeMetadata = function (type) {
|
|
var resolvedSymbol = this.symbolResolver.resolveSymbol(type);
|
|
return resolvedSymbol && resolvedSymbol.metadata ? resolvedSymbol.metadata :
|
|
{ __symbolic: 'class' };
|
|
};
|
|
StaticReflector.prototype.reportError = function (error, context, path) {
|
|
if (this.errorRecorder) {
|
|
this.errorRecorder(formatMetadataError(error, context), (context && context.filePath) || path);
|
|
}
|
|
else {
|
|
throw error;
|
|
}
|
|
};
|
|
StaticReflector.prototype.error = function (_a, reportingContext) {
|
|
var message = _a.message, summary = _a.summary, advise = _a.advise, position = _a.position, context = _a.context, value = _a.value, symbol = _a.symbol, chain = _a.chain;
|
|
this.reportError(metadataError(message, summary, advise, position, symbol, context, chain), reportingContext);
|
|
};
|
|
return StaticReflector;
|
|
}());
|
|
var METADATA_ERROR = 'ngMetadataError';
|
|
function metadataError(message, summary, advise, position, symbol, context, chain) {
|
|
var error = syntaxError(message);
|
|
error[METADATA_ERROR] = true;
|
|
if (advise)
|
|
error.advise = advise;
|
|
if (position)
|
|
error.position = position;
|
|
if (summary)
|
|
error.summary = summary;
|
|
if (context)
|
|
error.context = context;
|
|
if (chain)
|
|
error.chain = chain;
|
|
if (symbol)
|
|
error.symbol = symbol;
|
|
return error;
|
|
}
|
|
function isMetadataError(error) {
|
|
return !!error[METADATA_ERROR];
|
|
}
|
|
var REFERENCE_TO_NONEXPORTED_CLASS = 'Reference to non-exported class';
|
|
var VARIABLE_NOT_INITIALIZED = 'Variable not initialized';
|
|
var DESTRUCTURE_NOT_SUPPORTED = 'Destructuring not supported';
|
|
var COULD_NOT_RESOLVE_TYPE = 'Could not resolve type';
|
|
var FUNCTION_CALL_NOT_SUPPORTED = 'Function call not supported';
|
|
var REFERENCE_TO_LOCAL_SYMBOL = 'Reference to a local symbol';
|
|
var LAMBDA_NOT_SUPPORTED = 'Lambda not supported';
|
|
function expandedMessage(message, context) {
|
|
switch (message) {
|
|
case REFERENCE_TO_NONEXPORTED_CLASS:
|
|
if (context && context.className) {
|
|
return "References to a non-exported class are not supported in decorators but " + context.className + " was referenced.";
|
|
}
|
|
break;
|
|
case VARIABLE_NOT_INITIALIZED:
|
|
return 'Only initialized variables and constants can be referenced in decorators because the value of this variable is needed by the template compiler';
|
|
case DESTRUCTURE_NOT_SUPPORTED:
|
|
return 'Referencing an exported destructured variable or constant is not supported in decorators and this value is needed by the template compiler';
|
|
case COULD_NOT_RESOLVE_TYPE:
|
|
if (context && context.typeName) {
|
|
return "Could not resolve type " + context.typeName;
|
|
}
|
|
break;
|
|
case FUNCTION_CALL_NOT_SUPPORTED:
|
|
if (context && context.name) {
|
|
return "Function calls are not supported in decorators but '" + context.name + "' was called";
|
|
}
|
|
return 'Function calls are not supported in decorators';
|
|
case REFERENCE_TO_LOCAL_SYMBOL:
|
|
if (context && context.name) {
|
|
return "Reference to a local (non-exported) symbols are not supported in decorators but '" + context.name + "' was referenced";
|
|
}
|
|
break;
|
|
case LAMBDA_NOT_SUPPORTED:
|
|
return "Function expressions are not supported in decorators";
|
|
}
|
|
return message;
|
|
}
|
|
function messageAdvise(message, context) {
|
|
switch (message) {
|
|
case REFERENCE_TO_NONEXPORTED_CLASS:
|
|
if (context && context.className) {
|
|
return "Consider exporting '" + context.className + "'";
|
|
}
|
|
break;
|
|
case DESTRUCTURE_NOT_SUPPORTED:
|
|
return 'Consider simplifying to avoid destructuring';
|
|
case REFERENCE_TO_LOCAL_SYMBOL:
|
|
if (context && context.name) {
|
|
return "Consider exporting '" + context.name + "'";
|
|
}
|
|
break;
|
|
case LAMBDA_NOT_SUPPORTED:
|
|
return "Consider changing the function expression into an exported function";
|
|
}
|
|
return undefined;
|
|
}
|
|
function errorSummary(error) {
|
|
if (error.summary) {
|
|
return error.summary;
|
|
}
|
|
switch (error.message) {
|
|
case REFERENCE_TO_NONEXPORTED_CLASS:
|
|
if (error.context && error.context.className) {
|
|
return "references non-exported class " + error.context.className;
|
|
}
|
|
break;
|
|
case VARIABLE_NOT_INITIALIZED:
|
|
return 'is not initialized';
|
|
case DESTRUCTURE_NOT_SUPPORTED:
|
|
return 'is a destructured variable';
|
|
case COULD_NOT_RESOLVE_TYPE:
|
|
return 'could not be resolved';
|
|
case FUNCTION_CALL_NOT_SUPPORTED:
|
|
if (error.context && error.context.name) {
|
|
return "calls '" + error.context.name + "'";
|
|
}
|
|
return "calls a function";
|
|
case REFERENCE_TO_LOCAL_SYMBOL:
|
|
if (error.context && error.context.name) {
|
|
return "references local variable " + error.context.name;
|
|
}
|
|
return "references a local variable";
|
|
}
|
|
return 'contains the error';
|
|
}
|
|
function mapStringMap(input, transform) {
|
|
if (!input)
|
|
return {};
|
|
var result = {};
|
|
Object.keys(input).forEach(function (key) {
|
|
var value = transform(input[key], key);
|
|
if (!shouldIgnore(value)) {
|
|
if (HIDDEN_KEY.test(key)) {
|
|
Object.defineProperty(result, key, { enumerable: false, configurable: true, value: value });
|
|
}
|
|
else {
|
|
result[key] = value;
|
|
}
|
|
}
|
|
});
|
|
return result;
|
|
}
|
|
function isPrimitive(o) {
|
|
return o === null || (typeof o !== 'function' && typeof o !== 'object');
|
|
}
|
|
var BindingScope$1 = /** @class */ (function () {
|
|
function BindingScope() {
|
|
}
|
|
BindingScope.build = function () {
|
|
var current = new Map();
|
|
return {
|
|
define: function (name, value) {
|
|
current.set(name, value);
|
|
return this;
|
|
},
|
|
done: function () {
|
|
return current.size > 0 ? new PopulatedScope(current) : BindingScope.empty;
|
|
}
|
|
};
|
|
};
|
|
return BindingScope;
|
|
}());
|
|
BindingScope$1.missing = {};
|
|
BindingScope$1.empty = { resolve: function (name) { return BindingScope$1.missing; } };
|
|
var PopulatedScope = /** @class */ (function (_super) {
|
|
__extends(PopulatedScope, _super);
|
|
function PopulatedScope(bindings) {
|
|
var _this = _super.call(this) || this;
|
|
_this.bindings = bindings;
|
|
return _this;
|
|
}
|
|
PopulatedScope.prototype.resolve = function (name) {
|
|
return this.bindings.has(name) ? this.bindings.get(name) : BindingScope$1.missing;
|
|
};
|
|
return PopulatedScope;
|
|
}(BindingScope$1));
|
|
function formatMetadataMessageChain(chain, advise) {
|
|
var expanded = expandedMessage(chain.message, chain.context);
|
|
var nesting = chain.symbol ? " in '" + chain.symbol.name + "'" : '';
|
|
var message = "" + expanded + nesting;
|
|
var position = chain.position;
|
|
var next = chain.next ?
|
|
formatMetadataMessageChain(chain.next, advise) :
|
|
advise ? { message: advise } : undefined;
|
|
return { message: message, position: position, next: next ? [next] : undefined };
|
|
}
|
|
function formatMetadataError(e, context) {
|
|
if (isMetadataError(e)) {
|
|
// Produce a formatted version of the and leaving enough information in the original error
|
|
// to recover the formatting information to eventually produce a diagnostic error message.
|
|
var position = e.position;
|
|
var chain = {
|
|
message: "Error during template compile of '" + context.name + "'",
|
|
position: position,
|
|
next: { message: e.message, next: e.chain, context: e.context, symbol: e.symbol }
|
|
};
|
|
var advise = e.advise || messageAdvise(e.message, e.context);
|
|
return formattedError(formatMetadataMessageChain(chain, advise));
|
|
}
|
|
return e;
|
|
}
|
|
|
|
/**
|
|
* @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 AotSummaryResolver = /** @class */ (function () {
|
|
function AotSummaryResolver(host, staticSymbolCache) {
|
|
this.host = host;
|
|
this.staticSymbolCache = staticSymbolCache;
|
|
// Note: this will only contain StaticSymbols without members!
|
|
this.summaryCache = new Map();
|
|
this.loadedFilePaths = new Map();
|
|
// Note: this will only contain StaticSymbols without members!
|
|
this.importAs = new Map();
|
|
this.knownFileNameToModuleNames = new Map();
|
|
}
|
|
AotSummaryResolver.prototype.isLibraryFile = function (filePath) {
|
|
// Note: We need to strip the .ngfactory. file path,
|
|
// so this method also works for generated files
|
|
// (for which host.isSourceFile will always return false).
|
|
return !this.host.isSourceFile(stripGeneratedFileSuffix(filePath));
|
|
};
|
|
AotSummaryResolver.prototype.toSummaryFileName = function (filePath, referringSrcFileName) {
|
|
return this.host.toSummaryFileName(filePath, referringSrcFileName);
|
|
};
|
|
AotSummaryResolver.prototype.fromSummaryFileName = function (fileName, referringLibFileName) {
|
|
return this.host.fromSummaryFileName(fileName, referringLibFileName);
|
|
};
|
|
AotSummaryResolver.prototype.resolveSummary = function (staticSymbol) {
|
|
var rootSymbol = staticSymbol.members.length ?
|
|
this.staticSymbolCache.get(staticSymbol.filePath, staticSymbol.name) :
|
|
staticSymbol;
|
|
var summary = this.summaryCache.get(rootSymbol);
|
|
if (!summary) {
|
|
this._loadSummaryFile(staticSymbol.filePath);
|
|
summary = this.summaryCache.get(staticSymbol);
|
|
}
|
|
return (rootSymbol === staticSymbol && summary) || null;
|
|
};
|
|
AotSummaryResolver.prototype.getSymbolsOf = function (filePath) {
|
|
if (this._loadSummaryFile(filePath)) {
|
|
return Array.from(this.summaryCache.keys()).filter(function (symbol) { return symbol.filePath === filePath; });
|
|
}
|
|
return null;
|
|
};
|
|
AotSummaryResolver.prototype.getImportAs = function (staticSymbol) {
|
|
staticSymbol.assertNoMembers();
|
|
return this.importAs.get(staticSymbol);
|
|
};
|
|
/**
|
|
* Converts a file path to a module name that can be used as an `import`.
|
|
*/
|
|
AotSummaryResolver.prototype.getKnownModuleName = function (importedFilePath) {
|
|
return this.knownFileNameToModuleNames.get(importedFilePath) || null;
|
|
};
|
|
AotSummaryResolver.prototype.addSummary = function (summary) {
|
|
this.summaryCache.set(summary.symbol, summary);
|
|
};
|
|
AotSummaryResolver.prototype._loadSummaryFile = function (filePath) {
|
|
var _this = this;
|
|
var hasSummary = this.loadedFilePaths.get(filePath);
|
|
if (hasSummary != null) {
|
|
return hasSummary;
|
|
}
|
|
var json = null;
|
|
if (this.isLibraryFile(filePath)) {
|
|
var summaryFilePath = summaryFileName(filePath);
|
|
try {
|
|
json = this.host.loadSummary(summaryFilePath);
|
|
}
|
|
catch (e) {
|
|
console.error("Error loading summary file " + summaryFilePath);
|
|
throw e;
|
|
}
|
|
}
|
|
hasSummary = json != null;
|
|
this.loadedFilePaths.set(filePath, hasSummary);
|
|
if (json) {
|
|
var _a = deserializeSummaries(this.staticSymbolCache, this, filePath, json), moduleName = _a.moduleName, summaries = _a.summaries, importAs = _a.importAs;
|
|
summaries.forEach(function (summary) { return _this.summaryCache.set(summary.symbol, summary); });
|
|
if (moduleName) {
|
|
this.knownFileNameToModuleNames.set(filePath, moduleName);
|
|
}
|
|
importAs.forEach(function (importAs) {
|
|
_this.importAs.set(importAs.symbol, importAs.importAs);
|
|
});
|
|
}
|
|
return hasSummary;
|
|
};
|
|
return AotSummaryResolver;
|
|
}());
|
|
|
|
/**
|
|
* @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 createAotUrlResolver(host) {
|
|
return {
|
|
resolve: function (basePath, url) {
|
|
var filePath = host.resourceNameToFileName(url, basePath);
|
|
if (!filePath) {
|
|
throw syntaxError("Couldn't resolve resource " + url + " from " + basePath);
|
|
}
|
|
return filePath;
|
|
}
|
|
};
|
|
}
|
|
/**
|
|
* Creates a new AotCompiler based on options and a host.
|
|
*/
|
|
function createAotCompiler(compilerHost, options, errorCollector) {
|
|
var translations = options.translations || '';
|
|
var urlResolver = createAotUrlResolver(compilerHost);
|
|
var symbolCache = new StaticSymbolCache();
|
|
var summaryResolver = new AotSummaryResolver(compilerHost, symbolCache);
|
|
var symbolResolver = new StaticSymbolResolver(compilerHost, symbolCache, summaryResolver);
|
|
var staticReflector = new StaticReflector(summaryResolver, symbolResolver, [], [], errorCollector);
|
|
var htmlParser;
|
|
if (!!options.enableIvy) {
|
|
// Ivy handles i18n at the compiler level so we must use a regular parser
|
|
htmlParser = new HtmlParser();
|
|
}
|
|
else {
|
|
htmlParser = new I18NHtmlParser(new HtmlParser(), translations, options.i18nFormat, options.missingTranslation, console);
|
|
}
|
|
var config = new CompilerConfig({
|
|
defaultEncapsulation: ViewEncapsulation.Emulated,
|
|
useJit: false,
|
|
missingTranslation: options.missingTranslation,
|
|
preserveWhitespaces: options.preserveWhitespaces,
|
|
strictInjectionParameters: options.strictInjectionParameters,
|
|
});
|
|
var normalizer = new DirectiveNormalizer({ get: function (url) { return compilerHost.loadResource(url); } }, urlResolver, htmlParser, config);
|
|
var expressionParser = new Parser$1(new Lexer());
|
|
var elementSchemaRegistry = new DomElementSchemaRegistry();
|
|
var tmplParser = new TemplateParser(config, staticReflector, expressionParser, elementSchemaRegistry, htmlParser, console, []);
|
|
var resolver = new CompileMetadataResolver(config, htmlParser, new NgModuleResolver(staticReflector), new DirectiveResolver(staticReflector), new PipeResolver(staticReflector), summaryResolver, elementSchemaRegistry, normalizer, console, symbolCache, staticReflector, errorCollector);
|
|
// TODO(vicb): do not pass options.i18nFormat here
|
|
var viewCompiler = new ViewCompiler(staticReflector);
|
|
var typeCheckCompiler = new TypeCheckCompiler(options, staticReflector);
|
|
var compiler = new AotCompiler(config, options, compilerHost, staticReflector, resolver, tmplParser, new StyleCompiler(urlResolver), viewCompiler, typeCheckCompiler, new NgModuleCompiler(staticReflector), new InjectableCompiler(staticReflector, !!options.enableIvy), new TypeScriptEmitter(), summaryResolver, symbolResolver);
|
|
return { compiler: compiler, reflector: staticReflector };
|
|
}
|
|
|
|
var SummaryResolver = /** @class */ (function () {
|
|
function SummaryResolver() {
|
|
}
|
|
return SummaryResolver;
|
|
}());
|
|
var JitSummaryResolver = /** @class */ (function () {
|
|
function JitSummaryResolver() {
|
|
this._summaries = new Map();
|
|
}
|
|
JitSummaryResolver.prototype.isLibraryFile = function () {
|
|
return false;
|
|
};
|
|
JitSummaryResolver.prototype.toSummaryFileName = function (fileName) {
|
|
return fileName;
|
|
};
|
|
JitSummaryResolver.prototype.fromSummaryFileName = function (fileName) {
|
|
return fileName;
|
|
};
|
|
JitSummaryResolver.prototype.resolveSummary = function (reference) {
|
|
return this._summaries.get(reference) || null;
|
|
};
|
|
JitSummaryResolver.prototype.getSymbolsOf = function () {
|
|
return [];
|
|
};
|
|
JitSummaryResolver.prototype.getImportAs = function (reference) {
|
|
return reference;
|
|
};
|
|
JitSummaryResolver.prototype.getKnownModuleName = function (fileName) {
|
|
return null;
|
|
};
|
|
JitSummaryResolver.prototype.addSummary = function (summary) {
|
|
this._summaries.set(summary.symbol, summary);
|
|
};
|
|
return JitSummaryResolver;
|
|
}());
|
|
|
|
function interpretStatements(statements, reflector) {
|
|
var ctx = new _ExecutionContext(null, null, null, new Map());
|
|
var visitor = new StatementInterpreter(reflector);
|
|
visitor.visitAllStatements(statements, ctx);
|
|
var result = {};
|
|
ctx.exports.forEach(function (exportName) {
|
|
result[exportName] = ctx.vars.get(exportName);
|
|
});
|
|
return result;
|
|
}
|
|
function _executeFunctionStatements(varNames, varValues, statements, ctx, visitor) {
|
|
var childCtx = ctx.createChildWihtLocalVars();
|
|
for (var i = 0; i < varNames.length; i++) {
|
|
childCtx.vars.set(varNames[i], varValues[i]);
|
|
}
|
|
var result = visitor.visitAllStatements(statements, childCtx);
|
|
return result ? result.value : null;
|
|
}
|
|
var _ExecutionContext = /** @class */ (function () {
|
|
function _ExecutionContext(parent, instance, className, vars) {
|
|
this.parent = parent;
|
|
this.instance = instance;
|
|
this.className = className;
|
|
this.vars = vars;
|
|
this.exports = [];
|
|
}
|
|
_ExecutionContext.prototype.createChildWihtLocalVars = function () {
|
|
return new _ExecutionContext(this, this.instance, this.className, new Map());
|
|
};
|
|
return _ExecutionContext;
|
|
}());
|
|
var ReturnValue = /** @class */ (function () {
|
|
function ReturnValue(value) {
|
|
this.value = value;
|
|
}
|
|
return ReturnValue;
|
|
}());
|
|
function createDynamicClass(_classStmt, _ctx, _visitor) {
|
|
var propertyDescriptors = {};
|
|
_classStmt.getters.forEach(function (getter) {
|
|
// Note: use `function` instead of arrow function to capture `this`
|
|
propertyDescriptors[getter.name] = {
|
|
configurable: false,
|
|
get: function () {
|
|
var instanceCtx = new _ExecutionContext(_ctx, this, _classStmt.name, _ctx.vars);
|
|
return _executeFunctionStatements([], [], getter.body, instanceCtx, _visitor);
|
|
}
|
|
};
|
|
});
|
|
_classStmt.methods.forEach(function (method) {
|
|
var paramNames = method.params.map(function (param) { return param.name; });
|
|
// Note: use `function` instead of arrow function to capture `this`
|
|
propertyDescriptors[method.name] = {
|
|
writable: false,
|
|
configurable: false,
|
|
value: function () {
|
|
var args = [];
|
|
for (var _i = 0; _i < arguments.length; _i++) {
|
|
args[_i] = arguments[_i];
|
|
}
|
|
var instanceCtx = new _ExecutionContext(_ctx, this, _classStmt.name, _ctx.vars);
|
|
return _executeFunctionStatements(paramNames, args, method.body, instanceCtx, _visitor);
|
|
}
|
|
};
|
|
});
|
|
var ctorParamNames = _classStmt.constructorMethod.params.map(function (param) { return param.name; });
|
|
// Note: use `function` instead of arrow function to capture `this`
|
|
var ctor = function () {
|
|
var _this = this;
|
|
var args = [];
|
|
for (var _i = 0; _i < arguments.length; _i++) {
|
|
args[_i] = arguments[_i];
|
|
}
|
|
var instanceCtx = new _ExecutionContext(_ctx, this, _classStmt.name, _ctx.vars);
|
|
_classStmt.fields.forEach(function (field) {
|
|
_this[field.name] = undefined;
|
|
});
|
|
_executeFunctionStatements(ctorParamNames, args, _classStmt.constructorMethod.body, instanceCtx, _visitor);
|
|
};
|
|
var superClass = _classStmt.parent ? _classStmt.parent.visitExpression(_visitor, _ctx) : Object;
|
|
ctor.prototype = Object.create(superClass.prototype, propertyDescriptors);
|
|
return ctor;
|
|
}
|
|
var StatementInterpreter = /** @class */ (function () {
|
|
function StatementInterpreter(reflector) {
|
|
this.reflector = reflector;
|
|
}
|
|
StatementInterpreter.prototype.debugAst = function (ast) {
|
|
return debugOutputAstAsTypeScript(ast);
|
|
};
|
|
StatementInterpreter.prototype.visitDeclareVarStmt = function (stmt, ctx) {
|
|
var initialValue = stmt.value ? stmt.value.visitExpression(this, ctx) : undefined;
|
|
ctx.vars.set(stmt.name, initialValue);
|
|
if (stmt.hasModifier(exports.StmtModifier.Exported)) {
|
|
ctx.exports.push(stmt.name);
|
|
}
|
|
return null;
|
|
};
|
|
StatementInterpreter.prototype.visitWriteVarExpr = function (expr, ctx) {
|
|
var value = expr.value.visitExpression(this, ctx);
|
|
var currCtx = ctx;
|
|
while (currCtx != null) {
|
|
if (currCtx.vars.has(expr.name)) {
|
|
currCtx.vars.set(expr.name, value);
|
|
return value;
|
|
}
|
|
currCtx = currCtx.parent;
|
|
}
|
|
throw new Error("Not declared variable " + expr.name);
|
|
};
|
|
StatementInterpreter.prototype.visitWrappedNodeExpr = function (ast, ctx) {
|
|
throw new Error('Cannot interpret a WrappedNodeExpr.');
|
|
};
|
|
StatementInterpreter.prototype.visitTypeofExpr = function (ast, ctx) {
|
|
throw new Error('Cannot interpret a TypeofExpr');
|
|
};
|
|
StatementInterpreter.prototype.visitReadVarExpr = function (ast, ctx) {
|
|
var varName = ast.name;
|
|
if (ast.builtin != null) {
|
|
switch (ast.builtin) {
|
|
case exports.BuiltinVar.Super:
|
|
return Object.getPrototypeOf(ctx.instance);
|
|
case exports.BuiltinVar.This:
|
|
return ctx.instance;
|
|
case exports.BuiltinVar.CatchError:
|
|
varName = CATCH_ERROR_VAR$2;
|
|
break;
|
|
case exports.BuiltinVar.CatchStack:
|
|
varName = CATCH_STACK_VAR$2;
|
|
break;
|
|
default:
|
|
throw new Error("Unknown builtin variable " + ast.builtin);
|
|
}
|
|
}
|
|
var currCtx = ctx;
|
|
while (currCtx != null) {
|
|
if (currCtx.vars.has(varName)) {
|
|
return currCtx.vars.get(varName);
|
|
}
|
|
currCtx = currCtx.parent;
|
|
}
|
|
throw new Error("Not declared variable " + varName);
|
|
};
|
|
StatementInterpreter.prototype.visitWriteKeyExpr = function (expr, ctx) {
|
|
var receiver = expr.receiver.visitExpression(this, ctx);
|
|
var index = expr.index.visitExpression(this, ctx);
|
|
var value = expr.value.visitExpression(this, ctx);
|
|
receiver[index] = value;
|
|
return value;
|
|
};
|
|
StatementInterpreter.prototype.visitWritePropExpr = function (expr, ctx) {
|
|
var receiver = expr.receiver.visitExpression(this, ctx);
|
|
var value = expr.value.visitExpression(this, ctx);
|
|
receiver[expr.name] = value;
|
|
return value;
|
|
};
|
|
StatementInterpreter.prototype.visitInvokeMethodExpr = function (expr, ctx) {
|
|
var receiver = expr.receiver.visitExpression(this, ctx);
|
|
var args = this.visitAllExpressions(expr.args, ctx);
|
|
var result;
|
|
if (expr.builtin != null) {
|
|
switch (expr.builtin) {
|
|
case exports.BuiltinMethod.ConcatArray:
|
|
result = receiver.concat.apply(receiver, __spreadArray([], __read(args)));
|
|
break;
|
|
case exports.BuiltinMethod.SubscribeObservable:
|
|
result = receiver.subscribe({ next: args[0] });
|
|
break;
|
|
case exports.BuiltinMethod.Bind:
|
|
result = receiver.bind.apply(receiver, __spreadArray([], __read(args)));
|
|
break;
|
|
default:
|
|
throw new Error("Unknown builtin method " + expr.builtin);
|
|
}
|
|
}
|
|
else {
|
|
result = receiver[expr.name].apply(receiver, args);
|
|
}
|
|
return result;
|
|
};
|
|
StatementInterpreter.prototype.visitInvokeFunctionExpr = function (stmt, ctx) {
|
|
var args = this.visitAllExpressions(stmt.args, ctx);
|
|
var fnExpr = stmt.fn;
|
|
if (fnExpr instanceof ReadVarExpr && fnExpr.builtin === exports.BuiltinVar.Super) {
|
|
ctx.instance.constructor.prototype.constructor.apply(ctx.instance, args);
|
|
return null;
|
|
}
|
|
else {
|
|
var fn = stmt.fn.visitExpression(this, ctx);
|
|
return fn.apply(null, args);
|
|
}
|
|
};
|
|
StatementInterpreter.prototype.visitTaggedTemplateExpr = function (expr, ctx) {
|
|
var templateElements = expr.template.elements.map(function (e) { return e.text; });
|
|
Object.defineProperty(templateElements, 'raw', { value: expr.template.elements.map(function (e) { return e.rawText; }) });
|
|
var args = this.visitAllExpressions(expr.template.expressions, ctx);
|
|
args.unshift(templateElements);
|
|
var tag = expr.tag.visitExpression(this, ctx);
|
|
return tag.apply(null, args);
|
|
};
|
|
StatementInterpreter.prototype.visitReturnStmt = function (stmt, ctx) {
|
|
return new ReturnValue(stmt.value.visitExpression(this, ctx));
|
|
};
|
|
StatementInterpreter.prototype.visitDeclareClassStmt = function (stmt, ctx) {
|
|
var clazz = createDynamicClass(stmt, ctx, this);
|
|
ctx.vars.set(stmt.name, clazz);
|
|
if (stmt.hasModifier(exports.StmtModifier.Exported)) {
|
|
ctx.exports.push(stmt.name);
|
|
}
|
|
return null;
|
|
};
|
|
StatementInterpreter.prototype.visitExpressionStmt = function (stmt, ctx) {
|
|
return stmt.expr.visitExpression(this, ctx);
|
|
};
|
|
StatementInterpreter.prototype.visitIfStmt = function (stmt, ctx) {
|
|
var condition = stmt.condition.visitExpression(this, ctx);
|
|
if (condition) {
|
|
return this.visitAllStatements(stmt.trueCase, ctx);
|
|
}
|
|
else if (stmt.falseCase != null) {
|
|
return this.visitAllStatements(stmt.falseCase, ctx);
|
|
}
|
|
return null;
|
|
};
|
|
StatementInterpreter.prototype.visitTryCatchStmt = function (stmt, ctx) {
|
|
try {
|
|
return this.visitAllStatements(stmt.bodyStmts, ctx);
|
|
}
|
|
catch (e) {
|
|
var childCtx = ctx.createChildWihtLocalVars();
|
|
childCtx.vars.set(CATCH_ERROR_VAR$2, e);
|
|
childCtx.vars.set(CATCH_STACK_VAR$2, e.stack);
|
|
return this.visitAllStatements(stmt.catchStmts, childCtx);
|
|
}
|
|
};
|
|
StatementInterpreter.prototype.visitThrowStmt = function (stmt, ctx) {
|
|
throw stmt.error.visitExpression(this, ctx);
|
|
};
|
|
StatementInterpreter.prototype.visitInstantiateExpr = function (ast, ctx) {
|
|
var args = this.visitAllExpressions(ast.args, ctx);
|
|
var clazz = ast.classExpr.visitExpression(this, ctx);
|
|
return new (clazz.bind.apply(clazz, __spreadArray([void 0], __read(args))))();
|
|
};
|
|
StatementInterpreter.prototype.visitLiteralExpr = function (ast, ctx) {
|
|
return ast.value;
|
|
};
|
|
StatementInterpreter.prototype.visitLocalizedString = function (ast, context) {
|
|
return null;
|
|
};
|
|
StatementInterpreter.prototype.visitExternalExpr = function (ast, ctx) {
|
|
return this.reflector.resolveExternalReference(ast.value);
|
|
};
|
|
StatementInterpreter.prototype.visitConditionalExpr = function (ast, ctx) {
|
|
if (ast.condition.visitExpression(this, ctx)) {
|
|
return ast.trueCase.visitExpression(this, ctx);
|
|
}
|
|
else if (ast.falseCase != null) {
|
|
return ast.falseCase.visitExpression(this, ctx);
|
|
}
|
|
return null;
|
|
};
|
|
StatementInterpreter.prototype.visitNotExpr = function (ast, ctx) {
|
|
return !ast.condition.visitExpression(this, ctx);
|
|
};
|
|
StatementInterpreter.prototype.visitAssertNotNullExpr = function (ast, ctx) {
|
|
return ast.condition.visitExpression(this, ctx);
|
|
};
|
|
StatementInterpreter.prototype.visitCastExpr = function (ast, ctx) {
|
|
return ast.value.visitExpression(this, ctx);
|
|
};
|
|
StatementInterpreter.prototype.visitFunctionExpr = function (ast, ctx) {
|
|
var paramNames = ast.params.map(function (param) { return param.name; });
|
|
return _declareFn(paramNames, ast.statements, ctx, this);
|
|
};
|
|
StatementInterpreter.prototype.visitDeclareFunctionStmt = function (stmt, ctx) {
|
|
var paramNames = stmt.params.map(function (param) { return param.name; });
|
|
ctx.vars.set(stmt.name, _declareFn(paramNames, stmt.statements, ctx, this));
|
|
if (stmt.hasModifier(exports.StmtModifier.Exported)) {
|
|
ctx.exports.push(stmt.name);
|
|
}
|
|
return null;
|
|
};
|
|
StatementInterpreter.prototype.visitUnaryOperatorExpr = function (ast, ctx) {
|
|
var _this = this;
|
|
var rhs = function () { return ast.expr.visitExpression(_this, ctx); };
|
|
switch (ast.operator) {
|
|
case exports.UnaryOperator.Plus:
|
|
return +rhs();
|
|
case exports.UnaryOperator.Minus:
|
|
return -rhs();
|
|
default:
|
|
throw new Error("Unknown operator " + ast.operator);
|
|
}
|
|
};
|
|
StatementInterpreter.prototype.visitBinaryOperatorExpr = function (ast, ctx) {
|
|
var _this = this;
|
|
var _a;
|
|
var lhs = function () { return ast.lhs.visitExpression(_this, ctx); };
|
|
var rhs = function () { return ast.rhs.visitExpression(_this, ctx); };
|
|
switch (ast.operator) {
|
|
case exports.BinaryOperator.Equals:
|
|
return lhs() == rhs();
|
|
case exports.BinaryOperator.Identical:
|
|
return lhs() === rhs();
|
|
case exports.BinaryOperator.NotEquals:
|
|
return lhs() != rhs();
|
|
case exports.BinaryOperator.NotIdentical:
|
|
return lhs() !== rhs();
|
|
case exports.BinaryOperator.And:
|
|
return lhs() && rhs();
|
|
case exports.BinaryOperator.Or:
|
|
return lhs() || rhs();
|
|
case exports.BinaryOperator.Plus:
|
|
return lhs() + rhs();
|
|
case exports.BinaryOperator.Minus:
|
|
return lhs() - rhs();
|
|
case exports.BinaryOperator.Divide:
|
|
return lhs() / rhs();
|
|
case exports.BinaryOperator.Multiply:
|
|
return lhs() * rhs();
|
|
case exports.BinaryOperator.Modulo:
|
|
return lhs() % rhs();
|
|
case exports.BinaryOperator.Lower:
|
|
return lhs() < rhs();
|
|
case exports.BinaryOperator.LowerEquals:
|
|
return lhs() <= rhs();
|
|
case exports.BinaryOperator.Bigger:
|
|
return lhs() > rhs();
|
|
case exports.BinaryOperator.BiggerEquals:
|
|
return lhs() >= rhs();
|
|
case exports.BinaryOperator.NullishCoalesce:
|
|
return (_a = lhs()) !== null && _a !== void 0 ? _a : rhs();
|
|
default:
|
|
throw new Error("Unknown operator " + ast.operator);
|
|
}
|
|
};
|
|
StatementInterpreter.prototype.visitReadPropExpr = function (ast, ctx) {
|
|
var result;
|
|
var receiver = ast.receiver.visitExpression(this, ctx);
|
|
result = receiver[ast.name];
|
|
return result;
|
|
};
|
|
StatementInterpreter.prototype.visitReadKeyExpr = function (ast, ctx) {
|
|
var receiver = ast.receiver.visitExpression(this, ctx);
|
|
var prop = ast.index.visitExpression(this, ctx);
|
|
return receiver[prop];
|
|
};
|
|
StatementInterpreter.prototype.visitLiteralArrayExpr = function (ast, ctx) {
|
|
return this.visitAllExpressions(ast.entries, ctx);
|
|
};
|
|
StatementInterpreter.prototype.visitLiteralMapExpr = function (ast, ctx) {
|
|
var _this = this;
|
|
var result = {};
|
|
ast.entries.forEach(function (entry) { return result[entry.key] = entry.value.visitExpression(_this, ctx); });
|
|
return result;
|
|
};
|
|
StatementInterpreter.prototype.visitCommaExpr = function (ast, context) {
|
|
var values = this.visitAllExpressions(ast.parts, context);
|
|
return values[values.length - 1];
|
|
};
|
|
StatementInterpreter.prototype.visitAllExpressions = function (expressions, ctx) {
|
|
var _this = this;
|
|
return expressions.map(function (expr) { return expr.visitExpression(_this, ctx); });
|
|
};
|
|
StatementInterpreter.prototype.visitAllStatements = function (statements, ctx) {
|
|
for (var i = 0; i < statements.length; i++) {
|
|
var stmt = statements[i];
|
|
var val = stmt.visitStatement(this, ctx);
|
|
if (val instanceof ReturnValue) {
|
|
return val;
|
|
}
|
|
}
|
|
return null;
|
|
};
|
|
return StatementInterpreter;
|
|
}());
|
|
function _declareFn(varNames, statements, ctx, visitor) {
|
|
return function () {
|
|
var args = [];
|
|
for (var _i = 0; _i < arguments.length; _i++) {
|
|
args[_i] = arguments[_i];
|
|
}
|
|
return _executeFunctionStatements(varNames, args, statements, ctx, visitor);
|
|
};
|
|
}
|
|
var CATCH_ERROR_VAR$2 = 'error';
|
|
var CATCH_STACK_VAR$2 = 'stack';
|
|
|
|
/**
|
|
* @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
|
|
*/
|
|
/**
|
|
* An internal module of the Angular compiler that begins with component types,
|
|
* extracts templates, and eventually produces a compiled version of the component
|
|
* ready for linking into an application.
|
|
*
|
|
* @security When compiling templates at runtime, you must ensure that the entire template comes
|
|
* from a trusted source. Attacker-controlled data introduced by a template could expose your
|
|
* application to XSS risks. For more detail, see the [Security Guide](https://g.co/ng/security).
|
|
*/
|
|
var JitCompiler = /** @class */ (function () {
|
|
function JitCompiler(_metadataResolver, _templateParser, _styleCompiler, _viewCompiler, _ngModuleCompiler, _summaryResolver, _reflector, _jitEvaluator, _compilerConfig, _console, getExtraNgModuleProviders) {
|
|
this._metadataResolver = _metadataResolver;
|
|
this._templateParser = _templateParser;
|
|
this._styleCompiler = _styleCompiler;
|
|
this._viewCompiler = _viewCompiler;
|
|
this._ngModuleCompiler = _ngModuleCompiler;
|
|
this._summaryResolver = _summaryResolver;
|
|
this._reflector = _reflector;
|
|
this._jitEvaluator = _jitEvaluator;
|
|
this._compilerConfig = _compilerConfig;
|
|
this._console = _console;
|
|
this.getExtraNgModuleProviders = getExtraNgModuleProviders;
|
|
this._compiledTemplateCache = new Map();
|
|
this._compiledHostTemplateCache = new Map();
|
|
this._compiledDirectiveWrapperCache = new Map();
|
|
this._compiledNgModuleCache = new Map();
|
|
this._sharedStylesheetCount = 0;
|
|
this._addedAotSummaries = new Set();
|
|
}
|
|
JitCompiler.prototype.compileModuleSync = function (moduleType) {
|
|
return SyncAsync.assertSync(this._compileModuleAndComponents(moduleType, true));
|
|
};
|
|
JitCompiler.prototype.compileModuleAsync = function (moduleType) {
|
|
return Promise.resolve(this._compileModuleAndComponents(moduleType, false));
|
|
};
|
|
JitCompiler.prototype.compileModuleAndAllComponentsSync = function (moduleType) {
|
|
return SyncAsync.assertSync(this._compileModuleAndAllComponents(moduleType, true));
|
|
};
|
|
JitCompiler.prototype.compileModuleAndAllComponentsAsync = function (moduleType) {
|
|
return Promise.resolve(this._compileModuleAndAllComponents(moduleType, false));
|
|
};
|
|
JitCompiler.prototype.getComponentFactory = function (component) {
|
|
var summary = this._metadataResolver.getDirectiveSummary(component);
|
|
return summary.componentFactory;
|
|
};
|
|
JitCompiler.prototype.loadAotSummaries = function (summaries) {
|
|
this.clearCache();
|
|
this._addAotSummaries(summaries);
|
|
};
|
|
JitCompiler.prototype._addAotSummaries = function (fn) {
|
|
if (this._addedAotSummaries.has(fn)) {
|
|
return;
|
|
}
|
|
this._addedAotSummaries.add(fn);
|
|
var summaries = fn();
|
|
for (var i = 0; i < summaries.length; i++) {
|
|
var entry = summaries[i];
|
|
if (typeof entry === 'function') {
|
|
this._addAotSummaries(entry);
|
|
}
|
|
else {
|
|
var summary = entry;
|
|
this._summaryResolver.addSummary({ symbol: summary.type.reference, metadata: null, type: summary });
|
|
}
|
|
}
|
|
};
|
|
JitCompiler.prototype.hasAotSummary = function (ref) {
|
|
return !!this._summaryResolver.resolveSummary(ref);
|
|
};
|
|
JitCompiler.prototype._filterJitIdentifiers = function (ids) {
|
|
var _this = this;
|
|
return ids.map(function (mod) { return mod.reference; }).filter(function (ref) { return !_this.hasAotSummary(ref); });
|
|
};
|
|
JitCompiler.prototype._compileModuleAndComponents = function (moduleType, isSync) {
|
|
var _this = this;
|
|
return SyncAsync.then(this._loadModules(moduleType, isSync), function () {
|
|
_this._compileComponents(moduleType, null);
|
|
return _this._compileModule(moduleType);
|
|
});
|
|
};
|
|
JitCompiler.prototype._compileModuleAndAllComponents = function (moduleType, isSync) {
|
|
var _this = this;
|
|
return SyncAsync.then(this._loadModules(moduleType, isSync), function () {
|
|
var componentFactories = [];
|
|
_this._compileComponents(moduleType, componentFactories);
|
|
return {
|
|
ngModuleFactory: _this._compileModule(moduleType),
|
|
componentFactories: componentFactories
|
|
};
|
|
});
|
|
};
|
|
JitCompiler.prototype._loadModules = function (mainModule, isSync) {
|
|
var _this = this;
|
|
var loading = [];
|
|
var mainNgModule = this._metadataResolver.getNgModuleMetadata(mainModule);
|
|
// Note: for runtime compilation, we want to transitively compile all modules,
|
|
// so we also need to load the declared directives / pipes for all nested modules.
|
|
this._filterJitIdentifiers(mainNgModule.transitiveModule.modules).forEach(function (nestedNgModule) {
|
|
// getNgModuleMetadata only returns null if the value passed in is not an NgModule
|
|
var moduleMeta = _this._metadataResolver.getNgModuleMetadata(nestedNgModule);
|
|
_this._filterJitIdentifiers(moduleMeta.declaredDirectives).forEach(function (ref) {
|
|
var promise = _this._metadataResolver.loadDirectiveMetadata(moduleMeta.type.reference, ref, isSync);
|
|
if (promise) {
|
|
loading.push(promise);
|
|
}
|
|
});
|
|
_this._filterJitIdentifiers(moduleMeta.declaredPipes)
|
|
.forEach(function (ref) { return _this._metadataResolver.getOrLoadPipeMetadata(ref); });
|
|
});
|
|
return SyncAsync.all(loading);
|
|
};
|
|
JitCompiler.prototype._compileModule = function (moduleType) {
|
|
var ngModuleFactory = this._compiledNgModuleCache.get(moduleType);
|
|
if (!ngModuleFactory) {
|
|
var moduleMeta = this._metadataResolver.getNgModuleMetadata(moduleType);
|
|
// Always provide a bound Compiler
|
|
var extraProviders = this.getExtraNgModuleProviders(moduleMeta.type.reference);
|
|
var outputCtx = createOutputContext();
|
|
var compileResult = this._ngModuleCompiler.compile(outputCtx, moduleMeta, extraProviders);
|
|
ngModuleFactory = this._interpretOrJit(ngModuleJitUrl(moduleMeta), outputCtx.statements)[compileResult.ngModuleFactoryVar];
|
|
this._compiledNgModuleCache.set(moduleMeta.type.reference, ngModuleFactory);
|
|
}
|
|
return ngModuleFactory;
|
|
};
|
|
/**
|
|
* @internal
|
|
*/
|
|
JitCompiler.prototype._compileComponents = function (mainModule, allComponentFactories) {
|
|
var _this = this;
|
|
var ngModule = this._metadataResolver.getNgModuleMetadata(mainModule);
|
|
var moduleByJitDirective = new Map();
|
|
var templates = new Set();
|
|
var transJitModules = this._filterJitIdentifiers(ngModule.transitiveModule.modules);
|
|
transJitModules.forEach(function (localMod) {
|
|
var localModuleMeta = _this._metadataResolver.getNgModuleMetadata(localMod);
|
|
_this._filterJitIdentifiers(localModuleMeta.declaredDirectives).forEach(function (dirRef) {
|
|
moduleByJitDirective.set(dirRef, localModuleMeta);
|
|
var dirMeta = _this._metadataResolver.getDirectiveMetadata(dirRef);
|
|
if (dirMeta.isComponent) {
|
|
templates.add(_this._createCompiledTemplate(dirMeta, localModuleMeta));
|
|
if (allComponentFactories) {
|
|
var template = _this._createCompiledHostTemplate(dirMeta.type.reference, localModuleMeta);
|
|
templates.add(template);
|
|
allComponentFactories.push(dirMeta.componentFactory);
|
|
}
|
|
}
|
|
});
|
|
});
|
|
transJitModules.forEach(function (localMod) {
|
|
var localModuleMeta = _this._metadataResolver.getNgModuleMetadata(localMod);
|
|
_this._filterJitIdentifiers(localModuleMeta.declaredDirectives).forEach(function (dirRef) {
|
|
var dirMeta = _this._metadataResolver.getDirectiveMetadata(dirRef);
|
|
if (dirMeta.isComponent) {
|
|
dirMeta.entryComponents.forEach(function (entryComponentType) {
|
|
var moduleMeta = moduleByJitDirective.get(entryComponentType.componentType);
|
|
templates.add(_this._createCompiledHostTemplate(entryComponentType.componentType, moduleMeta));
|
|
});
|
|
}
|
|
});
|
|
localModuleMeta.entryComponents.forEach(function (entryComponentType) {
|
|
if (!_this.hasAotSummary(entryComponentType.componentType)) {
|
|
var moduleMeta = moduleByJitDirective.get(entryComponentType.componentType);
|
|
templates.add(_this._createCompiledHostTemplate(entryComponentType.componentType, moduleMeta));
|
|
}
|
|
});
|
|
});
|
|
templates.forEach(function (template) { return _this._compileTemplate(template); });
|
|
};
|
|
JitCompiler.prototype.clearCacheFor = function (type) {
|
|
this._compiledNgModuleCache.delete(type);
|
|
this._metadataResolver.clearCacheFor(type);
|
|
this._compiledHostTemplateCache.delete(type);
|
|
var compiledTemplate = this._compiledTemplateCache.get(type);
|
|
if (compiledTemplate) {
|
|
this._compiledTemplateCache.delete(type);
|
|
}
|
|
};
|
|
JitCompiler.prototype.clearCache = function () {
|
|
// Note: don't clear the _addedAotSummaries, as they don't change!
|
|
this._metadataResolver.clearCache();
|
|
this._compiledTemplateCache.clear();
|
|
this._compiledHostTemplateCache.clear();
|
|
this._compiledNgModuleCache.clear();
|
|
};
|
|
JitCompiler.prototype._createCompiledHostTemplate = function (compType, ngModule) {
|
|
if (!ngModule) {
|
|
throw new Error("Component " + stringify(compType) + " is not part of any NgModule or the module has not been imported into your module.");
|
|
}
|
|
var compiledTemplate = this._compiledHostTemplateCache.get(compType);
|
|
if (!compiledTemplate) {
|
|
var compMeta = this._metadataResolver.getDirectiveMetadata(compType);
|
|
assertComponent(compMeta);
|
|
var hostMeta = this._metadataResolver.getHostComponentMetadata(compMeta, compMeta.componentFactory.viewDefFactory);
|
|
compiledTemplate =
|
|
new CompiledTemplate(true, compMeta.type, hostMeta, ngModule, [compMeta.type]);
|
|
this._compiledHostTemplateCache.set(compType, compiledTemplate);
|
|
}
|
|
return compiledTemplate;
|
|
};
|
|
JitCompiler.prototype._createCompiledTemplate = function (compMeta, ngModule) {
|
|
var compiledTemplate = this._compiledTemplateCache.get(compMeta.type.reference);
|
|
if (!compiledTemplate) {
|
|
assertComponent(compMeta);
|
|
compiledTemplate = new CompiledTemplate(false, compMeta.type, compMeta, ngModule, ngModule.transitiveModule.directives);
|
|
this._compiledTemplateCache.set(compMeta.type.reference, compiledTemplate);
|
|
}
|
|
return compiledTemplate;
|
|
};
|
|
JitCompiler.prototype._compileTemplate = function (template) {
|
|
var _this = this;
|
|
if (template.isCompiled) {
|
|
return;
|
|
}
|
|
var compMeta = template.compMeta;
|
|
var externalStylesheetsByModuleUrl = new Map();
|
|
var outputContext = createOutputContext();
|
|
var componentStylesheet = this._styleCompiler.compileComponent(outputContext, compMeta);
|
|
compMeta.template.externalStylesheets.forEach(function (stylesheetMeta) {
|
|
var compiledStylesheet = _this._styleCompiler.compileStyles(createOutputContext(), compMeta, stylesheetMeta);
|
|
externalStylesheetsByModuleUrl.set(stylesheetMeta.moduleUrl, compiledStylesheet);
|
|
});
|
|
this._resolveStylesCompileResult(componentStylesheet, externalStylesheetsByModuleUrl);
|
|
var pipes = template.ngModule.transitiveModule.pipes.map(function (pipe) { return _this._metadataResolver.getPipeSummary(pipe.reference); });
|
|
var _a = this._parseTemplate(compMeta, template.ngModule, template.directives), parsedTemplate = _a.template, usedPipes = _a.pipes;
|
|
var compileResult = this._viewCompiler.compileComponent(outputContext, compMeta, parsedTemplate, variable(componentStylesheet.stylesVar), usedPipes);
|
|
var evalResult = this._interpretOrJit(templateJitUrl(template.ngModule.type, template.compMeta), outputContext.statements);
|
|
var viewClass = evalResult[compileResult.viewClassVar];
|
|
var rendererType = evalResult[compileResult.rendererTypeVar];
|
|
template.compiled(viewClass, rendererType);
|
|
};
|
|
JitCompiler.prototype._parseTemplate = function (compMeta, ngModule, directiveIdentifiers) {
|
|
var _this = this;
|
|
// Note: ! is ok here as components always have a template.
|
|
var preserveWhitespaces = compMeta.template.preserveWhitespaces;
|
|
var directives = directiveIdentifiers.map(function (dir) { return _this._metadataResolver.getDirectiveSummary(dir.reference); });
|
|
var pipes = ngModule.transitiveModule.pipes.map(function (pipe) { return _this._metadataResolver.getPipeSummary(pipe.reference); });
|
|
return this._templateParser.parse(compMeta, compMeta.template.htmlAst, directives, pipes, ngModule.schemas, templateSourceUrl(ngModule.type, compMeta, compMeta.template), preserveWhitespaces);
|
|
};
|
|
JitCompiler.prototype._resolveStylesCompileResult = function (result, externalStylesheetsByModuleUrl) {
|
|
var _this = this;
|
|
result.dependencies.forEach(function (dep, i) {
|
|
var nestedCompileResult = externalStylesheetsByModuleUrl.get(dep.moduleUrl);
|
|
var nestedStylesArr = _this._resolveAndEvalStylesCompileResult(nestedCompileResult, externalStylesheetsByModuleUrl);
|
|
dep.setValue(nestedStylesArr);
|
|
});
|
|
};
|
|
JitCompiler.prototype._resolveAndEvalStylesCompileResult = function (result, externalStylesheetsByModuleUrl) {
|
|
this._resolveStylesCompileResult(result, externalStylesheetsByModuleUrl);
|
|
return this._interpretOrJit(sharedStylesheetJitUrl(result.meta, this._sharedStylesheetCount++), result.outputCtx.statements)[result.stylesVar];
|
|
};
|
|
JitCompiler.prototype._interpretOrJit = function (sourceUrl, statements) {
|
|
if (!this._compilerConfig.useJit) {
|
|
return interpretStatements(statements, this._reflector);
|
|
}
|
|
else {
|
|
return this._jitEvaluator.evaluateStatements(sourceUrl, statements, this._reflector, this._compilerConfig.jitDevMode);
|
|
}
|
|
};
|
|
return JitCompiler;
|
|
}());
|
|
var CompiledTemplate = /** @class */ (function () {
|
|
function CompiledTemplate(isHost, compType, compMeta, ngModule, directives) {
|
|
this.isHost = isHost;
|
|
this.compType = compType;
|
|
this.compMeta = compMeta;
|
|
this.ngModule = ngModule;
|
|
this.directives = directives;
|
|
this._viewClass = null;
|
|
this.isCompiled = false;
|
|
}
|
|
CompiledTemplate.prototype.compiled = function (viewClass, rendererType) {
|
|
this._viewClass = viewClass;
|
|
this.compMeta.componentViewType.setDelegate(viewClass);
|
|
for (var prop in rendererType) {
|
|
this.compMeta.rendererType[prop] = rendererType[prop];
|
|
}
|
|
this.isCompiled = true;
|
|
};
|
|
return CompiledTemplate;
|
|
}());
|
|
function assertComponent(meta) {
|
|
if (!meta.isComponent) {
|
|
throw new Error("Could not compile '" + identifierName(meta.type) + "' because it is not a component.");
|
|
}
|
|
}
|
|
function createOutputContext() {
|
|
var importExpr$1 = function (symbol) { return importExpr({ name: identifierName(symbol), moduleName: null, runtime: symbol }); };
|
|
return { statements: [], genFilePath: '', importExpr: importExpr$1, constantPool: new ConstantPool() };
|
|
}
|
|
|
|
/**
|
|
* @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
|
|
*/
|
|
/**
|
|
* Provides access to reflection data about symbols that the compiler needs.
|
|
*/
|
|
var CompileReflector = /** @class */ (function () {
|
|
function CompileReflector() {
|
|
}
|
|
return CompileReflector;
|
|
}());
|
|
|
|
/**
|
|
* @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
|
|
*/
|
|
/**
|
|
* Create a {@link UrlResolver} with no package prefix.
|
|
*/
|
|
function createUrlResolverWithoutPackagePrefix() {
|
|
return new UrlResolver();
|
|
}
|
|
function createOfflineCompileUrlResolver() {
|
|
return new UrlResolver('.');
|
|
}
|
|
var UrlResolver = /** @class */ (function () {
|
|
function UrlResolverImpl(_packagePrefix) {
|
|
if (_packagePrefix === void 0) { _packagePrefix = null; }
|
|
this._packagePrefix = _packagePrefix;
|
|
}
|
|
/**
|
|
* Resolves the `url` given the `baseUrl`:
|
|
* - when the `url` is null, the `baseUrl` is returned,
|
|
* - if `url` is relative ('path/to/here', './path/to/here'), the resolved url is a combination of
|
|
* `baseUrl` and `url`,
|
|
* - if `url` is absolute (it has a scheme: 'http://', 'https://' or start with '/'), the `url` is
|
|
* returned as is (ignoring the `baseUrl`)
|
|
*/
|
|
UrlResolverImpl.prototype.resolve = function (baseUrl, url) {
|
|
var resolvedUrl = url;
|
|
if (baseUrl != null && baseUrl.length > 0) {
|
|
resolvedUrl = _resolveUrl(baseUrl, resolvedUrl);
|
|
}
|
|
var resolvedParts = _split(resolvedUrl);
|
|
var prefix = this._packagePrefix;
|
|
if (prefix != null && resolvedParts != null &&
|
|
resolvedParts[_ComponentIndex.Scheme] == 'package') {
|
|
var path = resolvedParts[_ComponentIndex.Path];
|
|
prefix = prefix.replace(/\/+$/, '');
|
|
path = path.replace(/^\/+/, '');
|
|
return prefix + "/" + path;
|
|
}
|
|
return resolvedUrl;
|
|
};
|
|
return UrlResolverImpl;
|
|
}());
|
|
/**
|
|
* Extract the scheme of a URL.
|
|
*/
|
|
function getUrlScheme(url) {
|
|
var match = _split(url);
|
|
return (match && match[_ComponentIndex.Scheme]) || '';
|
|
}
|
|
// The code below is adapted from Traceur:
|
|
// https://github.com/google/traceur-compiler/blob/9511c1dafa972bf0de1202a8a863bad02f0f95a8/src/runtime/url.js
|
|
/**
|
|
* Builds a URI string from already-encoded parts.
|
|
*
|
|
* No encoding is performed. Any component may be omitted as either null or
|
|
* undefined.
|
|
*
|
|
* @param opt_scheme The scheme such as 'http'.
|
|
* @param opt_userInfo The user name before the '@'.
|
|
* @param opt_domain The domain such as 'www.google.com', already
|
|
* URI-encoded.
|
|
* @param opt_port The port number.
|
|
* @param opt_path The path, already URI-encoded. If it is not
|
|
* empty, it must begin with a slash.
|
|
* @param opt_queryData The URI-encoded query data.
|
|
* @param opt_fragment The URI-encoded fragment identifier.
|
|
* @return The fully combined URI.
|
|
*/
|
|
function _buildFromEncodedParts(opt_scheme, opt_userInfo, opt_domain, opt_port, opt_path, opt_queryData, opt_fragment) {
|
|
var out = [];
|
|
if (opt_scheme != null) {
|
|
out.push(opt_scheme + ':');
|
|
}
|
|
if (opt_domain != null) {
|
|
out.push('//');
|
|
if (opt_userInfo != null) {
|
|
out.push(opt_userInfo + '@');
|
|
}
|
|
out.push(opt_domain);
|
|
if (opt_port != null) {
|
|
out.push(':' + opt_port);
|
|
}
|
|
}
|
|
if (opt_path != null) {
|
|
out.push(opt_path);
|
|
}
|
|
if (opt_queryData != null) {
|
|
out.push('?' + opt_queryData);
|
|
}
|
|
if (opt_fragment != null) {
|
|
out.push('#' + opt_fragment);
|
|
}
|
|
return out.join('');
|
|
}
|
|
/**
|
|
* A regular expression for breaking a URI into its component parts.
|
|
*
|
|
* {@link https://tools.ietf.org/html/rfc3986#appendix-B} says
|
|
* As the "first-match-wins" algorithm is identical to the "greedy"
|
|
* disambiguation method used by POSIX regular expressions, it is natural and
|
|
* commonplace to use a regular expression for parsing the potential five
|
|
* components of a URI reference.
|
|
*
|
|
* The following line is the regular expression for breaking-down a
|
|
* well-formed URI reference into its components.
|
|
*
|
|
* <pre>
|
|
* ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?
|
|
* 12 3 4 5 6 7 8 9
|
|
* </pre>
|
|
*
|
|
* The numbers in the second line above are only to assist readability; they
|
|
* indicate the reference points for each subexpression (i.e., each paired
|
|
* parenthesis). We refer to the value matched for subexpression <n> as $<n>.
|
|
* For example, matching the above expression to
|
|
* <pre>
|
|
* http://www.ics.uci.edu/pub/ietf/uri/#Related
|
|
* </pre>
|
|
* results in the following subexpression matches:
|
|
* <pre>
|
|
* $1 = http:
|
|
* $2 = http
|
|
* $3 = //www.ics.uci.edu
|
|
* $4 = www.ics.uci.edu
|
|
* $5 = /pub/ietf/uri/
|
|
* $6 = <undefined>
|
|
* $7 = <undefined>
|
|
* $8 = #Related
|
|
* $9 = Related
|
|
* </pre>
|
|
* where <undefined> indicates that the component is not present, as is the
|
|
* case for the query component in the above example. Therefore, we can
|
|
* determine the value of the five components as
|
|
* <pre>
|
|
* scheme = $2
|
|
* authority = $4
|
|
* path = $5
|
|
* query = $7
|
|
* fragment = $9
|
|
* </pre>
|
|
*
|
|
* The regular expression has been modified slightly to expose the
|
|
* userInfo, domain, and port separately from the authority.
|
|
* The modified version yields
|
|
* <pre>
|
|
* $1 = http scheme
|
|
* $2 = <undefined> userInfo -\
|
|
* $3 = www.ics.uci.edu domain | authority
|
|
* $4 = <undefined> port -/
|
|
* $5 = /pub/ietf/uri/ path
|
|
* $6 = <undefined> query without ?
|
|
* $7 = Related fragment without #
|
|
* </pre>
|
|
* @internal
|
|
*/
|
|
var _splitRe = new RegExp('^' +
|
|
'(?:' +
|
|
'([^:/?#.]+)' + // scheme - ignore special characters
|
|
// used by other URL parts such as :,
|
|
// ?, /, #, and .
|
|
':)?' +
|
|
'(?://' +
|
|
'(?:([^/?#]*)@)?' + // userInfo
|
|
'([\\w\\d\\-\\u0100-\\uffff.%]*)' + // domain - restrict to letters,
|
|
// digits, dashes, dots, percent
|
|
// escapes, and unicode characters.
|
|
'(?::([0-9]+))?' + // port
|
|
')?' +
|
|
'([^?#]+)?' + // path
|
|
'(?:\\?([^#]*))?' + // query
|
|
'(?:#(.*))?' + // fragment
|
|
'$');
|
|
/**
|
|
* The index of each URI component in the return value of goog.uri.utils.split.
|
|
* @enum {number}
|
|
*/
|
|
var _ComponentIndex;
|
|
(function (_ComponentIndex) {
|
|
_ComponentIndex[_ComponentIndex["Scheme"] = 1] = "Scheme";
|
|
_ComponentIndex[_ComponentIndex["UserInfo"] = 2] = "UserInfo";
|
|
_ComponentIndex[_ComponentIndex["Domain"] = 3] = "Domain";
|
|
_ComponentIndex[_ComponentIndex["Port"] = 4] = "Port";
|
|
_ComponentIndex[_ComponentIndex["Path"] = 5] = "Path";
|
|
_ComponentIndex[_ComponentIndex["QueryData"] = 6] = "QueryData";
|
|
_ComponentIndex[_ComponentIndex["Fragment"] = 7] = "Fragment";
|
|
})(_ComponentIndex || (_ComponentIndex = {}));
|
|
/**
|
|
* Splits a URI into its component parts.
|
|
*
|
|
* Each component can be accessed via the component indices; for example:
|
|
* <pre>
|
|
* goog.uri.utils.split(someStr)[goog.uri.utils.CompontentIndex.QUERY_DATA];
|
|
* </pre>
|
|
*
|
|
* @param uri The URI string to examine.
|
|
* @return Each component still URI-encoded.
|
|
* Each component that is present will contain the encoded value, whereas
|
|
* components that are not present will be undefined or empty, depending
|
|
* on the browser's regular expression implementation. Never null, since
|
|
* arbitrary strings may still look like path names.
|
|
*/
|
|
function _split(uri) {
|
|
return uri.match(_splitRe);
|
|
}
|
|
/**
|
|
* Removes dot segments in given path component, as described in
|
|
* RFC 3986, section 5.2.4.
|
|
*
|
|
* @param path A non-empty path component.
|
|
* @return Path component with removed dot segments.
|
|
*/
|
|
function _removeDotSegments(path) {
|
|
if (path == '/')
|
|
return '/';
|
|
var leadingSlash = path[0] == '/' ? '/' : '';
|
|
var trailingSlash = path[path.length - 1] === '/' ? '/' : '';
|
|
var segments = path.split('/');
|
|
var out = [];
|
|
var up = 0;
|
|
for (var pos = 0; pos < segments.length; pos++) {
|
|
var segment = segments[pos];
|
|
switch (segment) {
|
|
case '':
|
|
case '.':
|
|
break;
|
|
case '..':
|
|
if (out.length > 0) {
|
|
out.pop();
|
|
}
|
|
else {
|
|
up++;
|
|
}
|
|
break;
|
|
default:
|
|
out.push(segment);
|
|
}
|
|
}
|
|
if (leadingSlash == '') {
|
|
while (up-- > 0) {
|
|
out.unshift('..');
|
|
}
|
|
if (out.length === 0)
|
|
out.push('.');
|
|
}
|
|
return leadingSlash + out.join('/') + trailingSlash;
|
|
}
|
|
/**
|
|
* Takes an array of the parts from split and canonicalizes the path part
|
|
* and then joins all the parts.
|
|
*/
|
|
function _joinAndCanonicalizePath(parts) {
|
|
var path = parts[_ComponentIndex.Path];
|
|
path = path == null ? '' : _removeDotSegments(path);
|
|
parts[_ComponentIndex.Path] = path;
|
|
return _buildFromEncodedParts(parts[_ComponentIndex.Scheme], parts[_ComponentIndex.UserInfo], parts[_ComponentIndex.Domain], parts[_ComponentIndex.Port], path, parts[_ComponentIndex.QueryData], parts[_ComponentIndex.Fragment]);
|
|
}
|
|
/**
|
|
* Resolves a URL.
|
|
* @param base The URL acting as the base URL.
|
|
* @param to The URL to resolve.
|
|
*/
|
|
function _resolveUrl(base, url) {
|
|
var parts = _split(encodeURI(url));
|
|
var baseParts = _split(base);
|
|
if (parts[_ComponentIndex.Scheme] != null) {
|
|
return _joinAndCanonicalizePath(parts);
|
|
}
|
|
else {
|
|
parts[_ComponentIndex.Scheme] = baseParts[_ComponentIndex.Scheme];
|
|
}
|
|
for (var i = _ComponentIndex.Scheme; i <= _ComponentIndex.Port; i++) {
|
|
if (parts[i] == null) {
|
|
parts[i] = baseParts[i];
|
|
}
|
|
}
|
|
if (parts[_ComponentIndex.Path][0] == '/') {
|
|
return _joinAndCanonicalizePath(parts);
|
|
}
|
|
var path = baseParts[_ComponentIndex.Path];
|
|
if (path == null)
|
|
path = '/';
|
|
var index = path.lastIndexOf('/');
|
|
path = path.substring(0, index + 1) + parts[_ComponentIndex.Path];
|
|
parts[_ComponentIndex.Path] = path;
|
|
return _joinAndCanonicalizePath(parts);
|
|
}
|
|
|
|
var Extractor = /** @class */ (function () {
|
|
function Extractor(host, staticSymbolResolver, messageBundle, metadataResolver) {
|
|
this.host = host;
|
|
this.staticSymbolResolver = staticSymbolResolver;
|
|
this.messageBundle = messageBundle;
|
|
this.metadataResolver = metadataResolver;
|
|
}
|
|
Extractor.prototype.extract = function (rootFiles) {
|
|
var _this = this;
|
|
var _a = analyzeAndValidateNgModules(rootFiles, this.host, this.staticSymbolResolver, this.metadataResolver), files = _a.files, ngModules = _a.ngModules;
|
|
return Promise
|
|
.all(ngModules.map(function (ngModule) { return _this.metadataResolver.loadNgModuleDirectiveAndPipeMetadata(ngModule.type.reference, false); }))
|
|
.then(function () {
|
|
var errors = [];
|
|
files.forEach(function (file) {
|
|
var compMetas = [];
|
|
file.directives.forEach(function (directiveType) {
|
|
var dirMeta = _this.metadataResolver.getDirectiveMetadata(directiveType);
|
|
if (dirMeta && dirMeta.isComponent) {
|
|
compMetas.push(dirMeta);
|
|
}
|
|
});
|
|
compMetas.forEach(function (compMeta) {
|
|
var html = compMeta.template.template;
|
|
// Template URL points to either an HTML or TS file depending on
|
|
// whether the file is used with `templateUrl:` or `template:`,
|
|
// respectively.
|
|
var templateUrl = compMeta.template.templateUrl;
|
|
var interpolationConfig = InterpolationConfig.fromArray(compMeta.template.interpolation);
|
|
errors.push.apply(errors, __spreadArray([], __read(_this.messageBundle.updateFromTemplate(html, templateUrl, interpolationConfig))));
|
|
});
|
|
});
|
|
if (errors.length) {
|
|
throw new Error(errors.map(function (e) { return e.toString(); }).join('\n'));
|
|
}
|
|
return _this.messageBundle;
|
|
});
|
|
};
|
|
Extractor.create = function (host, locale) {
|
|
var htmlParser = new HtmlParser();
|
|
var urlResolver = createAotUrlResolver(host);
|
|
var symbolCache = new StaticSymbolCache();
|
|
var summaryResolver = new AotSummaryResolver(host, symbolCache);
|
|
var staticSymbolResolver = new StaticSymbolResolver(host, symbolCache, summaryResolver);
|
|
var staticReflector = new StaticReflector(summaryResolver, staticSymbolResolver);
|
|
var config = new CompilerConfig({ defaultEncapsulation: ViewEncapsulation.Emulated, useJit: false });
|
|
var normalizer = new DirectiveNormalizer({ get: function (url) { return host.loadResource(url); } }, urlResolver, htmlParser, config);
|
|
var elementSchemaRegistry = new DomElementSchemaRegistry();
|
|
var resolver = new CompileMetadataResolver(config, htmlParser, new NgModuleResolver(staticReflector), new DirectiveResolver(staticReflector), new PipeResolver(staticReflector), summaryResolver, elementSchemaRegistry, normalizer, console, symbolCache, staticReflector);
|
|
// TODO(vicb): implicit tags & attributes
|
|
var messageBundle = new MessageBundle(htmlParser, [], {}, locale);
|
|
var extractor = new Extractor(host, staticSymbolResolver, messageBundle, resolver);
|
|
return { extractor: extractor, staticReflector: staticReflector };
|
|
};
|
|
return Extractor;
|
|
}());
|
|
|
|
/**
|
|
* @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 FactoryTarget;
|
|
(function (FactoryTarget) {
|
|
FactoryTarget[FactoryTarget["Directive"] = 0] = "Directive";
|
|
FactoryTarget[FactoryTarget["Component"] = 1] = "Component";
|
|
FactoryTarget[FactoryTarget["Injectable"] = 2] = "Injectable";
|
|
FactoryTarget[FactoryTarget["Pipe"] = 3] = "Pipe";
|
|
FactoryTarget[FactoryTarget["NgModule"] = 4] = "NgModule";
|
|
})(FactoryTarget || (FactoryTarget = {}));
|
|
|
|
/**
|
|
* Processes `Target`s with a given set of directives and performs a binding operation, which
|
|
* returns an object similar to TypeScript's `ts.TypeChecker` that contains knowledge about the
|
|
* target.
|
|
*/
|
|
var R3TargetBinder = /** @class */ (function () {
|
|
function R3TargetBinder(directiveMatcher) {
|
|
this.directiveMatcher = directiveMatcher;
|
|
}
|
|
/**
|
|
* Perform a binding operation on the given `Target` and return a `BoundTarget` which contains
|
|
* metadata about the types referenced in the template.
|
|
*/
|
|
R3TargetBinder.prototype.bind = function (target) {
|
|
if (!target.template) {
|
|
// TODO(alxhub): handle targets which contain things like HostBindings, etc.
|
|
throw new Error('Binding without a template not yet supported');
|
|
}
|
|
// First, parse the template into a `Scope` structure. This operation captures the syntactic
|
|
// scopes in the template and makes them available for later use.
|
|
var scope = Scope.apply(target.template);
|
|
// Use the `Scope` to extract the entities present at every level of the template.
|
|
var templateEntities = extractTemplateEntities(scope);
|
|
// Next, perform directive matching on the template using the `DirectiveBinder`. This returns:
|
|
// - directives: Map of nodes (elements & ng-templates) to the directives on them.
|
|
// - bindings: Map of inputs, outputs, and attributes to the directive/element that claims
|
|
// them. TODO(alxhub): handle multiple directives claiming an input/output/etc.
|
|
// - references: Map of #references to their targets.
|
|
var _b = DirectiveBinder.apply(target.template, this.directiveMatcher), directives = _b.directives, bindings = _b.bindings, references = _b.references;
|
|
// Finally, run the TemplateBinder to bind references, variables, and other entities within the
|
|
// template. This extracts all the metadata that doesn't depend on directive matching.
|
|
var _c = TemplateBinder.applyWithScope(target.template, scope), expressions = _c.expressions, symbols = _c.symbols, nestingLevel = _c.nestingLevel, usedPipes = _c.usedPipes;
|
|
return new R3BoundTarget(target, directives, bindings, references, expressions, symbols, nestingLevel, templateEntities, usedPipes);
|
|
};
|
|
return R3TargetBinder;
|
|
}());
|
|
/**
|
|
* Represents a binding scope within a template.
|
|
*
|
|
* Any variables, references, or other named entities declared within the template will
|
|
* be captured and available by name in `namedEntities`. Additionally, child templates will
|
|
* be analyzed and have their child `Scope`s available in `childScopes`.
|
|
*/
|
|
var Scope = /** @class */ (function () {
|
|
function Scope(parentScope, template) {
|
|
this.parentScope = parentScope;
|
|
this.template = template;
|
|
/**
|
|
* Named members of the `Scope`, such as `Reference`s or `Variable`s.
|
|
*/
|
|
this.namedEntities = new Map();
|
|
/**
|
|
* Child `Scope`s for immediately nested `Template`s.
|
|
*/
|
|
this.childScopes = new Map();
|
|
}
|
|
Scope.newRootScope = function () {
|
|
return new Scope(null, null);
|
|
};
|
|
/**
|
|
* Process a template (either as a `Template` sub-template with variables, or a plain array of
|
|
* template `Node`s) and construct its `Scope`.
|
|
*/
|
|
Scope.apply = function (template) {
|
|
var scope = Scope.newRootScope();
|
|
scope.ingest(template);
|
|
return scope;
|
|
};
|
|
/**
|
|
* Internal method to process the template and populate the `Scope`.
|
|
*/
|
|
Scope.prototype.ingest = function (template) {
|
|
var _this = this;
|
|
if (template instanceof Template) {
|
|
// Variables on an <ng-template> are defined in the inner scope.
|
|
template.variables.forEach(function (node) { return _this.visitVariable(node); });
|
|
// Process the nodes of the template.
|
|
template.children.forEach(function (node) { return node.visit(_this); });
|
|
}
|
|
else {
|
|
// No overarching `Template` instance, so process the nodes directly.
|
|
template.forEach(function (node) { return node.visit(_this); });
|
|
}
|
|
};
|
|
Scope.prototype.visitElement = function (element) {
|
|
var _this = this;
|
|
// `Element`s in the template may have `Reference`s which are captured in the scope.
|
|
element.references.forEach(function (node) { return _this.visitReference(node); });
|
|
// Recurse into the `Element`'s children.
|
|
element.children.forEach(function (node) { return node.visit(_this); });
|
|
};
|
|
Scope.prototype.visitTemplate = function (template) {
|
|
var _this = this;
|
|
// References on a <ng-template> are defined in the outer scope, so capture them before
|
|
// processing the template's child scope.
|
|
template.references.forEach(function (node) { return _this.visitReference(node); });
|
|
// Next, create an inner scope and process the template within it.
|
|
var scope = new Scope(this, template);
|
|
scope.ingest(template);
|
|
this.childScopes.set(template, scope);
|
|
};
|
|
Scope.prototype.visitVariable = function (variable) {
|
|
// Declare the variable if it's not already.
|
|
this.maybeDeclare(variable);
|
|
};
|
|
Scope.prototype.visitReference = function (reference) {
|
|
// Declare the variable if it's not already.
|
|
this.maybeDeclare(reference);
|
|
};
|
|
// Unused visitors.
|
|
Scope.prototype.visitContent = function (content) { };
|
|
Scope.prototype.visitBoundAttribute = function (attr) { };
|
|
Scope.prototype.visitBoundEvent = function (event) { };
|
|
Scope.prototype.visitBoundText = function (text) { };
|
|
Scope.prototype.visitText = function (text) { };
|
|
Scope.prototype.visitTextAttribute = function (attr) { };
|
|
Scope.prototype.visitIcu = function (icu) { };
|
|
Scope.prototype.maybeDeclare = function (thing) {
|
|
// Declare something with a name, as long as that name isn't taken.
|
|
if (!this.namedEntities.has(thing.name)) {
|
|
this.namedEntities.set(thing.name, thing);
|
|
}
|
|
};
|
|
/**
|
|
* Look up a variable within this `Scope`.
|
|
*
|
|
* This can recurse into a parent `Scope` if it's available.
|
|
*/
|
|
Scope.prototype.lookup = function (name) {
|
|
if (this.namedEntities.has(name)) {
|
|
// Found in the local scope.
|
|
return this.namedEntities.get(name);
|
|
}
|
|
else if (this.parentScope !== null) {
|
|
// Not in the local scope, but there's a parent scope so check there.
|
|
return this.parentScope.lookup(name);
|
|
}
|
|
else {
|
|
// At the top level and it wasn't found.
|
|
return null;
|
|
}
|
|
};
|
|
/**
|
|
* Get the child scope for a `Template`.
|
|
*
|
|
* This should always be defined.
|
|
*/
|
|
Scope.prototype.getChildScope = function (template) {
|
|
var res = this.childScopes.get(template);
|
|
if (res === undefined) {
|
|
throw new Error("Assertion error: child scope for " + template + " not found");
|
|
}
|
|
return res;
|
|
};
|
|
return Scope;
|
|
}());
|
|
/**
|
|
* Processes a template and matches directives on nodes (elements and templates).
|
|
*
|
|
* Usually used via the static `apply()` method.
|
|
*/
|
|
var DirectiveBinder = /** @class */ (function () {
|
|
function DirectiveBinder(matcher, directives, bindings, references) {
|
|
this.matcher = matcher;
|
|
this.directives = directives;
|
|
this.bindings = bindings;
|
|
this.references = references;
|
|
}
|
|
/**
|
|
* Process a template (list of `Node`s) and perform directive matching against each node.
|
|
*
|
|
* @param template the list of template `Node`s to match (recursively).
|
|
* @param selectorMatcher a `SelectorMatcher` containing the directives that are in scope for
|
|
* this template.
|
|
* @returns three maps which contain information about directives in the template: the
|
|
* `directives` map which lists directives matched on each node, the `bindings` map which
|
|
* indicates which directives claimed which bindings (inputs, outputs, etc), and the `references`
|
|
* map which resolves #references (`Reference`s) within the template to the named directive or
|
|
* template node.
|
|
*/
|
|
DirectiveBinder.apply = function (template, selectorMatcher) {
|
|
var directives = new Map();
|
|
var bindings = new Map();
|
|
var references = new Map();
|
|
var matcher = new DirectiveBinder(selectorMatcher, directives, bindings, references);
|
|
matcher.ingest(template);
|
|
return { directives: directives, bindings: bindings, references: references };
|
|
};
|
|
DirectiveBinder.prototype.ingest = function (template) {
|
|
var _this = this;
|
|
template.forEach(function (node) { return node.visit(_this); });
|
|
};
|
|
DirectiveBinder.prototype.visitElement = function (element) {
|
|
this.visitElementOrTemplate(element.name, element);
|
|
};
|
|
DirectiveBinder.prototype.visitTemplate = function (template) {
|
|
this.visitElementOrTemplate('ng-template', template);
|
|
};
|
|
DirectiveBinder.prototype.visitElementOrTemplate = function (elementName, node) {
|
|
var _this = this;
|
|
// First, determine the HTML shape of the node for the purpose of directive matching.
|
|
// Do this by building up a `CssSelector` for the node.
|
|
var cssSelector = createCssSelector(elementName, getAttrsForDirectiveMatching(node));
|
|
// Next, use the `SelectorMatcher` to get the list of directives on the node.
|
|
var directives = [];
|
|
this.matcher.match(cssSelector, function (_, directive) { return directives.push(directive); });
|
|
if (directives.length > 0) {
|
|
this.directives.set(node, directives);
|
|
}
|
|
// Resolve any references that are created on this node.
|
|
node.references.forEach(function (ref) {
|
|
var dirTarget = null;
|
|
// If the reference expression is empty, then it matches the "primary" directive on the node
|
|
// (if there is one). Otherwise it matches the host node itself (either an element or
|
|
// <ng-template> node).
|
|
if (ref.value.trim() === '') {
|
|
// This could be a reference to a component if there is one.
|
|
dirTarget = directives.find(function (dir) { return dir.isComponent; }) || null;
|
|
}
|
|
else {
|
|
// This should be a reference to a directive exported via exportAs.
|
|
dirTarget =
|
|
directives.find(function (dir) { return dir.exportAs !== null && dir.exportAs.some(function (value) { return value === ref.value; }); }) ||
|
|
null;
|
|
// Check if a matching directive was found.
|
|
if (dirTarget === null) {
|
|
// No matching directive was found - this reference points to an unknown target. Leave it
|
|
// unmapped.
|
|
return;
|
|
}
|
|
}
|
|
if (dirTarget !== null) {
|
|
// This reference points to a directive.
|
|
_this.references.set(ref, { directive: dirTarget, node: node });
|
|
}
|
|
else {
|
|
// This reference points to the node itself.
|
|
_this.references.set(ref, node);
|
|
}
|
|
});
|
|
var setAttributeBinding = function (attribute, ioType) {
|
|
var dir = directives.find(function (dir) { return dir[ioType].hasBindingPropertyName(attribute.name); });
|
|
var binding = dir !== undefined ? dir : node;
|
|
_this.bindings.set(attribute, binding);
|
|
};
|
|
// Node inputs (bound attributes) and text attributes can be bound to an
|
|
// input on a directive.
|
|
node.inputs.forEach(function (input) { return setAttributeBinding(input, 'inputs'); });
|
|
node.attributes.forEach(function (attr) { return setAttributeBinding(attr, 'inputs'); });
|
|
if (node instanceof Template) {
|
|
node.templateAttrs.forEach(function (attr) { return setAttributeBinding(attr, 'inputs'); });
|
|
}
|
|
// Node outputs (bound events) can be bound to an output on a directive.
|
|
node.outputs.forEach(function (output) { return setAttributeBinding(output, 'outputs'); });
|
|
// Recurse into the node's children.
|
|
node.children.forEach(function (child) { return child.visit(_this); });
|
|
};
|
|
// Unused visitors.
|
|
DirectiveBinder.prototype.visitContent = function (content) { };
|
|
DirectiveBinder.prototype.visitVariable = function (variable) { };
|
|
DirectiveBinder.prototype.visitReference = function (reference) { };
|
|
DirectiveBinder.prototype.visitTextAttribute = function (attribute) { };
|
|
DirectiveBinder.prototype.visitBoundAttribute = function (attribute) { };
|
|
DirectiveBinder.prototype.visitBoundEvent = function (attribute) { };
|
|
DirectiveBinder.prototype.visitBoundAttributeOrEvent = function (node) { };
|
|
DirectiveBinder.prototype.visitText = function (text) { };
|
|
DirectiveBinder.prototype.visitBoundText = function (text) { };
|
|
DirectiveBinder.prototype.visitIcu = function (icu) { };
|
|
return DirectiveBinder;
|
|
}());
|
|
/**
|
|
* Processes a template and extract metadata about expressions and symbols within.
|
|
*
|
|
* This is a companion to the `DirectiveBinder` that doesn't require knowledge of directives matched
|
|
* within the template in order to operate.
|
|
*
|
|
* Expressions are visited by the superclass `RecursiveAstVisitor`, with custom logic provided
|
|
* by overridden methods from that visitor.
|
|
*/
|
|
var TemplateBinder = /** @class */ (function (_super) {
|
|
__extends(TemplateBinder, _super);
|
|
function TemplateBinder(bindings, symbols, usedPipes, nestingLevel, scope, template, level) {
|
|
var _this = _super.call(this) || this;
|
|
_this.bindings = bindings;
|
|
_this.symbols = symbols;
|
|
_this.usedPipes = usedPipes;
|
|
_this.nestingLevel = nestingLevel;
|
|
_this.scope = scope;
|
|
_this.template = template;
|
|
_this.level = level;
|
|
_this.pipesUsed = [];
|
|
// Save a bit of processing time by constructing this closure in advance.
|
|
_this.visitNode = function (node) { return node.visit(_this); };
|
|
return _this;
|
|
}
|
|
// This method is defined to reconcile the type of TemplateBinder since both
|
|
// RecursiveAstVisitor and Visitor define the visit() method in their
|
|
// interfaces.
|
|
TemplateBinder.prototype.visit = function (node, context) {
|
|
if (node instanceof AST) {
|
|
node.visit(this, context);
|
|
}
|
|
else {
|
|
node.visit(this);
|
|
}
|
|
};
|
|
/**
|
|
* Process a template and extract metadata about expressions and symbols within.
|
|
*
|
|
* @param template the nodes of the template to process
|
|
* @param scope the `Scope` of the template being processed.
|
|
* @returns three maps which contain metadata about the template: `expressions` which interprets
|
|
* special `AST` nodes in expressions as pointing to references or variables declared within the
|
|
* template, `symbols` which maps those variables and references to the nested `Template` which
|
|
* declares them, if any, and `nestingLevel` which associates each `Template` with a integer
|
|
* nesting level (how many levels deep within the template structure the `Template` is), starting
|
|
* at 1.
|
|
*/
|
|
TemplateBinder.applyWithScope = function (template, scope) {
|
|
var expressions = new Map();
|
|
var symbols = new Map();
|
|
var nestingLevel = new Map();
|
|
var usedPipes = new Set();
|
|
// The top-level template has nesting level 0.
|
|
var binder = new TemplateBinder(expressions, symbols, usedPipes, nestingLevel, scope, template instanceof Template ? template : null, 0);
|
|
binder.ingest(template);
|
|
return { expressions: expressions, symbols: symbols, nestingLevel: nestingLevel, usedPipes: usedPipes };
|
|
};
|
|
TemplateBinder.prototype.ingest = function (template) {
|
|
if (template instanceof Template) {
|
|
// For <ng-template>s, process only variables and child nodes. Inputs, outputs, templateAttrs,
|
|
// and references were all processed in the scope of the containing template.
|
|
template.variables.forEach(this.visitNode);
|
|
template.children.forEach(this.visitNode);
|
|
// Set the nesting level.
|
|
this.nestingLevel.set(template, this.level);
|
|
}
|
|
else {
|
|
// Visit each node from the top-level template.
|
|
template.forEach(this.visitNode);
|
|
}
|
|
};
|
|
TemplateBinder.prototype.visitElement = function (element) {
|
|
// Visit the inputs, outputs, and children of the element.
|
|
element.inputs.forEach(this.visitNode);
|
|
element.outputs.forEach(this.visitNode);
|
|
element.children.forEach(this.visitNode);
|
|
};
|
|
TemplateBinder.prototype.visitTemplate = function (template) {
|
|
// First, visit inputs, outputs and template attributes of the template node.
|
|
template.inputs.forEach(this.visitNode);
|
|
template.outputs.forEach(this.visitNode);
|
|
template.templateAttrs.forEach(this.visitNode);
|
|
// References are also evaluated in the outer context.
|
|
template.references.forEach(this.visitNode);
|
|
// Next, recurse into the template using its scope, and bumping the nesting level up by one.
|
|
var childScope = this.scope.getChildScope(template);
|
|
var binder = new TemplateBinder(this.bindings, this.symbols, this.usedPipes, this.nestingLevel, childScope, template, this.level + 1);
|
|
binder.ingest(template);
|
|
};
|
|
TemplateBinder.prototype.visitVariable = function (variable) {
|
|
// Register the `Variable` as a symbol in the current `Template`.
|
|
if (this.template !== null) {
|
|
this.symbols.set(variable, this.template);
|
|
}
|
|
};
|
|
TemplateBinder.prototype.visitReference = function (reference) {
|
|
// Register the `Reference` as a symbol in the current `Template`.
|
|
if (this.template !== null) {
|
|
this.symbols.set(reference, this.template);
|
|
}
|
|
};
|
|
// Unused template visitors
|
|
TemplateBinder.prototype.visitText = function (text) { };
|
|
TemplateBinder.prototype.visitContent = function (content) { };
|
|
TemplateBinder.prototype.visitTextAttribute = function (attribute) { };
|
|
TemplateBinder.prototype.visitIcu = function (icu) {
|
|
var _this = this;
|
|
Object.keys(icu.vars).forEach(function (key) { return icu.vars[key].visit(_this); });
|
|
Object.keys(icu.placeholders).forEach(function (key) { return icu.placeholders[key].visit(_this); });
|
|
};
|
|
// The remaining visitors are concerned with processing AST expressions within template bindings
|
|
TemplateBinder.prototype.visitBoundAttribute = function (attribute) {
|
|
attribute.value.visit(this);
|
|
};
|
|
TemplateBinder.prototype.visitBoundEvent = function (event) {
|
|
event.handler.visit(this);
|
|
};
|
|
TemplateBinder.prototype.visitBoundText = function (text) {
|
|
text.value.visit(this);
|
|
};
|
|
TemplateBinder.prototype.visitPipe = function (ast, context) {
|
|
this.usedPipes.add(ast.name);
|
|
return _super.prototype.visitPipe.call(this, ast, context);
|
|
};
|
|
// These five types of AST expressions can refer to expression roots, which could be variables
|
|
// or references in the current scope.
|
|
TemplateBinder.prototype.visitPropertyRead = function (ast, context) {
|
|
this.maybeMap(context, ast, ast.name);
|
|
return _super.prototype.visitPropertyRead.call(this, ast, context);
|
|
};
|
|
TemplateBinder.prototype.visitSafePropertyRead = function (ast, context) {
|
|
this.maybeMap(context, ast, ast.name);
|
|
return _super.prototype.visitSafePropertyRead.call(this, ast, context);
|
|
};
|
|
TemplateBinder.prototype.visitPropertyWrite = function (ast, context) {
|
|
this.maybeMap(context, ast, ast.name);
|
|
return _super.prototype.visitPropertyWrite.call(this, ast, context);
|
|
};
|
|
TemplateBinder.prototype.visitMethodCall = function (ast, context) {
|
|
this.maybeMap(context, ast, ast.name);
|
|
return _super.prototype.visitMethodCall.call(this, ast, context);
|
|
};
|
|
TemplateBinder.prototype.visitSafeMethodCall = function (ast, context) {
|
|
this.maybeMap(context, ast, ast.name);
|
|
return _super.prototype.visitSafeMethodCall.call(this, ast, context);
|
|
};
|
|
TemplateBinder.prototype.maybeMap = function (scope, ast, name) {
|
|
// If the receiver of the expression isn't the `ImplicitReceiver`, this isn't the root of an
|
|
// `AST` expression that maps to a `Variable` or `Reference`.
|
|
if (!(ast.receiver instanceof ImplicitReceiver)) {
|
|
return;
|
|
}
|
|
// Check whether the name exists in the current scope. If so, map it. Otherwise, the name is
|
|
// probably a property on the top-level component context.
|
|
var target = this.scope.lookup(name);
|
|
if (target !== null) {
|
|
this.bindings.set(ast, target);
|
|
}
|
|
};
|
|
return TemplateBinder;
|
|
}(RecursiveAstVisitor$1));
|
|
/**
|
|
* Metadata container for a `Target` that allows queries for specific bits of metadata.
|
|
*
|
|
* See `BoundTarget` for documentation on the individual methods.
|
|
*/
|
|
var R3BoundTarget = /** @class */ (function () {
|
|
function R3BoundTarget(target, directives, bindings, references, exprTargets, symbols, nestingLevel, templateEntities, usedPipes) {
|
|
this.target = target;
|
|
this.directives = directives;
|
|
this.bindings = bindings;
|
|
this.references = references;
|
|
this.exprTargets = exprTargets;
|
|
this.symbols = symbols;
|
|
this.nestingLevel = nestingLevel;
|
|
this.templateEntities = templateEntities;
|
|
this.usedPipes = usedPipes;
|
|
}
|
|
R3BoundTarget.prototype.getEntitiesInTemplateScope = function (template) {
|
|
var _a;
|
|
return (_a = this.templateEntities.get(template)) !== null && _a !== void 0 ? _a : new Set();
|
|
};
|
|
R3BoundTarget.prototype.getDirectivesOfNode = function (node) {
|
|
return this.directives.get(node) || null;
|
|
};
|
|
R3BoundTarget.prototype.getReferenceTarget = function (ref) {
|
|
return this.references.get(ref) || null;
|
|
};
|
|
R3BoundTarget.prototype.getConsumerOfBinding = function (binding) {
|
|
return this.bindings.get(binding) || null;
|
|
};
|
|
R3BoundTarget.prototype.getExpressionTarget = function (expr) {
|
|
return this.exprTargets.get(expr) || null;
|
|
};
|
|
R3BoundTarget.prototype.getTemplateOfSymbol = function (symbol) {
|
|
return this.symbols.get(symbol) || null;
|
|
};
|
|
R3BoundTarget.prototype.getNestingLevel = function (template) {
|
|
return this.nestingLevel.get(template) || 0;
|
|
};
|
|
R3BoundTarget.prototype.getUsedDirectives = function () {
|
|
var set = new Set();
|
|
this.directives.forEach(function (dirs) { return dirs.forEach(function (dir) { return set.add(dir); }); });
|
|
return Array.from(set.values());
|
|
};
|
|
R3BoundTarget.prototype.getUsedPipes = function () {
|
|
return Array.from(this.usedPipes);
|
|
};
|
|
return R3BoundTarget;
|
|
}());
|
|
function extractTemplateEntities(rootScope) {
|
|
var e_1, _b, e_2, _c;
|
|
var entityMap = new Map();
|
|
function extractScopeEntities(scope) {
|
|
if (entityMap.has(scope.template)) {
|
|
return entityMap.get(scope.template);
|
|
}
|
|
var currentEntities = scope.namedEntities;
|
|
var templateEntities;
|
|
if (scope.parentScope !== null) {
|
|
templateEntities = new Map(__spreadArray(__spreadArray([], __read(extractScopeEntities(scope.parentScope))), __read(currentEntities)));
|
|
}
|
|
else {
|
|
templateEntities = new Map(currentEntities);
|
|
}
|
|
entityMap.set(scope.template, templateEntities);
|
|
return templateEntities;
|
|
}
|
|
var scopesToProcess = [rootScope];
|
|
while (scopesToProcess.length > 0) {
|
|
var scope = scopesToProcess.pop();
|
|
try {
|
|
for (var _d = (e_1 = void 0, __values(scope.childScopes.values())), _e = _d.next(); !_e.done; _e = _d.next()) {
|
|
var childScope = _e.value;
|
|
scopesToProcess.push(childScope);
|
|
}
|
|
}
|
|
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
finally {
|
|
try {
|
|
if (_e && !_e.done && (_b = _d.return)) _b.call(_d);
|
|
}
|
|
finally { if (e_1) throw e_1.error; }
|
|
}
|
|
extractScopeEntities(scope);
|
|
}
|
|
var templateEntities = new Map();
|
|
try {
|
|
for (var entityMap_1 = __values(entityMap), entityMap_1_1 = entityMap_1.next(); !entityMap_1_1.done; entityMap_1_1 = entityMap_1.next()) {
|
|
var _f = __read(entityMap_1_1.value, 2), template = _f[0], entities = _f[1];
|
|
templateEntities.set(template, new Set(entities.values()));
|
|
}
|
|
}
|
|
catch (e_2_1) { e_2 = { error: e_2_1 }; }
|
|
finally {
|
|
try {
|
|
if (entityMap_1_1 && !entityMap_1_1.done && (_c = entityMap_1.return)) _c.call(entityMap_1);
|
|
}
|
|
finally { if (e_2) throw e_2.error; }
|
|
}
|
|
return templateEntities;
|
|
}
|
|
|
|
/**
|
|
* @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 compileClassMetadata(metadata) {
|
|
var _a, _b;
|
|
// Generate an ngDevMode guarded call to setClassMetadata with the class identifier and its
|
|
// metadata.
|
|
var fnCall = importExpr(Identifiers.setClassMetadata).callFn([
|
|
metadata.type,
|
|
metadata.decorators,
|
|
(_a = metadata.ctorParameters) !== null && _a !== void 0 ? _a : literal(null),
|
|
(_b = metadata.propDecorators) !== null && _b !== void 0 ? _b : literal(null),
|
|
]);
|
|
var iife = fn([], [devOnlyGuardedExpression(fnCall).toStmt()]);
|
|
return iife.callFn([]);
|
|
}
|
|
|
|
/**
|
|
* @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
|
|
*/
|
|
/**
|
|
* Every time we make a breaking change to the declaration interface or partial-linker behavior, we
|
|
* must update this constant to prevent old partial-linkers from incorrectly processing the
|
|
* declaration.
|
|
*
|
|
* Do not include any prerelease in these versions as they are ignored.
|
|
*/
|
|
var MINIMUM_PARTIAL_LINKER_VERSION = '12.0.0';
|
|
function compileDeclareClassMetadata(metadata) {
|
|
var definitionMap = new DefinitionMap();
|
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION));
|
|
definitionMap.set('version', literal('12.2.16'));
|
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
definitionMap.set('type', metadata.type);
|
|
definitionMap.set('decorators', metadata.decorators);
|
|
definitionMap.set('ctorParameters', metadata.ctorParameters);
|
|
definitionMap.set('propDecorators', metadata.propDecorators);
|
|
return importExpr(Identifiers.declareClassMetadata).callFn([definitionMap.toLiteralMap()]);
|
|
}
|
|
|
|
/**
|
|
* @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
|
|
*/
|
|
/**
|
|
* Creates an array literal expression from the given array, mapping all values to an expression
|
|
* using the provided mapping function. If the array is empty or null, then null is returned.
|
|
*
|
|
* @param values The array to transfer into literal array expression.
|
|
* @param mapper The logic to use for creating an expression for the array's values.
|
|
* @returns An array literal expression representing `values`, or null if `values` is empty or
|
|
* is itself null.
|
|
*/
|
|
function toOptionalLiteralArray(values, mapper) {
|
|
if (values === null || values.length === 0) {
|
|
return null;
|
|
}
|
|
return literalArr(values.map(function (value) { return mapper(value); }));
|
|
}
|
|
/**
|
|
* Creates an object literal expression from the given object, mapping all values to an expression
|
|
* using the provided mapping function. If the object has no keys, then null is returned.
|
|
*
|
|
* @param object The object to transfer into an object literal expression.
|
|
* @param mapper The logic to use for creating an expression for the object's values.
|
|
* @returns An object literal expression representing `object`, or null if `object` does not have
|
|
* any keys.
|
|
*/
|
|
function toOptionalLiteralMap(object, mapper) {
|
|
var entries = Object.keys(object).map(function (key) {
|
|
var value = object[key];
|
|
return { key: key, value: mapper(value), quoted: true };
|
|
});
|
|
if (entries.length > 0) {
|
|
return literalMap(entries);
|
|
}
|
|
else {
|
|
return null;
|
|
}
|
|
}
|
|
function compileDependencies(deps) {
|
|
if (deps === 'invalid') {
|
|
// The `deps` can be set to the string "invalid" by the `unwrapConstructorDependencies()`
|
|
// function, which tries to convert `ConstructorDeps` into `R3DependencyMetadata[]`.
|
|
return literal('invalid');
|
|
}
|
|
else if (deps === null) {
|
|
return literal(null);
|
|
}
|
|
else {
|
|
return literalArr(deps.map(compileDependency));
|
|
}
|
|
}
|
|
function compileDependency(dep) {
|
|
var depMeta = new DefinitionMap();
|
|
depMeta.set('token', dep.token);
|
|
if (dep.attributeNameType !== null) {
|
|
depMeta.set('attribute', literal(true));
|
|
}
|
|
if (dep.host) {
|
|
depMeta.set('host', literal(true));
|
|
}
|
|
if (dep.optional) {
|
|
depMeta.set('optional', literal(true));
|
|
}
|
|
if (dep.self) {
|
|
depMeta.set('self', literal(true));
|
|
}
|
|
if (dep.skipSelf) {
|
|
depMeta.set('skipSelf', literal(true));
|
|
}
|
|
return depMeta.toLiteralMap();
|
|
}
|
|
|
|
/**
|
|
* @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
|
|
*/
|
|
/**
|
|
* Every time we make a breaking change to the declaration interface or partial-linker behavior, we
|
|
* must update this constant to prevent old partial-linkers from incorrectly processing the
|
|
* declaration.
|
|
*
|
|
* Do not include any prerelease in these versions as they are ignored.
|
|
*/
|
|
var MINIMUM_PARTIAL_LINKER_VERSION$1 = '12.0.0';
|
|
/**
|
|
* Compile a directive declaration defined by the `R3DirectiveMetadata`.
|
|
*/
|
|
function compileDeclareDirectiveFromMetadata(meta) {
|
|
var definitionMap = createDirectiveDefinitionMap(meta);
|
|
var expression = importExpr(Identifiers.declareDirective).callFn([definitionMap.toLiteralMap()]);
|
|
var type = createDirectiveType(meta);
|
|
return { expression: expression, type: type, statements: [] };
|
|
}
|
|
/**
|
|
* Gathers the declaration fields for a directive into a `DefinitionMap`. This allows for reusing
|
|
* this logic for components, as they extend the directive metadata.
|
|
*/
|
|
function createDirectiveDefinitionMap(meta) {
|
|
var definitionMap = new DefinitionMap();
|
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$1));
|
|
definitionMap.set('version', literal('12.2.16'));
|
|
// e.g. `type: MyDirective`
|
|
definitionMap.set('type', meta.internalType);
|
|
// e.g. `selector: 'some-dir'`
|
|
if (meta.selector !== null) {
|
|
definitionMap.set('selector', literal(meta.selector));
|
|
}
|
|
definitionMap.set('inputs', conditionallyCreateMapObjectLiteral(meta.inputs, true));
|
|
definitionMap.set('outputs', conditionallyCreateMapObjectLiteral(meta.outputs));
|
|
definitionMap.set('host', compileHostMetadata(meta.host));
|
|
definitionMap.set('providers', meta.providers);
|
|
if (meta.queries.length > 0) {
|
|
definitionMap.set('queries', literalArr(meta.queries.map(compileQuery)));
|
|
}
|
|
if (meta.viewQueries.length > 0) {
|
|
definitionMap.set('viewQueries', literalArr(meta.viewQueries.map(compileQuery)));
|
|
}
|
|
if (meta.exportAs !== null) {
|
|
definitionMap.set('exportAs', asLiteral(meta.exportAs));
|
|
}
|
|
if (meta.usesInheritance) {
|
|
definitionMap.set('usesInheritance', literal(true));
|
|
}
|
|
if (meta.lifecycle.usesOnChanges) {
|
|
definitionMap.set('usesOnChanges', literal(true));
|
|
}
|
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
return definitionMap;
|
|
}
|
|
/**
|
|
* Compiles the metadata of a single query into its partial declaration form as declared
|
|
* by `R3DeclareQueryMetadata`.
|
|
*/
|
|
function compileQuery(query) {
|
|
var meta = new DefinitionMap();
|
|
meta.set('propertyName', literal(query.propertyName));
|
|
if (query.first) {
|
|
meta.set('first', literal(true));
|
|
}
|
|
meta.set('predicate', Array.isArray(query.predicate) ? asLiteral(query.predicate) :
|
|
convertFromMaybeForwardRefExpression(query.predicate));
|
|
if (!query.emitDistinctChangesOnly) {
|
|
// `emitDistinctChangesOnly` is special because we expect it to be `true`.
|
|
// Therefore we explicitly emit the field, and explicitly place it only when it's `false`.
|
|
meta.set('emitDistinctChangesOnly', literal(false));
|
|
}
|
|
else {
|
|
// The linker will assume that an absent `emitDistinctChangesOnly` flag is by default `true`.
|
|
}
|
|
if (query.descendants) {
|
|
meta.set('descendants', literal(true));
|
|
}
|
|
meta.set('read', query.read);
|
|
if (query.static) {
|
|
meta.set('static', literal(true));
|
|
}
|
|
return meta.toLiteralMap();
|
|
}
|
|
/**
|
|
* Compiles the host metadata into its partial declaration form as declared
|
|
* in `R3DeclareDirectiveMetadata['host']`
|
|
*/
|
|
function compileHostMetadata(meta) {
|
|
var hostMetadata = new DefinitionMap();
|
|
hostMetadata.set('attributes', toOptionalLiteralMap(meta.attributes, function (expression) { return expression; }));
|
|
hostMetadata.set('listeners', toOptionalLiteralMap(meta.listeners, literal));
|
|
hostMetadata.set('properties', toOptionalLiteralMap(meta.properties, literal));
|
|
if (meta.specialAttributes.styleAttr) {
|
|
hostMetadata.set('styleAttribute', literal(meta.specialAttributes.styleAttr));
|
|
}
|
|
if (meta.specialAttributes.classAttr) {
|
|
hostMetadata.set('classAttribute', literal(meta.specialAttributes.classAttr));
|
|
}
|
|
if (hostMetadata.values.length > 0) {
|
|
return hostMetadata.toLiteralMap();
|
|
}
|
|
else {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Compile a component declaration defined by the `R3ComponentMetadata`.
|
|
*/
|
|
function compileDeclareComponentFromMetadata(meta, template, additionalTemplateInfo) {
|
|
var definitionMap = createComponentDefinitionMap(meta, template, additionalTemplateInfo);
|
|
var expression = importExpr(Identifiers.declareComponent).callFn([definitionMap.toLiteralMap()]);
|
|
var type = createComponentType(meta);
|
|
return { expression: expression, type: type, statements: [] };
|
|
}
|
|
/**
|
|
* Gathers the declaration fields for a component into a `DefinitionMap`.
|
|
*/
|
|
function createComponentDefinitionMap(meta, template, templateInfo) {
|
|
var definitionMap = createDirectiveDefinitionMap(meta);
|
|
definitionMap.set('template', getTemplateExpression(template, templateInfo));
|
|
if (templateInfo.isInline) {
|
|
definitionMap.set('isInline', literal(true));
|
|
}
|
|
definitionMap.set('styles', toOptionalLiteralArray(meta.styles, literal));
|
|
definitionMap.set('components', compileUsedDirectiveMetadata(meta, function (directive) { return directive.isComponent === true; }));
|
|
definitionMap.set('directives', compileUsedDirectiveMetadata(meta, function (directive) { return directive.isComponent !== true; }));
|
|
definitionMap.set('pipes', compileUsedPipeMetadata(meta));
|
|
definitionMap.set('viewProviders', meta.viewProviders);
|
|
definitionMap.set('animations', meta.animations);
|
|
if (meta.changeDetection !== undefined) {
|
|
definitionMap.set('changeDetection', importExpr(Identifiers.ChangeDetectionStrategy)
|
|
.prop(ChangeDetectionStrategy[meta.changeDetection]));
|
|
}
|
|
if (meta.encapsulation !== ViewEncapsulation.Emulated) {
|
|
definitionMap.set('encapsulation', importExpr(Identifiers.ViewEncapsulation).prop(ViewEncapsulation[meta.encapsulation]));
|
|
}
|
|
if (meta.interpolation !== DEFAULT_INTERPOLATION_CONFIG) {
|
|
definitionMap.set('interpolation', literalArr([literal(meta.interpolation.start), literal(meta.interpolation.end)]));
|
|
}
|
|
if (template.preserveWhitespaces === true) {
|
|
definitionMap.set('preserveWhitespaces', literal(true));
|
|
}
|
|
return definitionMap;
|
|
}
|
|
function getTemplateExpression(template, templateInfo) {
|
|
// If the template has been defined using a direct literal, we use that expression directly
|
|
// without any modifications. This is ensures proper source mapping from the partially
|
|
// compiled code to the source file declaring the template. Note that this does not capture
|
|
// template literals referenced indirectly through an identifier.
|
|
if (templateInfo.inlineTemplateLiteralExpression !== null) {
|
|
return templateInfo.inlineTemplateLiteralExpression;
|
|
}
|
|
// If the template is defined inline but not through a literal, the template has been resolved
|
|
// through static interpretation. We create a literal but cannot provide any source span. Note
|
|
// that we cannot use the expression defining the template because the linker expects the template
|
|
// to be defined as a literal in the declaration.
|
|
if (templateInfo.isInline) {
|
|
return literal(templateInfo.content, null, null);
|
|
}
|
|
// The template is external so we must synthesize an expression node with
|
|
// the appropriate source-span.
|
|
var contents = templateInfo.content;
|
|
var file = new ParseSourceFile(contents, templateInfo.sourceUrl);
|
|
var start = new ParseLocation(file, 0, 0, 0);
|
|
var end = computeEndLocation(file, contents);
|
|
var span = new ParseSourceSpan(start, end);
|
|
return literal(contents, null, span);
|
|
}
|
|
function computeEndLocation(file, contents) {
|
|
var length = contents.length;
|
|
var lineStart = 0;
|
|
var lastLineStart = 0;
|
|
var line = 0;
|
|
do {
|
|
lineStart = contents.indexOf('\n', lastLineStart);
|
|
if (lineStart !== -1) {
|
|
lastLineStart = lineStart + 1;
|
|
line++;
|
|
}
|
|
} while (lineStart !== -1);
|
|
return new ParseLocation(file, length, line, length - lastLineStart);
|
|
}
|
|
/**
|
|
* Compiles the directives as registered in the component metadata into an array literal of the
|
|
* individual directives. If the component does not use any directives, then null is returned.
|
|
*/
|
|
function compileUsedDirectiveMetadata(meta, predicate) {
|
|
var wrapType = meta.declarationListEmitMode !== 0 /* Direct */ ?
|
|
generateForwardRef :
|
|
function (expr) { return expr; };
|
|
var directives = meta.directives.filter(predicate);
|
|
return toOptionalLiteralArray(directives, function (directive) {
|
|
var dirMeta = new DefinitionMap();
|
|
dirMeta.set('type', wrapType(directive.type));
|
|
dirMeta.set('selector', literal(directive.selector));
|
|
dirMeta.set('inputs', toOptionalLiteralArray(directive.inputs, literal));
|
|
dirMeta.set('outputs', toOptionalLiteralArray(directive.outputs, literal));
|
|
dirMeta.set('exportAs', toOptionalLiteralArray(directive.exportAs, literal));
|
|
return dirMeta.toLiteralMap();
|
|
});
|
|
}
|
|
/**
|
|
* Compiles the pipes as registered in the component metadata into an object literal, where the
|
|
* pipe's name is used as key and a reference to its type as value. If the component does not use
|
|
* any pipes, then null is returned.
|
|
*/
|
|
function compileUsedPipeMetadata(meta) {
|
|
var e_1, _a;
|
|
if (meta.pipes.size === 0) {
|
|
return null;
|
|
}
|
|
var wrapType = meta.declarationListEmitMode !== 0 /* Direct */ ?
|
|
generateForwardRef :
|
|
function (expr) { return expr; };
|
|
var entries = [];
|
|
try {
|
|
for (var _b = __values(meta.pipes), _c = _b.next(); !_c.done; _c = _b.next()) {
|
|
var _d = __read(_c.value, 2), name = _d[0], pipe = _d[1];
|
|
entries.push({ key: name, value: wrapType(pipe), quoted: true });
|
|
}
|
|
}
|
|
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
finally {
|
|
try {
|
|
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
|
|
}
|
|
finally { if (e_1) throw e_1.error; }
|
|
}
|
|
return literalMap(entries);
|
|
}
|
|
|
|
/**
|
|
* @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
|
|
*/
|
|
/**
|
|
* Every time we make a breaking change to the declaration interface or partial-linker behavior, we
|
|
* must update this constant to prevent old partial-linkers from incorrectly processing the
|
|
* declaration.
|
|
*
|
|
* Do not include any prerelease in these versions as they are ignored.
|
|
*/
|
|
var MINIMUM_PARTIAL_LINKER_VERSION$2 = '12.0.0';
|
|
function compileDeclareFactoryFunction(meta) {
|
|
var definitionMap = new DefinitionMap();
|
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$2));
|
|
definitionMap.set('version', literal('12.2.16'));
|
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
definitionMap.set('type', meta.internalType);
|
|
definitionMap.set('deps', compileDependencies(meta.deps));
|
|
definitionMap.set('target', importExpr(Identifiers.FactoryTarget).prop(exports.FactoryTarget[meta.target]));
|
|
return {
|
|
expression: importExpr(Identifiers.declareFactory).callFn([definitionMap.toLiteralMap()]),
|
|
statements: [],
|
|
type: createFactoryType(meta),
|
|
};
|
|
}
|
|
|
|
/**
|
|
* @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
|
|
*/
|
|
/**
|
|
* Every time we make a breaking change to the declaration interface or partial-linker behavior, we
|
|
* must update this constant to prevent old partial-linkers from incorrectly processing the
|
|
* declaration.
|
|
*
|
|
* Do not include any prerelease in these versions as they are ignored.
|
|
*/
|
|
var MINIMUM_PARTIAL_LINKER_VERSION$3 = '12.0.0';
|
|
/**
|
|
* Compile a Injectable declaration defined by the `R3InjectableMetadata`.
|
|
*/
|
|
function compileDeclareInjectableFromMetadata(meta) {
|
|
var definitionMap = createInjectableDefinitionMap(meta);
|
|
var expression = importExpr(Identifiers.declareInjectable).callFn([definitionMap.toLiteralMap()]);
|
|
var type = createInjectableType(meta);
|
|
return { expression: expression, type: type, statements: [] };
|
|
}
|
|
/**
|
|
* Gathers the declaration fields for a Injectable into a `DefinitionMap`.
|
|
*/
|
|
function createInjectableDefinitionMap(meta) {
|
|
var definitionMap = new DefinitionMap();
|
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$3));
|
|
definitionMap.set('version', literal('12.2.16'));
|
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
definitionMap.set('type', meta.internalType);
|
|
// Only generate providedIn property if it has a non-null value
|
|
if (meta.providedIn !== undefined) {
|
|
var providedIn = convertFromMaybeForwardRefExpression(meta.providedIn);
|
|
if (providedIn.value !== null) {
|
|
definitionMap.set('providedIn', providedIn);
|
|
}
|
|
}
|
|
if (meta.useClass !== undefined) {
|
|
definitionMap.set('useClass', convertFromMaybeForwardRefExpression(meta.useClass));
|
|
}
|
|
if (meta.useExisting !== undefined) {
|
|
definitionMap.set('useExisting', convertFromMaybeForwardRefExpression(meta.useExisting));
|
|
}
|
|
if (meta.useValue !== undefined) {
|
|
definitionMap.set('useValue', convertFromMaybeForwardRefExpression(meta.useValue));
|
|
}
|
|
// Factories do not contain `ForwardRef`s since any types are already wrapped in a function call
|
|
// so the types will not be eagerly evaluated. Therefore we do not need to process this expression
|
|
// with `convertFromProviderExpression()`.
|
|
if (meta.useFactory !== undefined) {
|
|
definitionMap.set('useFactory', meta.useFactory);
|
|
}
|
|
if (meta.deps !== undefined) {
|
|
definitionMap.set('deps', literalArr(meta.deps.map(compileDependency)));
|
|
}
|
|
return definitionMap;
|
|
}
|
|
|
|
/**
|
|
* @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
|
|
*/
|
|
/**
|
|
* Every time we make a breaking change to the declaration interface or partial-linker behavior, we
|
|
* must update this constant to prevent old partial-linkers from incorrectly processing the
|
|
* declaration.
|
|
*
|
|
* Do not include any prerelease in these versions as they are ignored.
|
|
*/
|
|
var MINIMUM_PARTIAL_LINKER_VERSION$4 = '12.0.0';
|
|
function compileDeclareInjectorFromMetadata(meta) {
|
|
var definitionMap = createInjectorDefinitionMap(meta);
|
|
var expression = importExpr(Identifiers.declareInjector).callFn([definitionMap.toLiteralMap()]);
|
|
var type = createInjectorType(meta);
|
|
return { expression: expression, type: type, statements: [] };
|
|
}
|
|
/**
|
|
* Gathers the declaration fields for an Injector into a `DefinitionMap`.
|
|
*/
|
|
function createInjectorDefinitionMap(meta) {
|
|
var definitionMap = new DefinitionMap();
|
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$4));
|
|
definitionMap.set('version', literal('12.2.16'));
|
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
definitionMap.set('type', meta.internalType);
|
|
definitionMap.set('providers', meta.providers);
|
|
if (meta.imports.length > 0) {
|
|
definitionMap.set('imports', literalArr(meta.imports));
|
|
}
|
|
return definitionMap;
|
|
}
|
|
|
|
/**
|
|
* @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
|
|
*/
|
|
/**
|
|
* Every time we make a breaking change to the declaration interface or partial-linker behavior, we
|
|
* must update this constant to prevent old partial-linkers from incorrectly processing the
|
|
* declaration.
|
|
*
|
|
* Do not include any prerelease in these versions as they are ignored.
|
|
*/
|
|
var MINIMUM_PARTIAL_LINKER_VERSION$5 = '12.0.0';
|
|
function compileDeclareNgModuleFromMetadata(meta) {
|
|
var definitionMap = createNgModuleDefinitionMap(meta);
|
|
var expression = importExpr(Identifiers.declareNgModule).callFn([definitionMap.toLiteralMap()]);
|
|
var type = createNgModuleType(meta);
|
|
return { expression: expression, type: type, statements: [] };
|
|
}
|
|
/**
|
|
* Gathers the declaration fields for an NgModule into a `DefinitionMap`.
|
|
*/
|
|
function createNgModuleDefinitionMap(meta) {
|
|
var definitionMap = new DefinitionMap();
|
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$5));
|
|
definitionMap.set('version', literal('12.2.16'));
|
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
definitionMap.set('type', meta.internalType);
|
|
// We only generate the keys in the metadata if the arrays contain values.
|
|
// We must wrap the arrays inside a function if any of the values are a forward reference to a
|
|
// not-yet-declared class. This is to support JIT execution of the `ɵɵngDeclareNgModule()` call.
|
|
// In the linker these wrappers are stripped and then reapplied for the `ɵɵdefineNgModule()` call.
|
|
if (meta.bootstrap.length > 0) {
|
|
definitionMap.set('bootstrap', refsToArray(meta.bootstrap, meta.containsForwardDecls));
|
|
}
|
|
if (meta.declarations.length > 0) {
|
|
definitionMap.set('declarations', refsToArray(meta.declarations, meta.containsForwardDecls));
|
|
}
|
|
if (meta.imports.length > 0) {
|
|
definitionMap.set('imports', refsToArray(meta.imports, meta.containsForwardDecls));
|
|
}
|
|
if (meta.exports.length > 0) {
|
|
definitionMap.set('exports', refsToArray(meta.exports, meta.containsForwardDecls));
|
|
}
|
|
if (meta.schemas !== null && meta.schemas.length > 0) {
|
|
definitionMap.set('schemas', literalArr(meta.schemas.map(function (ref) { return ref.value; })));
|
|
}
|
|
if (meta.id !== null) {
|
|
definitionMap.set('id', meta.id);
|
|
}
|
|
return definitionMap;
|
|
}
|
|
|
|
/**
|
|
* @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
|
|
*/
|
|
/**
|
|
* Every time we make a breaking change to the declaration interface or partial-linker behavior, we
|
|
* must update this constant to prevent old partial-linkers from incorrectly processing the
|
|
* declaration.
|
|
*
|
|
* Do not include any prerelease in these versions as they are ignored.
|
|
*/
|
|
var MINIMUM_PARTIAL_LINKER_VERSION$6 = '12.0.0';
|
|
/**
|
|
* Compile a Pipe declaration defined by the `R3PipeMetadata`.
|
|
*/
|
|
function compileDeclarePipeFromMetadata(meta) {
|
|
var definitionMap = createPipeDefinitionMap(meta);
|
|
var expression = importExpr(Identifiers.declarePipe).callFn([definitionMap.toLiteralMap()]);
|
|
var type = createPipeType(meta);
|
|
return { expression: expression, type: type, statements: [] };
|
|
}
|
|
/**
|
|
* Gathers the declaration fields for a Pipe into a `DefinitionMap`.
|
|
*/
|
|
function createPipeDefinitionMap(meta) {
|
|
var definitionMap = new DefinitionMap();
|
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$6));
|
|
definitionMap.set('version', literal('12.2.16'));
|
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
// e.g. `type: MyPipe`
|
|
definitionMap.set('type', meta.internalType);
|
|
// e.g. `name: "myPipe"`
|
|
definitionMap.set('name', literal(meta.pipeName));
|
|
if (meta.pure === false) {
|
|
// e.g. `pure: false`
|
|
definitionMap.set('pure', literal(meta.pure));
|
|
}
|
|
return definitionMap;
|
|
}
|
|
|
|
/**
|
|
* @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 file only reexports content of the `src` folder. Keep it that way.
|
|
// This function call has a global side effects and publishes the compiler into global namespace for
|
|
// the late binding of the Compiler to the @angular/core for jit compilation.
|
|
publishFacade(_global);
|
|
|
|
/**
|
|
* @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 file only reexports content of the `src` folder. Keep it that way.
|
|
|
|
/**
|
|
* @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
|
|
*/
|
|
|
|
/**
|
|
* @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
|
|
*/
|
|
|
|
exports.AST = AST;
|
|
exports.ASTWithName = ASTWithName;
|
|
exports.ASTWithSource = ASTWithSource;
|
|
exports.AbsoluteSourceSpan = AbsoluteSourceSpan;
|
|
exports.AotCompiler = AotCompiler;
|
|
exports.AotSummaryResolver = AotSummaryResolver;
|
|
exports.ArrayType = ArrayType;
|
|
exports.AssertNotNull = AssertNotNull;
|
|
exports.AstMemoryEfficientTransformer = AstMemoryEfficientTransformer;
|
|
exports.AstPath = AstPath;
|
|
exports.AstTransformer = AstTransformer$1;
|
|
exports.AttrAst = AttrAst;
|
|
exports.Attribute = Attribute;
|
|
exports.Binary = Binary;
|
|
exports.BinaryOperatorExpr = BinaryOperatorExpr;
|
|
exports.BindingPipe = BindingPipe;
|
|
exports.BoundDirectivePropertyAst = BoundDirectivePropertyAst;
|
|
exports.BoundElementProperty = BoundElementProperty;
|
|
exports.BoundElementPropertyAst = BoundElementPropertyAst;
|
|
exports.BoundEventAst = BoundEventAst;
|
|
exports.BoundTextAst = BoundTextAst;
|
|
exports.BuiltinType = BuiltinType;
|
|
exports.CONTENT_ATTR = CONTENT_ATTR;
|
|
exports.CUSTOM_ELEMENTS_SCHEMA = CUSTOM_ELEMENTS_SCHEMA;
|
|
exports.CastExpr = CastExpr;
|
|
exports.Chain = Chain;
|
|
exports.ClassField = ClassField;
|
|
exports.ClassMethod = ClassMethod;
|
|
exports.ClassStmt = ClassStmt;
|
|
exports.CommaExpr = CommaExpr;
|
|
exports.Comment = Comment$1;
|
|
exports.CompileDirectiveMetadata = CompileDirectiveMetadata;
|
|
exports.CompileMetadataResolver = CompileMetadataResolver;
|
|
exports.CompileNgModuleMetadata = CompileNgModuleMetadata;
|
|
exports.CompilePipeMetadata = CompilePipeMetadata;
|
|
exports.CompileReflector = CompileReflector;
|
|
exports.CompileShallowModuleMetadata = CompileShallowModuleMetadata;
|
|
exports.CompileStylesheetMetadata = CompileStylesheetMetadata;
|
|
exports.CompileTemplateMetadata = CompileTemplateMetadata;
|
|
exports.CompiledStylesheet = CompiledStylesheet;
|
|
exports.CompilerConfig = CompilerConfig;
|
|
exports.Conditional = Conditional;
|
|
exports.ConditionalExpr = ConditionalExpr;
|
|
exports.ConstantPool = ConstantPool;
|
|
exports.CssSelector = CssSelector;
|
|
exports.DEFAULT_INTERPOLATION_CONFIG = DEFAULT_INTERPOLATION_CONFIG;
|
|
exports.DYNAMIC_TYPE = DYNAMIC_TYPE;
|
|
exports.DeclareFunctionStmt = DeclareFunctionStmt;
|
|
exports.DeclareVarStmt = DeclareVarStmt;
|
|
exports.DirectiveAst = DirectiveAst;
|
|
exports.DirectiveNormalizer = DirectiveNormalizer;
|
|
exports.DirectiveResolver = DirectiveResolver;
|
|
exports.DomElementSchemaRegistry = DomElementSchemaRegistry;
|
|
exports.EOF = EOF;
|
|
exports.ERROR_COMPONENT_TYPE = ERROR_COMPONENT_TYPE;
|
|
exports.Element = Element$1;
|
|
exports.ElementAst = ElementAst;
|
|
exports.ElementSchemaRegistry = ElementSchemaRegistry;
|
|
exports.EmbeddedTemplateAst = EmbeddedTemplateAst;
|
|
exports.EmitterVisitorContext = EmitterVisitorContext;
|
|
exports.EmptyExpr = EmptyExpr;
|
|
exports.Expansion = Expansion;
|
|
exports.ExpansionCase = ExpansionCase;
|
|
exports.Expression = Expression;
|
|
exports.ExpressionBinding = ExpressionBinding;
|
|
exports.ExpressionStatement = ExpressionStatement;
|
|
exports.ExpressionType = ExpressionType;
|
|
exports.ExternalExpr = ExternalExpr;
|
|
exports.ExternalReference = ExternalReference;
|
|
exports.Extractor = Extractor;
|
|
exports.FunctionCall = FunctionCall;
|
|
exports.FunctionExpr = FunctionExpr;
|
|
exports.GeneratedFile = GeneratedFile;
|
|
exports.HOST_ATTR = HOST_ATTR;
|
|
exports.HtmlParser = HtmlParser;
|
|
exports.HtmlTagDefinition = HtmlTagDefinition;
|
|
exports.I18NHtmlParser = I18NHtmlParser;
|
|
exports.Identifiers = Identifiers$1;
|
|
exports.IfStmt = IfStmt;
|
|
exports.ImplicitReceiver = ImplicitReceiver;
|
|
exports.InstantiateExpr = InstantiateExpr;
|
|
exports.Interpolation = Interpolation;
|
|
exports.InterpolationConfig = InterpolationConfig;
|
|
exports.InvokeFunctionExpr = InvokeFunctionExpr;
|
|
exports.InvokeMethodExpr = InvokeMethodExpr;
|
|
exports.IvyParser = IvyParser;
|
|
exports.JSDocComment = JSDocComment;
|
|
exports.JitCompiler = JitCompiler;
|
|
exports.JitEvaluator = JitEvaluator;
|
|
exports.JitSummaryResolver = JitSummaryResolver;
|
|
exports.KeyedRead = KeyedRead;
|
|
exports.KeyedWrite = KeyedWrite;
|
|
exports.LeadingComment = LeadingComment;
|
|
exports.Lexer = Lexer;
|
|
exports.LiteralArray = LiteralArray;
|
|
exports.LiteralArrayExpr = LiteralArrayExpr;
|
|
exports.LiteralExpr = LiteralExpr;
|
|
exports.LiteralMap = LiteralMap;
|
|
exports.LiteralMapExpr = LiteralMapExpr;
|
|
exports.LiteralPrimitive = LiteralPrimitive;
|
|
exports.LocalizedString = LocalizedString;
|
|
exports.MapType = MapType;
|
|
exports.MessageBundle = MessageBundle;
|
|
exports.MethodCall = MethodCall;
|
|
exports.NONE_TYPE = NONE_TYPE;
|
|
exports.NO_ERRORS_SCHEMA = NO_ERRORS_SCHEMA;
|
|
exports.NgContentAst = NgContentAst;
|
|
exports.NgModuleCompiler = NgModuleCompiler;
|
|
exports.NgModuleResolver = NgModuleResolver;
|
|
exports.NodeWithI18n = NodeWithI18n;
|
|
exports.NonNullAssert = NonNullAssert;
|
|
exports.NotExpr = NotExpr;
|
|
exports.NullTemplateVisitor = NullTemplateVisitor;
|
|
exports.ParseError = ParseError;
|
|
exports.ParseLocation = ParseLocation;
|
|
exports.ParseSourceFile = ParseSourceFile;
|
|
exports.ParseSourceSpan = ParseSourceSpan;
|
|
exports.ParseSpan = ParseSpan;
|
|
exports.ParseTreeResult = ParseTreeResult;
|
|
exports.ParsedEvent = ParsedEvent;
|
|
exports.ParsedProperty = ParsedProperty;
|
|
exports.ParsedVariable = ParsedVariable;
|
|
exports.Parser = Parser$1;
|
|
exports.ParserError = ParserError;
|
|
exports.PipeResolver = PipeResolver;
|
|
exports.PrefixNot = PrefixNot;
|
|
exports.PropertyRead = PropertyRead;
|
|
exports.PropertyWrite = PropertyWrite;
|
|
exports.ProviderAst = ProviderAst;
|
|
exports.ProviderMeta = ProviderMeta;
|
|
exports.Quote = Quote;
|
|
exports.R3BoundTarget = R3BoundTarget;
|
|
exports.R3Identifiers = Identifiers;
|
|
exports.R3TargetBinder = R3TargetBinder;
|
|
exports.ReadKeyExpr = ReadKeyExpr;
|
|
exports.ReadPropExpr = ReadPropExpr;
|
|
exports.ReadVarExpr = ReadVarExpr;
|
|
exports.RecursiveAstVisitor = RecursiveAstVisitor$1;
|
|
exports.RecursiveTemplateAstVisitor = RecursiveTemplateAstVisitor;
|
|
exports.RecursiveVisitor = RecursiveVisitor$1;
|
|
exports.ReferenceAst = ReferenceAst;
|
|
exports.ResolvedStaticSymbol = ResolvedStaticSymbol;
|
|
exports.ResourceLoader = ResourceLoader;
|
|
exports.ReturnStatement = ReturnStatement;
|
|
exports.STRING_TYPE = STRING_TYPE;
|
|
exports.SafeKeyedRead = SafeKeyedRead;
|
|
exports.SafeMethodCall = SafeMethodCall;
|
|
exports.SafePropertyRead = SafePropertyRead;
|
|
exports.SelectorContext = SelectorContext;
|
|
exports.SelectorListContext = SelectorListContext;
|
|
exports.SelectorMatcher = SelectorMatcher;
|
|
exports.Serializer = Serializer;
|
|
exports.SplitInterpolation = SplitInterpolation;
|
|
exports.Statement = Statement;
|
|
exports.StaticReflector = StaticReflector;
|
|
exports.StaticSymbol = StaticSymbol;
|
|
exports.StaticSymbolCache = StaticSymbolCache;
|
|
exports.StaticSymbolResolver = StaticSymbolResolver;
|
|
exports.StyleCompiler = StyleCompiler;
|
|
exports.StylesCompileDependency = StylesCompileDependency;
|
|
exports.SummaryResolver = SummaryResolver;
|
|
exports.TaggedTemplateExpr = TaggedTemplateExpr;
|
|
exports.TemplateBindingParseResult = TemplateBindingParseResult;
|
|
exports.TemplateLiteral = TemplateLiteral;
|
|
exports.TemplateLiteralElement = TemplateLiteralElement;
|
|
exports.TemplateParseError = TemplateParseError;
|
|
exports.TemplateParseResult = TemplateParseResult;
|
|
exports.TemplateParser = TemplateParser;
|
|
exports.Text = Text$3;
|
|
exports.TextAst = TextAst;
|
|
exports.ThisReceiver = ThisReceiver;
|
|
exports.ThrowStmt = ThrowStmt;
|
|
exports.TmplAstBoundAttribute = BoundAttribute;
|
|
exports.TmplAstBoundEvent = BoundEvent;
|
|
exports.TmplAstBoundText = BoundText;
|
|
exports.TmplAstContent = Content;
|
|
exports.TmplAstElement = Element;
|
|
exports.TmplAstIcu = Icu;
|
|
exports.TmplAstRecursiveVisitor = RecursiveVisitor;
|
|
exports.TmplAstReference = Reference;
|
|
exports.TmplAstTemplate = Template;
|
|
exports.TmplAstText = Text;
|
|
exports.TmplAstTextAttribute = TextAttribute;
|
|
exports.TmplAstVariable = Variable;
|
|
exports.Token = Token;
|
|
exports.TransitiveCompileNgModuleMetadata = TransitiveCompileNgModuleMetadata;
|
|
exports.TreeError = TreeError;
|
|
exports.TryCatchStmt = TryCatchStmt;
|
|
exports.Type = Type$1;
|
|
exports.TypeScriptEmitter = TypeScriptEmitter;
|
|
exports.TypeofExpr = TypeofExpr;
|
|
exports.Unary = Unary;
|
|
exports.UnaryOperatorExpr = UnaryOperatorExpr;
|
|
exports.UrlResolver = UrlResolver;
|
|
exports.VERSION = VERSION$1;
|
|
exports.VariableAst = VariableAst;
|
|
exports.VariableBinding = VariableBinding;
|
|
exports.Version = Version;
|
|
exports.ViewCompiler = ViewCompiler;
|
|
exports.WrappedNodeExpr = WrappedNodeExpr;
|
|
exports.WriteKeyExpr = WriteKeyExpr;
|
|
exports.WritePropExpr = WritePropExpr;
|
|
exports.WriteVarExpr = WriteVarExpr;
|
|
exports.Xliff = Xliff;
|
|
exports.Xliff2 = Xliff2;
|
|
exports.Xmb = Xmb;
|
|
exports.XmlParser = XmlParser;
|
|
exports.Xtb = Xtb;
|
|
exports._ParseAST = _ParseAST;
|
|
exports.analyzeAndValidateNgModules = analyzeAndValidateNgModules;
|
|
exports.analyzeFile = analyzeFile;
|
|
exports.analyzeFileForInjectables = analyzeFileForInjectables;
|
|
exports.analyzeNgModules = analyzeNgModules;
|
|
exports.collectExternalReferences = collectExternalReferences;
|
|
exports.compileClassMetadata = compileClassMetadata;
|
|
exports.compileComponentFromMetadata = compileComponentFromMetadata;
|
|
exports.compileDeclareClassMetadata = compileDeclareClassMetadata;
|
|
exports.compileDeclareComponentFromMetadata = compileDeclareComponentFromMetadata;
|
|
exports.compileDeclareDirectiveFromMetadata = compileDeclareDirectiveFromMetadata;
|
|
exports.compileDeclareFactoryFunction = compileDeclareFactoryFunction;
|
|
exports.compileDeclareInjectableFromMetadata = compileDeclareInjectableFromMetadata;
|
|
exports.compileDeclareInjectorFromMetadata = compileDeclareInjectorFromMetadata;
|
|
exports.compileDeclareNgModuleFromMetadata = compileDeclareNgModuleFromMetadata;
|
|
exports.compileDeclarePipeFromMetadata = compileDeclarePipeFromMetadata;
|
|
exports.compileDirectiveFromMetadata = compileDirectiveFromMetadata;
|
|
exports.compileFactoryFunction = compileFactoryFunction;
|
|
exports.compileInjectable = compileInjectable;
|
|
exports.compileInjector = compileInjector;
|
|
exports.compileNgModule = compileNgModule;
|
|
exports.compilePipeFromMetadata = compilePipeFromMetadata;
|
|
exports.componentFactoryName = componentFactoryName;
|
|
exports.computeMsgId = computeMsgId;
|
|
exports.core = core;
|
|
exports.createAotCompiler = createAotCompiler;
|
|
exports.createAotUrlResolver = createAotUrlResolver;
|
|
exports.createElementCssSelector = createElementCssSelector;
|
|
exports.createInjectableType = createInjectableType;
|
|
exports.createLoweredSymbol = createLoweredSymbol;
|
|
exports.createMayBeForwardRefExpression = createMayBeForwardRefExpression;
|
|
exports.createOfflineCompileUrlResolver = createOfflineCompileUrlResolver;
|
|
exports.createUrlResolverWithoutPackagePrefix = createUrlResolverWithoutPackagePrefix;
|
|
exports.debugOutputAstAsTypeScript = debugOutputAstAsTypeScript;
|
|
exports.devOnlyGuardedExpression = devOnlyGuardedExpression;
|
|
exports.findNode = findNode;
|
|
exports.flatten = flatten;
|
|
exports.formattedError = formattedError;
|
|
exports.getHtmlTagDefinition = getHtmlTagDefinition;
|
|
exports.getMissingNgModuleMetadataErrorData = getMissingNgModuleMetadataErrorData;
|
|
exports.getNsPrefix = getNsPrefix;
|
|
exports.getParseErrors = getParseErrors;
|
|
exports.getSafePropertyAccessString = getSafePropertyAccessString;
|
|
exports.getUrlScheme = getUrlScheme;
|
|
exports.hostViewClassName = hostViewClassName;
|
|
exports.identifierModuleUrl = identifierModuleUrl;
|
|
exports.identifierName = identifierName;
|
|
exports.isEmptyExpression = isEmptyExpression;
|
|
exports.isFormattedError = isFormattedError;
|
|
exports.isIdentifier = isIdentifier;
|
|
exports.isLoweredSymbol = isLoweredSymbol;
|
|
exports.isNgContainer = isNgContainer;
|
|
exports.isNgContent = isNgContent;
|
|
exports.isNgTemplate = isNgTemplate;
|
|
exports.isSyntaxError = isSyntaxError;
|
|
exports.jsDocComment = jsDocComment;
|
|
exports.leadingComment = leadingComment;
|
|
exports.literalMap = literalMap;
|
|
exports.makeBindingParser = makeBindingParser;
|
|
exports.mergeAnalyzedFiles = mergeAnalyzedFiles;
|
|
exports.mergeNsAndName = mergeNsAndName;
|
|
exports.ngModuleJitUrl = ngModuleJitUrl;
|
|
exports.parseHostBindings = parseHostBindings;
|
|
exports.parseTemplate = parseTemplate;
|
|
exports.preserveWhitespacesDefault = preserveWhitespacesDefault;
|
|
exports.publishFacade = publishFacade;
|
|
exports.r3JitTypeSourceSpan = r3JitTypeSourceSpan;
|
|
exports.removeSummaryDuplicates = removeSummaryDuplicates;
|
|
exports.rendererTypeName = rendererTypeName;
|
|
exports.sanitizeIdentifier = sanitizeIdentifier;
|
|
exports.sharedStylesheetJitUrl = sharedStylesheetJitUrl;
|
|
exports.splitClasses = splitClasses;
|
|
exports.splitNsName = splitNsName;
|
|
exports.syntaxError = syntaxError;
|
|
exports.templateJitUrl = templateJitUrl;
|
|
exports.templateSourceUrl = templateSourceUrl;
|
|
exports.templateVisitAll = templateVisitAll;
|
|
exports.toTypeScript = toTypeScript;
|
|
exports.tokenName = tokenName;
|
|
exports.tokenReference = tokenReference;
|
|
exports.typeSourceSpan = typeSourceSpan;
|
|
exports.unescapeIdentifier = unescapeIdentifier;
|
|
exports.unwrapResolvedMetadata = unwrapResolvedMetadata;
|
|
exports.verifyHostBindings = verifyHostBindings;
|
|
exports.viewClassName = viewClassName;
|
|
exports.visitAll = visitAll$1;
|
|
|
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
|
})));
|
|
//# sourceMappingURL=compiler.umd.js.map
|