@angular/compiler 16.0.0-next.7 → 16.0.0-rc.1

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.
Files changed (42) hide show
  1. package/esm2022/src/render3/partial/class_metadata.mjs +1 -1
  2. package/esm2022/src/render3/partial/directive.mjs +1 -1
  3. package/esm2022/src/render3/partial/factory.mjs +1 -1
  4. package/esm2022/src/render3/partial/injectable.mjs +1 -1
  5. package/esm2022/src/render3/partial/injector.mjs +1 -1
  6. package/esm2022/src/render3/partial/ng_module.mjs +1 -1
  7. package/esm2022/src/render3/partial/pipe.mjs +1 -1
  8. package/esm2022/src/render3/view/compiler.mjs +52 -27
  9. package/esm2022/src/render3/view/util.mjs +4 -2
  10. package/esm2022/src/template/pipeline/ir/index.mjs +17 -0
  11. package/esm2022/src/template/pipeline/ir/src/element.mjs +101 -0
  12. package/esm2022/src/template/pipeline/ir/src/enums.mjs +121 -0
  13. package/esm2022/src/template/pipeline/ir/src/expression.mjs +293 -0
  14. package/esm2022/src/template/pipeline/ir/src/operations.mjs +223 -0
  15. package/esm2022/src/template/pipeline/ir/src/ops/create.mjs +78 -0
  16. package/esm2022/src/template/pipeline/ir/src/ops/shared.mjs +43 -0
  17. package/esm2022/src/template/pipeline/ir/src/ops/update.mjs +49 -0
  18. package/esm2022/src/template/pipeline/ir/src/traits.mjs +68 -0
  19. package/esm2022/src/template/pipeline/ir/src/variable.mjs +9 -0
  20. package/esm2022/src/template/pipeline/src/compilation.mjs +122 -0
  21. package/esm2022/src/template/pipeline/src/emit.mjs +83 -0
  22. package/esm2022/src/template/pipeline/src/ingest.mjs +194 -0
  23. package/esm2022/src/template/pipeline/src/instruction.mjs +139 -0
  24. package/esm2022/src/template/pipeline/src/phases/const_collection.mjs +57 -0
  25. package/esm2022/src/template/pipeline/src/phases/empty_elements.mjs +27 -0
  26. package/esm2022/src/template/pipeline/src/phases/generate_advance.mjs +56 -0
  27. package/esm2022/src/template/pipeline/src/phases/generate_variables.mjs +146 -0
  28. package/esm2022/src/template/pipeline/src/phases/local_refs.mjs +44 -0
  29. package/esm2022/src/template/pipeline/src/phases/naming.mjs +61 -0
  30. package/esm2022/src/template/pipeline/src/phases/reify.mjs +157 -0
  31. package/esm2022/src/template/pipeline/src/phases/resolve_contexts.mjs +55 -0
  32. package/esm2022/src/template/pipeline/src/phases/resolve_names.mjs +95 -0
  33. package/esm2022/src/template/pipeline/src/phases/slot_allocation.mjs +75 -0
  34. package/esm2022/src/template/pipeline/src/phases/var_counting.mjs +60 -0
  35. package/esm2022/src/template/pipeline/switch/index.mjs +2 -0
  36. package/esm2022/src/version.mjs +1 -1
  37. package/fesm2022/compiler.mjs +2386 -231
  38. package/fesm2022/compiler.mjs.map +1 -1
  39. package/fesm2022/testing.mjs +1 -1
  40. package/index.d.ts +1 -1
  41. package/package.json +3 -3
  42. package/testing/index.d.ts +1 -1
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Angular v16.0.0-next.7
2
+ * @license Angular v16.0.0-rc.1
3
3
  * (c) 2010-2022 Google LLC. https://angular.io/
4
4
  * License: MIT
5
5
  */
@@ -4815,7 +4815,9 @@ function getAttrsForDirectiveMatching(elOrTpl) {
4815
4815
  }
