@angular/compiler 16.0.0-next.6 → 16.0.0-rc.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm2022/src/injectable_compiler_2.mjs +11 -12
- package/esm2022/src/jit_compiler_facade.mjs +1 -13
- package/esm2022/src/render3/partial/class_metadata.mjs +1 -1
- package/esm2022/src/render3/partial/directive.mjs +3 -3
- package/esm2022/src/render3/partial/factory.mjs +3 -3
- package/esm2022/src/render3/partial/injectable.mjs +3 -3
- package/esm2022/src/render3/partial/injector.mjs +3 -3
- package/esm2022/src/render3/partial/ng_module.mjs +3 -3
- package/esm2022/src/render3/partial/pipe.mjs +3 -3
- package/esm2022/src/render3/r3_factory.mjs +3 -3
- package/esm2022/src/render3/r3_injector_compiler.mjs +1 -1
- package/esm2022/src/render3/r3_module_compiler.mjs +6 -6
- package/esm2022/src/render3/r3_pipe_compiler.mjs +1 -1
- package/esm2022/src/render3/view/api.mjs +1 -1
- package/esm2022/src/render3/view/compiler.mjs +53 -28
- package/esm2022/src/render3/view/util.mjs +4 -2
- package/esm2022/src/template/pipeline/ir/index.mjs +17 -0
- package/esm2022/src/template/pipeline/ir/src/element.mjs +101 -0
- package/esm2022/src/template/pipeline/ir/src/enums.mjs +121 -0
- package/esm2022/src/template/pipeline/ir/src/expression.mjs +293 -0
- package/esm2022/src/template/pipeline/ir/src/operations.mjs +223 -0
- package/esm2022/src/template/pipeline/ir/src/ops/create.mjs +78 -0
- package/esm2022/src/template/pipeline/ir/src/ops/shared.mjs +43 -0
- package/esm2022/src/template/pipeline/ir/src/ops/update.mjs +49 -0
- package/esm2022/src/template/pipeline/ir/src/traits.mjs +68 -0
- package/esm2022/src/template/pipeline/ir/src/variable.mjs +9 -0
- package/esm2022/src/template/pipeline/src/compilation.mjs +122 -0
- package/esm2022/src/template/pipeline/src/emit.mjs +83 -0
- package/esm2022/src/template/pipeline/src/ingest.mjs +194 -0
- package/esm2022/src/template/pipeline/src/instruction.mjs +139 -0
- package/esm2022/src/template/pipeline/src/phases/const_collection.mjs +57 -0
- package/esm2022/src/template/pipeline/src/phases/empty_elements.mjs +27 -0
- package/esm2022/src/template/pipeline/src/phases/generate_advance.mjs +56 -0
- package/esm2022/src/template/pipeline/src/phases/generate_variables.mjs +146 -0
- package/esm2022/src/template/pipeline/src/phases/local_refs.mjs +44 -0
- package/esm2022/src/template/pipeline/src/phases/naming.mjs +61 -0
- package/esm2022/src/template/pipeline/src/phases/reify.mjs +157 -0
- package/esm2022/src/template/pipeline/src/phases/resolve_contexts.mjs +55 -0
- package/esm2022/src/template/pipeline/src/phases/resolve_names.mjs +95 -0
- package/esm2022/src/template/pipeline/src/phases/slot_allocation.mjs +75 -0
- package/esm2022/src/template/pipeline/src/phases/var_counting.mjs +60 -0
- package/esm2022/src/template/pipeline/switch/index.mjs +2 -0
- package/esm2022/src/version.mjs +1 -1
- package/fesm2022/compiler.mjs +2410 -268
- package/fesm2022/compiler.mjs.map +1 -1
- package/fesm2022/testing.mjs +1 -1
- package/index.d.ts +1 -43
- package/package.json +3 -3
- package/testing/index.d.ts +1 -1
package/fesm2022/compiler.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @license Angular v16.0.0-
|
|
2
|
+
* @license Angular v16.0.0-rc.0
|
|
3
3
|
* (c) 2010-2022 Google LLC. https://angular.io/
|
|
4
4
|
* License: MIT
|
|
5
5
|
*/
|
|
@@ -3500,7 +3500,7 @@ function compileFactoryFunction(meta) {
|
|
|
3500
3500
|
// delegated factory (which is used to create the current type) then this is only the type-to-
|
|
3501
3501
|
// create parameter (t).
|
|
3502
3502
|
const typeForCtor = !isDelegatedFactoryMetadata(meta) ?
|
|
3503
|
-
new BinaryOperatorExpr(BinaryOperator.Or, t, meta.
|
|
3503
|
+
new BinaryOperatorExpr(BinaryOperator.Or, t, meta.type.value) :
|
|
3504
3504
|
t;
|
|
3505
3505
|
let ctorExpr = null;
|
|
3506
3506
|
if (meta.deps !== null) {
|
|
@@ -3547,7 +3547,7 @@ function compileFactoryFunction(meta) {
|
|
|
3547
3547
|
}
|
|
3548
3548
|
else if (baseFactoryVar !== null) {
|
|
3549
3549
|
// This factory uses a base factory, so call `ɵɵgetInheritedFactory()` to compute it.
|
|
3550
|
-
const getInheritedFactoryCall = importExpr(Identifiers.getInheritedFactory).callFn([meta.
|
|
3550
|
+
const getInheritedFactoryCall = importExpr(Identifiers.getInheritedFactory).callFn([meta.type.value]);
|
|
3551
3551
|
// Memoize the base factoryFn: `baseFactory || (baseFactory = ɵɵgetInheritedFactory(...))`
|
|
3552
3552
|
const baseFactory = new BinaryOperatorExpr(BinaryOperator.Or, baseFactoryVar, baseFactoryVar.set(getInheritedFactoryCall));
|
|
3553
3553
|
body.push(new ReturnStatement(baseFactory.callFn([typeForCtor])));
|
|
@@ -4815,7 +4815,9 @@ function getAttrsForDirectiveMatching(elOrTpl) {
|
|
|
4815
4815
|
}
|
|
4816
4816
|
});
|
|
4817
4817
|
elOrTpl.inputs.forEach(i => {
|
|
4818
|
-
|
|
4818
|
+
if (i.type === 0 /* BindingType.Property */) {
|
|
4819
|
+
attributesMap[i.name] = '';
|
|
4820
|
+
}
|
|
4819
4821
|
});
|
|
4820
4822
|
elOrTpl.outputs.forEach(o => {
|
|
4821
4823
|
attributesMap[o.name] = '';
|
|
@@ -4883,7 +4885,6 @@ function compileInjectable(meta, resolveForwardRefs) {
|
|
|
4883
4885
|
const factoryMeta = {
|
|
4884
4886
|
name: meta.name,
|
|
4885
4887
|
type: meta.type,
|
|
4886
|
-
internalType: meta.internalType,
|
|
4887
4888
|
typeArgumentCount: meta.typeArgumentCount,
|
|
4888
4889
|
deps: [],
|
|
4889
4890
|
target: FactoryTarget$1.Injectable,
|
|
@@ -4895,7 +4896,7 @@ function compileInjectable(meta, resolveForwardRefs) {
|
|
|
4895
4896
|
//
|
|
4896
4897
|
// A special case exists for useClass: Type where Type is the injectable type itself and no
|
|
4897
4898
|
// deps are specified, in which case 'useClass' is effectively ignored.
|
|
4898
|
-
const useClassOnSelf = meta.useClass.expression.isEquivalent(meta.
|
|
4899
|
+
const useClassOnSelf = meta.useClass.expression.isEquivalent(meta.type.value);
|
|
4899
4900
|
let deps = undefined;
|
|
4900
4901
|
if (meta.deps !== undefined) {
|
|
4901
4902
|
deps = meta.deps;
|
|
@@ -4954,10 +4955,10 @@ function compileInjectable(meta, resolveForwardRefs) {
|
|
|
4954
4955
|
else {
|
|
4955
4956
|
result = {
|
|
4956
4957
|
statements: [],
|
|
4957
|
-
expression: delegateToFactory(meta.type.value, meta.
|
|
4958
|
+
expression: delegateToFactory(meta.type.value, meta.type.value, resolveForwardRefs)
|
|
4958
4959
|
};
|
|
4959
4960
|
}
|
|
4960
|
-
const token = meta.
|
|
4961
|
+
const token = meta.type.value;
|
|
4961
4962
|
const injectableProps = new DefinitionMap();
|
|
4962
4963
|
injectableProps.set('token', token);
|
|
4963
4964
|
injectableProps.set('factory', result.expression);
|
|
@@ -4976,28 +4977,28 @@ function compileInjectable(meta, resolveForwardRefs) {
|
|
|
4976
4977
|
function createInjectableType(meta) {
|
|
4977
4978
|
return new ExpressionType(importExpr(Identifiers.InjectableDeclaration, [typeWithParameters(meta.type.type, meta.typeArgumentCount)]));
|
|
4978
4979
|
}
|
|
4979
|
-
function delegateToFactory(type,
|
|
4980
|
-
if (type.node ===
|
|
4980
|
+
function delegateToFactory(type, useType, unwrapForwardRefs) {
|
|
4981
|
+
if (type.node === useType.node) {
|
|
4981
4982
|
// The types are the same, so we can simply delegate directly to the type's factory.
|
|
4982
4983
|
// ```
|
|
4983
4984
|
// factory: type.ɵfac
|
|
4984
4985
|
// ```
|
|
4985
|
-
return
|
|
4986
|
+
return useType.prop('ɵfac');
|
|
4986
4987
|
}
|
|
4987
4988
|
if (!unwrapForwardRefs) {
|
|
4988
4989
|
// The type is not wrapped in a `forwardRef()`, so we create a simple factory function that
|
|
4989
4990
|
// accepts a sub-type as an argument.
|
|
4990
4991
|
// ```
|
|
4991
|
-
// factory: function(t) { return
|
|
4992
|
+
// factory: function(t) { return useType.ɵfac(t); }
|
|
4992
4993
|
// ```
|
|
4993
|
-
return createFactoryFunction(
|
|
4994
|
+
return createFactoryFunction(useType);
|
|
4994
4995
|
}
|
|
4995
|
-
// The
|
|
4996
|
+
// The useType is actually wrapped in a `forwardRef()` so we need to resolve that before
|
|
4996
4997
|
// calling its factory.
|
|
4997
4998
|
// ```
|
|
4998
4999
|
// factory: function(t) { return core.resolveForwardRef(type).ɵfac(t); }
|
|
4999
5000
|
// ```
|
|
5000
|
-
const unwrappedType = importExpr(Identifiers.resolveForwardRef).callFn([
|
|
5001
|
+
const unwrappedType = importExpr(Identifiers.resolveForwardRef).callFn([useType]);
|
|
5001
5002
|
return createFactoryFunction(unwrappedType);
|
|
5002
5003
|
}
|
|
5003
5004
|
function createFactoryFunction(type) {
|
|
@@ -5701,10 +5702,10 @@ var R3SelectorScopeMode;
|
|
|
5701
5702
|
* Construct an `R3NgModuleDef` for the given `R3NgModuleMetadata`.
|
|
5702
5703
|
*/
|
|
5703
5704
|
function compileNgModule(meta) {
|
|
5704
|
-
const {
|
|
5705
|
+
const { type: moduleType, bootstrap, declarations, imports, exports, schemas, containsForwardDecls, selectorScopeMode, id } = meta;
|
|
5705
5706
|
const statements = [];
|
|
5706
5707
|
const definitionMap = new DefinitionMap();
|
|
5707
|
-
definitionMap.set('type',
|
|
5708
|
+
definitionMap.set('type', moduleType.value);
|
|
5708
5709
|
if (bootstrap.length > 0) {
|
|
5709
5710
|
definitionMap.set('bootstrap', refsToArray(bootstrap, containsForwardDecls));
|
|
5710
5711
|
}
|
|
@@ -5741,7 +5742,7 @@ function compileNgModule(meta) {
|
|
|
5741
5742
|
definitionMap.set('id', id);
|
|
5742
5743
|
// Generate a side-effectful call to register this NgModule by its id, as per the semantics of
|
|
5743
5744
|
// NgModule ids.
|
|
5744
|
-
statements.push(importExpr(Identifiers.registerNgModuleType).callFn([
|
|
5745
|
+
statements.push(importExpr(Identifiers.registerNgModuleType).callFn([moduleType.value, id]).toStmt());
|
|
5745
5746
|
}
|
|
5746
5747
|
const expression = importExpr(Identifiers.defineNgModule).callFn([definitionMap.toLiteralMap()], undefined, true);
|
|
5747
5748
|
const type = createNgModuleType(meta);
|
|
@@ -5790,7 +5791,7 @@ function createNgModuleType({ type: moduleType, declarations, exports, imports,
|
|
|
5790
5791
|
* symbols to become tree-shakeable.
|
|
5791
5792
|
*/
|
|
5792
5793
|
function generateSetNgModuleScopeCall(meta) {
|
|
5793
|
-
const {
|
|
5794
|
+
const { type: moduleType, declarations, imports, exports, containsForwardDecls } = meta;
|
|
5794
5795
|
const scopeMap = new DefinitionMap();
|
|
5795
5796
|
if (declarations.length > 0) {
|
|
5796
5797
|
scopeMap.set('declarations', refsToArray(declarations, containsForwardDecls));
|
|
@@ -5807,7 +5808,7 @@ function generateSetNgModuleScopeCall(meta) {
|
|
|
5807
5808
|
// setNgModuleScope(...)
|
|
5808
5809
|
const fnCall = new InvokeFunctionExpr(
|
|
5809
5810
|
/* fn */ importExpr(Identifiers.setNgModuleScope),
|
|
5810
|
-
/* args */ [moduleType, scopeMap.toLiteralMap()]);
|
|
5811
|
+
/* args */ [moduleType.value, scopeMap.toLiteralMap()]);
|
|
5811
5812
|
// (ngJitMode guard) && setNgModuleScope(...)
|
|
5812
5813
|
const guardedCall = jitOnlyGuardedExpression(fnCall);
|
|
5813
5814
|
// function() { (ngJitMode guard) && setNgModuleScope(...); }
|
|
@@ -8217,192 +8218,2358 @@ function escapeBlocks(input, charPairs, placeholder) {
|
|
|
8217
8218
|
escapedBlocks.push(input.substring(blockStartIndex));
|
|
8218
8219
|
resultParts.push(placeholder);
|
|
8219
8220
|
}
|
|
8220
|
-
else {
|
|
8221
|
-
resultParts.push(input.substring(nonBlockStartIndex));
|
|
8221
|
+
else {
|
|
8222
|
+
resultParts.push(input.substring(nonBlockStartIndex));
|
|
8223
|
+
}
|
|
8224
|
+
return new StringWithEscapedBlocks(resultParts.join(''), escapedBlocks);
|
|
8225
|
+
}
|
|
8226
|
+
/**
|
|
8227
|
+
* Object containing as keys characters that should be substituted by placeholders
|
|
8228
|
+
* when found in strings during the css text parsing, and as values the respective
|
|
8229
|
+
* placeholders
|
|
8230
|
+
*/
|
|
8231
|
+
const ESCAPE_IN_STRING_MAP = {
|
|
8232
|
+
';': SEMI_IN_PLACEHOLDER,
|
|
8233
|
+
',': COMMA_IN_PLACEHOLDER,
|
|
8234
|
+
':': COLON_IN_PLACEHOLDER
|
|
8235
|
+
};
|
|
8236
|
+
/**
|
|
8237
|
+
* Parse the provided css text and inside strings (meaning, inside pairs of unescaped single or
|
|
8238
|
+
* double quotes) replace specific characters with their respective placeholders as indicated
|
|
8239
|
+
* by the `ESCAPE_IN_STRING_MAP` map.
|
|
8240
|
+
*
|
|
8241
|
+
* For example convert the text
|
|
8242
|
+
* `animation: "my-anim:at\"ion" 1s;`
|
|
8243
|
+
* to
|
|
8244
|
+
* `animation: "my-anim%COLON_IN_PLACEHOLDER%at\"ion" 1s;`
|
|
8245
|
+
*
|
|
8246
|
+
* This is necessary in order to remove the meaning of some characters when found inside strings
|
|
8247
|
+
* (for example `;` indicates the end of a css declaration, `,` the sequence of values and `:` the
|
|
8248
|
+
* division between property and value during a declaration, none of these meanings apply when such
|
|
8249
|
+
* characters are within strings and so in order to prevent parsing issues they need to be replaced
|
|
8250
|
+
* with placeholder text for the duration of the css manipulation process).
|
|
8251
|
+
*
|
|
8252
|
+
* @param input the original css text.
|
|
8253
|
+
*
|
|
8254
|
+
* @returns the css text with specific characters in strings replaced by placeholders.
|
|
8255
|
+
**/
|
|
8256
|
+
function escapeInStrings(input) {
|
|
8257
|
+
let result = input;
|
|
8258
|
+
let currentQuoteChar = null;
|
|
8259
|
+
for (let i = 0; i < result.length; i++) {
|
|
8260
|
+
const char = result[i];
|
|
8261
|
+
if (char === '\\') {
|
|
8262
|
+
i++;
|
|
8263
|
+
}
|
|
8264
|
+
else {
|
|
8265
|
+
if (currentQuoteChar !== null) {
|
|
8266
|
+
// index i is inside a quoted sub-string
|
|
8267
|
+
if (char === currentQuoteChar) {
|
|
8268
|
+
currentQuoteChar = null;
|
|
8269
|
+
}
|
|
8270
|
+
else {
|
|
8271
|
+
const placeholder = ESCAPE_IN_STRING_MAP[char];
|
|
8272
|
+
if (placeholder) {
|
|
8273
|
+
result = `${result.substr(0, i)}${placeholder}${result.substr(i + 1)}`;
|
|
8274
|
+
i += placeholder.length - 1;
|
|
8275
|
+
}
|
|
8276
|
+
}
|
|
8277
|
+
}
|
|
8278
|
+
else if (char === '\'' || char === '"') {
|
|
8279
|
+
currentQuoteChar = char;
|
|
8280
|
+
}
|
|
8281
|
+
}
|
|
8282
|
+
}
|
|
8283
|
+
return result;
|
|
8284
|
+
}
|
|
8285
|
+
/**
|
|
8286
|
+
* Replace in a string all occurrences of keys in the `ESCAPE_IN_STRING_MAP` map with their
|
|
8287
|
+
* original representation, this is simply used to revert the changes applied by the
|
|
8288
|
+
* escapeInStrings function.
|
|
8289
|
+
*
|
|
8290
|
+
* For example it reverts the text:
|
|
8291
|
+
* `animation: "my-anim%COLON_IN_PLACEHOLDER%at\"ion" 1s;`
|
|
8292
|
+
* to it's original form of:
|
|
8293
|
+
* `animation: "my-anim:at\"ion" 1s;`
|
|
8294
|
+
*
|
|
8295
|
+
* Note: For the sake of simplicity this function does not check that the placeholders are
|
|
8296
|
+
* actually inside strings as it would anyway be extremely unlikely to find them outside of strings.
|
|
8297
|
+
*
|
|
8298
|
+
* @param input the css text containing the placeholders.
|
|
8299
|
+
*
|
|
8300
|
+
* @returns the css text without the placeholders.
|
|
8301
|
+
*/
|
|
8302
|
+
function unescapeInStrings(input) {
|
|
8303
|
+
let result = input.replace(_cssCommaInPlaceholderReGlobal, ',');
|
|
8304
|
+
result = result.replace(_cssSemiInPlaceholderReGlobal, ';');
|
|
8305
|
+
result = result.replace(_cssColonInPlaceholderReGlobal, ':');
|
|
8306
|
+
return result;
|
|
8307
|
+
}
|
|
8308
|
+
/**
|
|
8309
|
+
* Unescape all quotes present in a string, but only if the string was actually already
|
|
8310
|
+
* quoted.
|
|
8311
|
+
*
|
|
8312
|
+
* This generates a "canonical" representation of strings which can be used to match strings
|
|
8313
|
+
* which would otherwise only differ because of differently escaped quotes.
|
|
8314
|
+
*
|
|
8315
|
+
* For example it converts the string (assumed to be quoted):
|
|
8316
|
+
* `this \\"is\\" a \\'\\\\'test`
|
|
8317
|
+
* to:
|
|
8318
|
+
* `this "is" a '\\\\'test`
|
|
8319
|
+
* (note that the latter backslashes are not removed as they are not actually escaping the single
|
|
8320
|
+
* quote)
|
|
8321
|
+
*
|
|
8322
|
+
*
|
|
8323
|
+
* @param input the string possibly containing escaped quotes.
|
|
8324
|
+
* @param isQuoted boolean indicating whether the string was quoted inside a bigger string (if not
|
|
8325
|
+
* then it means that it doesn't represent an inner string and thus no unescaping is required)
|
|
8326
|
+
*
|
|
8327
|
+
* @returns the string in the "canonical" representation without escaped quotes.
|
|
8328
|
+
*/
|
|
8329
|
+
function unescapeQuotes(str, isQuoted) {
|
|
8330
|
+
return !isQuoted ? str : str.replace(/((?:^|[^\\])(?:\\\\)*)\\(?=['"])/g, '$1');
|
|
8331
|
+
}
|
|
8332
|
+
/**
|
|
8333
|
+
* Combine the `contextSelectors` with the `hostMarker` and the `otherSelectors`
|
|
8334
|
+
* to create a selector that matches the same as `:host-context()`.
|
|
8335
|
+
*
|
|
8336
|
+
* Given a single context selector `A` we need to output selectors that match on the host and as an
|
|
8337
|
+
* ancestor of the host:
|
|
8338
|
+
*
|
|
8339
|
+
* ```
|
|
8340
|
+
* A <hostMarker>, A<hostMarker> {}
|
|
8341
|
+
* ```
|
|
8342
|
+
*
|
|
8343
|
+
* When there is more than one context selector we also have to create combinations of those
|
|
8344
|
+
* selectors with each other. For example if there are `A` and `B` selectors the output is:
|
|
8345
|
+
*
|
|
8346
|
+
* ```
|
|
8347
|
+
* AB<hostMarker>, AB <hostMarker>, A B<hostMarker>,
|
|
8348
|
+
* B A<hostMarker>, A B <hostMarker>, B A <hostMarker> {}
|
|
8349
|
+
* ```
|
|
8350
|
+
*
|
|
8351
|
+
* And so on...
|
|
8352
|
+
*
|
|
8353
|
+
* @param hostMarker the string that selects the host element.
|
|
8354
|
+
* @param contextSelectors an array of context selectors that will be combined.
|
|
8355
|
+
* @param otherSelectors the rest of the selectors that are not context selectors.
|
|
8356
|
+
*/
|
|
8357
|
+
function combineHostContextSelectors(contextSelectors, otherSelectors) {
|
|
8358
|
+
const hostMarker = _polyfillHostNoCombinator;
|
|
8359
|
+
_polyfillHostRe.lastIndex = 0; // reset the regex to ensure we get an accurate test
|
|
8360
|
+
const otherSelectorsHasHost = _polyfillHostRe.test(otherSelectors);
|
|
8361
|
+
// If there are no context selectors then just output a host marker
|
|
8362
|
+
if (contextSelectors.length === 0) {
|
|
8363
|
+
return hostMarker + otherSelectors;
|
|
8364
|
+
}
|
|
8365
|
+
const combined = [contextSelectors.pop() || ''];
|
|
8366
|
+
while (contextSelectors.length > 0) {
|
|
8367
|
+
const length = combined.length;
|
|
8368
|
+
const contextSelector = contextSelectors.pop();
|
|
8369
|
+
for (let i = 0; i < length; i++) {
|
|
8370
|
+
const previousSelectors = combined[i];
|
|
8371
|
+
// Add the new selector as a descendant of the previous selectors
|
|
8372
|
+
combined[length * 2 + i] = previousSelectors + ' ' + contextSelector;
|
|
8373
|
+
// Add the new selector as an ancestor of the previous selectors
|
|
8374
|
+
combined[length + i] = contextSelector + ' ' + previousSelectors;
|
|
8375
|
+
// Add the new selector to act on the same element as the previous selectors
|
|
8376
|
+
combined[i] = contextSelector + previousSelectors;
|
|
8377
|
+
}
|
|
8378
|
+
}
|
|
8379
|
+
// Finally connect the selector to the `hostMarker`s: either acting directly on the host
|
|
8380
|
+
// (A<hostMarker>) or as an ancestor (A <hostMarker>).
|
|
8381
|
+
return combined
|
|
8382
|
+
.map(s => otherSelectorsHasHost ?
|
|
8383
|
+
`${s}${otherSelectors}` :
|
|
8384
|
+
`${s}${hostMarker}${otherSelectors}, ${s} ${hostMarker}${otherSelectors}`)
|
|
8385
|
+
.join(',');
|
|
8386
|
+
}
|
|
8387
|
+
/**
|
|
8388
|
+
* Mutate the given `groups` array so that there are `multiples` clones of the original array
|
|
8389
|
+
* stored.
|
|
8390
|
+
*
|
|
8391
|
+
* For example `repeatGroups([a, b], 3)` will result in `[a, b, a, b, a, b]` - but importantly the
|
|
8392
|
+
* newly added groups will be clones of the original.
|
|
8393
|
+
*
|
|
8394
|
+
* @param groups An array of groups of strings that will be repeated. This array is mutated
|
|
8395
|
+
* in-place.
|
|
8396
|
+
* @param multiples The number of times the current groups should appear.
|
|
8397
|
+
*/
|
|
8398
|
+
function repeatGroups(groups, multiples) {
|
|
8399
|
+
const length = groups.length;
|
|
8400
|
+
for (let i = 1; i < multiples; i++) {
|
|
8401
|
+
for (let j = 0; j < length; j++) {
|
|
8402
|
+
groups[j + (i * length)] = groups[j].slice(0);
|
|
8403
|
+
}
|
|
8404
|
+
}
|
|
8405
|
+
}
|
|
8406
|
+
|
|
8407
|
+
var TagContentType;
|
|
8408
|
+
(function (TagContentType) {
|
|
8409
|
+
TagContentType[TagContentType["RAW_TEXT"] = 0] = "RAW_TEXT";
|
|
8410
|
+
TagContentType[TagContentType["ESCAPABLE_RAW_TEXT"] = 1] = "ESCAPABLE_RAW_TEXT";
|
|
8411
|
+
TagContentType[TagContentType["PARSABLE_DATA"] = 2] = "PARSABLE_DATA";
|
|
8412
|
+
})(TagContentType || (TagContentType = {}));
|
|
8413
|
+
function splitNsName(elementName) {
|
|
8414
|
+
if (elementName[0] != ':') {
|
|
8415
|
+
return [null, elementName];
|
|
8416
|
+
}
|
|
8417
|
+
const colonIndex = elementName.indexOf(':', 1);
|
|
8418
|
+
if (colonIndex === -1) {
|
|
8419
|
+
throw new Error(`Unsupported format "${elementName}" expecting ":namespace:name"`);
|
|
8420
|
+
}
|
|
8421
|
+
return [elementName.slice(1, colonIndex), elementName.slice(colonIndex + 1)];
|
|
8422
|
+
}
|
|
8423
|
+
// `<ng-container>` tags work the same regardless the namespace
|
|
8424
|
+
function isNgContainer(tagName) {
|
|
8425
|
+
return splitNsName(tagName)[1] === 'ng-container';
|
|
8426
|
+
}
|
|
8427
|
+
// `<ng-content>` tags work the same regardless the namespace
|
|
8428
|
+
function isNgContent(tagName) {
|
|
8429
|
+
return splitNsName(tagName)[1] === 'ng-content';
|
|
8430
|
+
}
|
|
8431
|
+
// `<ng-template>` tags work the same regardless the namespace
|
|
8432
|
+
function isNgTemplate(tagName) {
|
|
8433
|
+
return splitNsName(tagName)[1] === 'ng-template';
|
|
8434
|
+
}
|
|
8435
|
+
function getNsPrefix(fullName) {
|
|
8436
|
+
return fullName === null ? null : splitNsName(fullName)[0];
|
|
8437
|
+
}
|
|
8438
|
+
function mergeNsAndName(prefix, localName) {
|
|
8439
|
+
return prefix ? `:${prefix}:${localName}` : localName;
|
|
8440
|
+
}
|
|
8441
|
+
|
|
8442
|
+
/**
|
|
8443
|
+
* Enumeration of the types of attributes which can be applied to an element.
|
|
8444
|
+
*/
|
|
8445
|
+
var ElementAttributeKind;
|
|
8446
|
+
(function (ElementAttributeKind) {
|
|
8447
|
+
/**
|
|
8448
|
+
* Static attributes.
|
|
8449
|
+
*/
|
|
8450
|
+
ElementAttributeKind[ElementAttributeKind["Attribute"] = 0] = "Attribute";
|
|
8451
|
+
/**
|
|
8452
|
+
* Class bindings.
|
|
8453
|
+
*/
|
|
8454
|
+
ElementAttributeKind[ElementAttributeKind["Class"] = 1] = "Class";
|
|
8455
|
+
/**
|
|
8456
|
+
* Style bindings.
|
|
8457
|
+
*/
|
|
8458
|
+
ElementAttributeKind[ElementAttributeKind["Style"] = 2] = "Style";
|
|
8459
|
+
/**
|
|
8460
|
+
* Dynamic property or attribute bindings.
|
|
8461
|
+
*/
|
|
8462
|
+
ElementAttributeKind[ElementAttributeKind["Binding"] = 3] = "Binding";
|
|
8463
|
+
/**
|
|
8464
|
+
* Attributes on a template node.
|
|
8465
|
+
*/
|
|
8466
|
+
ElementAttributeKind[ElementAttributeKind["Template"] = 4] = "Template";
|
|
8467
|
+
/**
|
|
8468
|
+
* Internationalized attributes.
|
|
8469
|
+
*/
|
|
8470
|
+
ElementAttributeKind[ElementAttributeKind["I18n"] = 5] = "I18n";
|
|
8471
|
+
})(ElementAttributeKind || (ElementAttributeKind = {}));
|
|
8472
|
+
const FLYWEIGHT_ARRAY = Object.freeze([]);
|
|
8473
|
+
/**
|
|
8474
|
+
* Container for all of the various kinds of attributes which are applied on an element.
|
|
8475
|
+
*/
|
|
8476
|
+
class ElementAttributes {
|
|
8477
|
+
constructor() {
|
|
8478
|
+
this.known = new Set();
|
|
8479
|
+
this.byKind = new Map;
|
|
8480
|
+
this.projectAs = null;
|
|
8481
|
+
}
|
|
8482
|
+
get attributes() {
|
|
8483
|
+
return this.byKind.get(ElementAttributeKind.Attribute) ?? FLYWEIGHT_ARRAY;
|
|
8484
|
+
}
|
|
8485
|
+
get classes() {
|
|
8486
|
+
return this.byKind.get(ElementAttributeKind.Class) ?? FLYWEIGHT_ARRAY;
|
|
8487
|
+
}
|
|
8488
|
+
get styles() {
|
|
8489
|
+
return this.byKind.get(ElementAttributeKind.Style) ?? FLYWEIGHT_ARRAY;
|
|
8490
|
+
}
|
|
8491
|
+
get bindings() {
|
|
8492
|
+
return this.byKind.get(ElementAttributeKind.Binding) ?? FLYWEIGHT_ARRAY;
|
|
8493
|
+
}
|
|
8494
|
+
get template() {
|
|
8495
|
+
return this.byKind.get(ElementAttributeKind.Template) ?? FLYWEIGHT_ARRAY;
|
|
8496
|
+
}
|
|
8497
|
+
get i18n() {
|
|
8498
|
+
return this.byKind.get(ElementAttributeKind.I18n) ?? FLYWEIGHT_ARRAY;
|
|
8499
|
+
}
|
|
8500
|
+
add(kind, name, value) {
|
|
8501
|
+
if (this.known.has(name)) {
|
|
8502
|
+
return;
|
|
8503
|
+
}
|
|
8504
|
+
this.known.add(name);
|
|
8505
|
+
const array = this.arrayFor(kind);
|
|
8506
|
+
array.push(...getAttributeNameLiterals$1(name));
|
|
8507
|
+
if (value !== null) {
|
|
8508
|
+
array.push(value);
|
|
8509
|
+
}
|
|
8510
|
+
}
|
|
8511
|
+
arrayFor(kind) {
|
|
8512
|
+
if (!this.byKind.has(kind)) {
|
|
8513
|
+
this.byKind.set(kind, []);
|
|
8514
|
+
}
|
|
8515
|
+
return this.byKind.get(kind);
|
|
8516
|
+
}
|
|
8517
|
+
}
|
|
8518
|
+
function getAttributeNameLiterals$1(name) {
|
|
8519
|
+
const [attributeNamespace, attributeName] = splitNsName(name);
|
|
8520
|
+
const nameLiteral = literal(attributeName);
|
|
8521
|
+
if (attributeNamespace) {
|
|
8522
|
+
return [
|
|
8523
|
+
literal(0 /* core.AttributeMarker.NamespaceURI */), literal(attributeNamespace), nameLiteral
|
|
8524
|
+
];
|
|
8525
|
+
}
|
|
8526
|
+
return [nameLiteral];
|
|
8527
|
+
}
|
|
8528
|
+
function assertIsElementAttributes(attrs) {
|
|
8529
|
+
if (!(attrs instanceof ElementAttributes)) {
|
|
8530
|
+
throw new Error(`AssertionError: ElementAttributes has already been coalesced into the view constants`);
|
|
8531
|
+
}
|
|
8532
|
+
}
|
|
8533
|
+
|
|
8534
|
+
/**
|
|
8535
|
+
* Distinguishes different kinds of IR operations.
|
|
8536
|
+
*
|
|
8537
|
+
* Includes both creation and update operations.
|
|
8538
|
+
*/
|
|
8539
|
+
var OpKind;
|
|
8540
|
+
(function (OpKind) {
|
|
8541
|
+
/**
|
|
8542
|
+
* A special operation type which is used to represent the beginning and end nodes of a linked
|
|
8543
|
+
* list of operations.
|
|
8544
|
+
*/
|
|
8545
|
+
OpKind[OpKind["ListEnd"] = 0] = "ListEnd";
|
|
8546
|
+
/**
|
|
8547
|
+
* An operation which wraps an output AST statement.
|
|
8548
|
+
*/
|
|
8549
|
+
OpKind[OpKind["Statement"] = 1] = "Statement";
|
|
8550
|
+
/**
|
|
8551
|
+
* An operation which declares and initializes a `SemanticVariable`.
|
|
8552
|
+
*/
|
|
8553
|
+
OpKind[OpKind["Variable"] = 2] = "Variable";
|
|
8554
|
+
/**
|
|
8555
|
+
* An operation to begin rendering of an element.
|
|
8556
|
+
*/
|
|
8557
|
+
OpKind[OpKind["ElementStart"] = 3] = "ElementStart";
|
|
8558
|
+
/**
|
|
8559
|
+
* An operation to render an element with no children.
|
|
8560
|
+
*/
|
|
8561
|
+
OpKind[OpKind["Element"] = 4] = "Element";
|
|
8562
|
+
/**
|
|
8563
|
+
* An operation which declares an embedded view.
|
|
8564
|
+
*/
|
|
8565
|
+
OpKind[OpKind["Template"] = 5] = "Template";
|
|
8566
|
+
/**
|
|
8567
|
+
* An operation to end rendering of an element previously started with `ElementStart`.
|
|
8568
|
+
*/
|
|
8569
|
+
OpKind[OpKind["ElementEnd"] = 6] = "ElementEnd";
|
|
8570
|
+
/**
|
|
8571
|
+
* An operation to render a text node.
|
|
8572
|
+
*/
|
|
8573
|
+
OpKind[OpKind["Text"] = 7] = "Text";
|
|
8574
|
+
/**
|
|
8575
|
+
* An operation declaring an event listener for an element.
|
|
8576
|
+
*/
|
|
8577
|
+
OpKind[OpKind["Listener"] = 8] = "Listener";
|
|
8578
|
+
/**
|
|
8579
|
+
* An operation to interpolate text into a text node.
|
|
8580
|
+
*/
|
|
8581
|
+
OpKind[OpKind["InterpolateText"] = 9] = "InterpolateText";
|
|
8582
|
+
/**
|
|
8583
|
+
* An operation to bind an expression to a property of an element.
|
|
8584
|
+
*/
|
|
8585
|
+
OpKind[OpKind["Property"] = 10] = "Property";
|
|
8586
|
+
/**
|
|
8587
|
+
* An operation to advance the runtime's implicit slot context during the update phase of a view.
|
|
8588
|
+
*/
|
|
8589
|
+
OpKind[OpKind["Advance"] = 11] = "Advance";
|
|
8590
|
+
})(OpKind || (OpKind = {}));
|
|
8591
|
+
/**
|
|
8592
|
+
* Distinguishes different kinds of IR expressions.
|
|
8593
|
+
*/
|
|
8594
|
+
var ExpressionKind;
|
|
8595
|
+
(function (ExpressionKind) {
|
|
8596
|
+
/**
|
|
8597
|
+
* Read of a variable in a lexical scope.
|
|
8598
|
+
*/
|
|
8599
|
+
ExpressionKind[ExpressionKind["LexicalRead"] = 0] = "LexicalRead";
|
|
8600
|
+
/**
|
|
8601
|
+
* A reference to the current view context.
|
|
8602
|
+
*/
|
|
8603
|
+
ExpressionKind[ExpressionKind["Context"] = 1] = "Context";
|
|
8604
|
+
/**
|
|
8605
|
+
* Read of a variable declared in a `VariableOp`.
|
|
8606
|
+
*/
|
|
8607
|
+
ExpressionKind[ExpressionKind["ReadVariable"] = 2] = "ReadVariable";
|
|
8608
|
+
/**
|
|
8609
|
+
* Runtime operation to navigate to the next view context in the view hierarchy.
|
|
8610
|
+
*/
|
|
8611
|
+
ExpressionKind[ExpressionKind["NextContext"] = 3] = "NextContext";
|
|
8612
|
+
/**
|
|
8613
|
+
* Runtime operation to retrieve the value of a local reference.
|
|
8614
|
+
*/
|
|
8615
|
+
ExpressionKind[ExpressionKind["Reference"] = 4] = "Reference";
|
|
8616
|
+
/**
|
|
8617
|
+
* Runtime operation to snapshot the current view context.
|
|
8618
|
+
*/
|
|
8619
|
+
ExpressionKind[ExpressionKind["GetCurrentView"] = 5] = "GetCurrentView";
|
|
8620
|
+
/**
|
|
8621
|
+
* Runtime operation to restore a snapshotted view.
|
|
8622
|
+
*/
|
|
8623
|
+
ExpressionKind[ExpressionKind["RestoreView"] = 6] = "RestoreView";
|
|
8624
|
+
/**
|
|
8625
|
+
* Runtime operation to reset the current view context after `RestoreView`.
|
|
8626
|
+
*/
|
|
8627
|
+
ExpressionKind[ExpressionKind["ResetView"] = 7] = "ResetView";
|
|
8628
|
+
})(ExpressionKind || (ExpressionKind = {}));
|
|
8629
|
+
/**
|
|
8630
|
+
* Distinguishes between different kinds of `SemanticVariable`s.
|
|
8631
|
+
*/
|
|
8632
|
+
var SemanticVariableKind;
|
|
8633
|
+
(function (SemanticVariableKind) {
|
|
8634
|
+
/**
|
|
8635
|
+
* Represents the context of a particular view.
|
|
8636
|
+
*/
|
|
8637
|
+
SemanticVariableKind[SemanticVariableKind["Context"] = 0] = "Context";
|
|
8638
|
+
/**
|
|
8639
|
+
* Represents an identifier declared in the lexical scope of a view.
|
|
8640
|
+
*/
|
|
8641
|
+
SemanticVariableKind[SemanticVariableKind["Identifier"] = 1] = "Identifier";
|
|
8642
|
+
/**
|
|
8643
|
+
* Represents a saved state that can be used to restore a view in a listener handler function.
|
|
8644
|
+
*/
|
|
8645
|
+
SemanticVariableKind[SemanticVariableKind["SavedView"] = 2] = "SavedView";
|
|
8646
|
+
})(SemanticVariableKind || (SemanticVariableKind = {}));
|
|
8647
|
+
|
|
8648
|
+
/**
|
|
8649
|
+
* Marker symbol for `ConsumesSlotOpTrait`.
|
|
8650
|
+
*/
|
|
8651
|
+
const ConsumesSlot = Symbol('ConsumesSlot');
|
|
8652
|
+
/**
|
|
8653
|
+
* Marker symbol for `DependsOnSlotContextOpTrait`.
|
|
8654
|
+
*/
|
|
8655
|
+
const DependsOnSlotContext = Symbol('DependsOnSlotContext');
|
|
8656
|
+
/**
|
|
8657
|
+
* Marker symbol for `UsesSlotIndex` trait.
|
|
8658
|
+
*/
|
|
8659
|
+
const UsesSlotIndex = Symbol('UsesSlotIndex');
|
|
8660
|
+
/**
|
|
8661
|
+
* Marker symbol for `ConsumesVars` trait.
|
|
8662
|
+
*/
|
|
8663
|
+
const ConsumesVarsTrait = Symbol('UsesVars');
|
|
8664
|
+
/**
|
|
8665
|
+
* Default values for most `ConsumesSlotOpTrait` fields (used with the spread operator to initialize
|
|
8666
|
+
* implementors of the trait).
|
|
8667
|
+
*/
|
|
8668
|
+
const TRAIT_CONSUMES_SLOT = {
|
|
8669
|
+
[ConsumesSlot]: true,
|
|
8670
|
+
slot: null,
|
|
8671
|
+
numSlotsUsed: 1,
|
|
8672
|
+
};
|
|
8673
|
+
/**
|
|
8674
|
+
* Default values for most `DependsOnSlotContextOpTrait` fields (used with the spread operator to
|
|
8675
|
+
* initialize implementors of the trait).
|
|
8676
|
+
*/
|
|
8677
|
+
const TRAIT_DEPENDS_ON_SLOT_CONTEXT = {
|
|
8678
|
+
[DependsOnSlotContext]: true,
|
|
8679
|
+
};
|
|
8680
|
+
/**
|
|
8681
|
+
* Default values for `UsesVars` fields (used with the spread operator to initialize
|
|
8682
|
+
* implementors of the trait).
|
|
8683
|
+
*/
|
|
8684
|
+
const TRAIT_CONSUMES_VARS = {
|
|
8685
|
+
[ConsumesVarsTrait]: true,
|
|
8686
|
+
};
|
|
8687
|
+
/**
|
|
8688
|
+
* Test whether an operation implements `ConsumesSlotOpTrait`.
|
|
8689
|
+
*/
|
|
8690
|
+
function hasConsumesSlotTrait(op) {
|
|
8691
|
+
return op[ConsumesSlot] === true;
|
|
8692
|
+
}
|
|
8693
|
+
/**
|
|
8694
|
+
* Test whether an operation implements `DependsOnSlotContextOpTrait`.
|
|
8695
|
+
*/
|
|
8696
|
+
function hasDependsOnSlotContextTrait(op) {
|
|
8697
|
+
return op[DependsOnSlotContext] === true;
|
|
8698
|
+
}
|
|
8699
|
+
function hasConsumesVarsTrait(value) {
|
|
8700
|
+
return value[ConsumesVarsTrait] === true;
|
|
8701
|
+
}
|
|
8702
|
+
/**
|
|
8703
|
+
* Test whether an expression implements `UsesSlotIndexExprTrait`.
|
|
8704
|
+
*/
|
|
8705
|
+
function hasUsesSlotIndexTrait(expr) {
|
|
8706
|
+
return expr[UsesSlotIndex] === true;
|
|
8707
|
+
}
|
|
8708
|
+
|
|
8709
|
+
var _a;
|
|
8710
|
+
/**
|
|
8711
|
+
* Check whether a given `o.Expression` is a logical IR expression type.
|
|
8712
|
+
*/
|
|
8713
|
+
function isIrExpression(expr) {
|
|
8714
|
+
return expr instanceof ExpressionBase;
|
|
8715
|
+
}
|
|
8716
|
+
/**
|
|
8717
|
+
* Base type used for all logical IR expressions.
|
|
8718
|
+
*/
|
|
8719
|
+
class ExpressionBase extends Expression {
|
|
8720
|
+
constructor(sourceSpan = null) {
|
|
8721
|
+
super(null, sourceSpan);
|
|
8722
|
+
}
|
|
8723
|
+
}
|
|
8724
|
+
/**
|
|
8725
|
+
* Logical expression representing a lexical read of a variable name.
|
|
8726
|
+
*/
|
|
8727
|
+
class LexicalReadExpr extends ExpressionBase {
|
|
8728
|
+
constructor(name) {
|
|
8729
|
+
super();
|
|
8730
|
+
this.name = name;
|
|
8731
|
+
this.kind = ExpressionKind.LexicalRead;
|
|
8732
|
+
}
|
|
8733
|
+
visitExpression(visitor, context) { }
|
|
8734
|
+
isEquivalent() {
|
|
8735
|
+
return false;
|
|
8736
|
+
}
|
|
8737
|
+
isConstant() {
|
|
8738
|
+
return false;
|
|
8739
|
+
}
|
|
8740
|
+
transformInternalExpressions() { }
|
|
8741
|
+
}
|
|
8742
|
+
/**
|
|
8743
|
+
* Runtime operation to retrieve the value of a local reference.
|
|
8744
|
+
*/
|
|
8745
|
+
class ReferenceExpr extends ExpressionBase {
|
|
8746
|
+
static { _a = UsesSlotIndex; }
|
|
8747
|
+
constructor(target, offset) {
|
|
8748
|
+
super();
|
|
8749
|
+
this.target = target;
|
|
8750
|
+
this.offset = offset;
|
|
8751
|
+
this.kind = ExpressionKind.Reference;
|
|
8752
|
+
this[_a] = true;
|
|
8753
|
+
this.slot = null;
|
|
8754
|
+
}
|
|
8755
|
+
visitExpression() { }
|
|
8756
|
+
isEquivalent(e) {
|
|
8757
|
+
return e instanceof ReferenceExpr && e.target === this.target;
|
|
8758
|
+
}
|
|
8759
|
+
isConstant() {
|
|
8760
|
+
return false;
|
|
8761
|
+
}
|
|
8762
|
+
transformInternalExpressions() { }
|
|
8763
|
+
}
|
|
8764
|
+
/**
|
|
8765
|
+
* A reference to the current view context (usually the `ctx` variable in a template function).
|
|
8766
|
+
*/
|
|
8767
|
+
class ContextExpr extends ExpressionBase {
|
|
8768
|
+
constructor(view) {
|
|
8769
|
+
super();
|
|
8770
|
+
this.view = view;
|
|
8771
|
+
this.kind = ExpressionKind.Context;
|
|
8772
|
+
}
|
|
8773
|
+
visitExpression() { }
|
|
8774
|
+
isEquivalent(e) {
|
|
8775
|
+
return e instanceof ContextExpr && e.view === this.view;
|
|
8776
|
+
}
|
|
8777
|
+
isConstant() {
|
|
8778
|
+
return false;
|
|
8779
|
+
}
|
|
8780
|
+
transformInternalExpressions() { }
|
|
8781
|
+
}
|
|
8782
|
+
/**
|
|
8783
|
+
* Runtime operation to navigate to the next view context in the view hierarchy.
|
|
8784
|
+
*/
|
|
8785
|
+
class NextContextExpr extends ExpressionBase {
|
|
8786
|
+
constructor() {
|
|
8787
|
+
super();
|
|
8788
|
+
this.kind = ExpressionKind.NextContext;
|
|
8789
|
+
}
|
|
8790
|
+
visitExpression() { }
|
|
8791
|
+
isEquivalent(e) {
|
|
8792
|
+
return e instanceof NextContextExpr;
|
|
8793
|
+
}
|
|
8794
|
+
isConstant() {
|
|
8795
|
+
return false;
|
|
8796
|
+
}
|
|
8797
|
+
transformInternalExpressions() { }
|
|
8798
|
+
}
|
|
8799
|
+
/**
|
|
8800
|
+
* Runtime operation to snapshot the current view context.
|
|
8801
|
+
*
|
|
8802
|
+
* The result of this operation can be stored in a variable and later used with the `RestoreView`
|
|
8803
|
+
* operation.
|
|
8804
|
+
*/
|
|
8805
|
+
class GetCurrentViewExpr extends ExpressionBase {
|
|
8806
|
+
constructor() {
|
|
8807
|
+
super();
|
|
8808
|
+
this.kind = ExpressionKind.GetCurrentView;
|
|
8809
|
+
}
|
|
8810
|
+
visitExpression() { }
|
|
8811
|
+
isEquivalent(e) {
|
|
8812
|
+
return e instanceof GetCurrentViewExpr;
|
|
8813
|
+
}
|
|
8814
|
+
isConstant() {
|
|
8815
|
+
return false;
|
|
8816
|
+
}
|
|
8817
|
+
transformInternalExpressions() { }
|
|
8818
|
+
}
|
|
8819
|
+
/**
|
|
8820
|
+
* Runtime operation to restore a snapshotted view.
|
|
8821
|
+
*/
|
|
8822
|
+
class RestoreViewExpr extends ExpressionBase {
|
|
8823
|
+
constructor(view) {
|
|
8824
|
+
super();
|
|
8825
|
+
this.view = view;
|
|
8826
|
+
this.kind = ExpressionKind.RestoreView;
|
|
8827
|
+
}
|
|
8828
|
+
visitExpression(visitor, context) {
|
|
8829
|
+
if (typeof this.view !== 'number') {
|
|
8830
|
+
this.view.visitExpression(visitor, context);
|
|
8831
|
+
}
|
|
8832
|
+
}
|
|
8833
|
+
isEquivalent(e) {
|
|
8834
|
+
if (!(e instanceof RestoreViewExpr) || typeof e.view !== typeof this.view) {
|
|
8835
|
+
return false;
|
|
8836
|
+
}
|
|
8837
|
+
if (typeof this.view === 'number') {
|
|
8838
|
+
return this.view === e.view;
|
|
8839
|
+
}
|
|
8840
|
+
else {
|
|
8841
|
+
return this.view.isEquivalent(e.view);
|
|
8842
|
+
}
|
|
8843
|
+
}
|
|
8844
|
+
isConstant() {
|
|
8845
|
+
return false;
|
|
8846
|
+
}
|
|
8847
|
+
transformInternalExpressions(transform) {
|
|
8848
|
+
if (typeof this.view !== 'number') {
|
|
8849
|
+
this.view = transformExpressionsInExpression(this.view, transform);
|
|
8850
|
+
}
|
|
8851
|
+
}
|
|
8852
|
+
}
|
|
8853
|
+
/**
|
|
8854
|
+
* Runtime operation to reset the current view context after `RestoreView`.
|
|
8855
|
+
*/
|
|
8856
|
+
class ResetViewExpr extends ExpressionBase {
|
|
8857
|
+
constructor(expr) {
|
|
8858
|
+
super();
|
|
8859
|
+
this.expr = expr;
|
|
8860
|
+
this.kind = ExpressionKind.ResetView;
|
|
8861
|
+
}
|
|
8862
|
+
visitExpression(visitor, context) {
|
|
8863
|
+
this.expr.visitExpression(visitor, context);
|
|
8864
|
+
}
|
|
8865
|
+
isEquivalent(e) {
|
|
8866
|
+
return e instanceof ResetViewExpr && this.expr.isEquivalent(e.expr);
|
|
8867
|
+
}
|
|
8868
|
+
isConstant() {
|
|
8869
|
+
return false;
|
|
8870
|
+
}
|
|
8871
|
+
transformInternalExpressions(transform) {
|
|
8872
|
+
this.expr = transformExpressionsInExpression(this.expr, transform);
|
|
8873
|
+
}
|
|
8874
|
+
}
|
|
8875
|
+
/**
|
|
8876
|
+
* Read of a variable declared as an `ir.VariableOp` and referenced through its `ir.XrefId`.
|
|
8877
|
+
*/
|
|
8878
|
+
class ReadVariableExpr extends ExpressionBase {
|
|
8879
|
+
constructor(xref) {
|
|
8880
|
+
super();
|
|
8881
|
+
this.xref = xref;
|
|
8882
|
+
this.kind = ExpressionKind.ReadVariable;
|
|
8883
|
+
this.name = null;
|
|
8884
|
+
}
|
|
8885
|
+
visitExpression() { }
|
|
8886
|
+
isEquivalent(other) {
|
|
8887
|
+
return other instanceof ReadVariableExpr && other.xref === this.xref;
|
|
8888
|
+
}
|
|
8889
|
+
isConstant() {
|
|
8890
|
+
return false;
|
|
8891
|
+
}
|
|
8892
|
+
transformInternalExpressions() { }
|
|
8893
|
+
}
|
|
8894
|
+
/**
|
|
8895
|
+
* Visits all `Expression`s in the AST of `op` with the `visitor` function.
|
|
8896
|
+
*/
|
|
8897
|
+
function visitExpressionsInOp(op, visitor) {
|
|
8898
|
+
transformExpressionsInOp(op, (expr) => {
|
|
8899
|
+
visitor(expr);
|
|
8900
|
+
return expr;
|
|
8901
|
+
});
|
|
8902
|
+
}
|
|
8903
|
+
/**
|
|
8904
|
+
* Transform all `Expression`s in the AST of `op` with the `transform` function.
|
|
8905
|
+
*
|
|
8906
|
+
* All such operations will be replaced with the result of applying `transform`, which may be an
|
|
8907
|
+
* identity transformation.
|
|
8908
|
+
*/
|
|
8909
|
+
function transformExpressionsInOp(op, transform) {
|
|
8910
|
+
switch (op.kind) {
|
|
8911
|
+
case OpKind.Property:
|
|
8912
|
+
op.expression = transformExpressionsInExpression(op.expression, transform);
|
|
8913
|
+
break;
|
|
8914
|
+
case OpKind.Statement:
|
|
8915
|
+
transformExpressionsInStatement(op.statement, transform);
|
|
8916
|
+
break;
|
|
8917
|
+
case OpKind.Variable:
|
|
8918
|
+
op.initializer = transformExpressionsInExpression(op.initializer, transform);
|
|
8919
|
+
break;
|
|
8920
|
+
case OpKind.InterpolateText:
|
|
8921
|
+
for (let i = 0; i < op.expressions.length; i++) {
|
|
8922
|
+
op.expressions[i] = transformExpressionsInExpression(op.expressions[i], transform);
|
|
8923
|
+
}
|
|
8924
|
+
break;
|
|
8925
|
+
case OpKind.Listener:
|
|
8926
|
+
for (const innerOp of op.handlerOps) {
|
|
8927
|
+
transformExpressionsInOp(innerOp, transform);
|
|
8928
|
+
}
|
|
8929
|
+
break;
|
|
8930
|
+
case OpKind.Element:
|
|
8931
|
+
case OpKind.ElementStart:
|
|
8932
|
+
case OpKind.ElementEnd:
|
|
8933
|
+
case OpKind.Template:
|
|
8934
|
+
case OpKind.Text:
|
|
8935
|
+
// These operations contain no expressions.
|
|
8936
|
+
break;
|
|
8937
|
+
default:
|
|
8938
|
+
throw new Error(`AssertionError: transformExpressionsInOp doesn't handle ${OpKind[op.kind]}`);
|
|
8939
|
+
}
|
|
8940
|
+
}
|
|
8941
|
+
/**
|
|
8942
|
+
* Transform all `Expression`s in the AST of `expr` with the `transform` function.
|
|
8943
|
+
*
|
|
8944
|
+
* All such operations will be replaced with the result of applying `transform`, which may be an
|
|
8945
|
+
* identity transformation.
|
|
8946
|
+
*/
|
|
8947
|
+
function transformExpressionsInExpression(expr, transform) {
|
|
8948
|
+
if (expr instanceof ExpressionBase) {
|
|
8949
|
+
expr.transformInternalExpressions(transform);
|
|
8950
|
+
return transform(expr);
|
|
8951
|
+
}
|
|
8952
|
+
else if (expr instanceof BinaryOperatorExpr) {
|
|
8953
|
+
expr.lhs = transformExpressionsInExpression(expr.lhs, transform);
|
|
8954
|
+
expr.rhs = transformExpressionsInExpression(expr.rhs, transform);
|
|
8955
|
+
}
|
|
8956
|
+
else if (expr instanceof ReadPropExpr) {
|
|
8957
|
+
expr.receiver = transformExpressionsInExpression(expr.receiver, transform);
|
|
8958
|
+
}
|
|
8959
|
+
else if (expr instanceof InvokeFunctionExpr) {
|
|
8960
|
+
expr.fn = transformExpressionsInExpression(expr.fn, transform);
|
|
8961
|
+
for (let i = 0; i < expr.args.length; i++) {
|
|
8962
|
+
expr.args[i] = transformExpressionsInExpression(expr.args[i], transform);
|
|
8963
|
+
}
|
|
8964
|
+
}
|
|
8965
|
+
else if (expr instanceof ReadVarExpr || expr instanceof ExternalExpr ||
|
|
8966
|
+
expr instanceof LiteralExpr) {
|
|
8967
|
+
// No action for these types.
|
|
8968
|
+
}
|
|
8969
|
+
else {
|
|
8970
|
+
throw new Error(`Unhandled expression kind: ${expr.constructor.name}`);
|
|
8971
|
+
}
|
|
8972
|
+
return expr;
|
|
8973
|
+
}
|
|
8974
|
+
/**
|
|
8975
|
+
* Transform all `Expression`s in the AST of `stmt` with the `transform` function.
|
|
8976
|
+
*
|
|
8977
|
+
* All such operations will be replaced with the result of applying `transform`, which may be an
|
|
8978
|
+
* identity transformation.
|
|
8979
|
+
*/
|
|
8980
|
+
function transformExpressionsInStatement(stmt, transform) {
|
|
8981
|
+
if (stmt instanceof ExpressionStatement) {
|
|
8982
|
+
stmt.expr = transformExpressionsInExpression(stmt.expr, transform);
|
|
8983
|
+
}
|
|
8984
|
+
else if (stmt instanceof ReturnStatement) {
|
|
8985
|
+
stmt.value = transformExpressionsInExpression(stmt.value, transform);
|
|
8986
|
+
}
|
|
8987
|
+
else {
|
|
8988
|
+
throw new Error(`Unhandled statement kind: ${stmt.constructor.name}`);
|
|
8989
|
+
}
|
|
8990
|
+
}
|
|
8991
|
+
|
|
8992
|
+
/**
|
|
8993
|
+
* A linked list of `Op` nodes of a given subtype.
|
|
8994
|
+
*
|
|
8995
|
+
* @param OpT specific subtype of `Op` nodes which this list contains.
|
|
8996
|
+
*/
|
|
8997
|
+
class OpList {
|
|
8998
|
+
static { this.nextListId = 0; }
|
|
8999
|
+
constructor() {
|
|
9000
|
+
/**
|
|
9001
|
+
* Debug ID of this `OpList` instance.
|
|
9002
|
+
*/
|
|
9003
|
+
this.debugListId = OpList.nextListId++;
|
|
9004
|
+
// OpList uses static head/tail nodes of a special `ListEnd` type.
|
|
9005
|
+
// This avoids the need for special casing of the first and last list
|
|
9006
|
+
// elements in all list operations.
|
|
9007
|
+
this.head = {
|
|
9008
|
+
kind: OpKind.ListEnd,
|
|
9009
|
+
next: null,
|
|
9010
|
+
prev: null,
|
|
9011
|
+
debugListId: this.debugListId,
|
|
9012
|
+
};
|
|
9013
|
+
this.tail = {
|
|
9014
|
+
kind: OpKind.ListEnd,
|
|
9015
|
+
next: null,
|
|
9016
|
+
prev: null,
|
|
9017
|
+
debugListId: this.debugListId,
|
|
9018
|
+
};
|
|
9019
|
+
// Link `head` and `tail` together at the start (list is empty).
|
|
9020
|
+
this.head.next = this.tail;
|
|
9021
|
+
this.tail.prev = this.head;
|
|
9022
|
+
}
|
|
9023
|
+
/**
|
|
9024
|
+
* Push a new operation to the tail of the list.
|
|
9025
|
+
*/
|
|
9026
|
+
push(op) {
|
|
9027
|
+
OpList.assertIsNotEnd(op);
|
|
9028
|
+
OpList.assertIsUnowned(op);
|
|
9029
|
+
op.debugListId = this.debugListId;
|
|
9030
|
+
// The old "previous" node (which might be the head, if the list is empty).
|
|
9031
|
+
const oldLast = this.tail.prev;
|
|
9032
|
+
// Insert `op` following the old last node.
|
|
9033
|
+
op.prev = oldLast;
|
|
9034
|
+
oldLast.next = op;
|
|
9035
|
+
// Connect `op` with the list tail.
|
|
9036
|
+
op.next = this.tail;
|
|
9037
|
+
this.tail.prev = op;
|
|
9038
|
+
}
|
|
9039
|
+
/**
|
|
9040
|
+
* Prepend one or more nodes to the start of the list.
|
|
9041
|
+
*/
|
|
9042
|
+
prepend(ops) {
|
|
9043
|
+
if (ops.length === 0) {
|
|
9044
|
+
return;
|
|
9045
|
+
}
|
|
9046
|
+
for (const op of ops) {
|
|
9047
|
+
OpList.assertIsNotEnd(op);
|
|
9048
|
+
OpList.assertIsUnowned(op);
|
|
9049
|
+
op.debugListId = this.debugListId;
|
|
9050
|
+
}
|
|
9051
|
+
const first = this.head.next;
|
|
9052
|
+
let prev = this.head;
|
|
9053
|
+
for (const op of ops) {
|
|
9054
|
+
prev.next = op;
|
|
9055
|
+
op.prev = prev;
|
|
9056
|
+
prev = op;
|
|
9057
|
+
}
|
|
9058
|
+
prev.next = first;
|
|
9059
|
+
first.prev = prev;
|
|
9060
|
+
}
|
|
9061
|
+
/**
|
|
9062
|
+
* `OpList` is iterable via the iteration protocol.
|
|
9063
|
+
*
|
|
9064
|
+
* It's safe to mutate the part of the list that has already been returned by the iterator, up to
|
|
9065
|
+
* and including the last operation returned. Mutations beyond that point _may_ be safe, but may
|
|
9066
|
+
* also corrupt the iteration position and should be avoided.
|
|
9067
|
+
*/
|
|
9068
|
+
*[Symbol.iterator]() {
|
|
9069
|
+
let current = this.head.next;
|
|
9070
|
+
while (current !== this.tail) {
|
|
9071
|
+
// Guards against corruption of the iterator state by mutations to the tail of the list during
|
|
9072
|
+
// iteration.
|
|
9073
|
+
OpList.assertIsOwned(current);
|
|
9074
|
+
const next = current.next;
|
|
9075
|
+
yield current;
|
|
9076
|
+
current = next;
|
|
9077
|
+
}
|
|
9078
|
+
}
|
|
9079
|
+
/**
|
|
9080
|
+
* Replace `oldOp` with `newOp` in the list.
|
|
9081
|
+
*/
|
|
9082
|
+
static replace(oldOp, newOp) {
|
|
9083
|
+
OpList.assertIsNotEnd(oldOp);
|
|
9084
|
+
OpList.assertIsNotEnd(newOp);
|
|
9085
|
+
OpList.assertIsOwned(oldOp);
|
|
9086
|
+
OpList.assertIsUnowned(newOp);
|
|
9087
|
+
newOp.debugListId = oldOp.debugListId;
|
|
9088
|
+
if (oldOp.prev !== null) {
|
|
9089
|
+
oldOp.prev.next = newOp;
|
|
9090
|
+
newOp.prev = oldOp.prev;
|
|
9091
|
+
}
|
|
9092
|
+
if (oldOp.next !== null) {
|
|
9093
|
+
oldOp.next.prev = newOp;
|
|
9094
|
+
newOp.next = oldOp.next;
|
|
9095
|
+
}
|
|
9096
|
+
oldOp.debugListId = null;
|
|
9097
|
+
oldOp.prev = null;
|
|
9098
|
+
oldOp.next = null;
|
|
9099
|
+
}
|
|
9100
|
+
/**
|
|
9101
|
+
* Replace `oldOp` with some number of new operations in the list (which may include `oldOp`).
|
|
9102
|
+
*/
|
|
9103
|
+
static replaceWithMany(oldOp, newOps) {
|
|
9104
|
+
if (newOps.length === 0) {
|
|
9105
|
+
// Replacing with an empty list -> pure removal.
|
|
9106
|
+
OpList.remove(oldOp);
|
|
9107
|
+
return;
|
|
9108
|
+
}
|
|
9109
|
+
OpList.assertIsNotEnd(oldOp);
|
|
9110
|
+
OpList.assertIsOwned(oldOp);
|
|
9111
|
+
const listId = oldOp.debugListId;
|
|
9112
|
+
oldOp.debugListId = null;
|
|
9113
|
+
for (const newOp of newOps) {
|
|
9114
|
+
OpList.assertIsNotEnd(newOp);
|
|
9115
|
+
// `newOp` might be `oldOp`, but at this point it's been marked as unowned.
|
|
9116
|
+
OpList.assertIsUnowned(newOp);
|
|
9117
|
+
}
|
|
9118
|
+
// It should be safe to reuse `oldOp` in the `newOps` list - maybe you want to sandwich an
|
|
9119
|
+
// operation between two new ops.
|
|
9120
|
+
const { prev: oldPrev, next: oldNext } = oldOp;
|
|
9121
|
+
oldOp.prev = null;
|
|
9122
|
+
oldOp.next = null;
|
|
9123
|
+
let prev = oldPrev;
|
|
9124
|
+
for (const newOp of newOps) {
|
|
9125
|
+
this.assertIsUnowned(newOp);
|
|
9126
|
+
newOp.debugListId = listId;
|
|
9127
|
+
prev.next = newOp;
|
|
9128
|
+
newOp.prev = prev;
|
|
9129
|
+
// This _should_ be the case, but set it just in case.
|
|
9130
|
+
newOp.next = null;
|
|
9131
|
+
prev = newOp;
|
|
9132
|
+
}
|
|
9133
|
+
// At the end of iteration, `prev` holds the last node in the list.
|
|
9134
|
+
const first = newOps[0];
|
|
9135
|
+
const last = prev;
|
|
9136
|
+
// Replace `oldOp` with the chain `first` -> `last`.
|
|
9137
|
+
if (oldPrev !== null) {
|
|
9138
|
+
oldPrev.next = first;
|
|
9139
|
+
first.prev = oldOp.prev;
|
|
9140
|
+
}
|
|
9141
|
+
if (oldNext !== null) {
|
|
9142
|
+
oldNext.prev = last;
|
|
9143
|
+
last.next = oldNext;
|
|
9144
|
+
}
|
|
9145
|
+
}
|
|
9146
|
+
/**
|
|
9147
|
+
* Remove the given node from the list which contains it.
|
|
9148
|
+
*/
|
|
9149
|
+
static remove(op) {
|
|
9150
|
+
OpList.assertIsNotEnd(op);
|
|
9151
|
+
OpList.assertIsOwned(op);
|
|
9152
|
+
op.prev.next = op.next;
|
|
9153
|
+
op.next.prev = op.prev;
|
|
9154
|
+
// Break any link between the node and this list to safeguard against its usage in future
|
|
9155
|
+
// operations.
|
|
9156
|
+
op.debugListId = null;
|
|
9157
|
+
op.prev = null;
|
|
9158
|
+
op.next = null;
|
|
9159
|
+
}
|
|
9160
|
+
/**
|
|
9161
|
+
* Insert `op` before `before`.
|
|
9162
|
+
*/
|
|
9163
|
+
static insertBefore(op, before) {
|
|
9164
|
+
OpList.assertIsNotEnd(before);
|
|
9165
|
+
OpList.assertIsNotEnd(op);
|
|
9166
|
+
OpList.assertIsUnowned(op);
|
|
9167
|
+
OpList.assertIsOwned(before, op.debugListId);
|
|
9168
|
+
op.debugListId = before.debugListId;
|
|
9169
|
+
// Just in case.
|
|
9170
|
+
op.prev = null;
|
|
9171
|
+
before.prev.next = op;
|
|
9172
|
+
op.prev = before.prev;
|
|
9173
|
+
op.next = before;
|
|
9174
|
+
before.prev = op;
|
|
9175
|
+
}
|
|
9176
|
+
/**
|
|
9177
|
+
* Asserts that `op` does not currently belong to a list.
|
|
9178
|
+
*/
|
|
9179
|
+
static assertIsUnowned(op) {
|
|
9180
|
+
if (op.debugListId !== null) {
|
|
9181
|
+
throw new Error(`AssertionError: illegal operation on owned node: ${OpKind[op.kind]}`);
|
|
9182
|
+
}
|
|
9183
|
+
}
|
|
9184
|
+
/**
|
|
9185
|
+
* Asserts that `op` currently belongs to a list. If `byList` is passed, `op` is asserted to
|
|
9186
|
+
* specifically belong to that list.
|
|
9187
|
+
*/
|
|
9188
|
+
static assertIsOwned(op, byList) {
|
|
9189
|
+
if (op.debugListId === null) {
|
|
9190
|
+
throw new Error(`AssertionError: illegal operation on unowned node: ${OpKind[op.kind]}`);
|
|
9191
|
+
}
|
|
9192
|
+
else if (byList !== undefined && op.debugListId !== byList) {
|
|
9193
|
+
throw new Error(`AssertionError: node belongs to the wrong list (expected ${byList}, actual ${op.debugListId})`);
|
|
9194
|
+
}
|
|
9195
|
+
}
|
|
9196
|
+
/**
|
|
9197
|
+
* Asserts that `op` is not a special `ListEnd` node.
|
|
9198
|
+
*/
|
|
9199
|
+
static assertIsNotEnd(op) {
|
|
9200
|
+
if (op.kind === OpKind.ListEnd) {
|
|
9201
|
+
throw new Error(`AssertionError: illegal operation on list head or tail`);
|
|
9202
|
+
}
|
|
9203
|
+
}
|
|
9204
|
+
}
|
|
9205
|
+
|
|
9206
|
+
/**
|
|
9207
|
+
* Create a `StatementOp`.
|
|
9208
|
+
*/
|
|
9209
|
+
function createStatementOp(statement) {
|
|
9210
|
+
return {
|
|
9211
|
+
kind: OpKind.Statement,
|
|
9212
|
+
statement,
|
|
9213
|
+
...NEW_OP,
|
|
9214
|
+
};
|
|
9215
|
+
}
|
|
9216
|
+
/**
|
|
9217
|
+
* Create a `VariableOp`.
|
|
9218
|
+
*/
|
|
9219
|
+
function createVariableOp(xref, variable, initializer) {
|
|
9220
|
+
return {
|
|
9221
|
+
kind: OpKind.Variable,
|
|
9222
|
+
xref,
|
|
9223
|
+
name: null,
|
|
9224
|
+
variable,
|
|
9225
|
+
initializer,
|
|
9226
|
+
...NEW_OP,
|
|
9227
|
+
};
|
|
9228
|
+
}
|
|
9229
|
+
/**
|
|
9230
|
+
* Static structure shared by all operations.
|
|
9231
|
+
*
|
|
9232
|
+
* Used as a convenience via the spread operator (`...NEW_OP`) when creating new operations, and
|
|
9233
|
+
* ensures the fields are always in the same order.
|
|
9234
|
+
*/
|
|
9235
|
+
const NEW_OP = {
|
|
9236
|
+
debugListId: null,
|
|
9237
|
+
prev: null,
|
|
9238
|
+
next: null,
|
|
9239
|
+
};
|
|
9240
|
+
|
|
9241
|
+
/**
|
|
9242
|
+
* Create an `ElementStartOp`.
|
|
9243
|
+
*/
|
|
9244
|
+
function createElementStartOp(tag, xref) {
|
|
9245
|
+
return {
|
|
9246
|
+
kind: OpKind.ElementStart,
|
|
9247
|
+
xref,
|
|
9248
|
+
tag,
|
|
9249
|
+
attributes: new ElementAttributes(),
|
|
9250
|
+
localRefs: [],
|
|
9251
|
+
...TRAIT_CONSUMES_SLOT,
|
|
9252
|
+
...NEW_OP,
|
|
9253
|
+
};
|
|
9254
|
+
}
|
|
9255
|
+
/**
|
|
9256
|
+
* Create a `TemplateOp`.
|
|
9257
|
+
*/
|
|
9258
|
+
function createTemplateOp(xref, tag) {
|
|
9259
|
+
return {
|
|
9260
|
+
kind: OpKind.Template,
|
|
9261
|
+
xref,
|
|
9262
|
+
attributes: new ElementAttributes(),
|
|
9263
|
+
tag,
|
|
9264
|
+
decls: null,
|
|
9265
|
+
vars: null,
|
|
9266
|
+
localRefs: [],
|
|
9267
|
+
...TRAIT_CONSUMES_SLOT,
|
|
9268
|
+
...NEW_OP,
|
|
9269
|
+
};
|
|
9270
|
+
}
|
|
9271
|
+
/**
|
|
9272
|
+
* Create an `ElementEndOp`.
|
|
9273
|
+
*/
|
|
9274
|
+
function createElementEndOp(xref) {
|
|
9275
|
+
return {
|
|
9276
|
+
kind: OpKind.ElementEnd,
|
|
9277
|
+
xref,
|
|
9278
|
+
...NEW_OP,
|
|
9279
|
+
};
|
|
9280
|
+
}
|
|
9281
|
+
/**
|
|
9282
|
+
* Create a `TextOp`.
|
|
9283
|
+
*/
|
|
9284
|
+
function createTextOp(xref, initialValue) {
|
|
9285
|
+
return {
|
|
9286
|
+
kind: OpKind.Text,
|
|
9287
|
+
xref,
|
|
9288
|
+
initialValue,
|
|
9289
|
+
...TRAIT_CONSUMES_SLOT,
|
|
9290
|
+
...NEW_OP,
|
|
9291
|
+
};
|
|
9292
|
+
}
|
|
9293
|
+
/**
|
|
9294
|
+
* Create a `ListenerOp`.
|
|
9295
|
+
*/
|
|
9296
|
+
function createListenerOp(xref, name) {
|
|
9297
|
+
return {
|
|
9298
|
+
kind: OpKind.Listener,
|
|
9299
|
+
xref,
|
|
9300
|
+
name,
|
|
9301
|
+
handlerOps: new OpList(),
|
|
9302
|
+
handlerFnName: null,
|
|
9303
|
+
...NEW_OP,
|
|
9304
|
+
};
|
|
9305
|
+
}
|
|
9306
|
+
|
|
9307
|
+
/**
|
|
9308
|
+
* Create an `InterpolationTextOp`.
|
|
9309
|
+
*/
|
|
9310
|
+
function createInterpolateTextOp(xref, strings, expressions) {
|
|
9311
|
+
return {
|
|
9312
|
+
kind: OpKind.InterpolateText,
|
|
9313
|
+
target: xref,
|
|
9314
|
+
strings,
|
|
9315
|
+
expressions,
|
|
9316
|
+
...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
|
|
9317
|
+
...TRAIT_CONSUMES_VARS,
|
|
9318
|
+
...NEW_OP,
|
|
9319
|
+
};
|
|
9320
|
+
}
|
|
9321
|
+
/**
|
|
9322
|
+
* Create a `PropertyOp`.
|
|
9323
|
+
*/
|
|
9324
|
+
function createPropertyOp(xref, name, expression) {
|
|
9325
|
+
return {
|
|
9326
|
+
kind: OpKind.Property,
|
|
9327
|
+
target: xref,
|
|
9328
|
+
name,
|
|
9329
|
+
expression,
|
|
9330
|
+
...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
|
|
9331
|
+
...TRAIT_CONSUMES_VARS,
|
|
9332
|
+
...NEW_OP,
|
|
9333
|
+
};
|
|
9334
|
+
}
|
|
9335
|
+
/**
|
|
9336
|
+
* Create an `AdvanceOp`.
|
|
9337
|
+
*/
|
|
9338
|
+
function createAdvanceOp(delta) {
|
|
9339
|
+
return {
|
|
9340
|
+
kind: OpKind.Advance,
|
|
9341
|
+
delta,
|
|
9342
|
+
...NEW_OP,
|
|
9343
|
+
};
|
|
9344
|
+
}
|
|
9345
|
+
|
|
9346
|
+
/**
|
|
9347
|
+
* Converts the semantic attributes of element-like operations (elements, templates) into constant
|
|
9348
|
+
* array expressions, and lifts them into the overall component `consts`.
|
|
9349
|
+
*/
|
|
9350
|
+
function phaseConstCollection(cpl) {
|
|
9351
|
+
for (const [_, view] of cpl.views) {
|
|
9352
|
+
for (const op of view.create) {
|
|
9353
|
+
if (op.kind !== OpKind.ElementStart && op.kind !== OpKind.Element &&
|
|
9354
|
+
op.kind !== OpKind.Template) {
|
|
9355
|
+
continue;
|
|
9356
|
+
}
|
|
9357
|
+
else if (!(op.attributes instanceof ElementAttributes)) {
|
|
9358
|
+
continue;
|
|
9359
|
+
}
|
|
9360
|
+
const attrArray = serializeAttributes(op.attributes);
|
|
9361
|
+
if (attrArray.entries.length > 0) {
|
|
9362
|
+
op.attributes = cpl.addConst(attrArray);
|
|
9363
|
+
}
|
|
9364
|
+
else {
|
|
9365
|
+
op.attributes = null;
|
|
9366
|
+
}
|
|
9367
|
+
}
|
|
9368
|
+
}
|
|
9369
|
+
}
|
|
9370
|
+
function serializeAttributes({ attributes, bindings, classes, i18n, projectAs, styles, template }) {
|
|
9371
|
+
const attrArray = [...attributes];
|
|
9372
|
+
if (projectAs !== null) {
|
|
9373
|
+
attrArray.push(literal(5 /* core.AttributeMarker.ProjectAs */), literal(projectAs));
|
|
9374
|
+
}
|
|
9375
|
+
if (classes.length > 0) {
|
|
9376
|
+
attrArray.push(literal(1 /* core.AttributeMarker.Classes */), ...classes);
|
|
9377
|
+
}
|
|
9378
|
+
if (styles.length > 0) {
|
|
9379
|
+
attrArray.push(literal(2 /* core.AttributeMarker.Styles */), ...styles);
|
|
9380
|
+
}
|
|
9381
|
+
if (bindings.length > 0) {
|
|
9382
|
+
attrArray.push(literal(3 /* core.AttributeMarker.Bindings */), ...bindings);
|
|
9383
|
+
}
|
|
9384
|
+
if (template.length > 0) {
|
|
9385
|
+
attrArray.push(literal(4 /* core.AttributeMarker.Template */), ...template);
|
|
9386
|
+
}
|
|
9387
|
+
if (i18n.length > 0) {
|
|
9388
|
+
attrArray.push(literal(6 /* core.AttributeMarker.I18n */), ...i18n);
|
|
9389
|
+
}
|
|
9390
|
+
return literalArr(attrArray);
|
|
9391
|
+
}
|
|
9392
|
+
|
|
9393
|
+
/**
|
|
9394
|
+
* Replace sequences of `ElementStart` followed by `ElementEnd` with a condensed `Element`
|
|
9395
|
+
* instruction.
|
|
9396
|
+
*/
|
|
9397
|
+
function phaseEmptyElements(cpl) {
|
|
9398
|
+
for (const [_, view] of cpl.views) {
|
|
9399
|
+
for (const op of view.create) {
|
|
9400
|
+
if (op.kind === OpKind.ElementEnd && op.prev !== null &&
|
|
9401
|
+
op.prev.kind === OpKind.ElementStart) {
|
|
9402
|
+
// Transmute the `ElementStart` instruction to `Element`. This is safe as they're designed
|
|
9403
|
+
// to be identical apart from the `kind`.
|
|
9404
|
+
op.prev.kind = OpKind.Element;
|
|
9405
|
+
// Remove the `ElementEnd` instruction.
|
|
9406
|
+
OpList.remove(op);
|
|
9407
|
+
}
|
|
9408
|
+
}
|
|
9409
|
+
}
|
|
9410
|
+
}
|
|
9411
|
+
|
|
9412
|
+
/**
|
|
9413
|
+
* Generate `ir.AdvanceOp`s in between `ir.UpdateOp`s that ensure the runtime's implicit slot
|
|
9414
|
+
* context will be advanced correctly.
|
|
9415
|
+
*/
|
|
9416
|
+
function phaseGenerateAdvance(cpl) {
|
|
9417
|
+
for (const [_, view] of cpl.views) {
|
|
9418
|
+
// First build a map of all of the declarations in the view that have assigned slots.
|
|
9419
|
+
const slotMap = new Map();
|
|
9420
|
+
for (const op of view.create) {
|
|
9421
|
+
if (!hasConsumesSlotTrait(op)) {
|
|
9422
|
+
continue;
|
|
9423
|
+
}
|
|
9424
|
+
else if (op.slot === null) {
|
|
9425
|
+
throw new Error(`AssertionError: expected slots to have been allocated before generating advance() calls`);
|
|
9426
|
+
}
|
|
9427
|
+
slotMap.set(op.xref, op.slot);
|
|
9428
|
+
}
|
|
9429
|
+
// Next, step through the update operations and generate `ir.AdvanceOp`s as required to ensure
|
|
9430
|
+
// the runtime's implicit slot counter will be set to the correct slot before executing each
|
|
9431
|
+
// update operation which depends on it.
|
|
9432
|
+
//
|
|
9433
|
+
// To do that, we track what the runtime's slot counter will be through the update operations.
|
|
9434
|
+
let slotContext = 0;
|
|
9435
|
+
for (const op of view.update) {
|
|
9436
|
+
if (!hasDependsOnSlotContextTrait(op)) {
|
|
9437
|
+
// `op` doesn't depend on the slot counter, so it can be skipped.
|
|
9438
|
+
continue;
|
|
9439
|
+
}
|
|
9440
|
+
else if (!slotMap.has(op.target)) {
|
|
9441
|
+
// We expect ops that _do_ depend on the slot counter to point at declarations that exist in
|
|
9442
|
+
// the `slotMap`.
|
|
9443
|
+
throw new Error(`AssertionError: reference to unknown slot for var ${op.target}`);
|
|
9444
|
+
}
|
|
9445
|
+
const slot = slotMap.get(op.target);
|
|
9446
|
+
// Does the slot counter need to be adjusted?
|
|
9447
|
+
if (slotContext !== slot) {
|
|
9448
|
+
// If so, generate an `ir.AdvanceOp` to advance the counter.
|
|
9449
|
+
const delta = slot - slotContext;
|
|
9450
|
+
if (delta < 0) {
|
|
9451
|
+
throw new Error(`AssertionError: slot counter should never need to move backwards`);
|
|
9452
|
+
}
|
|
9453
|
+
OpList.insertBefore(op, createAdvanceOp(delta));
|
|
9454
|
+
slotContext = slot;
|
|
9455
|
+
}
|
|
9456
|
+
}
|
|
9457
|
+
}
|
|
9458
|
+
}
|
|
9459
|
+
|
|
9460
|
+
// This file contains helpers for generating calls to Ivy instructions. In particular, each
|
|
9461
|
+
// instruction type is represented as a function, which may select a specific instruction variant
|
|
9462
|
+
// depending on the exact arguments.
|
|
9463
|
+
function element(slot, tag, constIndex, localRefIndex) {
|
|
9464
|
+
return elementStartBase(Identifiers.element, slot, tag, constIndex, localRefIndex);
|
|
9465
|
+
}
|
|
9466
|
+
function elementStart(slot, tag, constIndex, localRefIndex) {
|
|
9467
|
+
return elementStartBase(Identifiers.elementStart, slot, tag, constIndex, localRefIndex);
|
|
9468
|
+
}
|
|
9469
|
+
function elementStartBase(instruction, slot, tag, constIndex, localRefIndex) {
|
|
9470
|
+
const args = [
|
|
9471
|
+
literal(slot),
|
|
9472
|
+
literal(tag),
|
|
9473
|
+
];
|
|
9474
|
+
if (localRefIndex !== null) {
|
|
9475
|
+
args.push(literal(constIndex), // might be null, but that's okay.
|
|
9476
|
+
literal(localRefIndex));
|
|
9477
|
+
}
|
|
9478
|
+
else if (constIndex !== null) {
|
|
9479
|
+
args.push(literal(constIndex));
|
|
9480
|
+
}
|
|
9481
|
+
return call(instruction, args);
|
|
9482
|
+
}
|
|
9483
|
+
function elementEnd() {
|
|
9484
|
+
return call(Identifiers.elementEnd, []);
|
|
9485
|
+
}
|
|
9486
|
+
function template(slot, templateFnRef, decls, vars, tag, constIndex) {
|
|
9487
|
+
return call(Identifiers.templateCreate, [
|
|
9488
|
+
literal(slot),
|
|
9489
|
+
templateFnRef,
|
|
9490
|
+
literal(decls),
|
|
9491
|
+
literal(vars),
|
|
9492
|
+
literal(tag),
|
|
9493
|
+
literal(constIndex),
|
|
9494
|
+
]);
|
|
9495
|
+
}
|
|
9496
|
+
function listener(name, handlerFn) {
|
|
9497
|
+
return call(Identifiers.listener, [
|
|
9498
|
+
literal(name),
|
|
9499
|
+
handlerFn,
|
|
9500
|
+
]);
|
|
9501
|
+
}
|
|
9502
|
+
function advance(delta) {
|
|
9503
|
+
return call(Identifiers.advance, [
|
|
9504
|
+
literal(delta),
|
|
9505
|
+
]);
|
|
9506
|
+
}
|
|
9507
|
+
function reference(slot) {
|
|
9508
|
+
return importExpr(Identifiers.reference).callFn([
|
|
9509
|
+
literal(slot),
|
|
9510
|
+
]);
|
|
9511
|
+
}
|
|
9512
|
+
function nextContext() {
|
|
9513
|
+
return importExpr(Identifiers.nextContext).callFn([]);
|
|
9514
|
+
}
|
|
9515
|
+
function getCurrentView() {
|
|
9516
|
+
return importExpr(Identifiers.getCurrentView).callFn([]);
|
|
9517
|
+
}
|
|
9518
|
+
function restoreView(savedView) {
|
|
9519
|
+
return importExpr(Identifiers.restoreView).callFn([
|
|
9520
|
+
savedView,
|
|
9521
|
+
]);
|
|
9522
|
+
}
|
|
9523
|
+
function resetView(returnValue) {
|
|
9524
|
+
return importExpr(Identifiers.reference).callFn([
|
|
9525
|
+
returnValue,
|
|
9526
|
+
]);
|
|
9527
|
+
}
|
|
9528
|
+
function text(slot, initialValue) {
|
|
9529
|
+
const args = [literal(slot)];
|
|
9530
|
+
if (initialValue !== '') {
|
|
9531
|
+
args.push(literal(initialValue));
|
|
9532
|
+
}
|
|
9533
|
+
return call(Identifiers.text, args);
|
|
9534
|
+
}
|
|
9535
|
+
function property(name, expression) {
|
|
9536
|
+
return call(Identifiers.property, [
|
|
9537
|
+
literal(name),
|
|
9538
|
+
expression,
|
|
9539
|
+
]);
|
|
9540
|
+
}
|
|
9541
|
+
function textInterpolate(strings, expressions) {
|
|
9542
|
+
if (strings.length < 1 || expressions.length !== strings.length - 1) {
|
|
9543
|
+
throw new Error(`AssertionError: expected specific shape of args for strings/expressions in interpolation`);
|
|
9544
|
+
}
|
|
9545
|
+
const interpolationArgs = [];
|
|
9546
|
+
let idx;
|
|
9547
|
+
for (idx = 0; idx < expressions.length; idx++) {
|
|
9548
|
+
interpolationArgs.push(literal(strings[idx]), expressions[idx]);
|
|
9549
|
+
}
|
|
9550
|
+
// idx points at the last string.
|
|
9551
|
+
interpolationArgs.push(literal(strings[idx]));
|
|
9552
|
+
return callInterpolation(TEXT_INTERPOLATE_CONFIG, [], interpolationArgs);
|
|
9553
|
+
}
|
|
9554
|
+
function call(instruction, args) {
|
|
9555
|
+
return createStatementOp(importExpr(instruction).callFn(args).toStmt());
|
|
9556
|
+
}
|
|
9557
|
+
/**
|
|
9558
|
+
* `InterpolationConfig` for the `textInterpolate` instruction.
|
|
9559
|
+
*/
|
|
9560
|
+
const TEXT_INTERPOLATE_CONFIG = {
|
|
9561
|
+
constant: [
|
|
9562
|
+
Identifiers.textInterpolate,
|
|
9563
|
+
Identifiers.textInterpolate1,
|
|
9564
|
+
Identifiers.textInterpolate2,
|
|
9565
|
+
Identifiers.textInterpolate3,
|
|
9566
|
+
Identifiers.textInterpolate4,
|
|
9567
|
+
Identifiers.textInterpolate5,
|
|
9568
|
+
Identifiers.textInterpolate6,
|
|
9569
|
+
Identifiers.textInterpolate7,
|
|
9570
|
+
Identifiers.textInterpolate8,
|
|
9571
|
+
],
|
|
9572
|
+
variable: Identifiers.textInterpolateV,
|
|
9573
|
+
};
|
|
9574
|
+
function callInterpolation(config, baseArgs, interpolationArgs) {
|
|
9575
|
+
if (interpolationArgs.length % 2 === 0) {
|
|
9576
|
+
throw new Error(`Expected odd number of interpolation arguments`);
|
|
9577
|
+
}
|
|
9578
|
+
const n = (interpolationArgs.length - 1) / 2;
|
|
9579
|
+
if (n < config.constant.length) {
|
|
9580
|
+
// Constant calling pattern.
|
|
9581
|
+
return call(config.constant[n], [...baseArgs, ...interpolationArgs]);
|
|
9582
|
+
}
|
|
9583
|
+
else {
|
|
9584
|
+
// Variable calling pattern.
|
|
9585
|
+
return call(config.variable, [...baseArgs, literalArr(interpolationArgs)]);
|
|
9586
|
+
}
|
|
9587
|
+
}
|
|
9588
|
+
|
|
9589
|
+
/**
|
|
9590
|
+
* Compiles semantic operations across all views and generates output `o.Statement`s with actual
|
|
9591
|
+
* runtime calls in their place.
|
|
9592
|
+
*
|
|
9593
|
+
* Reification replaces semantic operations with selected Ivy instructions and other generated code
|
|
9594
|
+
* structures. After reification, the create/update operation lists of all views should only contain
|
|
9595
|
+
* `ir.StatementOp`s (which wrap generated `o.Statement`s).
|
|
9596
|
+
*/
|
|
9597
|
+
function phaseReify(cpl) {
|
|
9598
|
+
for (const [_, view] of cpl.views) {
|
|
9599
|
+
reifyCreateOperations(view, view.create);
|
|
9600
|
+
reifyUpdateOperations(view, view.update);
|
|
9601
|
+
}
|
|
9602
|
+
}
|
|
9603
|
+
function reifyCreateOperations(view, ops) {
|
|
9604
|
+
for (const op of ops) {
|
|
9605
|
+
transformExpressionsInOp(op, reifyIrExpression);
|
|
9606
|
+
switch (op.kind) {
|
|
9607
|
+
case OpKind.Text:
|
|
9608
|
+
OpList.replace(op, text(op.slot, op.initialValue));
|
|
9609
|
+
break;
|
|
9610
|
+
case OpKind.ElementStart:
|
|
9611
|
+
OpList.replace(op, elementStart(op.slot, op.tag, op.attributes, op.localRefs));
|
|
9612
|
+
break;
|
|
9613
|
+
case OpKind.Element:
|
|
9614
|
+
OpList.replace(op, element(op.slot, op.tag, op.attributes, op.localRefs));
|
|
9615
|
+
break;
|
|
9616
|
+
case OpKind.ElementEnd:
|
|
9617
|
+
OpList.replace(op, elementEnd());
|
|
9618
|
+
break;
|
|
9619
|
+
case OpKind.Template:
|
|
9620
|
+
const childView = view.tpl.views.get(op.xref);
|
|
9621
|
+
OpList.replace(op, template(op.slot, variable(childView.fnName), childView.decls, childView.vars, op.tag, op.localRefs));
|
|
9622
|
+
break;
|
|
9623
|
+
case OpKind.Listener:
|
|
9624
|
+
const listenerFn = reifyListenerHandler(view, op.handlerFnName, op.handlerOps);
|
|
9625
|
+
OpList.replace(op, listener(op.name, listenerFn));
|
|
9626
|
+
break;
|
|
9627
|
+
case OpKind.Variable:
|
|
9628
|
+
if (op.name === null) {
|
|
9629
|
+
throw new Error(`AssertionError: unnamed variable ${op.xref}`);
|
|
9630
|
+
}
|
|
9631
|
+
OpList.replace(op, createStatementOp(new DeclareVarStmt(op.name, op.initializer)));
|
|
9632
|
+
break;
|
|
9633
|
+
case OpKind.Statement:
|
|
9634
|
+
// Pass statement operations directly through.
|
|
9635
|
+
break;
|
|
9636
|
+
default:
|
|
9637
|
+
throw new Error(`AssertionError: Unsupported reification of create op ${OpKind[op.kind]}`);
|
|
9638
|
+
}
|
|
9639
|
+
}
|
|
9640
|
+
}
|
|
9641
|
+
function reifyUpdateOperations(_view, ops) {
|
|
9642
|
+
for (const op of ops) {
|
|
9643
|
+
transformExpressionsInOp(op, reifyIrExpression);
|
|
9644
|
+
switch (op.kind) {
|
|
9645
|
+
case OpKind.Advance:
|
|
9646
|
+
OpList.replace(op, advance(op.delta));
|
|
9647
|
+
break;
|
|
9648
|
+
case OpKind.Property:
|
|
9649
|
+
OpList.replace(op, property(op.name, op.expression));
|
|
9650
|
+
break;
|
|
9651
|
+
case OpKind.InterpolateText:
|
|
9652
|
+
OpList.replace(op, textInterpolate(op.strings, op.expressions));
|
|
9653
|
+
break;
|
|
9654
|
+
case OpKind.Variable:
|
|
9655
|
+
if (op.name === null) {
|
|
9656
|
+
throw new Error(`AssertionError: unnamed variable ${op.xref}`);
|
|
9657
|
+
}
|
|
9658
|
+
OpList.replace(op, createStatementOp(new DeclareVarStmt(op.name, op.initializer)));
|
|
9659
|
+
break;
|
|
9660
|
+
case OpKind.Statement:
|
|
9661
|
+
// Pass statement operations directly through.
|
|
9662
|
+
break;
|
|
9663
|
+
default:
|
|
9664
|
+
throw new Error(`AssertionError: Unsupported reification of update op ${OpKind[op.kind]}`);
|
|
9665
|
+
}
|
|
9666
|
+
}
|
|
9667
|
+
}
|
|
9668
|
+
function reifyIrExpression(expr) {
|
|
9669
|
+
switch (expr.kind) {
|
|
9670
|
+
case ExpressionKind.NextContext:
|
|
9671
|
+
return nextContext();
|
|
9672
|
+
case ExpressionKind.Reference:
|
|
9673
|
+
return reference(expr.slot + 1 + expr.offset);
|
|
9674
|
+
case ExpressionKind.LexicalRead:
|
|
9675
|
+
throw new Error(`AssertionError: unresolved LexicalRead of ${expr.name}`);
|
|
9676
|
+
case ExpressionKind.RestoreView:
|
|
9677
|
+
if (typeof expr.view === 'number') {
|
|
9678
|
+
throw new Error(`AssertionError: unresolved RestoreView`);
|
|
9679
|
+
}
|
|
9680
|
+
return restoreView(expr.view);
|
|
9681
|
+
case ExpressionKind.ResetView:
|
|
9682
|
+
return resetView(expr.expr);
|
|
9683
|
+
case ExpressionKind.GetCurrentView:
|
|
9684
|
+
return getCurrentView();
|
|
9685
|
+
case ExpressionKind.ReadVariable:
|
|
9686
|
+
if (expr.name === null) {
|
|
9687
|
+
throw new Error(`Read of unnamed variable ${expr.xref}`);
|
|
9688
|
+
}
|
|
9689
|
+
return variable(expr.name);
|
|
9690
|
+
default:
|
|
9691
|
+
throw new Error(`AssertionError: Unsupported reification of ir.Expression kind: ${ExpressionKind[expr.kind]}`);
|
|
9692
|
+
}
|
|
9693
|
+
}
|
|
9694
|
+
/**
|
|
9695
|
+
* Listeners get turned into a function expression, which may or may not have the `$event`
|
|
9696
|
+
* parameter defined.
|
|
9697
|
+
*/
|
|
9698
|
+
function reifyListenerHandler(view, name, handlerOps) {
|
|
9699
|
+
const lookForEvent = new LookForEventVisitor();
|
|
9700
|
+
// First, reify all instruction calls within `handlerOps`.
|
|
9701
|
+
reifyUpdateOperations(view, handlerOps);
|
|
9702
|
+
// Next, extract all the `o.Statement`s from the reified operations. We can expect that at this
|
|
9703
|
+
// point, all operations have been converted to statements.
|
|
9704
|
+
const handlerStmts = [];
|
|
9705
|
+
for (const op of handlerOps) {
|
|
9706
|
+
if (op.kind !== OpKind.Statement) {
|
|
9707
|
+
throw new Error(`AssertionError: expected reified statements, but found op ${OpKind[op.kind]}`);
|
|
9708
|
+
}
|
|
9709
|
+
handlerStmts.push(op.statement);
|
|
9710
|
+
}
|
|
9711
|
+
// Scan the statement list for usages of `$event`. If referenced, we need to generate it as a
|
|
9712
|
+
// parameter.
|
|
9713
|
+
lookForEvent.visitAllStatements(handlerStmts, null);
|
|
9714
|
+
const params = [];
|
|
9715
|
+
if (lookForEvent.seenEventRead) {
|
|
9716
|
+
// We need the `$event` parameter.
|
|
9717
|
+
params.push(new FnParam('$event'));
|
|
9718
|
+
}
|
|
9719
|
+
return fn(params, handlerStmts, undefined, undefined, name);
|
|
9720
|
+
}
|
|
9721
|
+
/**
|
|
9722
|
+
* Visitor which scans for reads of the `$event` special variable.
|
|
9723
|
+
*/
|
|
9724
|
+
class LookForEventVisitor extends RecursiveAstVisitor$1 {
|
|
9725
|
+
constructor() {
|
|
9726
|
+
super(...arguments);
|
|
9727
|
+
this.seenEventRead = false;
|
|
9728
|
+
}
|
|
9729
|
+
visitReadVarExpr(ast, context) {
|
|
9730
|
+
if (ast.name === '$event') {
|
|
9731
|
+
this.seenEventRead = true;
|
|
9732
|
+
}
|
|
9733
|
+
}
|
|
9734
|
+
}
|
|
9735
|
+
|
|
9736
|
+
/**
|
|
9737
|
+
* Assign data slots for all operations which implement `ConsumesSlotOpTrait`, and propagate the
|
|
9738
|
+
* assigned data slots of those operations to any expressions which reference them via
|
|
9739
|
+
* `UsesSlotIndexExprTrait`.
|
|
9740
|
+
*
|
|
9741
|
+
* This phase is also responsible for counting the number of slots used for each view (its `decls`)
|
|
9742
|
+
* and propagating that number into the `Template` operations which declare embedded views.
|
|
9743
|
+
*/
|
|
9744
|
+
function phaseSlotAllocation(cpl) {
|
|
9745
|
+
// Map of all declarations in all views within the component which require an assigned slot index.
|
|
9746
|
+
// This map needs to be global (across all views within the component) since it's possible to
|
|
9747
|
+
// reference a slot from one view from an expression within another (e.g. local references work
|
|
9748
|
+
// this way).
|
|
9749
|
+
const slotMap = new Map();
|
|
9750
|
+
// Process all views in the component and assign slot indexes.
|
|
9751
|
+
for (const [_, view] of cpl.views) {
|
|
9752
|
+
// Slot indices start at 0 for each view (and are not unique between views).
|
|
9753
|
+
let slotCount = 0;
|
|
9754
|
+
for (const op of view.create) {
|
|
9755
|
+
// Only consider declarations which consume data slots.
|
|
9756
|
+
if (!hasConsumesSlotTrait(op)) {
|
|
9757
|
+
continue;
|
|
9758
|
+
}
|
|
9759
|
+
// Assign slots to this declaration starting at the current `slotCount`.
|
|
9760
|
+
op.slot = slotCount;
|
|
9761
|
+
// And track its assigned slot in the `slotMap`.
|
|
9762
|
+
slotMap.set(op.xref, op.slot);
|
|
9763
|
+
// Each declaration may use more than 1 slot, so increment `slotCount` to reserve the number
|
|
9764
|
+
// of slots required.
|
|
9765
|
+
slotCount += op.numSlotsUsed;
|
|
9766
|
+
}
|
|
9767
|
+
// Record the total number of slots used on the view itself. This will later be propagated into
|
|
9768
|
+
// `ir.TemplateOp`s which declare those views (except for the root view).
|
|
9769
|
+
view.decls = slotCount;
|
|
9770
|
+
}
|
|
9771
|
+
// After slot assignment, `slotMap` now contains slot assignments for every declaration in the
|
|
9772
|
+
// whole template, across all views. Next, look for expressions which implement
|
|
9773
|
+
// `UsesSlotIndexExprTrait` and propagate the assigned slot indexes into them.
|
|
9774
|
+
// Additionally, this second scan allows us to find `ir.TemplateOp`s which declare views and
|
|
9775
|
+
// propagate the number of slots used for each view into the operation which declares it.
|
|
9776
|
+
for (const [_, view] of cpl.views) {
|
|
9777
|
+
for (const op of view.ops()) {
|
|
9778
|
+
if (op.kind === OpKind.Template) {
|
|
9779
|
+
// Record the number of slots used by the view this `ir.TemplateOp` declares in the
|
|
9780
|
+
// operation itself, so it can be emitted later.
|
|
9781
|
+
const childView = cpl.views.get(op.xref);
|
|
9782
|
+
op.decls = childView.decls;
|
|
9783
|
+
}
|
|
9784
|
+
// Process all `ir.Expression`s within this view, and look for `usesSlotIndexExprTrait`.
|
|
9785
|
+
visitExpressionsInOp(op, expr => {
|
|
9786
|
+
if (!hasUsesSlotIndexTrait(expr) || expr.slot !== null) {
|
|
9787
|
+
return;
|
|
9788
|
+
}
|
|
9789
|
+
// The `UsesSlotIndexExprTrait` indicates that this expression references something declared
|
|
9790
|
+
// in this component template by its slot index. Use the `target` `ir.XrefId` to find the
|
|
9791
|
+
// allocated slot for that declaration in `slotMap`.
|
|
9792
|
+
if (!slotMap.has(expr.target)) {
|
|
9793
|
+
// We do expect to find a slot allocated for everything which might be referenced.
|
|
9794
|
+
throw new Error(`AssertionError: no slot allocated for ${expr.constructor.name} target ${expr.target}`);
|
|
9795
|
+
}
|
|
9796
|
+
// Record the allocated slot on the expression.
|
|
9797
|
+
expr.slot = slotMap.get(expr.target);
|
|
9798
|
+
});
|
|
9799
|
+
}
|
|
9800
|
+
}
|
|
9801
|
+
}
|
|
9802
|
+
|
|
9803
|
+
/**
|
|
9804
|
+
* Counts the number of variable slots used within each view, and stores that on the view itself, as
|
|
9805
|
+
* well as propagates it to the `ir.TemplateOp` for embedded views.
|
|
9806
|
+
*/
|
|
9807
|
+
function phaseVarCounting(cpl) {
|
|
9808
|
+
// First, count the vars used in each view, and update the view-level counter.
|
|
9809
|
+
for (const [_, view] of cpl.views) {
|
|
9810
|
+
let varCount = 0;
|
|
9811
|
+
for (const op of view.ops()) {
|
|
9812
|
+
if (hasConsumesVarsTrait(op)) {
|
|
9813
|
+
varCount += varsUsedByOp(op);
|
|
9814
|
+
}
|
|
9815
|
+
visitExpressionsInOp(op, expr => {
|
|
9816
|
+
if (hasConsumesVarsTrait(expr)) {
|
|
9817
|
+
varCount += varsUsedByIrExpression(expr);
|
|
9818
|
+
}
|
|
9819
|
+
});
|
|
9820
|
+
}
|
|
9821
|
+
view.vars = varCount;
|
|
9822
|
+
}
|
|
9823
|
+
// Add var counts for each view to the `ir.TemplateOp` which declares that view (if the view is an
|
|
9824
|
+
// embedded view).
|
|
9825
|
+
for (const [_, view] of cpl.views) {
|
|
9826
|
+
for (const op of view.create) {
|
|
9827
|
+
if (op.kind !== OpKind.Template) {
|
|
9828
|
+
continue;
|
|
9829
|
+
}
|
|
9830
|
+
const childView = cpl.views.get(op.xref);
|
|
9831
|
+
op.vars = childView.vars;
|
|
9832
|
+
}
|
|
9833
|
+
}
|
|
9834
|
+
}
|
|
9835
|
+
/**
|
|
9836
|
+
* Different operations that implement `ir.UsesVarsTrait` use different numbers of variables, so
|
|
9837
|
+
* count the variables used by any particular `op`.
|
|
9838
|
+
*/
|
|
9839
|
+
function varsUsedByOp(op) {
|
|
9840
|
+
switch (op.kind) {
|
|
9841
|
+
case OpKind.Property:
|
|
9842
|
+
// Property bindings use 1 variable slot.
|
|
9843
|
+
return 1;
|
|
9844
|
+
case OpKind.InterpolateText:
|
|
9845
|
+
// `ir.InterpolateTextOp`s use a variable slot for each dynamic expression.
|
|
9846
|
+
return op.expressions.length;
|
|
9847
|
+
default:
|
|
9848
|
+
throw new Error(`Unhandled op: ${OpKind[op.kind]}`);
|
|
9849
|
+
}
|
|
9850
|
+
}
|
|
9851
|
+
function varsUsedByIrExpression(expr) {
|
|
9852
|
+
return 0;
|
|
9853
|
+
}
|
|
9854
|
+
|
|
9855
|
+
/**
|
|
9856
|
+
* Generate names for functions and variables across all views.
|
|
9857
|
+
*
|
|
9858
|
+
* This includes propagating those names into any `ir.ReadVariableExpr`s of those variables, so that
|
|
9859
|
+
* the reads can be emitted correctly.
|
|
9860
|
+
*/
|
|
9861
|
+
function phaseNaming(cpl) {
|
|
9862
|
+
// TODO(alxhub): convert this temporary name to match how the `TemplateDefinitionBuilder`
|
|
9863
|
+
// names the main component template function.
|
|
9864
|
+
cpl.root.fnName = `${cpl.componentName}_Template`;
|
|
9865
|
+
for (const [id, view] of cpl.views) {
|
|
9866
|
+
let vIndex = 0;
|
|
9867
|
+
if (view.fnName === null) {
|
|
9868
|
+
// TODO(alxhub): convert this temporary name to match how the `TemplateDefinitionBuilder`
|
|
9869
|
+
// names embedded view functions.
|
|
9870
|
+
view.fnName = `${cpl.componentName}_EmbeddedView_${id}`;
|
|
9871
|
+
}
|
|
9872
|
+
// Keep track of the names we assign to variables in the view. We'll need to propagate these
|
|
9873
|
+
// into reads of those variables afterwards.
|
|
9874
|
+
const varNames = new Map();
|
|
9875
|
+
for (const op of view.ops()) {
|
|
9876
|
+
switch (op.kind) {
|
|
9877
|
+
case OpKind.Listener:
|
|
9878
|
+
if (op.handlerFnName === null) {
|
|
9879
|
+
// TODO(alxhub): convert this temporary name to match how the
|
|
9880
|
+
// `TemplateDefinitionBuilder` names listener functions.
|
|
9881
|
+
op.handlerFnName = `${view.fnName}_${op.name}_listener`;
|
|
9882
|
+
}
|
|
9883
|
+
break;
|
|
9884
|
+
case OpKind.Variable:
|
|
9885
|
+
if (op.name === null) {
|
|
9886
|
+
op.name = `_r${vIndex++}`;
|
|
9887
|
+
varNames.set(op.xref, op.name);
|
|
9888
|
+
}
|
|
9889
|
+
break;
|
|
9890
|
+
}
|
|
9891
|
+
}
|
|
9892
|
+
// Having named all variables declared in the view, now we can push those names into the
|
|
9893
|
+
// `ir.ReadVariableExpr` expressions which represent reads of those variables.
|
|
9894
|
+
for (const op of view.ops()) {
|
|
9895
|
+
visitExpressionsInOp(op, expr => {
|
|
9896
|
+
if (!(expr instanceof ReadVariableExpr) || expr.name !== null) {
|
|
9897
|
+
return;
|
|
9898
|
+
}
|
|
9899
|
+
if (!varNames.has(expr.xref)) {
|
|
9900
|
+
throw new Error(`Variable ${expr.xref} not yet named`);
|
|
9901
|
+
}
|
|
9902
|
+
expr.name = varNames.get(expr.xref);
|
|
9903
|
+
});
|
|
9904
|
+
}
|
|
9905
|
+
}
|
|
9906
|
+
}
|
|
9907
|
+
|
|
9908
|
+
/**
|
|
9909
|
+
* Lifts local reference declarations on element-like structures within each view into an entry in
|
|
9910
|
+
* the `consts` array for the whole component.
|
|
9911
|
+
*/
|
|
9912
|
+
function phaseLocalRefs(cpl) {
|
|
9913
|
+
for (const view of cpl.views.values()) {
|
|
9914
|
+
for (const op of view.create) {
|
|
9915
|
+
switch (op.kind) {
|
|
9916
|
+
case OpKind.ElementStart:
|
|
9917
|
+
case OpKind.Element:
|
|
9918
|
+
case OpKind.Template:
|
|
9919
|
+
if (!Array.isArray(op.localRefs)) {
|
|
9920
|
+
throw new Error(`AssertionError: expected localRefs to be an array still`);
|
|
9921
|
+
}
|
|
9922
|
+
op.numSlotsUsed += op.localRefs.length;
|
|
9923
|
+
if (op.localRefs.length > 0) {
|
|
9924
|
+
const localRefs = serializeLocalRefs(op.localRefs);
|
|
9925
|
+
op.localRefs = cpl.addConst(localRefs);
|
|
9926
|
+
}
|
|
9927
|
+
else {
|
|
9928
|
+
op.localRefs = null;
|
|
9929
|
+
}
|
|
9930
|
+
break;
|
|
9931
|
+
}
|
|
9932
|
+
}
|
|
9933
|
+
}
|
|
9934
|
+
}
|
|
9935
|
+
function serializeLocalRefs(refs) {
|
|
9936
|
+
const constRefs = [];
|
|
9937
|
+
for (const ref of refs) {
|
|
9938
|
+
constRefs.push(literal(ref.name), literal(ref.target));
|
|
9939
|
+
}
|
|
9940
|
+
return literalArr(constRefs);
|
|
9941
|
+
}
|
|
9942
|
+
|
|
9943
|
+
/**
|
|
9944
|
+
* Generate a preamble sequence for each view creation block and listener function which declares
|
|
9945
|
+
* any variables that be referenced in other operations in the block.
|
|
9946
|
+
*
|
|
9947
|
+
* Variables generated include:
|
|
9948
|
+
* * a saved view context to be used to restore the current view in event listeners.
|
|
9949
|
+
* * the context of the restored view within event listener handlers.
|
|
9950
|
+
* * context variables from the current view as well as all parent views (including the root
|
|
9951
|
+
* context if needed).
|
|
9952
|
+
* * local references from elements within the current view and any lexical parents.
|
|
9953
|
+
*
|
|
9954
|
+
* Variables are generated here unconditionally, and may optimized away in future operations if it
|
|
9955
|
+
* turns out their values (and any side effects) are unused.
|
|
9956
|
+
*/
|
|
9957
|
+
function phaseGenerateVariables(cpl) {
|
|
9958
|
+
recursivelyProcessView(cpl.root, /* there is no parent scope for the root view */ null);
|
|
9959
|
+
}
|
|
9960
|
+
/**
|
|
9961
|
+
* Process the given `ViewCompilation` and generate preambles for it and any listeners that it
|
|
9962
|
+
* declares.
|
|
9963
|
+
*
|
|
9964
|
+
* @param `parentScope` a scope extracted from the parent view which captures any variables which
|
|
9965
|
+
* should be inherited by this view. `null` if the current view is the root view.
|
|
9966
|
+
*/
|
|
9967
|
+
function recursivelyProcessView(view, parentScope) {
|
|
9968
|
+
// Extract a `Scope` from this view.
|
|
9969
|
+
const scope = getScopeForView(view, parentScope);
|
|
9970
|
+
// Start the view creation block with an operation to save the current view context. This may be
|
|
9971
|
+
// used to restore the view context in any listeners that may be present.
|
|
9972
|
+
view.create.prepend([
|
|
9973
|
+
createVariableOp(view.tpl.allocateXrefId(), {
|
|
9974
|
+
kind: SemanticVariableKind.SavedView,
|
|
9975
|
+
view: view.xref,
|
|
9976
|
+
}, new GetCurrentViewExpr()),
|
|
9977
|
+
]);
|
|
9978
|
+
for (const op of view.create) {
|
|
9979
|
+
switch (op.kind) {
|
|
9980
|
+
case OpKind.Template:
|
|
9981
|
+
// Descend into child embedded views.
|
|
9982
|
+
recursivelyProcessView(view.tpl.views.get(op.xref), scope);
|
|
9983
|
+
break;
|
|
9984
|
+
case OpKind.Listener:
|
|
9985
|
+
// Listeners get a preamble which starts with a call to restore the view.
|
|
9986
|
+
const preambleOps = [
|
|
9987
|
+
createVariableOp(view.tpl.allocateXrefId(), {
|
|
9988
|
+
kind: SemanticVariableKind.Context,
|
|
9989
|
+
view: view.xref,
|
|
9990
|
+
}, new RestoreViewExpr(view.xref)),
|
|
9991
|
+
// And includes all variables available to this view.
|
|
9992
|
+
...generateVariablesInScopeForView(view, scope)
|
|
9993
|
+
];
|
|
9994
|
+
op.handlerOps.prepend(preambleOps);
|
|
9995
|
+
// The "restore view" operation in listeners requires a call to `resetView` to reset the
|
|
9996
|
+
// context prior to returning from the listener operation. Find any `return` statements in
|
|
9997
|
+
// the listener body and wrap them in a call to reset the view.
|
|
9998
|
+
for (const handlerOp of op.handlerOps) {
|
|
9999
|
+
if (handlerOp.kind === OpKind.Statement &&
|
|
10000
|
+
handlerOp.statement instanceof ReturnStatement) {
|
|
10001
|
+
handlerOp.statement.value = new ResetViewExpr(handlerOp.statement.value);
|
|
10002
|
+
}
|
|
10003
|
+
}
|
|
10004
|
+
break;
|
|
10005
|
+
}
|
|
10006
|
+
}
|
|
10007
|
+
// Prepend the declarations for all available variables in scope to the `update` block.
|
|
10008
|
+
const preambleOps = generateVariablesInScopeForView(view, scope);
|
|
10009
|
+
view.update.prepend(preambleOps);
|
|
10010
|
+
}
|
|
10011
|
+
/**
|
|
10012
|
+
* Process a view and generate a `Scope` representing the variables available for reference within
|
|
10013
|
+
* that view.
|
|
10014
|
+
*/
|
|
10015
|
+
function getScopeForView(view, parent) {
|
|
10016
|
+
const scope = {
|
|
10017
|
+
view: view.xref,
|
|
10018
|
+
references: [],
|
|
10019
|
+
parent,
|
|
10020
|
+
};
|
|
10021
|
+
for (const op of view.create) {
|
|
10022
|
+
switch (op.kind) {
|
|
10023
|
+
case OpKind.Element:
|
|
10024
|
+
case OpKind.ElementStart:
|
|
10025
|
+
case OpKind.Template:
|
|
10026
|
+
if (!Array.isArray(op.localRefs)) {
|
|
10027
|
+
throw new Error(`AssertionError: expected localRefs to be an array`);
|
|
10028
|
+
}
|
|
10029
|
+
// Record available local references from this element.
|
|
10030
|
+
for (let offset = 0; offset < op.localRefs.length; offset++) {
|
|
10031
|
+
scope.references.push({
|
|
10032
|
+
name: op.localRefs[offset].name,
|
|
10033
|
+
targetId: op.xref,
|
|
10034
|
+
offset,
|
|
10035
|
+
});
|
|
10036
|
+
}
|
|
10037
|
+
break;
|
|
10038
|
+
}
|
|
10039
|
+
}
|
|
10040
|
+
return scope;
|
|
10041
|
+
}
|
|
10042
|
+
/**
|
|
10043
|
+
* Generate declarations for all variables that are in scope for a given view.
|
|
10044
|
+
*
|
|
10045
|
+
* This is a recursive process, as views inherit variables available from their parent view, which
|
|
10046
|
+
* itself may have inherited variables, etc.
|
|
10047
|
+
*/
|
|
10048
|
+
function generateVariablesInScopeForView(view, scope) {
|
|
10049
|
+
const newOps = [];
|
|
10050
|
+
if (scope.view !== view.xref) {
|
|
10051
|
+
// Before generating variables for a parent view, we need to switch to the context of the parent
|
|
10052
|
+
// view with a `nextContext` expression. This context switching operation itself declares a
|
|
10053
|
+
// variable, because the context of the view may be referenced directly.
|
|
10054
|
+
newOps.push(createVariableOp(view.tpl.allocateXrefId(), {
|
|
10055
|
+
kind: SemanticVariableKind.Context,
|
|
10056
|
+
view: scope.view,
|
|
10057
|
+
}, new NextContextExpr()));
|
|
10058
|
+
}
|
|
10059
|
+
// Add variables for all context variables available in this scope's view.
|
|
10060
|
+
for (const [name, value] of view.tpl.views.get(scope.view).contextVariables) {
|
|
10061
|
+
newOps.push(createVariableOp(view.tpl.allocateXrefId(), {
|
|
10062
|
+
kind: SemanticVariableKind.Identifier,
|
|
10063
|
+
name,
|
|
10064
|
+
}, new ReadPropExpr(new ContextExpr(view.xref), value)));
|
|
10065
|
+
}
|
|
10066
|
+
// Add variables for all local references declared for elements in this scope.
|
|
10067
|
+
for (const ref of scope.references) {
|
|
10068
|
+
newOps.push(createVariableOp(view.tpl.allocateXrefId(), {
|
|
10069
|
+
kind: SemanticVariableKind.Identifier,
|
|
10070
|
+
name: ref.name,
|
|
10071
|
+
}, new ReferenceExpr(ref.targetId, ref.offset)));
|
|
10072
|
+
}
|
|
10073
|
+
if (scope.parent !== null) {
|
|
10074
|
+
// Recursively add variables from the parent scope.
|
|
10075
|
+
newOps.push(...generateVariablesInScopeForView(view, scope.parent));
|
|
10076
|
+
}
|
|
10077
|
+
return newOps;
|
|
10078
|
+
}
|
|
10079
|
+
|
|
10080
|
+
/**
|
|
10081
|
+
* Resolves lexical references in views (`ir.LexicalReadExpr`) to either a target variable or to
|
|
10082
|
+
* property reads on the top-level component context.
|
|
10083
|
+
*
|
|
10084
|
+
* Also matches `ir.RestoreViewExpr` expressions with the variables of their corresponding saved
|
|
10085
|
+
* views.
|
|
10086
|
+
*/
|
|
10087
|
+
function phaseResolveNames(cpl) {
|
|
10088
|
+
for (const [_, view] of cpl.views) {
|
|
10089
|
+
processLexicalScope$1(view, view.create, null);
|
|
10090
|
+
processLexicalScope$1(view, view.update, null);
|
|
10091
|
+
}
|
|
10092
|
+
}
|
|
10093
|
+
function processLexicalScope$1(view, ops, savedView) {
|
|
10094
|
+
// Maps names defined in the lexical scope of this template to the `ir.XrefId`s of the variable
|
|
10095
|
+
// declarations which represent those values.
|
|
10096
|
+
//
|
|
10097
|
+
// Since variables are generated in each view for the entire lexical scope (including any
|
|
10098
|
+
// identifiers from parent templates) only local variables need be considered here.
|
|
10099
|
+
const scope = new Map();
|
|
10100
|
+
// First, step through the operations list and:
|
|
10101
|
+
// 1) build up the `scope` mapping
|
|
10102
|
+
// 2) recurse into any listener functions
|
|
10103
|
+
for (const op of ops) {
|
|
10104
|
+
switch (op.kind) {
|
|
10105
|
+
case OpKind.Variable:
|
|
10106
|
+
switch (op.variable.kind) {
|
|
10107
|
+
case SemanticVariableKind.Identifier:
|
|
10108
|
+
// This variable represents some kind of identifier which can be used in the template.
|
|
10109
|
+
if (scope.has(op.variable.name)) {
|
|
10110
|
+
continue;
|
|
10111
|
+
}
|
|
10112
|
+
scope.set(op.variable.name, op.xref);
|
|
10113
|
+
break;
|
|
10114
|
+
case SemanticVariableKind.SavedView:
|
|
10115
|
+
// This variable represents a snapshot of the current view context, and can be used to
|
|
10116
|
+
// restore that context within listener functions.
|
|
10117
|
+
savedView = {
|
|
10118
|
+
view: op.variable.view,
|
|
10119
|
+
variable: op.xref,
|
|
10120
|
+
};
|
|
10121
|
+
break;
|
|
10122
|
+
}
|
|
10123
|
+
break;
|
|
10124
|
+
case OpKind.Listener:
|
|
10125
|
+
// Listener functions have separate variable declarations, so process them as a separate
|
|
10126
|
+
// lexical scope.
|
|
10127
|
+
processLexicalScope$1(view, op.handlerOps, savedView);
|
|
10128
|
+
break;
|
|
10129
|
+
}
|
|
10130
|
+
}
|
|
10131
|
+
// Next, use the `scope` mapping to match `ir.LexicalReadExpr` with defined names in the lexical
|
|
10132
|
+
// scope. Also, look for `ir.RestoreViewExpr`s and match them with the snapshotted view context
|
|
10133
|
+
// variable.
|
|
10134
|
+
for (const op of ops) {
|
|
10135
|
+
transformExpressionsInOp(op, expr => {
|
|
10136
|
+
if (expr instanceof LexicalReadExpr) {
|
|
10137
|
+
// `expr` is a read of a name within the lexical scope of this view.
|
|
10138
|
+
// Either that name is defined within the current view, or it represents a property from the
|
|
10139
|
+
// main component context.
|
|
10140
|
+
if (scope.has(expr.name)) {
|
|
10141
|
+
// This was a defined variable in the current scope.
|
|
10142
|
+
return new ReadVariableExpr(scope.get(expr.name));
|
|
10143
|
+
}
|
|
10144
|
+
else {
|
|
10145
|
+
// Reading from the component context.
|
|
10146
|
+
return new ReadPropExpr(new ContextExpr(view.tpl.root.xref), expr.name);
|
|
10147
|
+
}
|
|
10148
|
+
}
|
|
10149
|
+
else if (expr instanceof RestoreViewExpr && typeof expr.view === 'number') {
|
|
10150
|
+
// `ir.RestoreViewExpr` happens in listener functions and restores a saved view from the
|
|
10151
|
+
// parent creation list. We expect to find that we captured the `savedView` previously, and
|
|
10152
|
+
// that it matches the expected view to be restored.
|
|
10153
|
+
if (savedView === null || savedView.view !== expr.view) {
|
|
10154
|
+
throw new Error(`AssertionError: no saved view ${expr.view} from view ${view.xref}`);
|
|
10155
|
+
}
|
|
10156
|
+
expr.view = new ReadVariableExpr(savedView.variable);
|
|
10157
|
+
return expr;
|
|
10158
|
+
}
|
|
10159
|
+
else {
|
|
10160
|
+
return expr;
|
|
10161
|
+
}
|
|
10162
|
+
});
|
|
10163
|
+
}
|
|
10164
|
+
}
|
|
10165
|
+
|
|
10166
|
+
/**
|
|
10167
|
+
* Resolves `ir.ContextExpr` expressions (which represent embedded view or component contexts) to
|
|
10168
|
+
* either the `ctx` parameter to component functions (for the current view context) or to variables
|
|
10169
|
+
* that store those contexts (for contexts accessed via the `nextContext()` instruction).
|
|
10170
|
+
*/
|
|
10171
|
+
function phaseResolveContexts(cpl) {
|
|
10172
|
+
for (const view of cpl.views.values()) {
|
|
10173
|
+
processLexicalScope(view, view.create);
|
|
10174
|
+
processLexicalScope(view, view.update);
|
|
10175
|
+
}
|
|
10176
|
+
}
|
|
10177
|
+
function processLexicalScope(view, ops) {
|
|
10178
|
+
// Track the expressions used to access all available contexts within the current view, by the
|
|
10179
|
+
// view `ir.XrefId`.
|
|
10180
|
+
const scope = new Map();
|
|
10181
|
+
// The current view's context is accessible via the `ctx` parameter.
|
|
10182
|
+
scope.set(view.xref, variable('ctx'));
|
|
10183
|
+
for (const op of ops) {
|
|
10184
|
+
switch (op.kind) {
|
|
10185
|
+
case OpKind.Variable:
|
|
10186
|
+
switch (op.variable.kind) {
|
|
10187
|
+
case SemanticVariableKind.Context:
|
|
10188
|
+
scope.set(op.variable.view, new ReadVariableExpr(op.xref));
|
|
10189
|
+
break;
|
|
10190
|
+
}
|
|
10191
|
+
break;
|
|
10192
|
+
case OpKind.Listener:
|
|
10193
|
+
processLexicalScope(view, op.handlerOps);
|
|
10194
|
+
break;
|
|
10195
|
+
}
|
|
10196
|
+
}
|
|
10197
|
+
for (const op of ops) {
|
|
10198
|
+
transformExpressionsInOp(op, expr => {
|
|
10199
|
+
if (expr instanceof ContextExpr) {
|
|
10200
|
+
if (!scope.has(expr.view)) {
|
|
10201
|
+
throw new Error(`No context found for reference to view ${expr.view} from view ${view.xref}`);
|
|
10202
|
+
}
|
|
10203
|
+
return scope.get(expr.view);
|
|
10204
|
+
}
|
|
10205
|
+
else {
|
|
10206
|
+
return expr;
|
|
10207
|
+
}
|
|
10208
|
+
});
|
|
10209
|
+
}
|
|
10210
|
+
}
|
|
10211
|
+
|
|
10212
|
+
/**
|
|
10213
|
+
* Run all transformation phases in the correct order against a `ComponentCompilation`. After this
|
|
10214
|
+
* processing, the compilation should be in a state where it can be emitted via `emitTemplateFn`.s
|
|
10215
|
+
*/
|
|
10216
|
+
function transformTemplate(cpl) {
|
|
10217
|
+
phaseGenerateVariables(cpl);
|
|
10218
|
+
phaseResolveNames(cpl);
|
|
10219
|
+
phaseResolveContexts(cpl);
|
|
10220
|
+
phaseLocalRefs(cpl);
|
|
10221
|
+
phaseEmptyElements(cpl);
|
|
10222
|
+
phaseConstCollection(cpl);
|
|
10223
|
+
phaseSlotAllocation(cpl);
|
|
10224
|
+
phaseVarCounting(cpl);
|
|
10225
|
+
phaseGenerateAdvance(cpl);
|
|
10226
|
+
phaseNaming(cpl);
|
|
10227
|
+
phaseReify(cpl);
|
|
10228
|
+
}
|
|
10229
|
+
/**
|
|
10230
|
+
* Compile all views in the given `ComponentCompilation` into the final template function, which may
|
|
10231
|
+
* reference constants defined in a `ConstantPool`.
|
|
10232
|
+
*/
|
|
10233
|
+
function emitTemplateFn(tpl, pool) {
|
|
10234
|
+
const rootFn = emitView(tpl.root);
|
|
10235
|
+
for (const view of tpl.views.values()) {
|
|
10236
|
+
if (view === tpl.root) {
|
|
10237
|
+
continue;
|
|
10238
|
+
}
|
|
10239
|
+
const viewFn = emitView(view);
|
|
10240
|
+
pool.statements.push(viewFn.toDeclStmt(viewFn.name));
|
|
10241
|
+
}
|
|
10242
|
+
return rootFn;
|
|
10243
|
+
}
|
|
10244
|
+
/**
|
|
10245
|
+
* Emit a template function for an individual `ViewCompilation` (which may be either the root view
|
|
10246
|
+
* or an embedded view).
|
|
10247
|
+
*/
|
|
10248
|
+
function emitView(view) {
|
|
10249
|
+
if (view.fnName === null) {
|
|
10250
|
+
throw new Error(`AssertionError: view ${view.xref} is unnamed`);
|
|
10251
|
+
}
|
|
10252
|
+
const createStatements = [];
|
|
10253
|
+
for (const op of view.create) {
|
|
10254
|
+
if (op.kind !== OpKind.Statement) {
|
|
10255
|
+
throw new Error(`AssertionError: expected all create ops to have been compiled, but got ${OpKind[op.kind]}`);
|
|
10256
|
+
}
|
|
10257
|
+
createStatements.push(op.statement);
|
|
10258
|
+
}
|
|
10259
|
+
const updateStatements = [];
|
|
10260
|
+
for (const op of view.update) {
|
|
10261
|
+
if (op.kind !== OpKind.Statement) {
|
|
10262
|
+
throw new Error(`AssertionError: expected all update ops to have been compiled, but got ${OpKind[op.kind]}`);
|
|
10263
|
+
}
|
|
10264
|
+
updateStatements.push(op.statement);
|
|
10265
|
+
}
|
|
10266
|
+
const rf = variable('rf');
|
|
10267
|
+
const createCond = ifStmt(new BinaryOperatorExpr(BinaryOperator.BitwiseAnd, rf, literal(1)), createStatements);
|
|
10268
|
+
const updateCond = ifStmt(new BinaryOperatorExpr(BinaryOperator.BitwiseAnd, rf, literal(2)), updateStatements);
|
|
10269
|
+
return fn([
|
|
10270
|
+
new FnParam('rf'),
|
|
10271
|
+
new FnParam('ctx'),
|
|
10272
|
+
], [createCond, updateCond], /* type */ undefined, /* sourceSpan */ undefined, view.fnName);
|
|
10273
|
+
}
|
|
10274
|
+
|
|
10275
|
+
/**
|
|
10276
|
+
* Compilation-in-progress of a whole component's template, including the main template and any
|
|
10277
|
+
* embedded views or host bindings.
|
|
10278
|
+
*/
|
|
10279
|
+
class ComponentCompilation {
|
|
10280
|
+
constructor(componentName) {
|
|
10281
|
+
this.componentName = componentName;
|
|
10282
|
+
/**
|
|
10283
|
+
* Tracks the next `ir.XrefId` which can be assigned as template structures are ingested.
|
|
10284
|
+
*/
|
|
10285
|
+
this.nextXrefId = 0;
|
|
10286
|
+
/**
|
|
10287
|
+
* Map of view IDs to `ViewCompilation`s.
|
|
10288
|
+
*/
|
|
10289
|
+
this.views = new Map();
|
|
10290
|
+
/**
|
|
10291
|
+
* Constant expressions used by operations within this component's compilation.
|
|
10292
|
+
*
|
|
10293
|
+
* This will eventually become the `consts` array in the component definition.
|
|
10294
|
+
*/
|
|
10295
|
+
this.consts = [];
|
|
10296
|
+
// Allocate the root view.
|
|
10297
|
+
const root = new ViewCompilation(this, this.allocateXrefId(), null);
|
|
10298
|
+
this.views.set(root.xref, root);
|
|
10299
|
+
this.root = root;
|
|
10300
|
+
}
|
|
10301
|
+
/**
|
|
10302
|
+
* Add a `ViewCompilation` for a new embedded view to this compilation.
|
|
10303
|
+
*/
|
|
10304
|
+
allocateView(parent) {
|
|
10305
|
+
const view = new ViewCompilation(this, this.allocateXrefId(), parent);
|
|
10306
|
+
this.views.set(view.xref, view);
|
|
10307
|
+
return view;
|
|
10308
|
+
}
|
|
10309
|
+
/**
|
|
10310
|
+
* Generate a new unique `ir.XrefId`.
|
|
10311
|
+
*/
|
|
10312
|
+
allocateXrefId() {
|
|
10313
|
+
return this.nextXrefId++;
|
|
10314
|
+
}
|
|
10315
|
+
/**
|
|
10316
|
+
* Add a constant `o.Expression` to the compilation and return its index in the `consts` array.
|
|
10317
|
+
*/
|
|
10318
|
+
addConst(newConst) {
|
|
10319
|
+
for (let idx = 0; idx < this.consts.length; idx++) {
|
|
10320
|
+
if (this.consts[idx].isEquivalent(newConst)) {
|
|
10321
|
+
return idx;
|
|
10322
|
+
}
|
|
10323
|
+
}
|
|
10324
|
+
const idx = this.consts.length;
|
|
10325
|
+
this.consts.push(newConst);
|
|
10326
|
+
return idx;
|
|
10327
|
+
}
|
|
10328
|
+
}
|
|
10329
|
+
/**
|
|
10330
|
+
* Compilation-in-progress of an individual view within a template.
|
|
10331
|
+
*/
|
|
10332
|
+
class ViewCompilation {
|
|
10333
|
+
constructor(tpl, xref, parent) {
|
|
10334
|
+
this.tpl = tpl;
|
|
10335
|
+
this.xref = xref;
|
|
10336
|
+
this.parent = parent;
|
|
10337
|
+
/**
|
|
10338
|
+
* Name of the function which will be generated for this view.
|
|
10339
|
+
*
|
|
10340
|
+
* May be `null` if not yet determined.
|
|
10341
|
+
*/
|
|
10342
|
+
this.fnName = null;
|
|
10343
|
+
/**
|
|
10344
|
+
* List of creation operations for this view.
|
|
10345
|
+
*
|
|
10346
|
+
* Creation operations may internally contain other operations, including update operations.
|
|
10347
|
+
*/
|
|
10348
|
+
this.create = new OpList();
|
|
10349
|
+
/**
|
|
10350
|
+
* List of update operations for this view.
|
|
10351
|
+
*/
|
|
10352
|
+
this.update = new OpList();
|
|
10353
|
+
/**
|
|
10354
|
+
* Map of declared variables available within this view to the property on the context object
|
|
10355
|
+
* which they alias.
|
|
10356
|
+
*/
|
|
10357
|
+
this.contextVariables = new Map();
|
|
10358
|
+
/**
|
|
10359
|
+
* Number of declaration slots used within this view, or `null` if slots have not yet been
|
|
10360
|
+
* allocated.
|
|
10361
|
+
*/
|
|
10362
|
+
this.decls = null;
|
|
10363
|
+
/**
|
|
10364
|
+
* Number of variable slots used within this view, or `null` if variables have not yet been
|
|
10365
|
+
* counted.
|
|
10366
|
+
*/
|
|
10367
|
+
this.vars = null;
|
|
10368
|
+
}
|
|
10369
|
+
/**
|
|
10370
|
+
* Iterate over all `ir.Op`s within this view.
|
|
10371
|
+
*
|
|
10372
|
+
* Some operations may have child operations, which this iterator will visit.
|
|
10373
|
+
*/
|
|
10374
|
+
*ops() {
|
|
10375
|
+
for (const op of this.create) {
|
|
10376
|
+
yield op;
|
|
10377
|
+
if (op.kind === OpKind.Listener) {
|
|
10378
|
+
for (const listenerOp of op.handlerOps) {
|
|
10379
|
+
yield listenerOp;
|
|
10380
|
+
}
|
|
10381
|
+
}
|
|
10382
|
+
}
|
|
10383
|
+
for (const op of this.update) {
|
|
10384
|
+
yield op;
|
|
10385
|
+
}
|
|
8222
10386
|
}
|
|
8223
|
-
return new StringWithEscapedBlocks(resultParts.join(''), escapedBlocks);
|
|
8224
10387
|
}
|
|
10388
|
+
|
|
8225
10389
|
/**
|
|
8226
|
-
*
|
|
8227
|
-
*
|
|
8228
|
-
* placeholders
|
|
10390
|
+
* Process a template AST and convert it into a `ComponentCompilation` in the intermediate
|
|
10391
|
+
* representation.
|
|
8229
10392
|
*/
|
|
8230
|
-
|
|
8231
|
-
|
|
8232
|
-
|
|
8233
|
-
|
|
8234
|
-
}
|
|
10393
|
+
function ingest(componentName, template) {
|
|
10394
|
+
const cpl = new ComponentCompilation(componentName);
|
|
10395
|
+
ingestNodes(cpl.root, template);
|
|
10396
|
+
return cpl;
|
|
10397
|
+
}
|
|
8235
10398
|
/**
|
|
8236
|
-
*
|
|
8237
|
-
|
|
8238
|
-
|
|
8239
|
-
|
|
8240
|
-
|
|
8241
|
-
|
|
8242
|
-
|
|
8243
|
-
|
|
8244
|
-
|
|
8245
|
-
|
|
8246
|
-
|
|
8247
|
-
|
|
8248
|
-
|
|
8249
|
-
|
|
8250
|
-
|
|
8251
|
-
* @param input the original css text.
|
|
8252
|
-
*
|
|
8253
|
-
* @returns the css text with specific characters in strings replaced by placeholders.
|
|
8254
|
-
**/
|
|
8255
|
-
function escapeInStrings(input) {
|
|
8256
|
-
let result = input;
|
|
8257
|
-
let currentQuoteChar = null;
|
|
8258
|
-
for (let i = 0; i < result.length; i++) {
|
|
8259
|
-
const char = result[i];
|
|
8260
|
-
if (char === '\\') {
|
|
8261
|
-
i++;
|
|
10399
|
+
* Ingest the nodes of a template AST into the given `ViewCompilation`.
|
|
10400
|
+
*/
|
|
10401
|
+
function ingestNodes(view, template) {
|
|
10402
|
+
for (const node of template) {
|
|
10403
|
+
if (node instanceof Element$1) {
|
|
10404
|
+
ingestElement(view, node);
|
|
10405
|
+
}
|
|
10406
|
+
else if (node instanceof Template) {
|
|
10407
|
+
ingestTemplate(view, node);
|
|
10408
|
+
}
|
|
10409
|
+
else if (node instanceof Text$3) {
|
|
10410
|
+
ingestText(view, node);
|
|
10411
|
+
}
|
|
10412
|
+
else if (node instanceof BoundText) {
|
|
10413
|
+
ingestBoundText(view, node);
|
|
8262
10414
|
}
|
|
8263
10415
|
else {
|
|
8264
|
-
|
|
8265
|
-
// index i is inside a quoted sub-string
|
|
8266
|
-
if (char === currentQuoteChar) {
|
|
8267
|
-
currentQuoteChar = null;
|
|
8268
|
-
}
|
|
8269
|
-
else {
|
|
8270
|
-
const placeholder = ESCAPE_IN_STRING_MAP[char];
|
|
8271
|
-
if (placeholder) {
|
|
8272
|
-
result = `${result.substr(0, i)}${placeholder}${result.substr(i + 1)}`;
|
|
8273
|
-
i += placeholder.length - 1;
|
|
8274
|
-
}
|
|
8275
|
-
}
|
|
8276
|
-
}
|
|
8277
|
-
else if (char === '\'' || char === '"') {
|
|
8278
|
-
currentQuoteChar = char;
|
|
8279
|
-
}
|
|
10416
|
+
throw new Error(`Unsupported template node: ${node.constructor.name}`);
|
|
8280
10417
|
}
|
|
8281
10418
|
}
|
|
8282
|
-
return result;
|
|
8283
10419
|
}
|
|
8284
10420
|
/**
|
|
8285
|
-
*
|
|
8286
|
-
* original representation, this is simply used to revert the changes applied by the
|
|
8287
|
-
* escapeInStrings function.
|
|
8288
|
-
*
|
|
8289
|
-
* For example it reverts the text:
|
|
8290
|
-
* `animation: "my-anim%COLON_IN_PLACEHOLDER%at\"ion" 1s;`
|
|
8291
|
-
* to it's original form of:
|
|
8292
|
-
* `animation: "my-anim:at\"ion" 1s;`
|
|
8293
|
-
*
|
|
8294
|
-
* Note: For the sake of simplicity this function does not check that the placeholders are
|
|
8295
|
-
* actually inside strings as it would anyway be extremely unlikely to find them outside of strings.
|
|
8296
|
-
*
|
|
8297
|
-
* @param input the css text containing the placeholders.
|
|
8298
|
-
*
|
|
8299
|
-
* @returns the css text without the placeholders.
|
|
10421
|
+
* Ingest an element AST from the template into the given `ViewCompilation`.
|
|
8300
10422
|
*/
|
|
8301
|
-
function
|
|
8302
|
-
|
|
8303
|
-
|
|
8304
|
-
|
|
8305
|
-
|
|
10423
|
+
function ingestElement(view, element) {
|
|
10424
|
+
const staticAttributes = {};
|
|
10425
|
+
for (const attr of element.attributes) {
|
|
10426
|
+
staticAttributes[attr.name] = attr.value;
|
|
10427
|
+
}
|
|
10428
|
+
const id = view.tpl.allocateXrefId();
|
|
10429
|
+
const startOp = createElementStartOp(element.name, id);
|
|
10430
|
+
view.create.push(startOp);
|
|
10431
|
+
ingestAttributes(startOp, element);
|
|
10432
|
+
ingestBindings(view, startOp, element);
|
|
10433
|
+
ingestReferences(startOp, element);
|
|
10434
|
+
ingestNodes(view, element.children);
|
|
10435
|
+
view.create.push(createElementEndOp(id));
|
|
8306
10436
|
}
|
|
8307
10437
|
/**
|
|
8308
|
-
*
|
|
8309
|
-
* quoted.
|
|
8310
|
-
*
|
|
8311
|
-
* This generates a "canonical" representation of strings which can be used to match strings
|
|
8312
|
-
* which would otherwise only differ because of differently escaped quotes.
|
|
8313
|
-
*
|
|
8314
|
-
* For example it converts the string (assumed to be quoted):
|
|
8315
|
-
* `this \\"is\\" a \\'\\\\'test`
|
|
8316
|
-
* to:
|
|
8317
|
-
* `this "is" a '\\\\'test`
|
|
8318
|
-
* (note that the latter backslashes are not removed as they are not actually escaping the single
|
|
8319
|
-
* quote)
|
|
8320
|
-
*
|
|
8321
|
-
*
|
|
8322
|
-
* @param input the string possibly containing escaped quotes.
|
|
8323
|
-
* @param isQuoted boolean indicating whether the string was quoted inside a bigger string (if not
|
|
8324
|
-
* then it means that it doesn't represent an inner string and thus no unescaping is required)
|
|
8325
|
-
*
|
|
8326
|
-
* @returns the string in the "canonical" representation without escaped quotes.
|
|
10438
|
+
* Ingest an `ng-template` node from the AST into the given `ViewCompilation`.
|
|
8327
10439
|
*/
|
|
8328
|
-
function
|
|
8329
|
-
|
|
10440
|
+
function ingestTemplate(view, tmpl) {
|
|
10441
|
+
const childView = view.tpl.allocateView(view.xref);
|
|
10442
|
+
// TODO: validate the fallback tag name here.
|
|
10443
|
+
const tplOp = createTemplateOp(childView.xref, tmpl.tagName ?? 'ng-template');
|
|
10444
|
+
view.create.push(tplOp);
|
|
10445
|
+
ingestAttributes(tplOp, tmpl);
|
|
10446
|
+
ingestBindings(view, tplOp, tmpl);
|
|
10447
|
+
ingestReferences(tplOp, tmpl);
|
|
10448
|
+
ingestNodes(childView, tmpl.children);
|
|
10449
|
+
for (const { name, value } of tmpl.variables) {
|
|
10450
|
+
childView.contextVariables.set(name, value);
|
|
10451
|
+
}
|
|
8330
10452
|
}
|
|
8331
10453
|
/**
|
|
8332
|
-
*
|
|
8333
|
-
* to create a selector that matches the same as `:host-context()`.
|
|
8334
|
-
*
|
|
8335
|
-
* Given a single context selector `A` we need to output selectors that match on the host and as an
|
|
8336
|
-
* ancestor of the host:
|
|
8337
|
-
*
|
|
8338
|
-
* ```
|
|
8339
|
-
* A <hostMarker>, A<hostMarker> {}
|
|
8340
|
-
* ```
|
|
8341
|
-
*
|
|
8342
|
-
* When there is more than one context selector we also have to create combinations of those
|
|
8343
|
-
* selectors with each other. For example if there are `A` and `B` selectors the output is:
|
|
8344
|
-
*
|
|
8345
|
-
* ```
|
|
8346
|
-
* AB<hostMarker>, AB <hostMarker>, A B<hostMarker>,
|
|
8347
|
-
* B A<hostMarker>, A B <hostMarker>, B A <hostMarker> {}
|
|
8348
|
-
* ```
|
|
8349
|
-
*
|
|
8350
|
-
* And so on...
|
|
8351
|
-
*
|
|
8352
|
-
* @param hostMarker the string that selects the host element.
|
|
8353
|
-
* @param contextSelectors an array of context selectors that will be combined.
|
|
8354
|
-
* @param otherSelectors the rest of the selectors that are not context selectors.
|
|
10454
|
+
* Ingest a literal text node from the AST into the given `ViewCompilation`.
|
|
8355
10455
|
*/
|
|
8356
|
-
function
|
|
8357
|
-
|
|
8358
|
-
|
|
8359
|
-
|
|
8360
|
-
|
|
8361
|
-
|
|
8362
|
-
|
|
10456
|
+
function ingestText(view, text) {
|
|
10457
|
+
view.create.push(createTextOp(view.tpl.allocateXrefId(), text.value));
|
|
10458
|
+
}
|
|
10459
|
+
/**
|
|
10460
|
+
* Ingest an interpolated text node from the AST into the given `ViewCompilation`.
|
|
10461
|
+
*/
|
|
10462
|
+
function ingestBoundText(view, text) {
|
|
10463
|
+
let value = text.value;
|
|
10464
|
+
if (value instanceof ASTWithSource) {
|
|
10465
|
+
value = value.ast;
|
|
8363
10466
|
}
|
|
8364
|
-
|
|
8365
|
-
|
|
8366
|
-
|
|
8367
|
-
|
|
8368
|
-
|
|
8369
|
-
|
|
8370
|
-
|
|
8371
|
-
|
|
8372
|
-
|
|
8373
|
-
|
|
8374
|
-
|
|
8375
|
-
|
|
10467
|
+
if (!(value instanceof Interpolation)) {
|
|
10468
|
+
throw new Error(`AssertionError: expected Interpolation for BoundText node, got ${value.constructor.name}`);
|
|
10469
|
+
}
|
|
10470
|
+
const textXref = view.tpl.allocateXrefId();
|
|
10471
|
+
view.create.push(createTextOp(textXref, ''));
|
|
10472
|
+
view.update.push(createInterpolateTextOp(textXref, value.strings, value.expressions.map(expr => convertAst(expr))));
|
|
10473
|
+
}
|
|
10474
|
+
/**
|
|
10475
|
+
* Convert a template AST expression into an output AST expression.
|
|
10476
|
+
*/
|
|
10477
|
+
function convertAst(ast) {
|
|
10478
|
+
if (ast instanceof ASTWithSource) {
|
|
10479
|
+
return convertAst(ast.ast);
|
|
10480
|
+
}
|
|
10481
|
+
else if (ast instanceof PropertyRead) {
|
|
10482
|
+
if (ast.receiver instanceof ImplicitReceiver) {
|
|
10483
|
+
return new LexicalReadExpr(ast.name);
|
|
10484
|
+
}
|
|
10485
|
+
else {
|
|
10486
|
+
return new ReadPropExpr(convertAst(ast.receiver), ast.name);
|
|
8376
10487
|
}
|
|
8377
10488
|
}
|
|
8378
|
-
|
|
8379
|
-
|
|
8380
|
-
|
|
8381
|
-
|
|
8382
|
-
|
|
8383
|
-
|
|
8384
|
-
|
|
10489
|
+
else if (ast instanceof Call) {
|
|
10490
|
+
if (ast.receiver instanceof ImplicitReceiver) {
|
|
10491
|
+
throw new Error(`Unexpected ImplicitReceiver`);
|
|
10492
|
+
}
|
|
10493
|
+
else {
|
|
10494
|
+
return new InvokeFunctionExpr(convertAst(ast.receiver), ast.args.map(arg => convertAst(arg)));
|
|
10495
|
+
}
|
|
10496
|
+
}
|
|
10497
|
+
else {
|
|
10498
|
+
throw new Error(`Unhandled expression type: ${ast.constructor.name}`);
|
|
10499
|
+
}
|
|
8385
10500
|
}
|
|
8386
10501
|
/**
|
|
8387
|
-
*
|
|
8388
|
-
*
|
|
8389
|
-
*
|
|
8390
|
-
* For example `repeatGroups([a, b], 3)` will result in `[a, b, a, b, a, b]` - but importantly the
|
|
8391
|
-
* newly added groups will be clones of the original.
|
|
8392
|
-
*
|
|
8393
|
-
* @param groups An array of groups of strings that will be repeated. This array is mutated
|
|
8394
|
-
* in-place.
|
|
8395
|
-
* @param multiples The number of times the current groups should appear.
|
|
10502
|
+
* Process all of the attributes on an element-like structure in the template AST and convert them
|
|
10503
|
+
* to their IR representation.
|
|
8396
10504
|
*/
|
|
8397
|
-
function
|
|
8398
|
-
|
|
8399
|
-
for (
|
|
8400
|
-
|
|
8401
|
-
|
|
10505
|
+
function ingestAttributes(op, element) {
|
|
10506
|
+
assertIsElementAttributes(op.attributes);
|
|
10507
|
+
for (const attr of element.attributes) {
|
|
10508
|
+
op.attributes.add(ElementAttributeKind.Attribute, attr.name, literal(attr.value));
|
|
10509
|
+
}
|
|
10510
|
+
for (const input of element.inputs) {
|
|
10511
|
+
op.attributes.add(ElementAttributeKind.Binding, input.name, null);
|
|
10512
|
+
}
|
|
10513
|
+
for (const output of element.outputs) {
|
|
10514
|
+
op.attributes.add(ElementAttributeKind.Binding, output.name, null);
|
|
10515
|
+
}
|
|
10516
|
+
if (element instanceof Template) {
|
|
10517
|
+
for (const attr of element.templateAttrs) {
|
|
10518
|
+
// TODO: what do we do about the value here?
|
|
10519
|
+
op.attributes.add(ElementAttributeKind.Template, attr.name, null);
|
|
10520
|
+
}
|
|
10521
|
+
}
|
|
10522
|
+
}
|
|
10523
|
+
/**
|
|
10524
|
+
* Process all of the bindings on an element-like structure in the template AST and convert them
|
|
10525
|
+
* to their IR representation.
|
|
10526
|
+
*/
|
|
10527
|
+
function ingestBindings(view, op, element) {
|
|
10528
|
+
if (element instanceof Template) {
|
|
10529
|
+
for (const attr of element.templateAttrs) {
|
|
10530
|
+
if (typeof attr.value === 'string') {
|
|
10531
|
+
throw new Error(`TODO: unhandled static attribute bindings (is this a thing?)`);
|
|
10532
|
+
}
|
|
10533
|
+
else {
|
|
10534
|
+
view.update.push(createPropertyOp(op.xref, attr.name, convertAst(attr.value)));
|
|
10535
|
+
}
|
|
10536
|
+
}
|
|
10537
|
+
}
|
|
10538
|
+
else {
|
|
10539
|
+
for (const input of element.inputs) {
|
|
10540
|
+
view.update.push(createPropertyOp(op.xref, input.name, convertAst(input.value)));
|
|
8402
10541
|
}
|
|
10542
|
+
for (const output of element.outputs) {
|
|
10543
|
+
const listenerOp = createListenerOp(op.xref, output.name);
|
|
10544
|
+
listenerOp.handlerOps.push(createStatementOp(new ReturnStatement(convertAst(output.handler))));
|
|
10545
|
+
view.create.push(listenerOp);
|
|
10546
|
+
}
|
|
10547
|
+
}
|
|
10548
|
+
}
|
|
10549
|
+
/**
|
|
10550
|
+
* Process all of the local references on an element-like structure in the template AST and convert
|
|
10551
|
+
* them to their IR representation.
|
|
10552
|
+
*/
|
|
10553
|
+
function ingestReferences(op, element) {
|
|
10554
|
+
assertIsArray(op.localRefs);
|
|
10555
|
+
for (const { name, value } of element.references) {
|
|
10556
|
+
op.localRefs.push({
|
|
10557
|
+
name,
|
|
10558
|
+
target: value,
|
|
10559
|
+
});
|
|
10560
|
+
}
|
|
10561
|
+
}
|
|
10562
|
+
/**
|
|
10563
|
+
* Assert that the given value is an array.
|
|
10564
|
+
*/
|
|
10565
|
+
function assertIsArray(value) {
|
|
10566
|
+
if (!Array.isArray(value)) {
|
|
10567
|
+
throw new Error(`AssertionError: expected an array`);
|
|
8403
10568
|
}
|
|
8404
10569
|
}
|
|
8405
10570
|
|
|
10571
|
+
const USE_TEMPLATE_PIPELINE = false;
|
|
10572
|
+
|
|
8406
10573
|
/**
|
|
8407
10574
|
* Parses string representation of a style and converts it into object literal.
|
|
8408
10575
|
*
|
|
@@ -10763,41 +12930,6 @@ class RecursiveVisitor {
|
|
|
10763
12930
|
}
|
|
10764
12931
|
}
|
|
10765
12932
|
|
|
10766
|
-
var TagContentType;
|
|
10767
|
-
(function (TagContentType) {
|
|
10768
|
-
TagContentType[TagContentType["RAW_TEXT"] = 0] = "RAW_TEXT";
|
|
10769
|
-
TagContentType[TagContentType["ESCAPABLE_RAW_TEXT"] = 1] = "ESCAPABLE_RAW_TEXT";
|
|
10770
|
-
TagContentType[TagContentType["PARSABLE_DATA"] = 2] = "PARSABLE_DATA";
|
|
10771
|
-
})(TagContentType || (TagContentType = {}));
|
|
10772
|
-
function splitNsName(elementName) {
|
|
10773
|
-
if (elementName[0] != ':') {
|
|
10774
|
-
return [null, elementName];
|
|
10775
|
-
}
|
|
10776
|
-
const colonIndex = elementName.indexOf(':', 1);
|
|
10777
|
-
if (colonIndex === -1) {
|
|
10778
|
-
throw new Error(`Unsupported format "${elementName}" expecting ":namespace:name"`);
|
|
10779
|
-
}
|
|
10780
|
-
return [elementName.slice(1, colonIndex), elementName.slice(colonIndex + 1)];
|
|
10781
|
-
}
|
|
10782
|
-
// `<ng-container>` tags work the same regardless the namespace
|
|
10783
|
-
function isNgContainer(tagName) {
|
|
10784
|
-
return splitNsName(tagName)[1] === 'ng-container';
|
|
10785
|
-
}
|
|
10786
|
-
// `<ng-content>` tags work the same regardless the namespace
|
|
10787
|
-
function isNgContent(tagName) {
|
|
10788
|
-
return splitNsName(tagName)[1] === 'ng-content';
|
|
10789
|
-
}
|
|
10790
|
-
// `<ng-template>` tags work the same regardless the namespace
|
|
10791
|
-
function isNgTemplate(tagName) {
|
|
10792
|
-
return splitNsName(tagName)[1] === 'ng-template';
|
|
10793
|
-
}
|
|
10794
|
-
function getNsPrefix(fullName) {
|
|
10795
|
-
return fullName === null ? null : splitNsName(fullName)[0];
|
|
10796
|
-
}
|
|
10797
|
-
function mergeNsAndName(prefix, localName) {
|
|
10798
|
-
return prefix ? `:${prefix}:${localName}` : localName;
|
|
10799
|
-
}
|
|
10800
|
-
|
|
10801
12933
|
class ElementSchemaRegistry {
|
|
10802
12934
|
}
|
|
10803
12935
|
|
|
@@ -18654,7 +20786,7 @@ function baseDirectiveFields(meta, constantPool, bindingParser) {
|
|
|
18654
20786
|
const definitionMap = new DefinitionMap();
|
|
18655
20787
|
const selectors = parseSelectorToR3Selector(meta.selector);
|
|
18656
20788
|
// e.g. `type: MyDirective`
|
|
18657
|
-
definitionMap.set('type', meta.
|
|
20789
|
+
definitionMap.set('type', meta.type.value);
|
|
18658
20790
|
// e.g. `selectors: [['', 'someDir', '']]`
|
|
18659
20791
|
if (selectors.length > 0) {
|
|
18660
20792
|
definitionMap.set('selectors', asLiteral(selectors));
|
|
@@ -18746,34 +20878,56 @@ function compileComponentFromMetadata(meta, constantPool, bindingParser) {
|
|
|
18746
20878
|
const templateTypeName = meta.name;
|
|
18747
20879
|
const templateName = templateTypeName ? `${templateTypeName}_Template` : null;
|
|
18748
20880
|
const changeDetection = meta.changeDetection;
|
|
18749
|
-
|
|
18750
|
-
|
|
18751
|
-
|
|
18752
|
-
|
|
18753
|
-
|
|
18754
|
-
|
|
18755
|
-
|
|
18756
|
-
|
|
18757
|
-
|
|
18758
|
-
|
|
18759
|
-
|
|
18760
|
-
|
|
18761
|
-
|
|
18762
|
-
|
|
18763
|
-
|
|
18764
|
-
|
|
18765
|
-
|
|
18766
|
-
|
|
18767
|
-
|
|
18768
|
-
|
|
18769
|
-
|
|
18770
|
-
//
|
|
18771
|
-
|
|
18772
|
-
|
|
18773
|
-
}
|
|
18774
|
-
|
|
18775
|
-
|
|
18776
|
-
|
|
20881
|
+
// Template compilation is currently conditional as we're in the process of rewriting it.
|
|
20882
|
+
if (!USE_TEMPLATE_PIPELINE) {
|
|
20883
|
+
// This is the main path currently used in compilation, which compiles the template with the
|
|
20884
|
+
// legacy `TemplateDefinitionBuilder`.
|
|
20885
|
+
const template = meta.template;
|
|
20886
|
+
const templateBuilder = new TemplateDefinitionBuilder(constantPool, BindingScope.createRootScope(), 0, templateTypeName, null, null, templateName, Identifiers.namespaceHTML, meta.relativeContextFilePath, meta.i18nUseExternalIds);
|
|
20887
|
+
const templateFunctionExpression = templateBuilder.buildTemplateFunction(template.nodes, []);
|
|
20888
|
+
// We need to provide this so that dynamically generated components know what
|
|
20889
|
+
// projected content blocks to pass through to the component when it is
|
|
20890
|
+
// instantiated.
|
|
20891
|
+
const ngContentSelectors = templateBuilder.getNgContentSelectors();
|
|
20892
|
+
if (ngContentSelectors) {
|
|
20893
|
+
definitionMap.set('ngContentSelectors', ngContentSelectors);
|
|
20894
|
+
}
|
|
20895
|
+
// e.g. `decls: 2`
|
|
20896
|
+
// definitionMap.set('decls', o.literal(tpl.root.decls!));
|
|
20897
|
+
definitionMap.set('decls', literal(templateBuilder.getConstCount()));
|
|
20898
|
+
// e.g. `vars: 2`
|
|
20899
|
+
// definitionMap.set('vars', o.literal(tpl.root.vars!));
|
|
20900
|
+
definitionMap.set('vars', literal(templateBuilder.getVarCount()));
|
|
20901
|
+
// Generate `consts` section of ComponentDef:
|
|
20902
|
+
// - either as an array:
|
|
20903
|
+
// `consts: [['one', 'two'], ['three', 'four']]`
|
|
20904
|
+
// - or as a factory function in case additional statements are present (to support i18n):
|
|
20905
|
+
// `consts: function() { var i18n_0; if (ngI18nClosureMode) {...} else {...} return [i18n_0];
|
|
20906
|
+
// }`
|
|
20907
|
+
const { constExpressions, prepareStatements } = templateBuilder.getConsts();
|
|
20908
|
+
if (constExpressions.length > 0) {
|
|
20909
|
+
let constsExpr = literalArr(constExpressions);
|
|
20910
|
+
// Prepare statements are present - turn `consts` into a function.
|
|
20911
|
+
if (prepareStatements.length > 0) {
|
|
20912
|
+
constsExpr = fn([], [...prepareStatements, new ReturnStatement(constsExpr)]);
|
|
20913
|
+
}
|
|
20914
|
+
definitionMap.set('consts', constsExpr);
|
|
20915
|
+
}
|
|
20916
|
+
definitionMap.set('template', templateFunctionExpression);
|
|
20917
|
+
}
|
|
20918
|
+
else {
|
|
20919
|
+
// This path compiles the template using the prototype template pipeline. First the template is
|
|
20920
|
+
// ingested into IR:
|
|
20921
|
+
const tpl = ingest(meta.name, meta.template.nodes);
|
|
20922
|
+
// Then the IR is transformed to prepare it for cod egeneration.
|
|
20923
|
+
transformTemplate(tpl);
|
|
20924
|
+
// Finally we emit the template function:
|
|
20925
|
+
const templateFn = emitTemplateFn(tpl, constantPool);
|
|
20926
|
+
definitionMap.set('template', templateFn);
|
|
20927
|
+
definitionMap.set('decls', literal(tpl.root.decls));
|
|
20928
|
+
definitionMap.set('vars', literal(tpl.root.vars));
|
|
20929
|
+
definitionMap.set('consts', literalArr(tpl.consts));
|
|
20930
|
+
}
|
|
18777
20931
|
if (meta.declarations.length > 0) {
|
|
18778
20932
|
definitionMap.set('dependencies', compileDeclarationList(literalArr(meta.declarations.map(decl => decl.type)), meta.declarationListEmitMode));
|
|
18779
20933
|
}
|
|
@@ -19352,7 +21506,6 @@ class CompilerFacadeImpl {
|
|
|
19352
21506
|
const metadata = {
|
|
19353
21507
|
name: facade.name,
|
|
19354
21508
|
type: wrapReference(facade.type),
|
|
19355
|
-
internalType: new WrappedNodeExpr(facade.type),
|
|
19356
21509
|
typeArgumentCount: 0,
|
|
19357
21510
|
deps: null,
|
|
19358
21511
|
pipeName: facade.pipeName,
|
|
@@ -19371,7 +21524,6 @@ class CompilerFacadeImpl {
|
|
|
19371
21524
|
const { expression, statements } = compileInjectable({
|
|
19372
21525
|
name: facade.name,
|
|
19373
21526
|
type: wrapReference(facade.type),
|
|
19374
|
-
internalType: new WrappedNodeExpr(facade.type),
|
|
19375
21527
|
typeArgumentCount: facade.typeArgumentCount,
|
|
19376
21528
|
providedIn: computeProvidedIn(facade.providedIn),
|
|
19377
21529
|
useClass: convertToProviderExpression(facade, 'useClass'),
|
|
@@ -19387,7 +21539,6 @@ class CompilerFacadeImpl {
|
|
|
19387
21539
|
const { expression, statements } = compileInjectable({
|
|
19388
21540
|
name: facade.type.name,
|
|
19389
21541
|
type: wrapReference(facade.type),
|
|
19390
|
-
internalType: new WrappedNodeExpr(facade.type),
|
|
19391
21542
|
typeArgumentCount: 0,
|
|
19392
21543
|
providedIn: computeProvidedIn(facade.providedIn),
|
|
19393
21544
|
useClass: convertToProviderExpression(facade, 'useClass'),
|
|
@@ -19403,7 +21554,6 @@ class CompilerFacadeImpl {
|
|
|
19403
21554
|
const meta = {
|
|
19404
21555
|
name: facade.name,
|
|
19405
21556
|
type: wrapReference(facade.type),
|
|
19406
|
-
internalType: new WrappedNodeExpr(facade.type),
|
|
19407
21557
|
providers: facade.providers && facade.providers.length > 0 ?
|
|
19408
21558
|
new WrappedNodeExpr(facade.providers) :
|
|
19409
21559
|
null,
|
|
@@ -19420,8 +21570,6 @@ class CompilerFacadeImpl {
|
|
|
19420
21570
|
compileNgModule(angularCoreEnv, sourceMapUrl, facade) {
|
|
19421
21571
|
const meta = {
|
|
19422
21572
|
type: wrapReference(facade.type),
|
|
19423
|
-
internalType: new WrappedNodeExpr(facade.type),
|
|
19424
|
-
adjacentType: new WrappedNodeExpr(facade.type),
|
|
19425
21573
|
bootstrap: facade.bootstrap.map(wrapReference),
|
|
19426
21574
|
declarations: facade.declarations.map(wrapReference),
|
|
19427
21575
|
publicDeclarationTypes: null,
|
|
@@ -19494,7 +21642,6 @@ class CompilerFacadeImpl {
|
|
|
19494
21642
|
const factoryRes = compileFactoryFunction({
|
|
19495
21643
|
name: meta.name,
|
|
19496
21644
|
type: wrapReference(meta.type),
|
|
19497
|
-
internalType: new WrappedNodeExpr(meta.type),
|
|
19498
21645
|
typeArgumentCount: meta.typeArgumentCount,
|
|
19499
21646
|
deps: convertR3DependencyMetadataArray(meta.deps),
|
|
19500
21647
|
target: meta.target,
|
|
@@ -19505,7 +21652,6 @@ class CompilerFacadeImpl {
|
|
|
19505
21652
|
const factoryRes = compileFactoryFunction({
|
|
19506
21653
|
name: meta.type.name,
|
|
19507
21654
|
type: wrapReference(meta.type),
|
|
19508
|
-
internalType: new WrappedNodeExpr(meta.type),
|
|
19509
21655
|
typeArgumentCount: 0,
|
|
19510
21656
|
deps: Array.isArray(meta.deps) ? meta.deps.map(convertR3DeclareDependencyMetadata) :
|
|
19511
21657
|
meta.deps,
|
|
@@ -19591,7 +21737,6 @@ function convertDirectiveFacadeToMetadata(facade) {
|
|
|
19591
21737
|
typeArgumentCount: 0,
|
|
19592
21738
|
typeSourceSpan: facade.typeSourceSpan,
|
|
19593
21739
|
type: wrapReference(facade.type),
|
|
19594
|
-
internalType: new WrappedNodeExpr(facade.type),
|
|
19595
21740
|
deps: null,
|
|
19596
21741
|
host: extractHostBindings(facade.propMetadata, facade.typeSourceSpan, facade.host),
|
|
19597
21742
|
inputs: { ...inputsFromMetadata, ...inputsFromType },
|
|
@@ -19608,7 +21753,6 @@ function convertDeclareDirectiveFacadeToMetadata(declaration, typeSourceSpan) {
|
|
|
19608
21753
|
name: declaration.type.name,
|
|
19609
21754
|
type: wrapReference(declaration.type),
|
|
19610
21755
|
typeSourceSpan,
|
|
19611
|
-
internalType: new WrappedNodeExpr(declaration.type),
|
|
19612
21756
|
selector: declaration.selector ?? null,
|
|
19613
21757
|
inputs: declaration.inputs ? inputsMappingToInputMetadata(declaration.inputs) : {},
|
|
19614
21758
|
outputs: declaration.outputs ?? {},
|
|
@@ -19886,7 +22030,6 @@ function convertDeclarePipeFacadeToMetadata(declaration) {
|
|
|
19886
22030
|
return {
|
|
19887
22031
|
name: declaration.type.name,
|
|
19888
22032
|
type: wrapReference(declaration.type),
|
|
19889
|
-
internalType: new WrappedNodeExpr(declaration.type),
|
|
19890
22033
|
typeArgumentCount: 0,
|
|
19891
22034
|
pipeName: declaration.name,
|
|
19892
22035
|
deps: null,
|
|
@@ -19898,7 +22041,6 @@ function convertDeclareInjectorFacadeToMetadata(declaration) {
|
|
|
19898
22041
|
return {
|
|
19899
22042
|
name: declaration.type.name,
|
|
19900
22043
|
type: wrapReference(declaration.type),
|
|
19901
|
-
internalType: new WrappedNodeExpr(declaration.type),
|
|
19902
22044
|
providers: declaration.providers !== undefined && declaration.providers.length > 0 ?
|
|
19903
22045
|
new WrappedNodeExpr(declaration.providers) :
|
|
19904
22046
|
null,
|
|
@@ -19917,7 +22059,7 @@ function publishFacade(global) {
|
|
|
19917
22059
|
* @description
|
|
19918
22060
|
* Entry point for all public APIs of the compiler package.
|
|
19919
22061
|
*/
|
|
19920
|
-
const VERSION = new Version('16.0.0-
|
|
22062
|
+
const VERSION = new Version('16.0.0-rc.0');
|
|
19921
22063
|
|
|
19922
22064
|
class CompilerConfig {
|
|
19923
22065
|
constructor({ defaultEncapsulation = ViewEncapsulation.Emulated, useJit = true, missingTranslation = null, preserveWhitespaces, strictInjectionParameters } = {}) {
|
|
@@ -21841,7 +23983,7 @@ const MINIMUM_PARTIAL_LINKER_VERSION$6 = '12.0.0';
|
|
|
21841
23983
|
function compileDeclareClassMetadata(metadata) {
|
|
21842
23984
|
const definitionMap = new DefinitionMap();
|
|
21843
23985
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$6));
|
|
21844
|
-
definitionMap.set('version', literal('16.0.0-
|
|
23986
|
+
definitionMap.set('version', literal('16.0.0-rc.0'));
|
|
21845
23987
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
21846
23988
|
definitionMap.set('type', metadata.type);
|
|
21847
23989
|
definitionMap.set('decorators', metadata.decorators);
|
|
@@ -21944,9 +24086,9 @@ function compileDeclareDirectiveFromMetadata(meta) {
|
|
|
21944
24086
|
function createDirectiveDefinitionMap(meta) {
|
|
21945
24087
|
const definitionMap = new DefinitionMap();
|
|
21946
24088
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$5));
|
|
21947
|
-
definitionMap.set('version', literal('16.0.0-
|
|
24089
|
+
definitionMap.set('version', literal('16.0.0-rc.0'));
|
|
21948
24090
|
// e.g. `type: MyDirective`
|
|
21949
|
-
definitionMap.set('type', meta.
|
|
24091
|
+
definitionMap.set('type', meta.type.value);
|
|
21950
24092
|
if (meta.isStandalone) {
|
|
21951
24093
|
definitionMap.set('isStandalone', literal(meta.isStandalone));
|
|
21952
24094
|
}
|
|
@@ -22169,9 +24311,9 @@ const MINIMUM_PARTIAL_LINKER_VERSION$4 = '12.0.0';
|
|
|
22169
24311
|
function compileDeclareFactoryFunction(meta) {
|
|
22170
24312
|
const definitionMap = new DefinitionMap();
|
|
22171
24313
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$4));
|
|
22172
|
-
definitionMap.set('version', literal('16.0.0-
|
|
24314
|
+
definitionMap.set('version', literal('16.0.0-rc.0'));
|
|
22173
24315
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
22174
|
-
definitionMap.set('type', meta.
|
|
24316
|
+
definitionMap.set('type', meta.type.value);
|
|
22175
24317
|
definitionMap.set('deps', compileDependencies(meta.deps));
|
|
22176
24318
|
definitionMap.set('target', importExpr(Identifiers.FactoryTarget).prop(FactoryTarget$1[meta.target]));
|
|
22177
24319
|
return {
|
|
@@ -22204,9 +24346,9 @@ function compileDeclareInjectableFromMetadata(meta) {
|
|
|
22204
24346
|
function createInjectableDefinitionMap(meta) {
|
|
22205
24347
|
const definitionMap = new DefinitionMap();
|
|
22206
24348
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$3));
|
|
22207
|
-
definitionMap.set('version', literal('16.0.0-
|
|
24349
|
+
definitionMap.set('version', literal('16.0.0-rc.0'));
|
|
22208
24350
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
22209
|
-
definitionMap.set('type', meta.
|
|
24351
|
+
definitionMap.set('type', meta.type.value);
|
|
22210
24352
|
// Only generate providedIn property if it has a non-null value
|
|
22211
24353
|
if (meta.providedIn !== undefined) {
|
|
22212
24354
|
const providedIn = convertFromMaybeForwardRefExpression(meta.providedIn);
|
|
@@ -22255,9 +24397,9 @@ function compileDeclareInjectorFromMetadata(meta) {
|
|
|
22255
24397
|
function createInjectorDefinitionMap(meta) {
|
|
22256
24398
|
const definitionMap = new DefinitionMap();
|
|
22257
24399
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$2));
|
|
22258
|
-
definitionMap.set('version', literal('16.0.0-
|
|
24400
|
+
definitionMap.set('version', literal('16.0.0-rc.0'));
|
|
22259
24401
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
22260
|
-
definitionMap.set('type', meta.
|
|
24402
|
+
definitionMap.set('type', meta.type.value);
|
|
22261
24403
|
definitionMap.set('providers', meta.providers);
|
|
22262
24404
|
if (meta.imports.length > 0) {
|
|
22263
24405
|
definitionMap.set('imports', literalArr(meta.imports));
|
|
@@ -22285,9 +24427,9 @@ function compileDeclareNgModuleFromMetadata(meta) {
|
|
|
22285
24427
|
function createNgModuleDefinitionMap(meta) {
|
|
22286
24428
|
const definitionMap = new DefinitionMap();
|
|
22287
24429
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$1));
|
|
22288
|
-
definitionMap.set('version', literal('16.0.0-
|
|
24430
|
+
definitionMap.set('version', literal('16.0.0-rc.0'));
|
|
22289
24431
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
22290
|
-
definitionMap.set('type', meta.
|
|
24432
|
+
definitionMap.set('type', meta.type.value);
|
|
22291
24433
|
// We only generate the keys in the metadata if the arrays contain values.
|
|
22292
24434
|
// We must wrap the arrays inside a function if any of the values are a forward reference to a
|
|
22293
24435
|
// not-yet-declared class. This is to support JIT execution of the `ɵɵngDeclareNgModule()` call.
|
|
@@ -22336,10 +24478,10 @@ function compileDeclarePipeFromMetadata(meta) {
|
|
|
22336
24478
|
function createPipeDefinitionMap(meta) {
|
|
22337
24479
|
const definitionMap = new DefinitionMap();
|
|
22338
24480
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION));
|
|
22339
|
-
definitionMap.set('version', literal('16.0.0-
|
|
24481
|
+
definitionMap.set('version', literal('16.0.0-rc.0'));
|
|
22340
24482
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
22341
24483
|
// e.g. `type: MyPipe`
|
|
22342
|
-
definitionMap.set('type', meta.
|
|
24484
|
+
definitionMap.set('type', meta.type.value);
|
|
22343
24485
|
if (meta.isStandalone) {
|
|
22344
24486
|
definitionMap.set('isStandalone', literal(meta.isStandalone));
|
|
22345
24487
|
}
|