@angular-eslint/bundled-angular-compiler 18.0.2-alpha.0 → 18.0.2-alpha.10

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 (2) hide show
  1. package/dist/index.js +528 -77
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  /**
4
- * @license Angular v18.0.0
4
+ * @license Angular v18.0.5
5
5
  * (c) 2010-2024 Google LLC. https://angular.io/
6
6
  * License: MIT
7
7
  */
@@ -2886,6 +2886,9 @@ class Identifiers {
2886
2886
  static { this.twoWayProperty = { name: 'ɵɵtwoWayProperty', moduleName: CORE }; }
2887
2887
  static { this.twoWayBindingSet = { name: 'ɵɵtwoWayBindingSet', moduleName: CORE }; }
2888
2888
  static { this.twoWayListener = { name: 'ɵɵtwoWayListener', moduleName: CORE }; }
2889
+ static { this.declareLet = { name: 'ɵɵdeclareLet', moduleName: CORE }; }
2890
+ static { this.storeLet = { name: 'ɵɵstoreLet', moduleName: CORE }; }
2891
+ static { this.readContextLet = { name: 'ɵɵreadContextLet', moduleName: CORE }; }
2889
2892
  static { this.NgOnChangesFeature = { name: 'ɵɵNgOnChangesFeature', moduleName: CORE }; }
2890
2893
  static { this.InheritDefinitionFeature = {
2891
2894
  name: 'ɵɵInheritDefinitionFeature',
@@ -5053,6 +5056,18 @@ class UnknownBlock {
5053
5056
  return visitor.visitUnknownBlock(this);
5054
5057
  }
5055
5058
  }
5059
+ class LetDeclaration$1 {
5060
+ constructor(name, value, sourceSpan, nameSpan, valueSpan) {
5061
+ this.name = name;
5062
+ this.value = value;
5063
+ this.sourceSpan = sourceSpan;
5064
+ this.nameSpan = nameSpan;
5065
+ this.valueSpan = valueSpan;
5066
+ }
5067
+ visit(visitor) {
5068
+ return visitor.visitLetDeclaration(this);
5069
+ }
5070
+ }
5056
5071
  class Template {
5057
5072
  constructor(
5058
5073
  // tagName is the name of the container element, if applicable.
@@ -5188,6 +5203,7 @@ class RecursiveVisitor$1 {
5188
5203
  visitIcu(icu) { }
5189
5204
  visitDeferredTrigger(trigger) { }
5190
5205
  visitUnknownBlock(block) { }
5206
+ visitLetDeclaration(decl) { }
5191
5207
  }
5192
5208
  function visitAll$1(visitor, nodes) {
5193
5209
  const result = [];
@@ -8191,46 +8207,54 @@ var OpKind;
8191
8207
  * An operation declaring the event side of a two-way binding.
8192
8208
  */
8193
8209
  OpKind[OpKind["TwoWayListener"] = 37] = "TwoWayListener";
8210
+ /**
8211
+ * A creation-time operation that initializes the slot for a `@let` declaration.
8212
+ */
8213
+ OpKind[OpKind["DeclareLet"] = 38] = "DeclareLet";
8214
+ /**
8215
+ * An update-time operation that stores the current value of a `@let` declaration.
8216
+ */
8217
+ OpKind[OpKind["StoreLet"] = 39] = "StoreLet";
8194
8218
  /**
8195
8219
  * The start of an i18n block.
8196
8220
  */
8197
- OpKind[OpKind["I18nStart"] = 38] = "I18nStart";
8221
+ OpKind[OpKind["I18nStart"] = 40] = "I18nStart";
8198
8222
  /**
8199
8223
  * A self-closing i18n on a single element.
8200
8224
  */
8201
- OpKind[OpKind["I18n"] = 39] = "I18n";
8225
+ OpKind[OpKind["I18n"] = 41] = "I18n";
8202
8226
  /**
8203
8227
  * The end of an i18n block.
8204
8228
  */
8205
- OpKind[OpKind["I18nEnd"] = 40] = "I18nEnd";
8229
+ OpKind[OpKind["I18nEnd"] = 42] = "I18nEnd";
8206
8230
  /**
8207
8231
  * An expression in an i18n message.
8208
8232
  */
8209
- OpKind[OpKind["I18nExpression"] = 41] = "I18nExpression";
8233
+ OpKind[OpKind["I18nExpression"] = 43] = "I18nExpression";
8210
8234
  /**
8211
8235
  * An instruction that applies a set of i18n expressions.
8212
8236
  */
8213
- OpKind[OpKind["I18nApply"] = 42] = "I18nApply";
8237
+ OpKind[OpKind["I18nApply"] = 44] = "I18nApply";
8214
8238
  /**
8215
8239
  * An instruction to create an ICU expression.
8216
8240
  */
8217
- OpKind[OpKind["IcuStart"] = 43] = "IcuStart";
8241
+ OpKind[OpKind["IcuStart"] = 45] = "IcuStart";
8218
8242
  /**
8219
8243
  * An instruction to update an ICU expression.
8220
8244
  */
8221
- OpKind[OpKind["IcuEnd"] = 44] = "IcuEnd";
8245
+ OpKind[OpKind["IcuEnd"] = 46] = "IcuEnd";
8222
8246
  /**
8223
8247
  * An instruction representing a placeholder in an ICU expression.
8224
8248
  */
8225
- OpKind[OpKind["IcuPlaceholder"] = 45] = "IcuPlaceholder";
8249
+ OpKind[OpKind["IcuPlaceholder"] = 47] = "IcuPlaceholder";
8226
8250
  /**
8227
8251
  * An i18n context containing information needed to generate an i18n message.
8228
8252
  */
8229
- OpKind[OpKind["I18nContext"] = 46] = "I18nContext";
8253
+ OpKind[OpKind["I18nContext"] = 48] = "I18nContext";
8230
8254
  /**
8231
8255
  * A creation op that corresponds to i18n attributes on an element.
8232
8256
  */
8233
- OpKind[OpKind["I18nAttributes"] = 47] = "I18nAttributes";
8257
+ OpKind[OpKind["I18nAttributes"] = 49] = "I18nAttributes";
8234
8258
  })(OpKind || (OpKind = {}));
8235
8259
  /**
8236
8260
  * Distinguishes different kinds of IR expressions.
@@ -8261,78 +8285,86 @@ var ExpressionKind;
8261
8285
  * Runtime operation to retrieve the value of a local reference.
8262
8286
  */
8263
8287
  ExpressionKind[ExpressionKind["Reference"] = 5] = "Reference";
8288
+ /**
8289
+ * A call storing the value of a `@let` declaration.
8290
+ */
8291
+ ExpressionKind[ExpressionKind["StoreLet"] = 6] = "StoreLet";
8292
+ /**
8293
+ * A reference to a `@let` declaration read from the context view.
8294
+ */
8295
+ ExpressionKind[ExpressionKind["ContextLetReference"] = 7] = "ContextLetReference";
8264
8296
  /**
8265
8297
  * Runtime operation to snapshot the current view context.
8266
8298
  */
8267
- ExpressionKind[ExpressionKind["GetCurrentView"] = 6] = "GetCurrentView";
8299
+ ExpressionKind[ExpressionKind["GetCurrentView"] = 8] = "GetCurrentView";
8268
8300
  /**
8269
8301
  * Runtime operation to restore a snapshotted view.
8270
8302
  */
8271
- ExpressionKind[ExpressionKind["RestoreView"] = 7] = "RestoreView";
8303
+ ExpressionKind[ExpressionKind["RestoreView"] = 9] = "RestoreView";
8272
8304
  /**
8273
8305
  * Runtime operation to reset the current view context after `RestoreView`.
8274
8306
  */
8275
- ExpressionKind[ExpressionKind["ResetView"] = 8] = "ResetView";
8307
+ ExpressionKind[ExpressionKind["ResetView"] = 10] = "ResetView";
8276
8308
  /**
8277
8309
  * Defines and calls a function with change-detected arguments.
8278
8310
  */
8279
- ExpressionKind[ExpressionKind["PureFunctionExpr"] = 9] = "PureFunctionExpr";
8311
+ ExpressionKind[ExpressionKind["PureFunctionExpr"] = 11] = "PureFunctionExpr";
8280
8312
  /**
8281
8313
  * Indicates a positional parameter to a pure function definition.
8282
8314
  */
8283
- ExpressionKind[ExpressionKind["PureFunctionParameterExpr"] = 10] = "PureFunctionParameterExpr";
8315
+ ExpressionKind[ExpressionKind["PureFunctionParameterExpr"] = 12] = "PureFunctionParameterExpr";
8284
8316
  /**
8285
8317
  * Binding to a pipe transformation.
8286
8318
  */
8287
- ExpressionKind[ExpressionKind["PipeBinding"] = 11] = "PipeBinding";
8319
+ ExpressionKind[ExpressionKind["PipeBinding"] = 13] = "PipeBinding";
8288
8320
  /**
8289
8321
  * Binding to a pipe transformation with a variable number of arguments.
8290
8322
  */
8291
- ExpressionKind[ExpressionKind["PipeBindingVariadic"] = 12] = "PipeBindingVariadic";
8323
+ ExpressionKind[ExpressionKind["PipeBindingVariadic"] = 14] = "PipeBindingVariadic";
8292
8324
  /*
8293
8325
  * A safe property read requiring expansion into a null check.
8294
8326
  */
8295
- ExpressionKind[ExpressionKind["SafePropertyRead"] = 13] = "SafePropertyRead";
8327
+ ExpressionKind[ExpressionKind["SafePropertyRead"] = 15] = "SafePropertyRead";
8296
8328
  /**
8297
8329
  * A safe keyed read requiring expansion into a null check.
8298
8330
  */
8299
- ExpressionKind[ExpressionKind["SafeKeyedRead"] = 14] = "SafeKeyedRead";
8331
+ ExpressionKind[ExpressionKind["SafeKeyedRead"] = 16] = "SafeKeyedRead";
8300
8332
  /**
8301
8333
  * A safe function call requiring expansion into a null check.
8302
8334
  */
8303
- ExpressionKind[ExpressionKind["SafeInvokeFunction"] = 15] = "SafeInvokeFunction";
8335
+ ExpressionKind[ExpressionKind["SafeInvokeFunction"] = 17] = "SafeInvokeFunction";
8304
8336
  /**
8305
8337
  * An intermediate expression that will be expanded from a safe read into an explicit ternary.
8306
8338
  */
8307
- ExpressionKind[ExpressionKind["SafeTernaryExpr"] = 16] = "SafeTernaryExpr";
8339
+ ExpressionKind[ExpressionKind["SafeTernaryExpr"] = 18] = "SafeTernaryExpr";
8308
8340
  /**
8309
8341
  * An empty expression that will be stipped before generating the final output.
8310
8342
  */
8311
- ExpressionKind[ExpressionKind["EmptyExpr"] = 17] = "EmptyExpr";
8343
+ ExpressionKind[ExpressionKind["EmptyExpr"] = 19] = "EmptyExpr";
8312
8344
  /*
8313
8345
  * An assignment to a temporary variable.
8314
8346
  */
8315
- ExpressionKind[ExpressionKind["AssignTemporaryExpr"] = 18] = "AssignTemporaryExpr";
8347
+ ExpressionKind[ExpressionKind["AssignTemporaryExpr"] = 20] = "AssignTemporaryExpr";
8316
8348
  /**
8317
8349
  * A reference to a temporary variable.
8318
8350
  */
8319
- ExpressionKind[ExpressionKind["ReadTemporaryExpr"] = 19] = "ReadTemporaryExpr";
8351
+ ExpressionKind[ExpressionKind["ReadTemporaryExpr"] = 21] = "ReadTemporaryExpr";
8320
8352
  /**
8321
8353
  * An expression that will cause a literal slot index to be emitted.
8322
8354
  */
8323
- ExpressionKind[ExpressionKind["SlotLiteralExpr"] = 20] = "SlotLiteralExpr";
8355
+ ExpressionKind[ExpressionKind["SlotLiteralExpr"] = 22] = "SlotLiteralExpr";
8324
8356
  /**
8325
8357
  * A test expression for a conditional op.
8326
8358
  */
8327
- ExpressionKind[ExpressionKind["ConditionalCase"] = 21] = "ConditionalCase";
8359
+ ExpressionKind[ExpressionKind["ConditionalCase"] = 23] = "ConditionalCase";
8328
8360
  /**
8329
8361
  * An expression that will be automatically extracted to the component const array.
8330
8362
  */
8331
- ExpressionKind[ExpressionKind["ConstCollected"] = 22] = "ConstCollected";
8363
+ ExpressionKind[ExpressionKind["ConstCollected"] = 24] = "ConstCollected";
8332
8364
  /**
8333
8365
  * Operation that sets the value of a two-way binding.
8334
8366
  */
8335
- ExpressionKind[ExpressionKind["TwoWayBindingSet"] = 23] = "TwoWayBindingSet";
8367
+ ExpressionKind[ExpressionKind["TwoWayBindingSet"] = 25] = "TwoWayBindingSet";
8336
8368
  })(ExpressionKind || (ExpressionKind = {}));
8337
8369
  var VariableFlags;
8338
8370
  (function (VariableFlags) {
@@ -8553,11 +8585,8 @@ const TRAIT_CONSUMES_VARS = {
8553
8585
  function hasConsumesSlotTrait(op) {
8554
8586
  return op[ConsumesSlot] === true;
8555
8587
  }
8556
- /**
8557
- * Test whether an operation implements `DependsOnSlotContextOpTrait`.
8558
- */
8559
- function hasDependsOnSlotContextTrait(op) {
8560
- return op[DependsOnSlotContext] === true;
8588
+ function hasDependsOnSlotContextTrait(value) {
8589
+ return value[DependsOnSlotContext] === true;
8561
8590
  }
8562
8591
  function hasConsumesVarsTrait(value) {
8563
8592
  return value[ConsumesVarsTrait] === true;
@@ -8855,8 +8884,23 @@ function createI18nApplyOp(owner, handle, sourceSpan) {
8855
8884
  ...NEW_OP,
8856
8885
  };
8857
8886
  }
8887
+ /**
8888
+ * Creates a `StoreLetOp`.
8889
+ */
8890
+ function createStoreLetOp(target, declaredName, value, sourceSpan) {
8891
+ return {
8892
+ kind: OpKind.StoreLet,
8893
+ target,
8894
+ declaredName,
8895
+ value,
8896
+ sourceSpan,
8897
+ ...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
8898
+ ...TRAIT_CONSUMES_VARS,
8899
+ ...NEW_OP,
8900
+ };
8901
+ }
8858
8902
 
8859
- var _a, _b, _c, _d, _e, _f;
8903
+ var _a, _b, _c, _d, _e, _f, _g, _h;
8860
8904
  /**
8861
8905
  * Check whether a given `o.Expression` is a logical IR expression type.
8862
8906
  */
@@ -8918,6 +8962,50 @@ class ReferenceExpr extends ExpressionBase {
8918
8962
  return new ReferenceExpr(this.target, this.targetSlot, this.offset);
8919
8963
  }
8920
8964
  }
8965
+ class StoreLetExpr extends ExpressionBase {
8966
+ static { _a = ConsumesVarsTrait, _b = DependsOnSlotContext; }
8967
+ constructor(target, value, sourceSpan) {
8968
+ super();
8969
+ this.target = target;
8970
+ this.value = value;
8971
+ this.sourceSpan = sourceSpan;
8972
+ this.kind = ExpressionKind.StoreLet;
8973
+ this[_a] = true;
8974
+ this[_b] = true;
8975
+ }
8976
+ visitExpression() { }
8977
+ isEquivalent(e) {
8978
+ return (e instanceof StoreLetExpr && e.target === this.target && e.value.isEquivalent(this.value));
8979
+ }
8980
+ isConstant() {
8981
+ return false;
8982
+ }
8983
+ transformInternalExpressions(transform, flags) {
8984
+ this.value = transformExpressionsInExpression(this.value, transform, flags);
8985
+ }
8986
+ clone() {
8987
+ return new StoreLetExpr(this.target, this.value, this.sourceSpan);
8988
+ }
8989
+ }
8990
+ class ContextLetReferenceExpr extends ExpressionBase {
8991
+ constructor(target, targetSlot) {
8992
+ super();
8993
+ this.target = target;
8994
+ this.targetSlot = targetSlot;
8995
+ this.kind = ExpressionKind.ContextLetReference;
8996
+ }
8997
+ visitExpression() { }
8998
+ isEquivalent(e) {
8999
+ return e instanceof ContextLetReferenceExpr && e.target === this.target;
9000
+ }
9001
+ isConstant() {
9002
+ return false;
9003
+ }
9004
+ transformInternalExpressions() { }
9005
+ clone() {
9006
+ return new ContextLetReferenceExpr(this.target, this.targetSlot);
9007
+ }
9008
+ }
8921
9009
  /**
8922
9010
  * A reference to the current view context (usually the `ctx` variable in a template function).
8923
9011
  */
@@ -9118,12 +9206,12 @@ class ReadVariableExpr extends ExpressionBase {
9118
9206
  }
9119
9207
  }
9120
9208
  class PureFunctionExpr extends ExpressionBase {
9121
- static { _a = ConsumesVarsTrait, _b = UsesVarOffset; }
9209
+ static { _c = ConsumesVarsTrait, _d = UsesVarOffset; }
9122
9210
  constructor(expression, args) {
9123
9211
  super();
9124
9212
  this.kind = ExpressionKind.PureFunctionExpr;
9125
- this[_a] = true;
9126
- this[_b] = true;
9213
+ this[_c] = true;
9214
+ this[_d] = true;
9127
9215
  this.varOffset = null;
9128
9216
  /**
9129
9217
  * Once extracted to the `ConstantPool`, a reference to the function which defines the computation
@@ -9189,7 +9277,7 @@ class PureFunctionParameterExpr extends ExpressionBase {
9189
9277
  }
9190
9278
  }
9191
9279
  class PipeBindingExpr extends ExpressionBase {
9192
- static { _c = ConsumesVarsTrait, _d = UsesVarOffset; }
9280
+ static { _e = ConsumesVarsTrait, _f = UsesVarOffset; }
9193
9281
  constructor(target, targetSlot, name, args) {
9194
9282
  super();
9195
9283
  this.target = target;
@@ -9197,8 +9285,8 @@ class PipeBindingExpr extends ExpressionBase {
9197
9285
  this.name = name;
9198
9286
  this.args = args;
9199
9287
  this.kind = ExpressionKind.PipeBinding;
9200
- this[_c] = true;
9201
- this[_d] = true;
9288
+ this[_e] = true;
9289
+ this[_f] = true;
9202
9290
  this.varOffset = null;
9203
9291
  }
9204
9292
  visitExpression(visitor, context) {
@@ -9224,7 +9312,7 @@ class PipeBindingExpr extends ExpressionBase {
9224
9312
  }
9225
9313
  }
9226
9314
  class PipeBindingVariadicExpr extends ExpressionBase {
9227
- static { _e = ConsumesVarsTrait, _f = UsesVarOffset; }
9315
+ static { _g = ConsumesVarsTrait, _h = UsesVarOffset; }
9228
9316
  constructor(target, targetSlot, name, args, numArgs) {
9229
9317
  super();
9230
9318
  this.target = target;
@@ -9233,8 +9321,8 @@ class PipeBindingVariadicExpr extends ExpressionBase {
9233
9321
  this.args = args;
9234
9322
  this.numArgs = numArgs;
9235
9323
  this.kind = ExpressionKind.PipeBindingVariadic;
9236
- this[_e] = true;
9237
- this[_f] = true;
9324
+ this[_g] = true;
9325
+ this[_h] = true;
9238
9326
  this.varOffset = null;
9239
9327
  }
9240
9328
  visitExpression(visitor, context) {
@@ -9628,6 +9716,9 @@ function transformExpressionsInOp(op, transform, flags) {
9628
9716
  case OpKind.DeferWhen:
9629
9717
  op.expr = transformExpressionsInExpression(op.expr, transform, flags);
9630
9718
  break;
9719
+ case OpKind.StoreLet:
9720
+ op.value = transformExpressionsInExpression(op.value, transform, flags);
9721
+ break;
9631
9722
  case OpKind.Advance:
9632
9723
  case OpKind.Container:
9633
9724
  case OpKind.ContainerEnd:
@@ -9653,6 +9744,7 @@ function transformExpressionsInOp(op, transform, flags) {
9653
9744
  case OpKind.Text:
9654
9745
  case OpKind.I18nAttributes:
9655
9746
  case OpKind.IcuPlaceholder:
9747
+ case OpKind.DeclareLet:
9656
9748
  // These operations contain no expressions.
9657
9749
  break;
9658
9750
  default:
@@ -10316,6 +10408,20 @@ function createDeferOnOp(defer, trigger, prefetch, sourceSpan) {
10316
10408
  ...NEW_OP,
10317
10409
  };
10318
10410
  }
10411
+ /**
10412
+ * Creates a `DeclareLetOp`.
10413
+ */
10414
+ function createDeclareLetOp(xref, declaredName, sourceSpan) {
10415
+ return {
10416
+ kind: OpKind.DeclareLet,
10417
+ xref,
10418
+ declaredName,
10419
+ sourceSpan,
10420
+ handle: new SlotHandle(),
10421
+ ...TRAIT_CONSUMES_SLOT,
10422
+ ...NEW_OP,
10423
+ };
10424
+ }
10319
10425
  /**
10320
10426
  * Create an `ExtractedMessageOp`.
10321
10427
  */
@@ -11009,6 +11115,7 @@ const CHAINABLE = new Set([
11009
11115
  Identifiers.templateCreate,
11010
11116
  Identifiers.twoWayProperty,
11011
11117
  Identifiers.twoWayListener,
11118
+ Identifiers.declareLet,
11012
11119
  ]);
11013
11120
  /**
11014
11121
  * Post-process a reified view compilation and convert sequential calls to chainable instructions
@@ -12174,16 +12281,26 @@ function generateAdvance(job) {
12174
12281
  // To do that, we track what the runtime's slot counter will be through the update operations.
12175
12282
  let slotContext = 0;
12176
12283
  for (const op of unit.update) {
12177
- if (!hasDependsOnSlotContextTrait(op)) {
12178
- // `op` doesn't depend on the slot counter, so it can be skipped.
12284
+ let consumer = null;
12285
+ if (hasDependsOnSlotContextTrait(op)) {
12286
+ consumer = op;
12287
+ }
12288
+ else {
12289
+ visitExpressionsInOp(op, (expr) => {
12290
+ if (consumer === null && hasDependsOnSlotContextTrait(expr)) {
12291
+ consumer = expr;
12292
+ }
12293
+ });
12294
+ }
12295
+ if (consumer === null) {
12179
12296
  continue;
12180
12297
  }
12181
- else if (!slotMap.has(op.target)) {
12298
+ if (!slotMap.has(consumer.target)) {
12182
12299
  // We expect ops that _do_ depend on the slot counter to point at declarations that exist in
12183
12300
  // the `slotMap`.
12184
- throw new Error(`AssertionError: reference to unknown slot for target ${op.target}`);
12301
+ throw new Error(`AssertionError: reference to unknown slot for target ${consumer.target}`);
12185
12302
  }
12186
- const slot = slotMap.get(op.target);
12303
+ const slot = slotMap.get(consumer.target);
12187
12304
  // Does the slot counter need to be adjusted?
12188
12305
  if (slotContext !== slot) {
12189
12306
  // If so, generate an `ir.AdvanceOp` to advance the counter.
@@ -12191,7 +12308,7 @@ function generateAdvance(job) {
12191
12308
  if (delta < 0) {
12192
12309
  throw new Error(`AssertionError: slot counter should never need to move backwards`);
12193
12310
  }
12194
- OpList.insertBefore(createAdvanceOp(delta, op.sourceSpan), op);
12311
+ OpList.insertBefore(createAdvanceOp(delta, consumer.sourceSpan), op);
12195
12312
  slotContext = slot;
12196
12313
  }
12197
12314
  }
@@ -12282,13 +12399,11 @@ function recursivelyProcessView(view, parentScope) {
12282
12399
  case OpKind.Listener:
12283
12400
  case OpKind.TwoWayListener:
12284
12401
  // Prepend variables to listener handler functions.
12285
- op.handlerOps.prepend(generateVariablesInScopeForView(view, scope));
12402
+ op.handlerOps.prepend(generateVariablesInScopeForView(view, scope, true));
12286
12403
  break;
12287
12404
  }
12288
12405
  }
12289
- // Prepend the declarations for all available variables in scope to the `update` block.
12290
- const preambleOps = generateVariablesInScopeForView(view, scope);
12291
- view.update.prepend(preambleOps);
12406
+ view.update.prepend(generateVariablesInScopeForView(view, scope, false));
12292
12407
  }
12293
12408
  /**
12294
12409
  * Process a view and generate a `Scope` representing the variables available for reference within
@@ -12305,6 +12420,7 @@ function getScopeForView(view, parent) {
12305
12420
  contextVariables: new Map(),
12306
12421
  aliases: view.aliases,
12307
12422
  references: [],
12423
+ letDeclarations: [],
12308
12424
  parent,
12309
12425
  };
12310
12426
  for (const identifier of view.contextVariables.keys()) {
@@ -12336,6 +12452,17 @@ function getScopeForView(view, parent) {
12336
12452
  });
12337
12453
  }
12338
12454
  break;
12455
+ case OpKind.DeclareLet:
12456
+ scope.letDeclarations.push({
12457
+ targetId: op.xref,
12458
+ targetSlot: op.handle,
12459
+ variable: {
12460
+ kind: SemanticVariableKind.Identifier,
12461
+ name: null,
12462
+ identifier: op.declaredName,
12463
+ },
12464
+ });
12465
+ break;
12339
12466
  }
12340
12467
  }
12341
12468
  return scope;
@@ -12346,7 +12473,7 @@ function getScopeForView(view, parent) {
12346
12473
  * This is a recursive process, as views inherit variables available from their parent view, which
12347
12474
  * itself may have inherited variables, etc.
12348
12475
  */
12349
- function generateVariablesInScopeForView(view, scope) {
12476
+ function generateVariablesInScopeForView(view, scope, isListener) {
12350
12477
  const newOps = [];
12351
12478
  if (scope.view !== view.xref) {
12352
12479
  // Before generating variables for a parent view, we need to switch to the context of the parent
@@ -12370,9 +12497,14 @@ function generateVariablesInScopeForView(view, scope) {
12370
12497
  for (const ref of scope.references) {
12371
12498
  newOps.push(createVariableOp(view.job.allocateXrefId(), ref.variable, new ReferenceExpr(ref.targetId, ref.targetSlot, ref.offset), VariableFlags.None));
12372
12499
  }
12500
+ if (scope.view !== view.xref || isListener) {
12501
+ for (const decl of scope.letDeclarations) {
12502
+ newOps.push(createVariableOp(view.job.allocateXrefId(), decl.variable, new ContextLetReferenceExpr(decl.targetId, decl.targetSlot), VariableFlags.None));
12503
+ }
12504
+ }
12373
12505
  if (scope.parent !== null) {
12374
12506
  // Recursively add variables from the parent scope.
12375
- newOps.push(...generateVariablesInScopeForView(view, scope.parent));
12507
+ newOps.push(...generateVariablesInScopeForView(view, scope.parent, false));
12376
12508
  }
12377
12509
  return newOps;
12378
12510
  }
@@ -13730,7 +13862,8 @@ class _ParseAST {
13730
13862
  const keyStart = this.inputIndex;
13731
13863
  const quoted = this.next.isString();
13732
13864
  const key = this.expectIdentifierOrKeywordOrString();
13733
- keys.push({ key, quoted });
13865
+ const literalMapKey = { key, quoted };
13866
+ keys.push(literalMapKey);
13734
13867
  // Properties with quoted keys can't use the shorthand syntax.
13735
13868
  if (quoted) {
13736
13869
  this.expectCharacter($COLON);
@@ -13740,6 +13873,7 @@ class _ParseAST {
13740
13873
  values.push(this.parsePipe());
13741
13874
  }
13742
13875
  else {
13876
+ literalMapKey.isShorthandInitialized = true;
13743
13877
  const span = this.span(keyStart);
13744
13878
  const sourceSpan = this.sourceSpan(keyStart);
13745
13879
  values.push(new PropertyRead(span, sourceSpan, sourceSpan, new ImplicitReceiver(span, sourceSpan), key));
@@ -14229,6 +14363,18 @@ class BlockParameter {
14229
14363
  return visitor.visitBlockParameter(this, context);
14230
14364
  }
14231
14365
  }
14366
+ class LetDeclaration {
14367
+ constructor(name, value, sourceSpan, nameSpan, valueSpan) {
14368
+ this.name = name;
14369
+ this.value = value;
14370
+ this.sourceSpan = sourceSpan;
14371
+ this.nameSpan = nameSpan;
14372
+ this.valueSpan = valueSpan;
14373
+ }
14374
+ visit(visitor, context) {
14375
+ return visitor.visitLetDeclaration(this, context);
14376
+ }
14377
+ }
14232
14378
  function visitAll(visitor, nodes, context = null) {
14233
14379
  const result = [];
14234
14380
  const visit = visitor.visit
@@ -14266,6 +14412,7 @@ class RecursiveVisitor {
14266
14412
  });
14267
14413
  }
14268
14414
  visitBlockParameter(ast, context) { }
14415
+ visitLetDeclaration(decl, context) { }
14269
14416
  visitChildren(context, cb) {
14270
14417
  let results = [];
14271
14418
  let t = this;
@@ -15229,6 +15376,9 @@ class _I18nVisitor {
15229
15376
  visitBlockParameter(_parameter, _context) {
15230
15377
  throw new Error('Unreachable code');
15231
15378
  }
15379
+ visitLetDeclaration(decl, context) {
15380
+ return null;
15381
+ }
15232
15382
  /**
15233
15383
  * Convert, text and interpolated tokens up into text and placeholder pieces.
15234
15384
  *
@@ -17554,6 +17704,8 @@ class _Tokenizer {
17554
17704
  this._preserveLineEndings = options.preserveLineEndings || false;
17555
17705
  this._i18nNormalizeLineEndingsInICUs = options.i18nNormalizeLineEndingsInICUs || false;
17556
17706
  this._tokenizeBlocks = options.tokenizeBlocks ?? true;
17707
+ // TODO(crisbeto): eventually set this to true.
17708
+ this._tokenizeLet = options.tokenizeLet || false;
17557
17709
  try {
17558
17710
  this._cursor.init();
17559
17711
  }
@@ -17594,6 +17746,14 @@ class _Tokenizer {
17594
17746
  this._consumeTagOpen(start);
17595
17747
  }
17596
17748
  }
17749
+ else if (this._tokenizeLet &&
17750
+ // Use `peek` instead of `attempCharCode` since we
17751
+ // don't want to advance in case it's not `@let`.
17752
+ this._cursor.peek() === $AT &&
17753
+ !this._inInterpolation &&
17754
+ this._attemptStr('@let')) {
17755
+ this._consumeLetDeclaration(start);
17756
+ }
17597
17757
  else if (this._tokenizeBlocks && this._attemptCharCode($AT)) {
17598
17758
  this._consumeBlockStart(start);
17599
17759
  }
@@ -17614,7 +17774,7 @@ class _Tokenizer {
17614
17774
  this.handleError(e);
17615
17775
  }
17616
17776
  }
17617
- this._beginToken(29 /* TokenType.EOF */);
17777
+ this._beginToken(33 /* TokenType.EOF */);
17618
17778
  this._endToken([]);
17619
17779
  }
17620
17780
  _getBlockName() {
@@ -17705,6 +17865,77 @@ class _Tokenizer {
17705
17865
  this._attemptCharCodeUntilFn(isBlockParameterChar);
17706
17866
  }
17707
17867
  }
17868
+ _consumeLetDeclaration(start) {
17869
+ this._beginToken(29 /* TokenType.LET_START */, start);
17870
+ // Require at least one white space after the `@let`.
17871
+ if (isWhitespace(this._cursor.peek())) {
17872
+ this._attemptCharCodeUntilFn(isNotWhitespace);
17873
+ }
17874
+ else {
17875
+ const token = this._endToken([this._cursor.getChars(start)]);
17876
+ token.type = 32 /* TokenType.INCOMPLETE_LET */;
17877
+ return;
17878
+ }
17879
+ const startToken = this._endToken([this._getLetDeclarationName()]);
17880
+ // Skip over white space before the equals character.
17881
+ this._attemptCharCodeUntilFn(isNotWhitespace);
17882
+ // Expect an equals sign.
17883
+ if (!this._attemptCharCode($EQ)) {
17884
+ startToken.type = 32 /* TokenType.INCOMPLETE_LET */;
17885
+ return;
17886
+ }
17887
+ // Skip spaces after the equals.
17888
+ this._attemptCharCodeUntilFn((code) => isNotWhitespace(code) && !isNewLine(code));
17889
+ this._consumeLetDeclarationValue();
17890
+ // Terminate the `@let` with a semicolon.
17891
+ const endChar = this._cursor.peek();
17892
+ if (endChar === $SEMICOLON) {
17893
+ this._beginToken(31 /* TokenType.LET_END */);
17894
+ this._endToken([]);
17895
+ this._cursor.advance();
17896
+ }
17897
+ else {
17898
+ startToken.type = 32 /* TokenType.INCOMPLETE_LET */;
17899
+ startToken.sourceSpan = this._cursor.getSpan(start);
17900
+ }
17901
+ }
17902
+ _getLetDeclarationName() {
17903
+ const nameCursor = this._cursor.clone();
17904
+ let allowDigit = false;
17905
+ this._attemptCharCodeUntilFn((code) => {
17906
+ // `@let` names can't start with a digit, but digits are valid anywhere else in the name.
17907
+ if (isAsciiLetter(code) || code === $_ || (allowDigit && isDigit(code))) {
17908
+ allowDigit = true;
17909
+ return false;
17910
+ }
17911
+ return true;
17912
+ });
17913
+ return this._cursor.getChars(nameCursor).trim();
17914
+ }
17915
+ _consumeLetDeclarationValue() {
17916
+ const start = this._cursor.clone();
17917
+ this._beginToken(30 /* TokenType.LET_VALUE */, start);
17918
+ while (this._cursor.peek() !== $EOF) {
17919
+ const char = this._cursor.peek();
17920
+ // `@let` declarations terminate with a semicolon.
17921
+ if (char === $SEMICOLON) {
17922
+ break;
17923
+ }
17924
+ // If we hit a quote, skip over its content since we don't care what's inside.
17925
+ if (isQuote(char)) {
17926
+ this._cursor.advance();
17927
+ this._attemptCharCodeUntilFn((inner) => {
17928
+ if (inner === $BACKSLASH) {
17929
+ this._cursor.advance();
17930
+ return false;
17931
+ }
17932
+ return inner === char;
17933
+ });
17934
+ }
17935
+ this._cursor.advance();
17936
+ }
17937
+ this._endToken([this._cursor.getChars(start)]);
17938
+ }
17708
17939
  /**
17709
17940
  * @returns whether an ICU token has been created
17710
17941
  * @internal
@@ -18635,7 +18866,7 @@ class _TreeBuilder {
18635
18866
  this._advance();
18636
18867
  }
18637
18868
  build() {
18638
- while (this._peek.type !== 29 /* TokenType.EOF */) {
18869
+ while (this._peek.type !== 33 /* TokenType.EOF */) {
18639
18870
  if (this._peek.type === 0 /* TokenType.TAG_OPEN_START */ ||
18640
18871
  this._peek.type === 4 /* TokenType.INCOMPLETE_TAG_OPEN */) {
18641
18872
  this._consumeStartTag(this._advance());
@@ -18672,6 +18903,14 @@ class _TreeBuilder {
18672
18903
  this._closeVoidElement();
18673
18904
  this._consumeIncompleteBlock(this._advance());
18674
18905
  }
18906
+ else if (this._peek.type === 29 /* TokenType.LET_START */) {
18907
+ this._closeVoidElement();
18908
+ this._consumeLet(this._advance());
18909
+ }
18910
+ else if (this._peek.type === 32 /* TokenType.INCOMPLETE_LET */) {
18911
+ this._closeVoidElement();
18912
+ this._consumeIncompleteLet(this._advance());
18913
+ }
18675
18914
  else {
18676
18915
  // Skip all other tokens...
18677
18916
  this._advance();
@@ -18745,7 +18984,7 @@ class _TreeBuilder {
18745
18984
  if (!exp)
18746
18985
  return null;
18747
18986
  const end = this._advance();
18748
- exp.push({ type: 29 /* TokenType.EOF */, parts: [], sourceSpan: end.sourceSpan });
18987
+ exp.push({ type: 33 /* TokenType.EOF */, parts: [], sourceSpan: end.sourceSpan });
18749
18988
  // parse everything in between { and }
18750
18989
  const expansionCaseParser = new _TreeBuilder(exp, this.getTagDefinition);
18751
18990
  expansionCaseParser.build();
@@ -18785,7 +19024,7 @@ class _TreeBuilder {
18785
19024
  return null;
18786
19025
  }
18787
19026
  }
18788
- if (this._peek.type === 29 /* TokenType.EOF */) {
19027
+ if (this._peek.type === 33 /* TokenType.EOF */) {
18789
19028
  this.errors.push(TreeError.create(null, start.sourceSpan, `Invalid ICU message. Missing '}'.`));
18790
19029
  return null;
18791
19030
  }
@@ -19015,6 +19254,51 @@ class _TreeBuilder {
19015
19254
  this.errors.push(TreeError.create(token.parts[0], span, `Incomplete block "${token.parts[0]}". If you meant to write the @ character, ` +
19016
19255
  `you should use the "&#64;" HTML entity instead.`));
19017
19256
  }
19257
+ _consumeLet(startToken) {
19258
+ const name = startToken.parts[0];
19259
+ let valueToken;
19260
+ let endToken;
19261
+ if (this._peek.type !== 30 /* TokenType.LET_VALUE */) {
19262
+ this.errors.push(TreeError.create(startToken.parts[0], startToken.sourceSpan, `Invalid @let declaration "${name}". Declaration must have a value.`));
19263
+ return;
19264
+ }
19265
+ else {
19266
+ valueToken = this._advance();
19267
+ }
19268
+ // Type cast is necessary here since TS narrowed the type of `peek` above.
19269
+ if (this._peek.type !== 31 /* TokenType.LET_END */) {
19270
+ this.errors.push(TreeError.create(startToken.parts[0], startToken.sourceSpan, `Unterminated @let declaration "${name}". Declaration must be terminated with a semicolon.`));
19271
+ return;
19272
+ }
19273
+ else {
19274
+ endToken = this._advance();
19275
+ }
19276
+ const end = endToken.sourceSpan.fullStart;
19277
+ const span = new ParseSourceSpan(startToken.sourceSpan.start, end, startToken.sourceSpan.fullStart);
19278
+ // The start token usually captures the `@let`. Construct a name span by
19279
+ // offsetting the start by the length of any text before the name.
19280
+ const startOffset = startToken.sourceSpan.toString().lastIndexOf(name);
19281
+ const nameStart = startToken.sourceSpan.start.moveBy(startOffset);
19282
+ const nameSpan = new ParseSourceSpan(nameStart, startToken.sourceSpan.end);
19283
+ const node = new LetDeclaration(name, valueToken.parts[0], span, nameSpan, valueToken.sourceSpan);
19284
+ this._addToParent(node);
19285
+ }
19286
+ _consumeIncompleteLet(token) {
19287
+ // Incomplete `@let` declaration may end up with an empty name.
19288
+ const name = token.parts[0] ?? '';
19289
+ const nameString = name ? ` "${name}"` : '';
19290
+ // If there's at least a name, we can salvage an AST node that can be used for completions.
19291
+ if (name.length > 0) {
19292
+ const startOffset = token.sourceSpan.toString().lastIndexOf(name);
19293
+ const nameStart = token.sourceSpan.start.moveBy(startOffset);
19294
+ const nameSpan = new ParseSourceSpan(nameStart, token.sourceSpan.end);
19295
+ const valueSpan = new ParseSourceSpan(token.sourceSpan.start, token.sourceSpan.start.moveBy(0));
19296
+ const node = new LetDeclaration(name, '', token.sourceSpan, nameSpan, valueSpan);
19297
+ this._addToParent(node);
19298
+ }
19299
+ this.errors.push(TreeError.create(token.parts[0], token.sourceSpan, `Incomplete @let declaration${nameString}. ` +
19300
+ `@let declarations must be written as \`@let <name> = <value>;\``));
19301
+ }
19018
19302
  _getContainer() {
19019
19303
  return this._containerStack.length > 0
19020
19304
  ? this._containerStack[this._containerStack.length - 1]
@@ -19243,6 +19527,9 @@ class I18nMetaVisitor {
19243
19527
  visitBlockParameter(parameter, context) {
19244
19528
  return parameter;
19245
19529
  }
19530
+ visitLetDeclaration(decl, context) {
19531
+ return decl;
19532
+ }
19246
19533
  /**
19247
19534
  * Parse the general form `meta` passed into extract the explicit metadata needed to create a
19248
19535
  * `Message`.
@@ -20351,6 +20638,7 @@ function mergeNextContextsInOps(ops) {
20351
20638
  break;
20352
20639
  case ExpressionKind.GetCurrentView:
20353
20640
  case ExpressionKind.Reference:
20641
+ case ExpressionKind.ContextLetReference:
20354
20642
  // Can't merge past a dependency on the context.
20355
20643
  tryToMerge = false;
20356
20644
  break;
@@ -21076,6 +21364,15 @@ function repeater(collection, sourceSpan) {
21076
21364
  function deferWhen(prefetch, expr, sourceSpan) {
21077
21365
  return call(prefetch ? Identifiers.deferPrefetchWhen : Identifiers.deferWhen, [expr], sourceSpan);
21078
21366
  }
21367
+ function declareLet(slot, sourceSpan) {
21368
+ return call(Identifiers.declareLet, [literal(slot)], sourceSpan);
21369
+ }
21370
+ function storeLet(value, sourceSpan) {
21371
+ return importExpr(Identifiers.storeLet).callFn([value], sourceSpan);
21372
+ }
21373
+ function readContextLet(slot) {
21374
+ return importExpr(Identifiers.readContextLet).callFn([literal(slot)]);
21375
+ }
21079
21376
  function i18n(slot, constIndex, subTemplateIndex, sourceSpan) {
21080
21377
  const args = [literal(slot), literal(constIndex)];
21081
21378
  if (subTemplateIndex) {
@@ -21487,6 +21784,9 @@ function reifyCreateOperations(unit, ops) {
21487
21784
  case OpKind.Pipe:
21488
21785
  OpList.replace(op, pipe(op.handle.slot, op.name));
21489
21786
  break;
21787
+ case OpKind.DeclareLet:
21788
+ OpList.replace(op, declareLet(op.handle.slot, op.sourceSpan));
21789
+ break;
21490
21790
  case OpKind.Listener:
21491
21791
  const listenerFn = reifyListenerHandler(unit, op.handlerFnName, op.handlerOps, op.consumesDollarEvent);
21492
21792
  const eventTargetResolver = op.eventTarget
@@ -21706,6 +22006,8 @@ function reifyUpdateOperations(_unit, ops) {
21706
22006
  case OpKind.DeferWhen:
21707
22007
  OpList.replace(op, deferWhen(op.prefetch, op.expr, op.sourceSpan));
21708
22008
  break;
22009
+ case OpKind.StoreLet:
22010
+ throw new Error(`AssertionError: unexpected storeLet ${op.declaredName}`);
21709
22011
  case OpKind.Statement:
21710
22012
  // Pass statement operations directly through.
21711
22013
  break;
@@ -21764,6 +22066,10 @@ function reifyIrExpression(expr) {
21764
22066
  return pipeBindV(expr.targetSlot.slot, expr.varOffset, expr.args);
21765
22067
  case ExpressionKind.SlotLiteralExpr:
21766
22068
  return literal(expr.slot.slot);
22069
+ case ExpressionKind.ContextLetReference:
22070
+ return readContextLet(expr.targetSlot.slot);
22071
+ case ExpressionKind.StoreLet:
22072
+ return storeLet(expr.value, expr.sourceSpan);
21767
22073
  default:
21768
22074
  throw new Error(`AssertionError: Unsupported reification of ir.Expression kind: ${ExpressionKind[expr.kind]}`);
21769
22075
  }
@@ -22522,7 +22828,7 @@ function saveAndRestoreView(job) {
22522
22828
  if (!needsRestoreView) {
22523
22829
  for (const handlerOp of op.handlerOps) {
22524
22830
  visitExpressionsInOp(handlerOp, (expr) => {
22525
- if (expr instanceof ReferenceExpr) {
22831
+ if (expr instanceof ReferenceExpr || expr instanceof ContextLetReferenceExpr) {
22526
22832
  // Listeners that reference() a local ref need the save/restore view operation.
22527
22833
  needsRestoreView = true;
22528
22834
  }
@@ -22820,7 +23126,7 @@ function optimizeTrackFns(job) {
22820
23126
  }
22821
23127
  }
22822
23128
  function isTrackByFunctionCall(rootView, expr) {
22823
- if (!(expr instanceof InvokeFunctionExpr) || expr.args.length !== 2) {
23129
+ if (!(expr instanceof InvokeFunctionExpr) || expr.args.length === 0 || expr.args.length > 2) {
22824
23130
  return false;
22825
23131
  }
22826
23132
  if (!(expr.receiver instanceof ReadPropExpr && expr.receiver.receiver instanceof ContextExpr) ||
@@ -22831,6 +23137,9 @@ function isTrackByFunctionCall(rootView, expr) {
22831
23137
  if (!(arg0 instanceof ReadVarExpr) || arg0.name !== '$index') {
22832
23138
  return false;
22833
23139
  }
23140
+ else if (expr.args.length === 1) {
23141
+ return true;
23142
+ }
22834
23143
  if (!(arg1 instanceof ReadVarExpr) || arg1.name !== '$item') {
22835
23144
  return false;
22836
23145
  }
@@ -22974,6 +23283,7 @@ function varsUsedByOp(op) {
22974
23283
  case OpKind.I18nExpression:
22975
23284
  case OpKind.Conditional:
22976
23285
  case OpKind.DeferWhen:
23286
+ case OpKind.StoreLet:
22977
23287
  return 1;
22978
23288
  case OpKind.RepeaterCreate:
22979
23289
  // Repeaters may require an extra variable binding slot, if they have an empty view, for the
@@ -22993,6 +23303,8 @@ function varsUsedByIrExpression(expr) {
22993
23303
  return 1 + expr.args.length;
22994
23304
  case ExpressionKind.PipeBindingVariadic:
22995
23305
  return 1 + expr.numArgs;
23306
+ case ExpressionKind.StoreLet:
23307
+ return 1;
22996
23308
  default:
22997
23309
  throw new Error(`AssertionError: unhandled ConsumesVarsTrait expression ${expr.constructor.name}`);
22998
23310
  }
@@ -23249,7 +23561,10 @@ function fencesForIrExpression(expr) {
23249
23561
  return Fence.ViewContextRead | Fence.ViewContextWrite;
23250
23562
  case ExpressionKind.RestoreView:
23251
23563
  return Fence.ViewContextRead | Fence.ViewContextWrite | Fence.SideEffectful;
23564
+ case ExpressionKind.StoreLet:
23565
+ return Fence.SideEffectful;
23252
23566
  case ExpressionKind.Reference:
23567
+ case ExpressionKind.ContextLetReference:
23253
23568
  return Fence.ViewContextRead;
23254
23569
  default:
23255
23570
  return Fence.None;
@@ -23451,6 +23766,87 @@ function wrapI18nIcus(job) {
23451
23766
  }
23452
23767
  }
23453
23768
 
23769
+ /*!
23770
+ * @license
23771
+ * Copyright Google LLC All Rights Reserved.
23772
+ *
23773
+ * Use of this source code is governed by an MIT-style license that can be
23774
+ * found in the LICENSE file at https://angular.io/license
23775
+ */
23776
+ /**
23777
+ * Removes any `storeLet` calls that aren't referenced outside of the current view.
23778
+ */
23779
+ function optimizeStoreLet(job) {
23780
+ const letUsedExternally = new Set();
23781
+ // Since `@let` declarations can be referenced in child views, both in
23782
+ // the creation block (via listeners) and in the update block, we have
23783
+ // to look through all the ops to find the references.
23784
+ for (const unit of job.units) {
23785
+ for (const op of unit.ops()) {
23786
+ visitExpressionsInOp(op, (expr) => {
23787
+ if (expr instanceof ContextLetReferenceExpr) {
23788
+ letUsedExternally.add(expr.target);
23789
+ }
23790
+ });
23791
+ }
23792
+ }
23793
+ // TODO(crisbeto): potentially remove the unused calls completely, pending discussion.
23794
+ for (const unit of job.units) {
23795
+ for (const op of unit.update) {
23796
+ transformExpressionsInOp(op, (expression) => expression instanceof StoreLetExpr && !letUsedExternally.has(expression.target)
23797
+ ? expression.value
23798
+ : expression, VisitorContextFlag.None);
23799
+ }
23800
+ }
23801
+ }
23802
+
23803
+ /**
23804
+ * It's not allowed to access a `@let` declaration before it has been defined. This is enforced
23805
+ * already via template type checking, however it can trip some of the assertions in the pipeline.
23806
+ * E.g. the naming phase can fail because we resolved the variable here, but the variable doesn't
23807
+ * exist anymore because the optimization phase removed it since it's invalid. To avoid surfacing
23808
+ * confusing errors to users in the case where template type checking isn't running (e.g. in JIT
23809
+ * mode) this phase detects illegal forward references and replaces them with `undefined`.
23810
+ * Eventually users will see the proper error from the template type checker.
23811
+ */
23812
+ function removeIllegalLetReferences(job) {
23813
+ for (const unit of job.units) {
23814
+ for (const op of unit.update) {
23815
+ if (op.kind !== OpKind.Variable ||
23816
+ op.variable.kind !== SemanticVariableKind.Identifier ||
23817
+ !(op.initializer instanceof StoreLetExpr)) {
23818
+ continue;
23819
+ }
23820
+ const name = op.variable.identifier;
23821
+ let current = op;
23822
+ while (current && current.kind !== OpKind.ListEnd) {
23823
+ transformExpressionsInOp(current, (expr) => expr instanceof LexicalReadExpr && expr.name === name ? literal(undefined) : expr, VisitorContextFlag.None);
23824
+ current = current.prev;
23825
+ }
23826
+ }
23827
+ }
23828
+ }
23829
+
23830
+ /**
23831
+ * Replaces the `storeLet` ops with variables that can be
23832
+ * used to reference the value within the same view.
23833
+ */
23834
+ function generateLocalLetReferences(job) {
23835
+ for (const unit of job.units) {
23836
+ for (const op of unit.update) {
23837
+ if (op.kind !== OpKind.StoreLet) {
23838
+ continue;
23839
+ }
23840
+ const variable = {
23841
+ kind: SemanticVariableKind.Identifier,
23842
+ name: null,
23843
+ identifier: op.declaredName,
23844
+ };
23845
+ OpList.replace(op, createVariableOp(job.allocateXrefId(), variable, new StoreLetExpr(op.target, op.value, op.sourceSpan), VariableFlags.None));
23846
+ }
23847
+ }
23848
+ }
23849
+
23454
23850
  /**
23455
23851
  *
23456
23852
  * @license
@@ -23485,11 +23881,13 @@ const phases = [
23485
23881
  { kind: CompilationJobKind.Tmpl, fn: createVariadicPipes },
23486
23882
  { kind: CompilationJobKind.Both, fn: generatePureLiteralStructures },
23487
23883
  { kind: CompilationJobKind.Tmpl, fn: generateProjectionDefs },
23884
+ { kind: CompilationJobKind.Tmpl, fn: generateLocalLetReferences },
23488
23885
  { kind: CompilationJobKind.Tmpl, fn: generateVariables },
23489
23886
  { kind: CompilationJobKind.Tmpl, fn: saveAndRestoreView },
23490
23887
  { kind: CompilationJobKind.Both, fn: deleteAnyCasts },
23491
23888
  { kind: CompilationJobKind.Both, fn: resolveDollarEvent },
23492
23889
  { kind: CompilationJobKind.Tmpl, fn: generateTrackVariables },
23890
+ { kind: CompilationJobKind.Tmpl, fn: removeIllegalLetReferences },
23493
23891
  { kind: CompilationJobKind.Both, fn: resolveNames },
23494
23892
  { kind: CompilationJobKind.Tmpl, fn: resolveDeferTargetNames },
23495
23893
  { kind: CompilationJobKind.Tmpl, fn: transformTwoWayBindingSet },
@@ -23501,6 +23899,7 @@ const phases = [
23501
23899
  { kind: CompilationJobKind.Both, fn: expandSafeReads },
23502
23900
  { kind: CompilationJobKind.Both, fn: generateTemporaryVariables },
23503
23901
  { kind: CompilationJobKind.Both, fn: optimizeVariables },
23902
+ { kind: CompilationJobKind.Both, fn: optimizeStoreLet },
23504
23903
  { kind: CompilationJobKind.Tmpl, fn: allocateSlots },
23505
23904
  { kind: CompilationJobKind.Tmpl, fn: resolveI18nElementPlaceholders },
23506
23905
  { kind: CompilationJobKind.Tmpl, fn: resolveI18nExpressionPlaceholders },
@@ -23737,6 +24136,9 @@ function ingestNodes(unit, template) {
23737
24136
  else if (node instanceof ForLoopBlock) {
23738
24137
  ingestForBlock(unit, node);
23739
24138
  }
24139
+ else if (node instanceof LetDeclaration$1) {
24140
+ ingestLetDeclaration(unit, node);
24141
+ }
23740
24142
  else {
23741
24143
  throw new Error(`Unsupported template node: ${node.constructor.name}`);
23742
24144
  }
@@ -24151,6 +24553,11 @@ function getComputedForLoopVariableExpression(variable, indexName, countName) {
24151
24553
  throw new Error(`AssertionError: unknown @for loop variable ${variable.value}`);
24152
24554
  }
24153
24555
  }
24556
+ function ingestLetDeclaration(unit, node) {
24557
+ const target = unit.job.allocateXrefId();
24558
+ unit.create.push(createDeclareLetOp(target, node.name, node.sourceSpan));
24559
+ unit.update.push(createStoreLetOp(target, node.name, convertAst(node.value, unit.job, node.valueSpan), node.sourceSpan));
24560
+ }
24154
24561
  /**
24155
24562
  * Convert a template AST expression into an output AST expression.
24156
24563
  */
@@ -24176,7 +24583,7 @@ function convertAst(ast, job, baseSourceSpan) {
24176
24583
  // The whole point of the explicit `this` was to access the class property, but TDB and the
24177
24584
  // current TCB treat the read as implicit, and give you the context property instead!
24178
24585
  //
24179
- // For now, we emulate this old behvaior by aggressively converting explicit reads to to
24586
+ // For now, we emulate this old behavior by aggressively converting explicit reads to to
24180
24587
  // implicit reads, except for the special cases that TDB and the current TCB protect. However,
24181
24588
  // it would be an improvement to fix this.
24182
24589
  //
@@ -24900,6 +25307,9 @@ class WhitespaceVisitor {
24900
25307
  visitBlockParameter(parameter, context) {
24901
25308
  return parameter;
24902
25309
  }
25310
+ visitLetDeclaration(decl, context) {
25311
+ return decl;
25312
+ }
24903
25313
  }
24904
25314
  function createWhitespaceProcessedTextToken({ type, parts, sourceSpan }) {
24905
25315
  return { type, parts: [processWhitespace(parts[0])], sourceSpan };
@@ -26555,6 +26965,13 @@ class HtmlAstToIvyAst {
26555
26965
  }
26556
26966
  return null;
26557
26967
  }
26968
+ visitLetDeclaration(decl, context) {
26969
+ const value = this.bindingParser.parseBinding(decl.value, false, decl.valueSpan, decl.valueSpan.start.offset);
26970
+ if (value.errors.length === 0 && value.ast instanceof EmptyExpr$1) {
26971
+ this.reportError('@let declaration value cannot be empty', decl.valueSpan);
26972
+ }
26973
+ return new LetDeclaration$1(decl.name, value, decl.sourceSpan, decl.nameSpan, decl.valueSpan);
26974
+ }
26558
26975
  visitBlockParameter() {
26559
26976
  return null;
26560
26977
  }
@@ -26833,6 +27250,9 @@ class NonBindableVisitor {
26833
27250
  visitBlockParameter(parameter, context) {
26834
27251
  return null;
26835
27252
  }
27253
+ visitLetDeclaration(decl, context) {
27254
+ return new Text$3(`@let ${decl.name} = ${decl.value};`, decl.sourceSpan);
27255
+ }
26836
27256
  }
26837
27257
  const NON_BINDABLE_VISITOR = new NonBindableVisitor();
26838
27258
  function normalizeAttributeName(attrName) {
@@ -26867,6 +27287,7 @@ function parseTemplate(template, templateUrl, options = {}) {
26867
27287
  ...options,
26868
27288
  tokenizeExpansionForms: true,
26869
27289
  tokenizeBlocks: options.enableBlockSyntax ?? true,
27290
+ tokenizeLet: options.enableLetSyntax ?? false,
26870
27291
  });
26871
27292
  if (!options.alwaysAttemptHtmlToR3AstConversion &&
26872
27293
  parseResult.errors &&
@@ -27636,6 +28057,9 @@ class Scope {
27636
28057
  visitContent(content) {
27637
28058
  this.ingestScopedNode(content);
27638
28059
  }
28060
+ visitLetDeclaration(decl) {
28061
+ this.maybeDeclare(decl);
28062
+ }
27639
28063
  // Unused visitors.
27640
28064
  visitBoundAttribute(attr) { }
27641
28065
  visitBoundEvent(event) { }
@@ -27848,6 +28272,7 @@ class DirectiveBinder {
27848
28272
  visitIcu(icu) { }
27849
28273
  visitDeferredTrigger(trigger) { }
27850
28274
  visitUnknownBlock(block) { }
28275
+ visitLetDeclaration(decl) { }
27851
28276
  }
27852
28277
  /**
27853
28278
  * Processes a template and extract metadata about expressions and symbols within.
@@ -28044,6 +28469,12 @@ class TemplateBinder extends RecursiveAstVisitor {
28044
28469
  visitBoundText(text) {
28045
28470
  text.value.visit(this);
28046
28471
  }
28472
+ visitLetDeclaration(decl) {
28473
+ decl.value.visit(this);
28474
+ if (this.rootNode !== null) {
28475
+ this.symbols.set(decl, this.rootNode);
28476
+ }
28477
+ }
28047
28478
  visitPipe(ast, context) {
28048
28479
  this.usedPipes.add(ast.name);
28049
28480
  if (!this.scope.isDeferred) {
@@ -28078,7 +28509,13 @@ class TemplateBinder extends RecursiveAstVisitor {
28078
28509
  }
28079
28510
  // Check whether the name exists in the current scope. If so, map it. Otherwise, the name is
28080
28511
  // probably a property on the top-level component context.
28081
- let target = this.scope.lookup(name);
28512
+ const target = this.scope.lookup(name);
28513
+ // It's not allowed to read template entities via `this`, however it previously worked by
28514
+ // accident (see #55115). Since `@let` declarations are new, we can fix it from the beginning,
28515
+ // whereas pre-existing template entities will be fixed in #55115.
28516
+ if (target instanceof LetDeclaration$1 && ast.receiver instanceof ThisReceiver) {
28517
+ return;
28518
+ }
28082
28519
  if (target !== null) {
28083
28520
  this.bindings.set(ast, target);
28084
28521
  }
@@ -28276,6 +28713,7 @@ function extractScopedNodeEntities(rootScope) {
28276
28713
  class ResourceLoader {
28277
28714
  }
28278
28715
 
28716
+ let enableLetSyntax = false;
28279
28717
  class CompilerFacadeImpl {
28280
28718
  constructor(jitEvaluator = new JitEvaluator()) {
28281
28719
  this.jitEvaluator = jitEvaluator;
@@ -28684,7 +29122,11 @@ function parseJitTemplate(template, typeName, sourceMapUrl, preserveWhitespaces,
28684
29122
  ? InterpolationConfig.fromArray(interpolation)
28685
29123
  : DEFAULT_INTERPOLATION_CONFIG;
28686
29124
  // Parse the template and check for errors.
28687
- const parsed = parseTemplate(template, sourceMapUrl, { preserveWhitespaces, interpolationConfig });
29125
+ const parsed = parseTemplate(template, sourceMapUrl, {
29126
+ preserveWhitespaces,
29127
+ interpolationConfig,
29128
+ enableLetSyntax,
29129
+ });
28688
29130
  if (parsed.errors !== null) {
28689
29131
  const errors = parsed.errors.map((err) => err.toString()).join(', ');
28690
29132
  throw new Error(`Errors during JIT compilation of template for ${typeName}: ${errors}`);
@@ -28913,7 +29355,7 @@ function publishFacade(global) {
28913
29355
  * @description
28914
29356
  * Entry point for all public APIs of the compiler package.
28915
29357
  */
28916
- const VERSION = new Version('18.0.0');
29358
+ const VERSION = new Version('18.0.5');
28917
29359
 
28918
29360
  class CompilerConfig {
28919
29361
  constructor({ defaultEncapsulation = exports.ViewEncapsulation.Emulated, preserveWhitespaces, strictInjectionParameters, } = {}) {
@@ -29138,6 +29580,7 @@ class _Visitor {
29138
29580
  visitAll(this, block.children, context);
29139
29581
  }
29140
29582
  visitBlockParameter(parameter, context) { }
29583
+ visitLetDeclaration(decl, context) { }
29141
29584
  _init(mode, interpolationConfig) {
29142
29585
  this._mode = mode;
29143
29586
  this._inI18nBlock = false;
@@ -29350,8 +29793,8 @@ class XmlParser extends Parser {
29350
29793
  super(getXmlTagDefinition);
29351
29794
  }
29352
29795
  parse(source, url, options = {}) {
29353
- // Blocks aren't supported in an XML context.
29354
- return super.parse(source, url, { ...options, tokenizeBlocks: false });
29796
+ // Blocks and let declarations aren't supported in an XML context.
29797
+ return super.parse(source, url, { ...options, tokenizeBlocks: false, tokenizeLet: false });
29355
29798
  }
29356
29799
  }
29357
29800
 
@@ -29572,6 +30015,7 @@ class XliffParser {
29572
30015
  visitExpansionCase(expansionCase, context) { }
29573
30016
  visitBlock(block, context) { }
29574
30017
  visitBlockParameter(parameter, context) { }
30018
+ visitLetDeclaration(decl, context) { }
29575
30019
  _addError(node, message) {
29576
30020
  this._errors.push(new I18nError(node.sourceSpan, message));
29577
30021
  }
@@ -29624,6 +30068,7 @@ class XmlToI18n$2 {
29624
30068
  visitAttribute(attribute, context) { }
29625
30069
  visitBlock(block, context) { }
29626
30070
  visitBlockParameter(parameter, context) { }
30071
+ visitLetDeclaration(decl, context) { }
29627
30072
  _addError(node, message) {
29628
30073
  this._errors.push(new I18nError(node.sourceSpan, message));
29629
30074
  }
@@ -29883,6 +30328,7 @@ class Xliff2Parser {
29883
30328
  visitExpansionCase(expansionCase, context) { }
29884
30329
  visitBlock(block, context) { }
29885
30330
  visitBlockParameter(parameter, context) { }
30331
+ visitLetDeclaration(decl, context) { }
29886
30332
  _addError(node, message) {
29887
30333
  this._errors.push(new I18nError(node.sourceSpan, message));
29888
30334
  }
@@ -29952,6 +30398,7 @@ class XmlToI18n$1 {
29952
30398
  visitAttribute(attribute, context) { }
29953
30399
  visitBlock(block, context) { }
29954
30400
  visitBlockParameter(parameter, context) { }
30401
+ visitLetDeclaration(decl, context) { }
29955
30402
  _addError(node, message) {
29956
30403
  this._errors.push(new I18nError(node.sourceSpan, message));
29957
30404
  }
@@ -30088,6 +30535,7 @@ class XtbParser {
30088
30535
  visitExpansionCase(expansionCase, context) { }
30089
30536
  visitBlock(block, context) { }
30090
30537
  visitBlockParameter(block, context) { }
30538
+ visitLetDeclaration(decl, context) { }
30091
30539
  _addError(node, message) {
30092
30540
  this._errors.push(new I18nError(node.sourceSpan, message));
30093
30541
  }
@@ -30138,6 +30586,7 @@ class XmlToI18n {
30138
30586
  visitAttribute(attribute, context) { }
30139
30587
  visitBlock(block, context) { }
30140
30588
  visitBlockParameter(block, context) { }
30589
+ visitLetDeclaration(decl, context) { }
30141
30590
  _addError(node, message) {
30142
30591
  this._errors.push(new I18nError(node.sourceSpan, message));
30143
30592
  }
@@ -30544,7 +30993,7 @@ const MINIMUM_PARTIAL_LINKER_DEFER_SUPPORT_VERSION = '18.0.0';
30544
30993
  function compileDeclareClassMetadata(metadata) {
30545
30994
  const definitionMap = new DefinitionMap();
30546
30995
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$5));
30547
- definitionMap.set('version', literal('18.0.0'));
30996
+ definitionMap.set('version', literal('18.0.5'));
30548
30997
  definitionMap.set('ngImport', importExpr(Identifiers.core));
30549
30998
  definitionMap.set('type', metadata.type);
30550
30999
  definitionMap.set('decorators', metadata.decorators);
@@ -30562,7 +31011,7 @@ function compileComponentDeclareClassMetadata(metadata, dependencies) {
30562
31011
  callbackReturnDefinitionMap.set('ctorParameters', metadata.ctorParameters ?? literal(null));
30563
31012
  callbackReturnDefinitionMap.set('propDecorators', metadata.propDecorators ?? literal(null));
30564
31013
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_DEFER_SUPPORT_VERSION));
30565
- definitionMap.set('version', literal('18.0.0'));
31014
+ definitionMap.set('version', literal('18.0.5'));
30566
31015
  definitionMap.set('ngImport', importExpr(Identifiers.core));
30567
31016
  definitionMap.set('type', metadata.type);
30568
31017
  definitionMap.set('resolveDeferredDeps', compileComponentMetadataAsyncResolver(dependencies));
@@ -30657,7 +31106,7 @@ function createDirectiveDefinitionMap(meta) {
30657
31106
  const definitionMap = new DefinitionMap();
30658
31107
  const minVersion = getMinimumVersionForPartialOutput(meta);
30659
31108
  definitionMap.set('minVersion', literal(minVersion));
30660
- definitionMap.set('version', literal('18.0.0'));
31109
+ definitionMap.set('version', literal('18.0.5'));
30661
31110
  // e.g. `type: MyDirective`
30662
31111
  definitionMap.set('type', meta.type.value);
30663
31112
  if (meta.isStandalone) {
@@ -31076,7 +31525,7 @@ const MINIMUM_PARTIAL_LINKER_VERSION$4 = '12.0.0';
31076
31525
  function compileDeclareFactoryFunction(meta) {
31077
31526
  const definitionMap = new DefinitionMap();
31078
31527
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$4));
31079
- definitionMap.set('version', literal('18.0.0'));
31528
+ definitionMap.set('version', literal('18.0.5'));
31080
31529
  definitionMap.set('ngImport', importExpr(Identifiers.core));
31081
31530
  definitionMap.set('type', meta.type.value);
31082
31531
  definitionMap.set('deps', compileDependencies(meta.deps));
@@ -31111,7 +31560,7 @@ function compileDeclareInjectableFromMetadata(meta) {
31111
31560
  function createInjectableDefinitionMap(meta) {
31112
31561
  const definitionMap = new DefinitionMap();
31113
31562
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$3));
31114
- definitionMap.set('version', literal('18.0.0'));
31563
+ definitionMap.set('version', literal('18.0.5'));
31115
31564
  definitionMap.set('ngImport', importExpr(Identifiers.core));
31116
31565
  definitionMap.set('type', meta.type.value);
31117
31566
  // Only generate providedIn property if it has a non-null value
@@ -31162,7 +31611,7 @@ function compileDeclareInjectorFromMetadata(meta) {
31162
31611
  function createInjectorDefinitionMap(meta) {
31163
31612
  const definitionMap = new DefinitionMap();
31164
31613
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$2));
31165
- definitionMap.set('version', literal('18.0.0'));
31614
+ definitionMap.set('version', literal('18.0.5'));
31166
31615
  definitionMap.set('ngImport', importExpr(Identifiers.core));
31167
31616
  definitionMap.set('type', meta.type.value);
31168
31617
  definitionMap.set('providers', meta.providers);
@@ -31195,7 +31644,7 @@ function createNgModuleDefinitionMap(meta) {
31195
31644
  throw new Error('Invalid path! Local compilation mode should not get into the partial compilation path');
31196
31645
  }
31197
31646
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$1));
31198
- definitionMap.set('version', literal('18.0.0'));
31647
+ definitionMap.set('version', literal('18.0.5'));
31199
31648
  definitionMap.set('ngImport', importExpr(Identifiers.core));
31200
31649
  definitionMap.set('type', meta.type.value);
31201
31650
  // We only generate the keys in the metadata if the arrays contain values.
@@ -31246,7 +31695,7 @@ function compileDeclarePipeFromMetadata(meta) {
31246
31695
  function createPipeDefinitionMap(meta) {
31247
31696
  const definitionMap = new DefinitionMap();
31248
31697
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION));
31249
- definitionMap.set('version', literal('18.0.0'));
31698
+ definitionMap.set('version', literal('18.0.5'));
31250
31699
  definitionMap.set('ngImport', importExpr(Identifiers.core));
31251
31700
  // e.g. `type: MyPipe`
31252
31701
  definitionMap.set('type', meta.type.value);
@@ -31328,6 +31777,7 @@ exports.JitEvaluator = JitEvaluator;
31328
31777
  exports.KeyedRead = KeyedRead;
31329
31778
  exports.KeyedWrite = KeyedWrite;
31330
31779
  exports.LeadingComment = LeadingComment;
31780
+ exports.LetDeclaration = LetDeclaration;
31331
31781
  exports.Lexer = Lexer;
31332
31782
  exports.LiteralArray = LiteralArray;
31333
31783
  exports.LiteralArrayExpr = LiteralArrayExpr;
@@ -31404,6 +31854,7 @@ exports.TmplAstIfBlock = IfBlock;
31404
31854
  exports.TmplAstIfBlockBranch = IfBlockBranch;
31405
31855
  exports.TmplAstImmediateDeferredTrigger = ImmediateDeferredTrigger;
31406
31856
  exports.TmplAstInteractionDeferredTrigger = InteractionDeferredTrigger;
31857
+ exports.TmplAstLetDeclaration = LetDeclaration$1;
31407
31858
  exports.TmplAstRecursiveVisitor = RecursiveVisitor$1;
31408
31859
  exports.TmplAstReference = Reference;
31409
31860
  exports.TmplAstSwitchBlock = SwitchBlock;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@angular-eslint/bundled-angular-compiler",
3
- "version": "18.0.2-alpha.0",
3
+ "version": "18.0.2-alpha.10",
4
4
  "description": "A CJS bundled version of @angular/compiler",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",