4816
4816
  });
4817
4817
  elOrTpl.inputs.forEach(i => {
4818
- attributesMap[i.name] = '';
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] = '';
@@ -8216,192 +8218,2358 @@ function escapeBlocks(input, charPairs, placeholder) {
8216
8218
  escapedBlocks.push(input.substring(blockStartIndex));
8217
8219
  resultParts.push(placeholder);
8218
8220
  }
8219
- else {
8220
- 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
+ }
8221
10386
  }
8222
- return new StringWithEscapedBlocks(resultParts.join(''), escapedBlocks);
8223
10387
  }
10388
+
8224
10389
  /**
8225
- * Object containing as keys characters that should be substituted by placeholders
8226
- * when found in strings during the css text parsing, and as values the respective
8227
- * placeholders
10390
+ * Process a template AST and convert it into a `ComponentCompilation` in the intermediate
10391
+ * representation.
8228
10392
  */
8229
- const ESCAPE_IN_STRING_MAP = {
8230
- ';': SEMI_IN_PLACEHOLDER,
8231
- ',': COMMA_IN_PLACEHOLDER,
8232
- ':': COLON_IN_PLACEHOLDER
8233
- };
10393
+ function ingest(componentName, template) {
10394
+ const cpl = new ComponentCompilation(componentName);
10395
+ ingestNodes(cpl.root, template);
10396
+ return cpl;
10397
+ }
8234
10398
  /**
8235
- * Parse the provided css text and inside strings (meaning, inside pairs of unescaped single or
8236
- * double quotes) replace specific characters with their respective placeholders as indicated
8237
- * by the `ESCAPE_IN_STRING_MAP` map.
8238
- *
8239
- * For example convert the text
8240
- * `animation: "my-anim:at\"ion" 1s;`
8241
- * to
8242
- * `animation: "my-anim%COLON_IN_PLACEHOLDER%at\"ion" 1s;`
8243
- *
8244
- * This is necessary in order to remove the meaning of some characters when found inside strings
8245
- * (for example `;` indicates the end of a css declaration, `,` the sequence of values and `:` the
8246
- * division between property and value during a declaration, none of these meanings apply when such
8247
- * characters are within strings and so in order to prevent parsing issues they need to be replaced
8248
- * with placeholder text for the duration of the css manipulation process).
8249
- *
8250
- * @param input the original css text.
8251
- *
8252
- * @returns the css text with specific characters in strings replaced by placeholders.
8253
- **/
8254
- function escapeInStrings(input) {
8255
- let result = input;
8256
- let currentQuoteChar = null;
8257
- for (let i = 0; i < result.length; i++) {
8258
- const char = result[i];
8259
- if (char === '\\') {
8260
- 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);
8261
10414
  }
8262
10415
  else {
8263
- if (currentQuoteChar !== null) {
8264
- // index i is inside a quoted sub-string
8265
- if (char === currentQuoteChar) {
8266
- currentQuoteChar = null;
8267
- }
8268
- else {
8269
- const placeholder = ESCAPE_IN_STRING_MAP[char];
8270
- if (placeholder) {
8271
- result = `${result.substr(0, i)}${placeholder}${result.substr(i + 1)}`;
8272
- i += placeholder.length - 1;
8273
- }
8274
- }
8275
- }
8276
- else if (char === '\'' || char === '"') {
8277
- currentQuoteChar = char;
8278
- }
10416
+ throw new Error(`Unsupported template node: ${node.constructor.name}`);
8279
10417
  }
8280
10418
  }
8281
- return result;
8282
10419
  }
