@angular/compiler 21.0.0-next.6 → 21.0.0-next.8

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.
@@ -1,6 +1,6 @@
1
1
  /**
2
- * @license Angular v21.0.0-next.6
3
- * (c) 2010-2025 Google LLC. https://angular.io/
2
+ * @license Angular v21.0.0-next.8
3
+ * (c) 2010-2025 Google LLC. https://angular.dev/
4
4
  * License: MIT
5
5
  */
6
6
 
@@ -2844,6 +2844,8 @@ class Identifiers {
2844
2844
  static domProperty = { name: 'ɵɵdomProperty', moduleName: CORE };
2845
2845
  static ariaProperty = { name: 'ɵɵariaProperty', moduleName: CORE };
2846
2846
  static property = { name: 'ɵɵproperty', moduleName: CORE };
2847
+ static control = { name: 'ɵɵcontrol', moduleName: CORE };
2848
+ static controlCreate = { name: 'ɵɵcontrolCreate', moduleName: CORE };
2847
2849
  static animationEnterListener = {
2848
2850
  name: 'ɵɵanimateEnterListener',
2849
2851
  moduleName: CORE,
@@ -3024,6 +3026,16 @@ class Identifiers {
3024
3026
  name: 'ɵɵvalidateIframeAttribute',
3025
3027
  moduleName: CORE,
3026
3028
  };
3029
+ // Decorators
3030
+ static inputDecorator = { name: 'Input', moduleName: CORE };
3031
+ static outputDecorator = { name: 'Output', moduleName: CORE };
3032
+ static viewChildDecorator = { name: 'ViewChild', moduleName: CORE };
3033
+ static viewChildrenDecorator = { name: 'ViewChildren', moduleName: CORE };
3034
+ static contentChildDecorator = { name: 'ContentChild', moduleName: CORE };
3035
+ static contentChildrenDecorator = {
3036
+ name: 'ContentChildren',
3037
+ moduleName: CORE,
3038
+ };
3027
3039
  // type-checking
3028
3040
  static InputSignalBrandWriteType = { name: 'ɵINPUT_SIGNAL_BRAND_WRITE_TYPE', moduleName: CORE };
3029
3041
  static UnwrapDirectiveSignalInputs = { name: 'ɵUnwrapDirectiveSignalInputs', moduleName: CORE };
@@ -4957,9 +4969,11 @@ class InteractionDeferredTrigger extends DeferredTrigger {
4957
4969
  }
4958
4970
  class ViewportDeferredTrigger extends DeferredTrigger {
4959
4971
  reference;
4960
- constructor(reference, nameSpan, sourceSpan, prefetchSpan, onSourceSpan, hydrateSpan) {
4972
+ options;
4973
+ constructor(reference, options, nameSpan, sourceSpan, prefetchSpan, onSourceSpan, hydrateSpan) {
4961
4974
  super(nameSpan, sourceSpan, prefetchSpan, onSourceSpan, hydrateSpan);
4962
4975
  this.reference = reference;
4976
+ this.options = options;
4963
4977
  }
4964
4978
  }
4965
4979
  class BlockNode {
@@ -8783,6 +8797,17 @@ var OpKind;
8783
8797
  * An operation to bind animation events to an element.
8784
8798
  */
8785
8799
  OpKind[OpKind["AnimationListener"] = 56] = "AnimationListener";
8800
+ /**
8801
+ * An operation to bind an expression to a `field` property of an element.
8802
+ */
8803
+ OpKind[OpKind["Control"] = 57] = "Control";
8804
+ /**
8805
+ * An operation to set up a corresponding {@link Control} operation.
8806
+ *
8807
+ * This is responsible for setting up event listeners on a native or custom form control when
8808
+ * bound to a specialized field directive.
8809
+ */
8810
+ OpKind[OpKind["ControlCreate"] = 58] = "ControlCreate";
8786
8811
  })(OpKind || (OpKind = {}));
8787
8812
  /**
8788
8813
  * Distinguishes different kinds of IR expressions.
@@ -9453,6 +9478,25 @@ function createStoreLetOp(target, declaredName, value, sourceSpan) {
9453
9478
  ...NEW_OP,
9454
9479
  };
9455
9480
  }
9481
+ /** Creates a {@link ControlOp}. */
9482
+ function createControlOp(op) {
9483
+ return {
9484
+ kind: OpKind.Control,
9485
+ target: op.target,
9486
+ expression: op.expression,
9487
+ bindingKind: op.bindingKind,
9488
+ securityContext: op.securityContext,
9489
+ sanitizer: null,
9490
+ isStructuralTemplateAttribute: op.isStructuralTemplateAttribute,
9491
+ templateKind: op.templateKind,
9492
+ i18nContext: op.i18nContext,
9493
+ i18nMessage: op.i18nMessage,
9494
+ sourceSpan: op.sourceSpan,
9495
+ ...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
9496
+ ...TRAIT_CONSUMES_VARS,
9497
+ ...NEW_OP,
9498
+ };
9499
+ }
9456
9500
 
9457
9501
  /**
9458
9502
  * Check whether a given `o.Expression` is a logical IR expression type.
@@ -10235,6 +10279,7 @@ function transformExpressionsInOp(op, transform, flags) {
10235
10279
  case OpKind.Property:
10236
10280
  case OpKind.DomProperty:
10237
10281
  case OpKind.Attribute:
10282
+ case OpKind.Control:
10238
10283
  if (op.expression instanceof Interpolation) {
10239
10284
  transformExpressionsInInterpolation(op.expression, transform, flags);
10240
10285
  }
@@ -10360,6 +10405,7 @@ function transformExpressionsInOp(op, transform, flags) {
10360
10405
  case OpKind.SourceLocation:
10361
10406
  case OpKind.ConditionalCreate:
10362
10407
  case OpKind.ConditionalBranchCreate:
10408
+ case OpKind.ControlCreate:
10363
10409
  // These operations contain no expressions.
10364
10410
  break;
10365
10411
  default:
@@ -11260,6 +11306,10 @@ function createSourceLocationOp(templatePath, locations) {
11260
11306
  ...NEW_OP,
11261
11307
  };
11262
11308
  }
11309
+ /** Creates a {@link ControlCreateOp}. */
11310
+ function createControlCreateOp(sourceSpan) {
11311
+ return { kind: OpKind.ControlCreate, sourceSpan, ...NEW_OP };
11312
+ }
11263
11313
 
11264
11314
  function createDomPropertyOp(name, expression, bindingKind, i18nContext, securityContext, sourceSpan) {
11265
11315
  return {
@@ -11738,6 +11788,14 @@ function extractAttributes(job) {
11738
11788
  /* i18nMessage */ null, op.securityContext), lookupElement$3(elements, op.target));
11739
11789
  }
11740
11790
  break;
11791
+ case OpKind.Control:
11792
+ OpList.insertBefore(
11793
+ // Deliberately null i18nMessage value
11794
+ createExtractedAttributeOp(op.target, BindingKind.Property, null, 'field',
11795
+ /* expression */ null,
11796
+ /* i18nContext */ null,
11797
+ /* i18nMessage */ null, op.securityContext), lookupElement$3(elements, op.target));
11798
+ break;
11741
11799
  case OpKind.TwoWayProperty:
11742
11800
  OpList.insertBefore(createExtractedAttributeOp(op.target, BindingKind.TwoWayProperty, null, op.name,
11743
11801
  /* expression */ null,
@@ -11897,6 +11955,9 @@ function specializeBindings(job) {
11897
11955
  else if (job.kind === CompilationJobKind.Host) {
11898
11956
  OpList.replace(op, createDomPropertyOp(op.name, op.expression, op.bindingKind, op.i18nContext, op.securityContext, op.sourceSpan));
11899
11957
  }
11958
+ else if (op.name === 'field') {
11959
+ OpList.replace(op, createControlOp(op));
11960
+ }
11900
11961
  else {
11901
11962
  OpList.replace(op, createPropertyOp(op.target, op.name, op.expression, op.bindingKind, op.securityContext, op.isStructuralTemplateAttribute, op.templateKind, op.i18nContext, op.i18nMessage, op.sourceSpan));
11902
11963
  }
@@ -23780,7 +23841,7 @@ function deferOn(trigger, args, modifier, sourceSpan) {
23780
23841
  if (instructionToCall === undefined) {
23781
23842
  throw new Error(`Unable to determine instruction for trigger ${trigger}`);
23782
23843
  }
23783
- return call(instructionToCall, args.map((a) => literal(a)), sourceSpan);
23844
+ return call(instructionToCall, args, sourceSpan);
23784
23845
  }
23785
23846
  function projectionDef(def) {
23786
23847
  return call(Identifiers.projectionDef, def ? [def] : [], null);
@@ -23909,6 +23970,22 @@ function ariaProperty(name, expression, sourceSpan) {
23909
23970
  function property(name, expression, sanitizer, sourceSpan) {
23910
23971
  return propertyBase(Identifiers.property, name, expression, sanitizer, sourceSpan);
23911
23972
  }
23973
+ function control(expression, sanitizer, sourceSpan) {
23974
+ const args = [];
23975
+ if (expression instanceof Interpolation) {
23976
+ args.push(interpolationToExpression(expression, sourceSpan));
23977
+ }
23978
+ else {
23979
+ args.push(expression);
23980
+ }
23981
+ if (sanitizer !== null) {
23982
+ args.push(sanitizer);
23983
+ }
23984
+ return call(Identifiers.control, args, sourceSpan);
23985
+ }
23986
+ function controlCreate(sourceSpan) {
23987
+ return call(Identifiers.controlCreate, [], sourceSpan);
23988
+ }
23912
23989
  function twoWayProperty(name, expression, sanitizer, sourceSpan) {
23913
23990
  const args = [literal(name), expression];
23914
23991
  if (sanitizer !== null) {
@@ -24355,11 +24432,30 @@ function reifyCreateOperations(unit, ops) {
24355
24432
  case DeferTriggerKind.Immediate:
24356
24433
  break;
24357
24434
  case DeferTriggerKind.Timer:
24358
- args = [op.trigger.delay];
24435
+ args = [literal(op.trigger.delay)];
24436
+ break;
24437
+ case DeferTriggerKind.Viewport:
24438
+ // `hydrate` triggers don't support targets.
24439
+ if (op.modifier === "hydrate" /* ir.DeferOpModifierKind.HYDRATE */) {
24440
+ args = op.trigger.options ? [op.trigger.options] : [];
24441
+ }
24442
+ else {
24443
+ // The slots not being defined at this point is invalid, however we
24444
+ // catch it during type checking. Pass in null in such cases.
24445
+ args = [literal(op.trigger.targetSlot?.slot ?? null)];
24446
+ if (op.trigger.targetSlotViewSteps !== 0) {
24447
+ args.push(literal(op.trigger.targetSlotViewSteps));
24448
+ }
24449
+ else if (op.trigger.options) {
24450
+ args.push(literal(null));
24451
+ }
24452
+ if (op.trigger.options) {
24453
+ args.push(op.trigger.options);
24454
+ }
24455
+ }
24359
24456
  break;
24360
24457
  case DeferTriggerKind.Interaction:
24361
24458
  case DeferTriggerKind.Hover:
24362
- case DeferTriggerKind.Viewport:
24363
24459
  // `hydrate` triggers don't support targets.
24364
24460
  if (op.modifier === "hydrate" /* ir.DeferOpModifierKind.HYDRATE */) {
24365
24461
  args = [];
@@ -24367,9 +24463,9 @@ function reifyCreateOperations(unit, ops) {
24367
24463
  else {
24368
24464
  // The slots not being defined at this point is invalid, however we
24369
24465
  // catch it during type checking. Pass in null in such cases.
24370
- args = [op.trigger.targetSlot?.slot ?? null];
24466
+ args = [literal(op.trigger.targetSlot?.slot ?? null)];
24371
24467
  if (op.trigger.targetSlotViewSteps !== 0) {
24372
- args.push(op.trigger.targetSlotViewSteps);
24468
+ args.push(literal(op.trigger.targetSlotViewSteps));
24373
24469
  }
24374
24470
  }
24375
24471
  break;
@@ -24469,6 +24565,9 @@ function reifyCreateOperations(unit, ops) {
24469
24565
  }));
24470
24566
  OpList.replace(op, attachSourceLocation(op.templatePath, locationsLiteral));
24471
24567
  break;
24568
+ case OpKind.ControlCreate:
24569
+ OpList.replace(op, controlCreate(op.sourceSpan));
24570
+ break;
24472
24571
  case OpKind.Statement:
24473
24572
  // Pass statement operations directly through.
24474
24573
  break;
@@ -24491,6 +24590,9 @@ function reifyUpdateOperations(unit, ops) {
24491
24590
  ? reifyDomProperty(op)
24492
24591
  : reifyProperty(op));
24493
24592
  break;
24593
+ case OpKind.Control:
24594
+ OpList.replace(op, reifyControl(op));
24595
+ break;
24494
24596
  case OpKind.TwoWayProperty:
24495
24597
  OpList.replace(op, twoWayProperty(op.name, op.expression, op.sanitizer, op.sourceSpan));
24496
24598
  break;
@@ -24586,6 +24688,9 @@ function reifyProperty(op) {
24586
24688
  ? ariaProperty(op.name, op.expression, op.sourceSpan)
24587
24689
  : property(op.name, op.expression, op.sanitizer, op.sourceSpan);
24588
24690
  }
24691
+ function reifyControl(op) {
24692
+ return control(op.expression, op.sanitizer, op.sourceSpan);
24693
+ }
24589
24694
  function reifyIrExpression(expr) {
24590
24695
  if (!isIrExpression(expr)) {
24591
24696
  return expr;
@@ -26098,6 +26203,7 @@ function varsUsedByOp(op) {
26098
26203
  return slots;
26099
26204
  case OpKind.Property:
26100
26205
  case OpKind.DomProperty:
26206
+ case OpKind.Control:
26101
26207
  slots = 1;
26102
26208
  // We need to assign a slot even for singleton interpolations, because the
26103
26209
  // runtime needs to store both the raw value and the stringified one.
@@ -27235,6 +27341,9 @@ function ingestDeferTriggers(modifier, triggers, onOps, whenOps, unit, deferXref
27235
27341
  targetSlot: null,
27236
27342
  targetView: null,
27237
27343
  targetSlotViewSteps: null,
27344
+ options: triggers.viewport.options
27345
+ ? convertAst(triggers.viewport.options, unit.job, triggers.viewport.sourceSpan)
27346
+ : null,
27238
27347
  }, modifier, triggers.viewport.sourceSpan);
27239
27348
  onOps.push(deferOnOp);
27240
27349
  }
@@ -27565,6 +27674,11 @@ function ingestElementBindings(unit, op, element) {
27565
27674
  }
27566
27675
  // All dynamic bindings (both attribute and property bindings).
27567
27676
  bindings.push(createBindingOp(op.xref, BINDING_KINDS.get(input.type), input.name, convertAstWithInterpolation(unit.job, astOf(input.value), input.i18n), input.unit, input.securityContext, false, false, null, asMessage(input.i18n) ?? null, input.sourceSpan));
27677
+ // If the input name is 'field', this could be a form control binding which requires a
27678
+ // `ControlCreateOp` to properly initialize.
27679
+ if (input.type === BindingType.Property && input.name === 'field') {
27680
+ unit.create.push(createControlCreateOp(input.sourceSpan));
27681
+ }
27568
27682
  }
27569
27683
  unit.create.push(bindings.filter((b) => b?.kind === OpKind.ExtractedAttribute));
27570
27684
  unit.update.push(bindings.filter((b) => b?.kind === OpKind.Binding));
@@ -28747,6 +28861,7 @@ function createForLoop(ast, connectedBlocks, visitor, bindingParser) {
28747
28861
  // main `for` body, use `mainSourceSpan`.
28748
28862
  const endSpan = empty?.endSourceSpan ?? ast.endSourceSpan;
28749
28863
  const sourceSpan = new ParseSourceSpan(ast.sourceSpan.start, endSpan?.end ?? ast.sourceSpan.end);
28864
+ validateTrackByExpression(params.trackBy.expression, params.trackBy.keywordSpan, errors);
28750
28865
  node = new ForLoopBlock(params.itemName, params.expression, params.trackBy.expression, params.trackBy.keywordSpan, params.context, visitAll(visitor, ast.children, ast.children), empty, sourceSpan, ast.sourceSpan, ast.startSourceSpan, endSpan, ast.nameSpan, ast.i18n);
28751
28866
  }
28752
28867
  }
@@ -28846,6 +28961,13 @@ function parseForLoopParameters(block, errors, bindingParser) {
28846
28961
  }
28847
28962
  return result;
28848
28963
  }
28964
+ function validateTrackByExpression(expression, parseSourceSpan, errors) {
28965
+ const visitor = new PipeVisitor();
28966
+ expression.ast.visit(visitor);
28967
+ if (visitor.hasPipe) {
28968
+ errors.push(new ParseError(parseSourceSpan, 'Cannot use pipes in track expressions'));
28969
+ }
28970
+ }
28849
28971
  /** Parses the `let` parameter of a `for` loop block. */
28850
28972
  function parseLetParameter(sourceSpan, expression, span, loopItemName, context, errors) {
28851
28973
  const parts = expression.split(',');
@@ -29056,6 +29178,12 @@ function stripOptionalParentheses(param, errors) {
29056
29178
  }
29057
29179
  return expression.slice(start, end);
29058
29180
  }
29181
+ class PipeVisitor extends RecursiveAstVisitor {
29182
+ hasPipe = false;
29183
+ visitPipe() {
29184
+ this.hasPipe = true;
29185
+ }
29186
+ }
29059
29187
 
29060
29188
  /** Pattern for a timing value in a trigger. */
29061
29189
  const TIME_PATTERN = /^\d+\.?\d*(ms|s)?$/;
@@ -29111,7 +29239,7 @@ function parseWhenTrigger({ expression, sourceSpan }, bindingParser, triggers, e
29111
29239
  }
29112
29240
  }
29113
29241
  /** Parses an `on` trigger */
29114
- function parseOnTrigger({ expression, sourceSpan }, triggers, errors, placeholder) {
29242
+ function parseOnTrigger({ expression, sourceSpan }, bindingParser, triggers, errors, placeholder) {
29115
29243
  const onIndex = expression.indexOf('on');
29116
29244
  const onSourceSpan = new ParseSourceSpan(sourceSpan.start.moveBy(onIndex), sourceSpan.start.moveBy(onIndex + 'on'.length));
29117
29245
  const prefetchSpan = getPrefetchSpan(expression, sourceSpan);
@@ -29123,9 +29251,10 @@ function parseOnTrigger({ expression, sourceSpan }, triggers, errors, placeholde
29123
29251
  }
29124
29252
  else {
29125
29253
  const start = getTriggerParametersStart(expression, onIndex + 1);
29126
- const parser = new OnTriggerParser(expression, start, sourceSpan, triggers, errors, expression.startsWith('hydrate')
29254
+ const isHydrationTrigger = expression.startsWith('hydrate');
29255
+ const parser = new OnTriggerParser(expression, bindingParser, start, sourceSpan, triggers, errors, isHydrationTrigger
29127
29256
  ? validateHydrateReferenceBasedTrigger
29128
- : validatePlainReferenceBasedTrigger, placeholder, prefetchSpan, onSourceSpan, hydrateSpan);
29257
+ : validatePlainReferenceBasedTrigger, isHydrationTrigger, prefetchSpan, onSourceSpan, hydrateSpan);
29129
29258
  parser.parse();
29130
29259
  }
29131
29260
  }
@@ -29143,25 +29272,27 @@ function getHydrateSpan(expression, sourceSpan) {
29143
29272
  }
29144
29273
  class OnTriggerParser {
29145
29274
  expression;
29275
+ bindingParser;
29146
29276
  start;
29147
29277
  span;
29148
29278
  triggers;
29149
29279
  errors;
29150
29280
  validator;
29151
- placeholder;
29281
+ isHydrationTrigger;
29152
29282
  prefetchSpan;
29153
29283
  onSourceSpan;
29154
29284
  hydrateSpan;
29155
29285
  index = 0;
29156
29286
  tokens;
29157
- constructor(expression, start, span, triggers, errors, validator, placeholder, prefetchSpan, onSourceSpan, hydrateSpan) {
29287
+ constructor(expression, bindingParser, start, span, triggers, errors, validator, isHydrationTrigger, prefetchSpan, onSourceSpan, hydrateSpan) {
29158
29288
  this.expression = expression;
29289
+ this.bindingParser = bindingParser;
29159
29290
  this.start = start;
29160
29291
  this.span = span;
29161
29292
  this.triggers = triggers;
29162
29293
  this.errors = errors;
29163
29294
  this.validator = validator;
29164
- this.placeholder = placeholder;
29295
+ this.isHydrationTrigger = isHydrationTrigger;
29165
29296
  this.prefetchSpan = prefetchSpan;
29166
29297
  this.onSourceSpan = onSourceSpan;
29167
29298
  this.hydrateSpan = hydrateSpan;
@@ -29235,10 +29366,10 @@ class OnTriggerParser {
29235
29366
  this.trackTrigger('immediate', createImmediateTrigger(parameters, nameSpan, sourceSpan, this.prefetchSpan, this.onSourceSpan, this.hydrateSpan));
29236
29367
  break;
29237
29368
  case OnTriggerType.HOVER:
29238
- this.trackTrigger('hover', createHoverTrigger(parameters, nameSpan, sourceSpan, this.prefetchSpan, this.onSourceSpan, this.hydrateSpan, this.placeholder, this.validator));
29369
+ this.trackTrigger('hover', createHoverTrigger(parameters, nameSpan, sourceSpan, this.prefetchSpan, this.onSourceSpan, this.hydrateSpan, this.validator));
29239
29370
  break;
29240
29371
  case OnTriggerType.VIEWPORT:
29241
- this.trackTrigger('viewport', createViewportTrigger(parameters, nameSpan, sourceSpan, this.prefetchSpan, this.onSourceSpan, this.hydrateSpan, this.validator));
29372
+ this.trackTrigger('viewport', createViewportTrigger(this.start, this.isHydrationTrigger, this.bindingParser, parameters, nameSpan, sourceSpan, this.prefetchSpan, this.onSourceSpan, this.hydrateSpan, this.validator));
29242
29373
  break;
29243
29374
  default:
29244
29375
  throw new Error(`Unrecognized trigger type "${identifier}"`);
@@ -29256,15 +29387,15 @@ class OnTriggerParser {
29256
29387
  }
29257
29388
  this.advance();
29258
29389
  const commaDelimStack = [];
29259
- let current = '';
29390
+ let tokens = [];
29260
29391
  while (this.index < this.tokens.length) {
29261
29392
  const token = this.token();
29262
29393
  // Stop parsing if we've hit the end character and we're outside of a comma-delimited syntax.
29263
29394
  // Note that we don't need to account for strings here since the lexer already parsed them
29264
29395
  // into string tokens.
29265
29396
  if (token.isCharacter($RPAREN) && commaDelimStack.length === 0) {
29266
- if (current.length) {
29267
- parameters.push(current);
29397
+ if (tokens.length) {
29398
+ parameters.push({ expression: this.tokenRangeText(tokens), start: tokens[0].index });
29268
29399
  }
29269
29400
  break;
29270
29401
  }
@@ -29283,14 +29414,14 @@ class OnTriggerParser {
29283
29414
  }
29284
29415
  // If we hit a comma outside of a comma-delimited syntax, it means
29285
29416
  // that we're at the top level and we're starting a new parameter.
29286
- if (commaDelimStack.length === 0 && token.isCharacter($COMMA) && current.length > 0) {
29287
- parameters.push(current);
29288
- current = '';
29417
+ if (commaDelimStack.length === 0 && token.isCharacter($COMMA) && tokens.length > 0) {
29418
+ parameters.push({ expression: this.tokenRangeText(tokens), start: tokens[0].index });
29289
29419
  this.advance();
29420
+ tokens = [];
29290
29421
  continue;
29291
29422
  }
29292
29423
  // Otherwise treat the token as a plain text character in the current parameter.
29293
- current += this.tokenText();
29424
+ tokens.push(token);
29294
29425
  this.advance();
29295
29426
  }
29296
29427
  if (!this.token().isCharacter($RPAREN) || commaDelimStack.length > 0) {
@@ -29302,10 +29433,11 @@ class OnTriggerParser {
29302
29433
  }
29303
29434
  return parameters;
29304
29435
  }
29305
- tokenText() {
29306
- // Tokens have a toString already which we could use, but for string tokens it omits the quotes.
29307
- // Eventually we could expose this information on the token directly.
29308
- return this.expression.slice(this.start + this.token().index, this.start + this.token().end);
29436
+ tokenRangeText(tokens) {
29437
+ if (tokens.length === 0) {
29438
+ return '';
29439
+ }
29440
+ return this.expression.slice(this.start + tokens[0].index, this.start + tokens[tokens.length - 1].end);
29309
29441
  }
29310
29442
  trackTrigger(name, trigger) {
29311
29443
  trackTrigger(name, this.triggers, this.errors, trigger);
@@ -29338,7 +29470,7 @@ function createTimerTrigger(parameters, nameSpan, sourceSpan, prefetchSpan, onSo
29338
29470
  if (parameters.length !== 1) {
29339
29471
  throw new Error(`"${OnTriggerType.TIMER}" trigger must have exactly one parameter`);
29340
29472
  }
29341
- const delay = parseDeferredTime(parameters[0]);
29473
+ const delay = parseDeferredTime(parameters[0].expression);
29342
29474
  if (delay === null) {
29343
29475
  throw new Error(`Could not parse time value of trigger "${OnTriggerType.TIMER}"`);
29344
29476
  }
@@ -29350,17 +29482,61 @@ function createImmediateTrigger(parameters, nameSpan, sourceSpan, prefetchSpan,
29350
29482
  }
29351
29483
  return new ImmediateDeferredTrigger(nameSpan, sourceSpan, prefetchSpan, onSourceSpan, hydrateSpan);
29352
29484
  }
29353
- function createHoverTrigger(parameters, nameSpan, sourceSpan, prefetchSpan, onSourceSpan, hydrateSpan, placeholder, validator) {
29485
+ function createHoverTrigger(parameters, nameSpan, sourceSpan, prefetchSpan, onSourceSpan, hydrateSpan, validator) {
29354
29486
  validator(OnTriggerType.HOVER, parameters);
29355
- return new HoverDeferredTrigger(parameters[0] ?? null, nameSpan, sourceSpan, prefetchSpan, onSourceSpan, hydrateSpan);
29487
+ return new HoverDeferredTrigger(parameters[0]?.expression ?? null, nameSpan, sourceSpan, prefetchSpan, onSourceSpan, hydrateSpan);
29356
29488
  }
29357
29489
  function createInteractionTrigger(parameters, nameSpan, sourceSpan, prefetchSpan, onSourceSpan, hydrateSpan, validator) {
29358
29490
  validator(OnTriggerType.INTERACTION, parameters);
29359
- return new InteractionDeferredTrigger(parameters[0] ?? null, nameSpan, sourceSpan, prefetchSpan, onSourceSpan, hydrateSpan);
29491
+ return new InteractionDeferredTrigger(parameters[0]?.expression ?? null, nameSpan, sourceSpan, prefetchSpan, onSourceSpan, hydrateSpan);
29360
29492
  }
29361
- function createViewportTrigger(parameters, nameSpan, sourceSpan, prefetchSpan, onSourceSpan, hydrateSpan, validator) {
29493
+ function createViewportTrigger(start, isHydrationTrigger, bindingParser, parameters, nameSpan, sourceSpan, prefetchSpan, onSourceSpan, hydrateSpan, validator) {
29362
29494
  validator(OnTriggerType.VIEWPORT, parameters);
29363
- return new ViewportDeferredTrigger(parameters[0] ?? null, nameSpan, sourceSpan, prefetchSpan, onSourceSpan, hydrateSpan);
29495
+ let reference;
29496
+ let options;
29497
+ if (parameters.length === 0) {
29498
+ reference = options = null;
29499
+ }
29500
+ else if (!parameters[0].expression.startsWith('{')) {
29501
+ reference = parameters[0].expression;
29502
+ options = null;
29503
+ }
29504
+ else {
29505
+ const parsed = bindingParser.parseBinding(parameters[0].expression, false, sourceSpan, sourceSpan.start.offset + start + parameters[0].start);
29506
+ if (!(parsed.ast instanceof LiteralMap)) {
29507
+ throw new Error('Options parameter of the "viewport" trigger must be an object literal');
29508
+ }
29509
+ else if (parsed.ast.keys.some((key) => key.key === 'root')) {
29510
+ throw new Error('The "root" option is not supported in the options parameter of the "viewport" trigger');
29511
+ }
29512
+ const triggerIndex = parsed.ast.keys.findIndex((key) => key.key === 'trigger');
29513
+ if (triggerIndex === -1) {
29514
+ reference = null;
29515
+ options = parsed.ast;
29516
+ }
29517
+ else {
29518
+ const value = parsed.ast.values[triggerIndex];
29519
+ const triggerFilter = (_, index) => index !== triggerIndex;
29520
+ if (!(value instanceof PropertyRead) ||
29521
+ !(value.receiver instanceof ImplicitReceiver) ||
29522
+ value.receiver instanceof ThisReceiver) {
29523
+ throw new Error(`"trigger" option of the "viewport" trigger must be an identifier`);
29524
+ }
29525
+ reference = value.name;
29526
+ options = new LiteralMap(parsed.ast.span, parsed.ast.sourceSpan, parsed.ast.keys.filter(triggerFilter), parsed.ast.values.filter(triggerFilter));
29527
+ }
29528
+ }
29529
+ if (isHydrationTrigger && reference !== null) {
29530
+ throw new Error(`"viewport" hydration trigger cannot have a "trigger"`);
29531
+ }
29532
+ else if (options) {
29533
+ const dynamicNode = DynamicAstValidator.findDynamicNode(options);
29534
+ if (dynamicNode !== null) {
29535
+ throw new Error(`Options of the "viewport" trigger must be an object ` +
29536
+ `literal containing only literal values, but "${dynamicNode.constructor.name}" was found`);
29537
+ }
29538
+ }
29539
+ return new ViewportDeferredTrigger(reference, options, nameSpan, sourceSpan, prefetchSpan, onSourceSpan, hydrateSpan);
29364
29540
  }
29365
29541
  /**
29366
29542
  * Checks whether the structure of a non-hydrate reference-based trigger is valid.
@@ -29378,6 +29554,12 @@ function validatePlainReferenceBasedTrigger(type, parameters) {
29378
29554
  * @param parameters Parameters of the trigger.
29379
29555
  */
29380
29556
  function validateHydrateReferenceBasedTrigger(type, parameters) {
29557
+ if (type === OnTriggerType.VIEWPORT) {
29558
+ if (parameters.length > 1) {
29559
+ throw new Error(`Hydration trigger "${type}" cannot have more than one parameter`);
29560
+ }
29561
+ return;
29562
+ }
29381
29563
  if (parameters.length > 0) {
29382
29564
  throw new Error(`Hydration trigger "${type}" cannot have parameters`);
29383
29565
  }
@@ -29407,6 +29589,25 @@ function parseDeferredTime(value) {
29407
29589
  const [time, units] = match;
29408
29590
  return parseFloat(time) * (units === 's' ? 1000 : 1);
29409
29591
  }
29592
+ class DynamicAstValidator extends RecursiveAstVisitor {
29593
+ dynamicNode = null;
29594
+ static findDynamicNode(ast) {
29595
+ const visitor = new DynamicAstValidator();
29596
+ visitor.visit(ast);
29597
+ return visitor.dynamicNode;
29598
+ }
29599
+ visit(ast) {
29600
+ if (!(ast instanceof ASTWithSource) &&
29601
+ !(ast instanceof LiteralPrimitive) &&
29602
+ !(ast instanceof LiteralArray) &&
29603
+ !(ast instanceof LiteralMap)) {
29604
+ this.dynamicNode = ast;
29605
+ }
29606
+ else {
29607
+ super.visit(ast);
29608
+ }
29609
+ }
29610
+ }
29410
29611
 
29411
29612
  /** Pattern to identify a `prefetch when` trigger. */
29412
29613
  const PREFETCH_WHEN_PATTERN = /^prefetch\s+when\s/;
@@ -29437,7 +29638,7 @@ function isConnectedDeferLoopBlock(name) {
29437
29638
  function createDeferredBlock(ast, connectedBlocks, visitor, bindingParser) {
29438
29639
  const errors = [];
29439
29640
  const { placeholder, loading, error } = parseConnectedBlocks(connectedBlocks, errors, visitor);
29440
- const { triggers, prefetchTriggers, hydrateTriggers } = parsePrimaryTriggers(ast, bindingParser, errors, placeholder);
29641
+ const { triggers, prefetchTriggers, hydrateTriggers } = parsePrimaryTriggers(ast, bindingParser, errors);
29441
29642
  // The `defer` block has a main span encompassing all of the connected branches as well.
29442
29643
  let lastEndSourceSpan = ast.endSourceSpan;
29443
29644
  let endOfLastSourceSpan = ast.sourceSpan.end;
@@ -29559,19 +29760,19 @@ function parsePrimaryTriggers(ast, bindingParser, errors, placeholder) {
29559
29760
  parseWhenTrigger(param, bindingParser, triggers, errors);
29560
29761
  }
29561
29762
  else if (ON_PARAMETER_PATTERN.test(param.expression)) {
29562
- parseOnTrigger(param, triggers, errors, placeholder);
29763
+ parseOnTrigger(param, bindingParser, triggers, errors);
29563
29764
  }
29564
29765
  else if (PREFETCH_WHEN_PATTERN.test(param.expression)) {
29565
29766
  parseWhenTrigger(param, bindingParser, prefetchTriggers, errors);
29566
29767
  }
29567
29768
  else if (PREFETCH_ON_PATTERN.test(param.expression)) {
29568
- parseOnTrigger(param, prefetchTriggers, errors, placeholder);
29769
+ parseOnTrigger(param, bindingParser, prefetchTriggers, errors);
29569
29770
  }
29570
29771
  else if (HYDRATE_WHEN_PATTERN.test(param.expression)) {
29571
29772
  parseWhenTrigger(param, bindingParser, hydrateTriggers, errors);
29572
29773
  }
29573
29774
  else if (HYDRATE_ON_PATTERN.test(param.expression)) {
29574
- parseOnTrigger(param, hydrateTriggers, errors, placeholder);
29775
+ parseOnTrigger(param, bindingParser, hydrateTriggers, errors);
29575
29776
  }
29576
29777
  else if (HYDRATE_NEVER_PATTERN.test(param.expression)) {
29577
29778
  parseNeverTrigger(param, hydrateTriggers, errors);
@@ -30526,7 +30727,7 @@ function compileComponentFromMetadata(meta, constantPool, bindingParser) {
30526
30727
  : TemplateCompilationMode.Full;
30527
30728
  // First the template is ingested into IR:
30528
30729
  const tpl = ingestComponent(meta.name, meta.template.nodes, constantPool, compilationMode, meta.relativeContextFilePath, meta.i18nUseExternalIds, meta.defer, allDeferrableDepsFn, meta.relativeTemplatePath, getTemplateSourceLocationsEnabled());
30529
- // Then the IR is transformed to prepare it for cod egeneration.
30730
+ // Then the IR is transformed to prepare it for code generation.
30530
30731
  transform(tpl, CompilationJobKind.Tmpl);
30531
30732
  // Finally we emit the template function:
30532
30733
  const templateFn = emitTemplateFn(tpl, constantPool);
@@ -31000,6 +31201,9 @@ class CombinedRecursiveAstVisitor extends RecursiveAstVisitor {
31000
31201
  if (trigger instanceof BoundDeferredTrigger) {
31001
31202
  this.visit(trigger.value);
31002
31203
  }
31204
+ else if (trigger instanceof ViewportDeferredTrigger && trigger.options !== null) {
31205
+ this.visit(trigger.options);
31206
+ }
31003
31207
  }
31004
31208
  visitDeferredBlockPlaceholder(block) {
31005
31209
  this.visitAllTemplateNodes(block.children);
@@ -34434,7 +34638,7 @@ const MINIMUM_PARTIAL_LINKER_DEFER_SUPPORT_VERSION = '18.0.0';
34434
34638
  function compileDeclareClassMetadata(metadata) {
34435
34639
  const definitionMap = new DefinitionMap();
34436
34640
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$5));
34437
- definitionMap.set('version', literal('21.0.0-next.6'));
34641
+ definitionMap.set('version', literal('21.0.0-next.8'));
34438
34642
  definitionMap.set('ngImport', importExpr(Identifiers.core));
34439
34643
  definitionMap.set('type', metadata.type);
34440
34644
  definitionMap.set('decorators', metadata.decorators);
@@ -34452,7 +34656,7 @@ function compileComponentDeclareClassMetadata(metadata, dependencies) {
34452
34656
  callbackReturnDefinitionMap.set('ctorParameters', metadata.ctorParameters ?? literal(null));
34453
34657
  callbackReturnDefinitionMap.set('propDecorators', metadata.propDecorators ?? literal(null));
34454
34658
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_DEFER_SUPPORT_VERSION));
34455
- definitionMap.set('version', literal('21.0.0-next.6'));
34659
+ definitionMap.set('version', literal('21.0.0-next.8'));
34456
34660
  definitionMap.set('ngImport', importExpr(Identifiers.core));
34457
34661
  definitionMap.set('type', metadata.type);
34458
34662
  definitionMap.set('resolveDeferredDeps', compileComponentMetadataAsyncResolver(dependencies));
@@ -34547,7 +34751,7 @@ function createDirectiveDefinitionMap(meta) {
34547
34751
  const definitionMap = new DefinitionMap();
34548
34752
  const minVersion = getMinimumVersionForPartialOutput(meta);
34549
34753
  definitionMap.set('minVersion', literal(minVersion));
34550
- definitionMap.set('version', literal('21.0.0-next.6'));
34754
+ definitionMap.set('version', literal('21.0.0-next.8'));
34551
34755
  // e.g. `type: MyDirective`
34552
34756
  definitionMap.set('type', meta.type.value);
34553
34757
  if (meta.isStandalone !== undefined) {
@@ -34960,7 +35164,7 @@ const MINIMUM_PARTIAL_LINKER_VERSION$4 = '12.0.0';
34960
35164
  function compileDeclareFactoryFunction(meta) {
34961
35165
  const definitionMap = new DefinitionMap();
34962
35166
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$4));
34963
- definitionMap.set('version', literal('21.0.0-next.6'));
35167
+ definitionMap.set('version', literal('21.0.0-next.8'));
34964
35168
  definitionMap.set('ngImport', importExpr(Identifiers.core));
34965
35169
  definitionMap.set('type', meta.type.value);
34966
35170
  definitionMap.set('deps', compileDependencies(meta.deps));
@@ -34995,7 +35199,7 @@ function compileDeclareInjectableFromMetadata(meta) {
34995
35199
  function createInjectableDefinitionMap(meta) {
34996
35200
  const definitionMap = new DefinitionMap();
34997
35201
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$3));
34998
- definitionMap.set('version', literal('21.0.0-next.6'));
35202
+ definitionMap.set('version', literal('21.0.0-next.8'));
34999
35203
  definitionMap.set('ngImport', importExpr(Identifiers.core));
35000
35204
  definitionMap.set('type', meta.type.value);
35001
35205
  // Only generate providedIn property if it has a non-null value
@@ -35046,7 +35250,7 @@ function compileDeclareInjectorFromMetadata(meta) {
35046
35250
  function createInjectorDefinitionMap(meta) {
35047
35251
  const definitionMap = new DefinitionMap();
35048
35252
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$2));
35049
- definitionMap.set('version', literal('21.0.0-next.6'));
35253
+ definitionMap.set('version', literal('21.0.0-next.8'));
35050
35254
  definitionMap.set('ngImport', importExpr(Identifiers.core));
35051
35255
  definitionMap.set('type', meta.type.value);
35052
35256
  definitionMap.set('providers', meta.providers);
@@ -35079,7 +35283,7 @@ function createNgModuleDefinitionMap(meta) {
35079
35283
  throw new Error('Invalid path! Local compilation mode should not get into the partial compilation path');
35080
35284
  }
35081
35285
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$1));
35082
- definitionMap.set('version', literal('21.0.0-next.6'));
35286
+ definitionMap.set('version', literal('21.0.0-next.8'));
35083
35287
  definitionMap.set('ngImport', importExpr(Identifiers.core));
35084
35288
  definitionMap.set('type', meta.type.value);
35085
35289
  // We only generate the keys in the metadata if the arrays contain values.
@@ -35130,7 +35334,7 @@ function compileDeclarePipeFromMetadata(meta) {
35130
35334
  function createPipeDefinitionMap(meta) {
35131
35335
  const definitionMap = new DefinitionMap();
35132
35336
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION));
35133
- definitionMap.set('version', literal('21.0.0-next.6'));
35337
+ definitionMap.set('version', literal('21.0.0-next.8'));
35134
35338
  definitionMap.set('ngImport', importExpr(Identifiers.core));
35135
35339
  // e.g. `type: MyPipe`
35136
35340
  definitionMap.set('type', meta.type.value);
@@ -35286,7 +35490,7 @@ function compileHmrUpdateCallback(definitions, constantStatements, meta) {
35286
35490
  * @description
35287
35491
  * Entry point for all public APIs of the compiler package.
35288
35492
  */
35289
- const VERSION = new Version('21.0.0-next.6');
35493
+ const VERSION = new Version('21.0.0-next.8');
35290
35494
 
35291
35495
  //////////////////////////////////////
35292
35496
  // THIS FILE HAS GLOBAL SIDE EFFECT //