8283
10420
  /**
8284
- * Replace in a string all occurrences of keys in the `ESCAPE_IN_STRING_MAP` map with their
8285
- * original representation, this is simply used to revert the changes applied by the
8286
- * escapeInStrings function.
8287
- *
8288
- * For example it reverts the text:
8289
- * `animation: "my-anim%COLON_IN_PLACEHOLDER%at\"ion" 1s;`
8290
- * to it's original form of:
8291
- * `animation: "my-anim:at\"ion" 1s;`
8292
- *
8293
- * Note: For the sake of simplicity this function does not check that the placeholders are
8294
- * actually inside strings as it would anyway be extremely unlikely to find them outside of strings.
8295
- *
8296
- * @param input the css text containing the placeholders.
8297
- *
8298
- * @returns the css text without the placeholders.
10421
+ * Ingest an element AST from the template into the given `ViewCompilation`.
8299
10422
  */
8300
- function unescapeInStrings(input) {
8301
- let result = input.replace(_cssCommaInPlaceholderReGlobal, ',');
8302
- result = result.replace(_cssSemiInPlaceholderReGlobal, ';');
8303
- result = result.replace(_cssColonInPlaceholderReGlobal, ':');
8304
- return result;
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));
8305
10436
  }
8306
10437
  /**
8307
- * Unescape all quotes present in a string, but only if the string was actually already
8308
- * quoted.
8309
- *
8310
- * This generates a "canonical" representation of strings which can be used to match strings
8311
- * which would otherwise only differ because of differently escaped quotes.
8312
- *
8313
- * For example it converts the string (assumed to be quoted):
8314
- * `this \\"is\\" a \\'\\\\'test`
8315
- * to:
8316
- * `this "is" a '\\\\'test`
8317
- * (note that the latter backslashes are not removed as they are not actually escaping the single
8318
- * quote)
8319
- *
8320
- *
8321
- * @param input the string possibly containing escaped quotes.
8322
- * @param isQuoted boolean indicating whether the string was quoted inside a bigger string (if not
8323
- * then it means that it doesn't represent an inner string and thus no unescaping is required)
8324
- *
8325
- * @returns the string in the "canonical" representation without escaped quotes.
10438
+ * Ingest an `ng-template` node from the AST into the given `ViewCompilation`.
8326
10439
  */
8327
- function unescapeQuotes(str, isQuoted) {
8328
- return !isQuoted ? str : str.replace(/((?:^|[^\\])(?:\\\\)*)\\(?=['"])/g, '$1');
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
+ }
8329
10452
  }
8330
10453
  /**
8331
- * Combine the `contextSelectors` with the `hostMarker` and the `otherSelectors`
8332
- * to create a selector that matches the same as `:host-context()`.
8333
- *
8334
- * Given a single context selector `A` we need to output selectors that match on the host and as an
8335
- * ancestor of the host:
8336
- *
8337
- * ```
8338
- * A <hostMarker>, A<hostMarker> {}
8339
- * ```
8340
- *
8341
- * When there is more than one context selector we also have to create combinations of those
8342
- * selectors with each other. For example if there are `A` and `B` selectors the output is:
8343
- *
8344
- * ```
8345
- * AB<hostMarker>, AB <hostMarker>, A B<hostMarker>,
8346
- * B A<hostMarker>, A B <hostMarker>, B A <hostMarker> {}
8347
- * ```
8348
- *
8349
- * And so on...
8350
- *
8351
- * @param hostMarker the string that selects the host element.
8352
- * @param contextSelectors an array of context selectors that will be combined.
8353
- * @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`.
8354
10455
  */
8355
- function combineHostContextSelectors(contextSelectors, otherSelectors) {
8356
- const hostMarker = _polyfillHostNoCombinator;
8357
- _polyfillHostRe.lastIndex = 0; // reset the regex to ensure we get an accurate test
8358
- const otherSelectorsHasHost = _polyfillHostRe.test(otherSelectors);
8359
- // If there are no context selectors then just output a host marker
8360
- if (contextSelectors.length === 0) {
8361
- return hostMarker + otherSelectors;
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;
8362
10466
  }
8363
- const combined = [contextSelectors.pop() || ''];
8364
- while (contextSelectors.length > 0) {
8365
- const length = combined.length;
8366
- const contextSelector = contextSelectors.pop();
8367
- for (let i = 0; i < length; i++) {
8368
- const previousSelectors = combined[i];
8369
- // Add the new selector as a descendant of the previous selectors
8370
- combined[length * 2 + i] = previousSelectors + ' ' + contextSelector;
8371
- // Add the new selector as an ancestor of the previous selectors
8372
- combined[length + i] = contextSelector + ' ' + previousSelectors;
8373
- // Add the new selector to act on the same element as the previous selectors
8374
- combined[i] = contextSelector + previousSelectors;
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);
8375
10487
  }
8376
10488
  }
8377
- // Finally connect the selector to the `hostMarker`s: either acting directly on the host
8378
- // (A<hostMarker>) or as an ancestor (A <hostMarker>).
8379
- return combined
8380
- .map(s => otherSelectorsHasHost ?
8381
- `${s}${otherSelectors}` :
8382
- `${s}${hostMarker}${otherSelectors}, ${s} ${hostMarker}${otherSelectors}`)
8383
- .join(',');
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
+ }
8384
10500
  }
8385
10501
  /**
8386
- * Mutate the given `groups` array so that there are `multiples` clones of the original array
8387
- * stored.
8388
- *
8389
- * For example `repeatGroups([a, b], 3)` will result in `[a, b, a, b, a, b]` - but importantly the
8390
- * newly added groups will be clones of the original.
8391
- *
8392
- * @param groups An array of groups of strings that will be repeated. This array is mutated
8393
- * in-place.
8394
- * @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.
8395
10504
  */
8396
- function repeatGroups(groups, multiples) {
8397
- const length = groups.length;
8398
- for (let i = 1; i < multiples; i++) {
8399
- for (let j = 0; j < length; j++) {
8400
- groups[j + (i * length)] = groups[j].slice(0);
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)));
8401
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`);
8402
10568
  }
8403
10569
  }
8404
10570
 
10571
+ const USE_TEMPLATE_PIPELINE = false;
10572
+
8405
10573
  /**
8406
10574
  * Parses string representation of a style and converts it into object literal.
8407
10575
  *
@@ -10762,41 +12930,6 @@ class RecursiveVisitor {
10762
12930
  }
10763
12931
  }
10764
12932
 
10765
- var TagContentType;
10766
- (function (TagContentType) {
10767
- TagContentType[TagContentType["RAW_TEXT"] = 0] = "RAW_TEXT";
10768
- TagContentType[TagContentType["ESCAPABLE_RAW_TEXT"] = 1] = "ESCAPABLE_RAW_TEXT";
10769
- TagContentType[TagContentType["PARSABLE_DATA"] = 2] = "PARSABLE_DATA";
10770
- })(TagContentType || (TagContentType = {}));
10771
- function splitNsName(elementName) {
10772
- if (elementName[0] != ':') {
10773
- return [null, elementName];
10774
- }
10775
- const colonIndex = elementName.indexOf(':', 1);
10776
- if (colonIndex === -1) {
10777
- throw new Error(`Unsupported format "${elementName}" expecting ":namespace:name"`);
10778
- }
10779
- return [elementName.slice(1, colonIndex), elementName.slice(colonIndex + 1)];
10780
- }
10781
- // `<ng-container>` tags work the same regardless the namespace
10782
- function isNgContainer(tagName) {
10783
- return splitNsName(tagName)[1] === 'ng-container';
10784
- }
10785
- // `<ng-content>` tags work the same regardless the namespace
10786
- function isNgContent(tagName) {
10787
- return splitNsName(tagName)[1] === 'ng-content';
10788
- }
10789
- // `<ng-template>` tags work the same regardless the namespace
10790
- function isNgTemplate(tagName) {
10791
- return splitNsName(tagName)[1] === 'ng-template';
10792
- }
10793
- function getNsPrefix(fullName) {
10794
- return fullName === null ? null : splitNsName(fullName)[0];
10795
- }
10796
- function mergeNsAndName(prefix, localName) {
10797
- return prefix ? `:${prefix}:${localName}` : localName;
10798
- }
10799
-
10800
12933
  class ElementSchemaRegistry {
10801
12934
  }
10802
12935
 
@@ -18745,34 +20878,56 @@ function compileComponentFromMetadata(meta, constantPool, bindingParser) {
18745
20878
  const templateTypeName = meta.name;
18746
20879
  const templateName = templateTypeName ? `${templateTypeName}_Template` : null;
18747
20880
  const changeDetection = meta.changeDetection;
18748
- const template = meta.template;
18749
- const templateBuilder = new TemplateDefinitionBuilder(constantPool, BindingScope.createRootScope(), 0, templateTypeName, null, null, templateName, Identifiers.namespaceHTML, meta.relativeContextFilePath, meta.i18nUseExternalIds);
18750
- const templateFunctionExpression = templateBuilder.buildTemplateFunction(template.nodes, []);
18751
- // We need to provide this so that dynamically generated components know what
18752
- // projected content blocks to pass through to the component when it is instantiated.
18753
- const ngContentSelectors = templateBuilder.getNgContentSelectors();
18754
- if (ngContentSelectors) {
18755
- definitionMap.set('ngContentSelectors', ngContentSelectors);
18756
- }
18757
- // e.g. `decls: 2`
18758
- definitionMap.set('decls', literal(templateBuilder.getConstCount()));
18759
- // e.g. `vars: 2`
18760
- definitionMap.set('vars', literal(templateBuilder.getVarCount()));
18761
- // Generate `consts` section of ComponentDef:
18762
- // - either as an array:
18763
- // `consts: [['one', 'two'], ['three', 'four']]`
18764
- // - or as a factory function in case additional statements are present (to support i18n):
18765
- // `consts: function() { var i18n_0; if (ngI18nClosureMode) {...} else {...} return [i18n_0]; }`
18766
- const { constExpressions, prepareStatements } = templateBuilder.getConsts();
18767
- if (constExpressions.length > 0) {
18768
- let constsExpr = literalArr(constExpressions);
18769
- // Prepare statements are present - turn `consts` into a function.
18770
- if (prepareStatements.length > 0) {
18771
- constsExpr = fn([], [...prepareStatements, new ReturnStatement(constsExpr)]);
18772
- }
18773
- definitionMap.set('consts', constsExpr);
18774
- }
18775
- definitionMap.set('template', templateFunctionExpression);
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
+ }
18776
20931
  if (meta.declarations.length > 0) {
18777
20932
  definitionMap.set('dependencies', compileDeclarationList(literalArr(meta.declarations.map(decl => decl.type)), meta.declarationListEmitMode));
18778
20933
  }
@@ -19904,7 +22059,7 @@ function publishFacade(global) {
19904
22059
  * @description
19905
22060
  * Entry point for all public APIs of the compiler package.
19906
22061
  */
19907
- const VERSION = new Version('16.0.0-next.7');
22062
+ const VERSION = new Version('16.0.0-rc.1');
19908
22063
 
19909
22064
  class CompilerConfig {
19910
22065
  constructor({ defaultEncapsulation = ViewEncapsulation.Emulated, useJit = true, missingTranslation = null, preserveWhitespaces, strictInjectionParameters } = {}) {
@@ -21828,7 +23983,7 @@ const MINIMUM_PARTIAL_LINKER_VERSION$6 = '12.0.0';
21828
23983
  function compileDeclareClassMetadata(metadata) {
21829
23984
  const definitionMap = new DefinitionMap();
21830
23985
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$6));
21831
- definitionMap.set('version', literal('16.0.0-next.7'));
23986
+ definitionMap.set('version', literal('16.0.0-rc.1'));
21832
23987
  definitionMap.set('ngImport', importExpr(Identifiers.core));
21833
23988
  definitionMap.set('type', metadata.type);
21834
23989
  definitionMap.set('decorators', metadata.decorators);
@@ -21931,7 +24086,7 @@ function compileDeclareDirectiveFromMetadata(meta) {
21931
24086
  function createDirectiveDefinitionMap(meta) {
21932
24087
  const definitionMap = new DefinitionMap();
21933
24088
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$5));
21934
- definitionMap.set('version', literal('16.0.0-next.7'));
24089
+ definitionMap.set('version', literal('16.0.0-rc.1'));
21935
24090
  // e.g. `type: MyDirective`
21936
24091
  definitionMap.set('type', meta.type.value);
21937
24092
  if (meta.isStandalone) {
@@ -22156,7 +24311,7 @@ const MINIMUM_PARTIAL_LINKER_VERSION$4 = '12.0.0';
22156
24311
  function compileDeclareFactoryFunction(meta) {
22157
24312
  const definitionMap = new DefinitionMap();
22158
24313
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$4));
22159
- definitionMap.set('version', literal('16.0.0-next.7'));
24314
+ definitionMap.set('version', literal('16.0.0-rc.1'));
22160
24315
  definitionMap.set('ngImport', importExpr(Identifiers.core));
22161
24316
  definitionMap.set('type', meta.type.value);
22162
24317
  definitionMap.set('deps', compileDependencies(meta.deps));
@@ -22191,7 +24346,7 @@ function compileDeclareInjectableFromMetadata(meta) {
22191
24346
  function createInjectableDefinitionMap(meta) {
22192
24347
  const definitionMap = new DefinitionMap();
22193
24348
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$3));
22194
- definitionMap.set('version', literal('16.0.0-next.7'));
24349
+ definitionMap.set('version', literal('16.0.0-rc.1'));
22195
24350
  definitionMap.set('ngImport', importExpr(Identifiers.core));
22196
24351
  definitionMap.set('type', meta.type.value);
22197
24352
  // Only generate providedIn property if it has a non-null value
@@ -22242,7 +24397,7 @@ function compileDeclareInjectorFromMetadata(meta) {
22242
24397
  function createInjectorDefinitionMap(meta) {
22243
24398
  const definitionMap = new DefinitionMap();
22244
24399
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$2));
22245
- definitionMap.set('version', literal('16.0.0-next.7'));
24400
+ definitionMap.set('version', literal('16.0.0-rc.1'));
22246
24401
  definitionMap.set('ngImport', importExpr(Identifiers.core));
22247
24402
  definitionMap.set('type', meta.type.value);
22248
24403
  definitionMap.set('providers', meta.providers);
@@ -22272,7 +24427,7 @@ function compileDeclareNgModuleFromMetadata(meta) {
22272
24427
  function createNgModuleDefinitionMap(meta) {
22273
24428
  const definitionMap = new DefinitionMap();
22274
24429
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$1));
22275
- definitionMap.set('version', literal('16.0.0-next.7'));
24430
+ definitionMap.set('version', literal('16.0.0-rc.1'));
22276
24431
  definitionMap.set('ngImport', importExpr(Identifiers.core));
22277
24432
  definitionMap.set('type', meta.type.value);
22278
24433
  // We only generate the keys in the metadata if the arrays contain values.
@@ -22323,7 +24478,7 @@ function compileDeclarePipeFromMetadata(meta) {
22323
24478
  function createPipeDefinitionMap(meta) {
22324
24479
  const definitionMap = new DefinitionMap();
22325
24480
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION));
22326
- definitionMap.set('version', literal('16.0.0-next.7'));
24481
+ definitionMap.set('version', literal('16.0.0-rc.1'));
22327
24482
  definitionMap.set('ngImport', importExpr(Identifiers.core));
22328
24483
  // e.g. `type: MyPipe`
22329
24484
  definitionMap.set('type', meta.type.value);