@angular/compiler 17.1.1 → 17.1.3

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 (28) hide show
  1. package/esm2022/src/constant_pool.mjs +14 -4
  2. package/esm2022/src/expression_parser/ast.mjs +2 -1
  3. package/esm2022/src/render3/partial/class_metadata.mjs +1 -1
  4. package/esm2022/src/render3/partial/directive.mjs +1 -1
  5. package/esm2022/src/render3/partial/factory.mjs +1 -1
  6. package/esm2022/src/render3/partial/injectable.mjs +1 -1
  7. package/esm2022/src/render3/partial/injector.mjs +1 -1
  8. package/esm2022/src/render3/partial/ng_module.mjs +1 -1
  9. package/esm2022/src/render3/partial/pipe.mjs +1 -1
  10. package/esm2022/src/render3/r3_class_metadata_compiler.mjs +5 -3
  11. package/esm2022/src/render3/r3_control_flow.mjs +39 -7
  12. package/esm2022/src/render3/r3_template_transform.mjs +5 -5
  13. package/esm2022/src/render3/view/api.mjs +1 -1
  14. package/esm2022/src/render3/view/compiler.mjs +10 -10
  15. package/esm2022/src/render3/view/template.mjs +10 -5
  16. package/esm2022/src/render3/view/util.mjs +2 -2
  17. package/esm2022/src/template/pipeline/ir/src/ops/create.mjs +3 -3
  18. package/esm2022/src/template/pipeline/src/compilation.mjs +3 -2
  19. package/esm2022/src/template/pipeline/src/emit.mjs +2 -2
  20. package/esm2022/src/template/pipeline/src/ingest.mjs +17 -7
  21. package/esm2022/src/template/pipeline/src/phases/create_defer_deps_fns.mjs +9 -3
  22. package/esm2022/src/template/pipeline/src/phases/naming.mjs +5 -2
  23. package/esm2022/src/template_parser/binding_parser.mjs +11 -10
  24. package/esm2022/src/version.mjs +1 -1
  25. package/fesm2022/compiler.mjs +131 -60
  26. package/fesm2022/compiler.mjs.map +1 -1
  27. package/index.d.ts +29 -9
  28. package/package.json +2 -2
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Angular v17.1.1
2
+ * @license Angular v17.1.3
3
3
  * (c) 2010-2022 Google LLC. https://angular.io/
4
4
  * License: MIT
5
5
  */
@@ -2236,6 +2236,13 @@ class ConstantPool {
2236
2236
  this.literals = new Map();
2237
2237
  this.literalFactories = new Map();
2238
2238
  this.sharedConstants = new Map();
2239
+ /**
2240
+ * Constant pool also tracks claimed names from {@link uniqueName}.
2241
+ * This is useful to avoid collisions if variables are intended to be
2242
+ * named a certain way- but may conflict. We wouldn't want to always suffix
2243
+ * them with unique numbers.
2244
+ */
2245
+ this._claimedNames = new Map();
2239
2246
  this.nextNameIndex = 0;
2240
2247
  }
2241
2248
  getConstLiteral(literal, forceShared) {
@@ -2358,14 +2365,17 @@ class ConstantPool {
2358
2365
  return { literalFactory, literalFactoryArguments };
2359
2366
  }
2360
2367
  /**
2361
- * Produce a unique name.
2368
+ * Produce a unique name in the context of this pool.
2362
2369
  *
2363
2370
  * The name might be unique among different prefixes if any of the prefixes end in
2364
2371
  * a digit so the prefix should be a constant string (not based on user input) and
2365
2372
  * must not end in a digit.
2366
2373
  */
2367
- uniqueName(prefix) {
2368
- return `${prefix}${this.nextNameIndex++}`;
2374
+ uniqueName(name, alwaysIncludeSuffix = true) {
2375
+ const count = this._claimedNames.get(name) ?? 0;
2376
+ const result = count === 0 && !alwaysIncludeSuffix ? `${name}` : `${name}${count}`;
2377
+ this._claimedNames.set(name, count + 1);
2378
+ return result;
2369
2379
  }
2370
2380
  freshName() {
2371
2381
  return this.uniqueName(CONSTANT_PREFIX);
@@ -5157,7 +5167,7 @@ function getAttrsForDirectiveMatching(elOrTpl) {
5157
5167
  }
5158
5168
  });
5159
5169
  elOrTpl.inputs.forEach(i => {
5160
- if (i.type === 0 /* BindingType.Property */) {
5170
+ if (i.type === 0 /* BindingType.Property */ || i.type === 5 /* BindingType.TwoWay */) {
5161
5171
  attributesMap[i.name] = '';
5162
5172
  }
5163
5173
  });
@@ -6949,6 +6959,7 @@ var ParsedPropertyType;
6949
6959
  ParsedPropertyType[ParsedPropertyType["DEFAULT"] = 0] = "DEFAULT";
6950
6960
  ParsedPropertyType[ParsedPropertyType["LITERAL_ATTR"] = 1] = "LITERAL_ATTR";
6951
6961
  ParsedPropertyType[ParsedPropertyType["ANIMATION"] = 2] = "ANIMATION";
6962
+ ParsedPropertyType[ParsedPropertyType["TWO_WAY"] = 3] = "TWO_WAY";
6952
6963
  })(ParsedPropertyType || (ParsedPropertyType = {}));
6953
6964
  class ParsedEvent {
6954
6965
  // Regular events have a target
@@ -11041,7 +11052,7 @@ function createExtractedAttributeOp(target, bindingKind, namespace, name, expres
11041
11052
  ...NEW_OP,
11042
11053
  };
11043
11054
  }
11044
- function createDeferOp(xref, main, mainSlot, metadata, sourceSpan) {
11055
+ function createDeferOp(xref, main, mainSlot, metadata, resolverFn, sourceSpan) {
11045
11056
  return {
11046
11057
  kind: OpKind.Defer,
11047
11058
  xref,
@@ -11060,7 +11071,7 @@ function createDeferOp(xref, main, mainSlot, metadata, sourceSpan) {
11060
11071
  errorView: null,
11061
11072
  errorSlot: null,
11062
11073
  metadata,
11063
- resolverFn: null,
11074
+ resolverFn,
11064
11075
  sourceSpan,
11065
11076
  ...NEW_OP,
11066
11077
  ...TRAIT_CONSUMES_SLOT,
@@ -11249,11 +11260,12 @@ class CompilationJob {
11249
11260
  * embedded views or host bindings.
11250
11261
  */
11251
11262
  class ComponentCompilationJob extends CompilationJob {
11252
- constructor(componentName, pool, compatibility, relativeContextFilePath, i18nUseExternalIds, deferBlocksMeta) {
11263
+ constructor(componentName, pool, compatibility, relativeContextFilePath, i18nUseExternalIds, deferBlocksMeta, allDeferrableDepsFn) {
11253
11264
  super(componentName, pool, compatibility);
11254
11265
  this.relativeContextFilePath = relativeContextFilePath;
11255
11266
  this.i18nUseExternalIds = i18nUseExternalIds;
11256
11267
  this.deferBlocksMeta = deferBlocksMeta;
11268
+ this.allDeferrableDepsFn = allDeferrableDepsFn;
11257
11269
  this.kind = CompilationJobKind.Tmpl;
11258
11270
  this.fnSuffix = 'Template';
11259
11271
  this.views = new Map();
@@ -12176,11 +12188,16 @@ function createDeferDepsFns(job) {
12176
12188
  if (op.metadata.deps.length === 0) {
12177
12189
  continue;
12178
12190
  }
12191
+ if (op.resolverFn !== null) {
12192
+ continue;
12193
+ }
12179
12194
  const dependencies = [];
12180
12195
  for (const dep of op.metadata.deps) {
12181
12196
  if (dep.isDeferrable) {
12182
12197
  // Callback function, e.g. `m () => m.MyCmp;`.
12183
- const innerFn = arrowFn([new FnParam('m', DYNAMIC_TYPE)], variable('m').prop(dep.symbolName));
12198
+ const innerFn = arrowFn(
12199
+ // Default imports are always accessed through the `default` property.
12200
+ [new FnParam('m', DYNAMIC_TYPE)], variable('m').prop(dep.isDefaultImport ? 'default' : dep.symbolName));
12184
12201
  // Dynamic import, e.g. `import('./a').then(...)`.
12185
12202
  const importExpr = (new DynamicImportExpr(dep.importPath)).prop('then').callFn([innerFn]);
12186
12203
  dependencies.push(importExpr);
@@ -12194,7 +12211,8 @@ function createDeferDepsFns(job) {
12194
12211
  if (op.handle.slot === null) {
12195
12212
  throw new Error('AssertionError: slot must be assigned bfore extracting defer deps functions');
12196
12213
  }
12197
- op.resolverFn = job.pool.getSharedFunctionReference(depsFnExpr, `${job.componentName}_Defer_${op.handle.slot}_DepsFn`,
12214
+ const fullPathName = unit.fnName?.replace(`_Template`, ``);
12215
+ op.resolverFn = job.pool.getSharedFunctionReference(depsFnExpr, `${fullPathName}_Defer_${op.handle.slot}_DepsFn`,
12198
12216
  /* Don't use unique names for TDB compatibility */ false);
12199
12217
  }
12200
12218
  }
@@ -20625,7 +20643,10 @@ function nameFunctionsAndVariables(job) {
20625
20643
  }
20626
20644
  function addNamesToView(unit, baseName, state, compatibility) {
20627
20645
  if (unit.fnName === null) {
20628
- unit.fnName = sanitizeIdentifier(`${baseName}_${unit.job.fnSuffix}`);
20646
+ // Ensure unique names for view units. This is necessary because there might be multiple
20647
+ // components with same names in the context of the same pool. Only add the suffix
20648
+ // if really needed.
20649
+ unit.fnName = unit.job.pool.uniqueName(sanitizeIdentifier(`${baseName}_${unit.job.fnSuffix}`), /* alwaysIncludeSuffix */ false);
20629
20650
  }
20630
20651
  // Keep track of the names we assign to variables in the view. We'll need to propagate these
20631
20652
  // into reads of those variables afterwards.
@@ -23954,7 +23975,6 @@ const phases = [
23954
23975
  { kind: CompilationJobKind.Both, fn: expandSafeReads },
23955
23976
  { kind: CompilationJobKind.Both, fn: generateTemporaryVariables },
23956
23977
  { kind: CompilationJobKind.Tmpl, fn: allocateSlots },
23957
- { kind: CompilationJobKind.Tmpl, fn: createDeferDepsFns },
23958
23978
  { kind: CompilationJobKind.Tmpl, fn: resolveI18nElementPlaceholders },
23959
23979
  { kind: CompilationJobKind.Tmpl, fn: resolveI18nExpressionPlaceholders },
23960
23980
  { kind: CompilationJobKind.Tmpl, fn: extractI18nMessages },
@@ -23967,6 +23987,7 @@ const phases = [
23967
23987
  { kind: CompilationJobKind.Tmpl, fn: generateAdvance },
23968
23988
  { kind: CompilationJobKind.Both, fn: optimizeVariables },
23969
23989
  { kind: CompilationJobKind.Both, fn: nameFunctionsAndVariables },
23990
+ { kind: CompilationJobKind.Tmpl, fn: createDeferDepsFns },
23970
23991
  { kind: CompilationJobKind.Tmpl, fn: mergeNextContextExpressions },
23971
23992
  { kind: CompilationJobKind.Tmpl, fn: generateNgContainerOps },
23972
23993
  { kind: CompilationJobKind.Tmpl, fn: collapseEmptyInstructions },
@@ -24092,8 +24113,8 @@ const NG_TEMPLATE_TAG_NAME$1 = 'ng-template';
24092
24113
  * representation.
24093
24114
  * TODO: Refactor more of the ingestion code into phases.
24094
24115
  */
24095
- function ingestComponent(componentName, template, constantPool, relativeContextFilePath, i18nUseExternalIds, deferBlocksMeta) {
24096
- const job = new ComponentCompilationJob(componentName, constantPool, compatibilityMode, relativeContextFilePath, i18nUseExternalIds, deferBlocksMeta);
24116
+ function ingestComponent(componentName, template, constantPool, relativeContextFilePath, i18nUseExternalIds, deferBlocksMeta, allDeferrableDepsFn) {
24117
+ const job = new ComponentCompilationJob(componentName, constantPool, compatibilityMode, relativeContextFilePath, i18nUseExternalIds, deferBlocksMeta, allDeferrableDepsFn);
24097
24118
  ingestNodes(job.root, template);
24098
24119
  return job;
24099
24120
  }
@@ -24151,7 +24172,7 @@ function ingestHostAttribute(job, name, value, securityContexts) {
24151
24172
  job.root.update.push(attrBinding);
24152
24173
  }
24153
24174
  function ingestHostEvent(job, event) {
24154
- const [phase, target] = event.type === 0 /* e.ParsedEventType.Regular */ ? [null, event.targetOrPhase] :
24175
+ const [phase, target] = event.type !== 1 /* e.ParsedEventType.Animation */ ? [null, event.targetOrPhase] :
24155
24176
  [event.targetOrPhase, null];
24156
24177
  const eventBinding = createListenerOp(job.root.xref, new SlotHandle(), event.name, null, makeListenerHandlerOps(job.root, event.handler, event.handlerSpan), phase, target, true, event.sourceSpan);
24157
24178
  job.root.create.push(eventBinding);
@@ -24417,7 +24438,7 @@ function ingestDeferBlock(unit, deferBlock) {
24417
24438
  const error = ingestDeferView(unit, 'Error', deferBlock.error?.i18n, deferBlock.error?.children, deferBlock.error?.sourceSpan);
24418
24439
  // Create the main defer op, and ops for all secondary views.
24419
24440
  const deferXref = unit.job.allocateXrefId();
24420
- const deferOp = createDeferOp(deferXref, main.xref, main.handle, blockMeta, deferBlock.sourceSpan);
24441
+ const deferOp = createDeferOp(deferXref, main.xref, main.handle, blockMeta, unit.job.allDeferrableDepsFn, deferBlock.sourceSpan);
24421
24442
  deferOp.placeholderView = placeholder?.xref ?? null;
24422
24443
  deferOp.placeholderSlot = placeholder?.handle ?? null;
24423
24444
  deferOp.loadingSlot = loading?.handle ?? null;
@@ -24742,6 +24763,8 @@ function convertAstWithInterpolation(job, value, i18nMeta, sourceSpan) {
24742
24763
  // TODO: Can we populate Template binding kinds in ingest?
24743
24764
  const BINDING_KINDS = new Map([
24744
24765
  [0 /* e.BindingType.Property */, BindingKind.Property],
24766
+ // TODO(crisbeto): we'll need a different BindingKind for two-way bindings.
24767
+ [5 /* e.BindingType.TwoWay */, BindingKind.Property],
24745
24768
  [1 /* e.BindingType.Attribute */, BindingKind.Attribute],
24746
24769
  [2 /* e.BindingType.Class */, BindingKind.ClassName],
24747
24770
  [3 /* e.BindingType.Style */, BindingKind.StyleProperty],
@@ -24785,12 +24808,20 @@ function asMessage(i18nMeta) {
24785
24808
  */
24786
24809
  function ingestElementBindings(unit, op, element) {
24787
24810
  let bindings = new Array();
24811
+ let i18nAttributeBindingNames = new Set();
24788
24812
  for (const attr of element.attributes) {
24789
24813
  // Attribute literal bindings, such as `attr.foo="bar"`.
24790
24814
  const securityContext = domSchema.securityContext(element.name, attr.name, true);
24791
24815
  bindings.push(createBindingOp(op.xref, BindingKind.Attribute, attr.name, convertAstWithInterpolation(unit.job, attr.value, attr.i18n), null, securityContext, true, false, null, asMessage(attr.i18n), attr.sourceSpan));
24816
+ if (attr.i18n) {
24817
+ i18nAttributeBindingNames.add(attr.name);
24818
+ }
24792
24819
  }
24793
24820
  for (const input of element.inputs) {
24821
+ if (i18nAttributeBindingNames.has(input.name)) {
24822
+ console.error(`On component ${unit.job.componentName}, the binding ${input
24823
+ .name} is both an i18n attribute and a property. You may want to remove the property binding. This will become a compilation error in future versions of Angular.`);
24824
+ }
24794
24825
  // All dynamic bindings (both attribute and property bindings).
24795
24826
  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));
24796
24827
  }
@@ -24887,8 +24918,8 @@ function createTemplateBinding(view, xref, type, name, value, unit, securityCont
24887
24918
  // update instruction.
24888
24919
  if (templateKind === TemplateKind.Structural) {
24889
24920
  if (!isStructuralTemplateAttribute &&
24890
- (type === 0 /* e.BindingType.Property */ || type === 2 /* e.BindingType.Class */ ||
24891
- type === 3 /* e.BindingType.Style */)) {
24921
+ (type === 0 /* e.BindingType.Property */ || type === 5 /* e.BindingType.TwoWay */ ||
24922
+ type === 2 /* e.BindingType.Class */ || type === 3 /* e.BindingType.Style */)) {
24892
24923
  // Because this binding doesn't really target the ng-template, it must be a binding on an
24893
24924
  // inner node of a structural template. We can't skip it entirely, because we still need it on
24894
24925
  // the ng-template's consts (e.g. for the purposes of directive matching). However, we should
@@ -25699,7 +25730,7 @@ class BindingParser {
25699
25730
  for (const propName of Object.keys(properties)) {
25700
25731
  const expression = properties[propName];
25701
25732
  if (typeof expression === 'string') {
25702
- this.parsePropertyBinding(propName, expression, true, sourceSpan, sourceSpan.start.offset, undefined, [],
25733
+ this.parsePropertyBinding(propName, expression, true, false, sourceSpan, sourceSpan.start.offset, undefined, [],
25703
25734
  // Use the `sourceSpan` for `keySpan`. This isn't really accurate, but neither is the
25704
25735
  // sourceSpan, as it represents the sourceSpan of the host itself rather than the
25705
25736
  // source of the host binding (which doesn't exist in the template). Regardless,
@@ -25795,7 +25826,7 @@ class BindingParser {
25795
25826
  else if (binding.value) {
25796
25827
  const srcSpan = isIvyAst ? bindingSpan : sourceSpan;
25797
25828
  const valueSpan = moveParseSourceSpan(sourceSpan, binding.value.ast.sourceSpan);
25798
- this._parsePropertyAst(key, binding.value, srcSpan, keySpan, valueSpan, targetMatchableAttrs, targetProps);
25829
+ this._parsePropertyAst(key, binding.value, false, srcSpan, keySpan, valueSpan, targetMatchableAttrs, targetProps);
25799
25830
  }
25800
25831
  else {
25801
25832
  targetMatchableAttrs.push([key, '' /* value */]);
@@ -25848,7 +25879,7 @@ class BindingParser {
25848
25879
  targetProps.push(new ParsedProperty(name, this._exprParser.wrapLiteralPrimitive(value, '', absoluteOffset), ParsedPropertyType.LITERAL_ATTR, sourceSpan, keySpan, valueSpan));
25849
25880
  }
25850
25881
  }
25851
- parsePropertyBinding(name, expression, isHost, sourceSpan, absoluteOffset, valueSpan, targetMatchableAttrs, targetProps, keySpan) {
25882
+ parsePropertyBinding(name, expression, isHost, isPartOfAssignmentBinding, sourceSpan, absoluteOffset, valueSpan, targetMatchableAttrs, targetProps, keySpan) {
25852
25883
  if (name.length === 0) {
25853
25884
  this._reportError(`Property name is missing in binding`, sourceSpan);
25854
25885
  }
@@ -25871,20 +25902,20 @@ class BindingParser {
25871
25902
  this._parseAnimation(name, expression, sourceSpan, absoluteOffset, keySpan, valueSpan, targetMatchableAttrs, targetProps);
25872
25903
  }
25873
25904
  else {
25874
- this._parsePropertyAst(name, this.parseBinding(expression, isHost, valueSpan || sourceSpan, absoluteOffset), sourceSpan, keySpan, valueSpan, targetMatchableAttrs, targetProps);
25905
+ this._parsePropertyAst(name, this.parseBinding(expression, isHost, valueSpan || sourceSpan, absoluteOffset), isPartOfAssignmentBinding, sourceSpan, keySpan, valueSpan, targetMatchableAttrs, targetProps);
25875
25906
  }
25876
25907
  }
25877
25908
  parsePropertyInterpolation(name, value, sourceSpan, valueSpan, targetMatchableAttrs, targetProps, keySpan, interpolatedTokens) {
25878
25909
  const expr = this.parseInterpolation(value, valueSpan || sourceSpan, interpolatedTokens);
25879
25910
  if (expr) {
25880
- this._parsePropertyAst(name, expr, sourceSpan, keySpan, valueSpan, targetMatchableAttrs, targetProps);
25911
+ this._parsePropertyAst(name, expr, false, sourceSpan, keySpan, valueSpan, targetMatchableAttrs, targetProps);
25881
25912
  return true;
25882
25913
  }
25883
25914
  return false;
25884
25915
  }
25885
- _parsePropertyAst(name, ast, sourceSpan, keySpan, valueSpan, targetMatchableAttrs, targetProps) {
25916
+ _parsePropertyAst(name, ast, isPartOfAssignmentBinding, sourceSpan, keySpan, valueSpan, targetMatchableAttrs, targetProps) {
25886
25917
  targetMatchableAttrs.push([name, ast.source]);
25887
- targetProps.push(new ParsedProperty(name, ast, ParsedPropertyType.DEFAULT, sourceSpan, keySpan, valueSpan));
25918
+ targetProps.push(new ParsedProperty(name, ast, isPartOfAssignmentBinding ? ParsedPropertyType.TWO_WAY : ParsedPropertyType.DEFAULT, sourceSpan, keySpan, valueSpan));
25888
25919
  }
25889
25920
  _parseAnimation(name, expression, sourceSpan, absoluteOffset, keySpan, valueSpan, targetMatchableAttrs, targetProps) {
25890
25921
  if (name.length === 0) {
@@ -25954,7 +25985,8 @@ class BindingParser {
25954
25985
  const mappedPropName = this._schemaRegistry.getMappedPropName(boundProp.name);
25955
25986
  boundPropertyName = mapPropertyName ? mappedPropName : boundProp.name;
25956
25987
  securityContexts = calcPossibleSecurityContexts(this._schemaRegistry, elementSelector, mappedPropName, false);
25957
- bindingType = 0 /* BindingType.Property */;
25988
+ bindingType =
25989
+ boundProp.type === ParsedPropertyType.TWO_WAY ? 5 /* BindingType.TwoWay */ : 0 /* BindingType.Property */;
25958
25990
  if (!skipValidation) {
25959
25991
  this._validatePropertyOrAttributeName(mappedPropName, boundProp.sourceSpan, false);
25960
25992
  }
@@ -26004,7 +26036,7 @@ class BindingParser {
26004
26036
  const [target, eventName] = splitAtColon(name, [null, name]);
26005
26037
  const ast = this._parseAction(expression, isAssignmentEvent, handlerSpan);
26006
26038
  targetMatchableAttrs.push([name, ast.source]);
26007
- targetEvents.push(new ParsedEvent(eventName, target, 0 /* ParsedEventType.Regular */, ast, sourceSpan, handlerSpan, keySpan));
26039
+ targetEvents.push(new ParsedEvent(eventName, target, isAssignmentEvent ? 2 /* ParsedEventType.TwoWay */ : 0 /* ParsedEventType.Regular */, ast, sourceSpan, handlerSpan, keySpan));
26008
26040
  // Don't detect directives for event names for now,
26009
26041
  // so don't add the event name to the matchableAttrs
26010
26042
  }
@@ -26179,11 +26211,16 @@ const FOR_LOOP_EXPRESSION_PATTERN = /^\s*([0-9A-Za-z_$]*)\s+of\s+([\S\s]*)/;
26179
26211
  /** Pattern for the tracking expression in a for loop block. */
26180
26212
  const FOR_LOOP_TRACK_PATTERN = /^track\s+([\S\s]*)/;
26181
26213
  /** Pattern for the `as` expression in a conditional block. */
26182
- const CONDITIONAL_ALIAS_PATTERN = /^as\s+(.*)/;
26214
+ const CONDITIONAL_ALIAS_PATTERN = /^(as\s)+(.*)/;
26183
26215
  /** Pattern used to identify an `else if` block. */
26184
26216
  const ELSE_IF_PATTERN = /^else[^\S\r\n]+if/;
26185
26217
  /** Pattern used to identify a `let` parameter. */
26186
26218
  const FOR_LOOP_LET_PATTERN = /^let\s+([\S\s]*)/;
26219
+ /**
26220
+ * Pattern to group a string into leading whitespace, non whitespace, and trailing whitespace.
26221
+ * Useful for getting the variable name span when a span can contain leading and trailing space.
26222
+ */
26223
+ const CHARACTERS_IN_SURROUNDING_WHITESPACE_PATTERN = /(\s*)(\S+)(\s*)/;
26187
26224
  /** Names of variables that are allowed to be used in the `let` expression of a `for` loop. */
26188
26225
  const ALLOWED_FOR_LOOP_LET_VARIABLES = new Set(['$index', '$first', '$last', '$even', '$odd', '$count']);
26189
26226
  /**
@@ -26323,8 +26360,13 @@ function parseForLoopParameters(block, errors, bindingParser) {
26323
26360
  return null;
26324
26361
  }
26325
26362
  const [, itemName, rawExpression] = match;
26363
+ // `expressionParam.expression` contains the variable declaration and the expression of the
26364
+ // for...of statement, i.e. 'user of users' The variable of a ForOfStatement is _only_ the "const
26365
+ // user" part and does not include "of x".
26366
+ const variableName = expressionParam.expression.split(' ')[0];
26367
+ const variableSpan = new ParseSourceSpan(expressionParam.sourceSpan.start, expressionParam.sourceSpan.start.moveBy(variableName.length));
26326
26368
  const result = {
26327
- itemName: new Variable(itemName, '$implicit', expressionParam.sourceSpan, expressionParam.sourceSpan),
26369
+ itemName: new Variable(itemName, '$implicit', variableSpan, variableSpan),
26328
26370
  trackBy: null,
26329
26371
  expression: parseBlockParameterToBinding(expressionParam, bindingParser, rawExpression),
26330
26372
  context: {},
@@ -26332,7 +26374,8 @@ function parseForLoopParameters(block, errors, bindingParser) {
26332
26374
  for (const param of secondaryParams) {
26333
26375
  const letMatch = param.expression.match(FOR_LOOP_LET_PATTERN);
26334
26376
  if (letMatch !== null) {
26335
- parseLetParameter(param.sourceSpan, letMatch[1], param.sourceSpan, result.context, errors);
26377
+ const variablesSpan = new ParseSourceSpan(param.sourceSpan.start.moveBy(letMatch[0].length - letMatch[1].length), param.sourceSpan.end);
26378
+ parseLetParameter(param.sourceSpan, letMatch[1], variablesSpan, result.context, errors);
26336
26379
  continue;
26337
26380
  }
26338
26381
  const trackMatch = param.expression.match(FOR_LOOP_TRACK_PATTERN);
@@ -26363,6 +26406,7 @@ function parseForLoopParameters(block, errors, bindingParser) {
26363
26406
  /** Parses the `let` parameter of a `for` loop block. */
26364
26407
  function parseLetParameter(sourceSpan, expression, span, context, errors) {
26365
26408
  const parts = expression.split(',');
26409
+ let startSpan = span.start;
26366
26410
  for (const part of parts) {
26367
26411
  const expressionParts = part.split('=');
26368
26412
  const name = expressionParts.length === 2 ? expressionParts[0].trim() : '';
@@ -26377,8 +26421,26 @@ function parseLetParameter(sourceSpan, expression, span, context, errors) {
26377
26421
  errors.push(new ParseError(sourceSpan, `Duplicate "let" parameter variable "${variableName}"`));
26378
26422
  }
26379
26423
  else {
26380
- context[variableName] = new Variable(name, variableName, span, span);
26424
+ const [, keyLeadingWhitespace, keyName] = expressionParts[0].match(CHARACTERS_IN_SURROUNDING_WHITESPACE_PATTERN) ?? [];
26425
+ const keySpan = keyLeadingWhitespace !== undefined && expressionParts.length === 2 ?
26426
+ new ParseSourceSpan(
26427
+ /* strip leading spaces */
26428
+ startSpan.moveBy(keyLeadingWhitespace.length),
26429
+ /* advance to end of the variable name */
26430
+ startSpan.moveBy(keyLeadingWhitespace.length + keyName.length)) :
26431
+ span;
26432
+ let valueSpan = undefined;
26433
+ if (expressionParts.length === 2) {
26434
+ const [, valueLeadingWhitespace, implicit] = expressionParts[1].match(CHARACTERS_IN_SURROUNDING_WHITESPACE_PATTERN) ?? [];
26435
+ valueSpan = valueLeadingWhitespace !== undefined ?
26436
+ new ParseSourceSpan(startSpan.moveBy(expressionParts[0].length + 1 + valueLeadingWhitespace.length), startSpan.moveBy(expressionParts[0].length + 1 + valueLeadingWhitespace.length +
26437
+ implicit.length)) :
26438
+ undefined;
26439
+ }
26440
+ const sourceSpan = new ParseSourceSpan(keySpan.start, valueSpan?.end ?? keySpan.end);
26441
+ context[variableName] = new Variable(name, variableName, sourceSpan, keySpan, valueSpan);
26381
26442
  }
26443
+ startSpan = startSpan.moveBy(part.length + 1 /* add 1 to move past the comma */);
26382
26444
  }
26383
26445
  }
26384
26446
  /**
@@ -26490,8 +26552,10 @@ function parseConditionalBlockParameters(block, errors, bindingParser) {
26490
26552
  errors.push(new ParseError(param.sourceSpan, 'Conditional can only have one "as" expression'));
26491
26553
  }
26492
26554
  else {
26493
- const name = aliasMatch[1].trim();
26494
- expressionAlias = new Variable(name, name, param.sourceSpan, param.sourceSpan);
26555
+ const name = aliasMatch[2].trim();
26556
+ const variableStart = param.sourceSpan.start.moveBy(aliasMatch[1].length);
26557
+ const variableSpan = new ParseSourceSpan(variableStart, variableStart.moveBy(name.length));
26558
+ expressionAlias = new Variable(name, name, variableSpan, variableSpan);
26495
26559
  }
26496
26560
  }
26497
26561
  return { expression, expressionAlias };
@@ -27352,7 +27416,7 @@ class HtmlAstToIvyAst {
27352
27416
  if (bindParts[KW_BIND_IDX] != null) {
27353
27417
  const identifier = bindParts[IDENT_KW_IDX];
27354
27418
  const keySpan = createKeySpan(srcSpan, bindParts[KW_BIND_IDX], identifier);
27355
- this.bindingParser.parsePropertyBinding(identifier, value, false, srcSpan, absoluteOffset, attribute.valueSpan, matchableAttributes, parsedProperties, keySpan);
27419
+ this.bindingParser.parsePropertyBinding(identifier, value, false, false, srcSpan, absoluteOffset, attribute.valueSpan, matchableAttributes, parsedProperties, keySpan);
27356
27420
  }
27357
27421
  else if (bindParts[KW_LET_IDX]) {
27358
27422
  if (isTemplateElement) {
@@ -27379,7 +27443,7 @@ class HtmlAstToIvyAst {
27379
27443
  else if (bindParts[KW_BINDON_IDX]) {
27380
27444
  const identifier = bindParts[IDENT_KW_IDX];
27381
27445
  const keySpan = createKeySpan(srcSpan, bindParts[KW_BINDON_IDX], identifier);
27382
- this.bindingParser.parsePropertyBinding(identifier, value, false, srcSpan, absoluteOffset, attribute.valueSpan, matchableAttributes, parsedProperties, keySpan);
27446
+ this.bindingParser.parsePropertyBinding(identifier, value, false, true, srcSpan, absoluteOffset, attribute.valueSpan, matchableAttributes, parsedProperties, keySpan);
27383
27447
  this.parseAssignmentEvent(identifier, value, srcSpan, attribute.valueSpan, matchableAttributes, boundEvents, keySpan);
27384
27448
  }
27385
27449
  else if (bindParts[KW_AT_IDX]) {
@@ -27409,11 +27473,11 @@ class HtmlAstToIvyAst {
27409
27473
  const identifier = name.substring(delims.start.length, name.length - delims.end.length);
27410
27474
  const keySpan = createKeySpan(srcSpan, delims.start, identifier);
27411
27475
  if (delims.start === BINDING_DELIMS.BANANA_BOX.start) {
27412
- this.bindingParser.parsePropertyBinding(identifier, value, false, srcSpan, absoluteOffset, attribute.valueSpan, matchableAttributes, parsedProperties, keySpan);
27476
+ this.bindingParser.parsePropertyBinding(identifier, value, false, true, srcSpan, absoluteOffset, attribute.valueSpan, matchableAttributes, parsedProperties, keySpan);
27413
27477
  this.parseAssignmentEvent(identifier, value, srcSpan, attribute.valueSpan, matchableAttributes, boundEvents, keySpan);
27414
27478
  }
27415
27479
  else if (delims.start === BINDING_DELIMS.PROPERTY.start) {
27416
- this.bindingParser.parsePropertyBinding(identifier, value, false, srcSpan, absoluteOffset, attribute.valueSpan, matchableAttributes, parsedProperties, keySpan);
27480
+ this.bindingParser.parsePropertyBinding(identifier, value, false, false, srcSpan, absoluteOffset, attribute.valueSpan, matchableAttributes, parsedProperties, keySpan);
27417
27481
  }
27418
27482
  else {
27419
27483
  const events = [];
@@ -28282,7 +28346,8 @@ class TemplateDefinitionBuilder {
28282
28346
  element.inputs.forEach(input => {
28283
28347
  const stylingInputWasSet = stylingBuilder.registerBoundInput(input);
28284
28348
  if (!stylingInputWasSet) {
28285
- if (input.type === 0 /* BindingType.Property */ && input.i18n) {
28349
+ if ((input.type === 0 /* BindingType.Property */ || input.type === 5 /* BindingType.TwoWay */) &&
28350
+ input.i18n) {
28286
28351
  boundI18nAttrs.push(input);
28287
28352
  }
28288
28353
  else {
@@ -28408,7 +28473,7 @@ class TemplateDefinitionBuilder {
28408
28473
  }
28409
28474
  }
28410
28475
  this.allocateBindingSlots(value);
28411
- if (inputType === 0 /* BindingType.Property */) {
28476
+ if (inputType === 0 /* BindingType.Property */ || inputType === 5 /* BindingType.TwoWay */) {
28412
28477
  if (value instanceof Interpolation$1) {
28413
28478
  // prop="{{value}}" and friends
28414
28479
  this.interpolatedUpdateInstruction(getPropertyInterpolationExpression(value), elementIndex, attrName, input, value, params);
@@ -28483,7 +28548,9 @@ class TemplateDefinitionBuilder {
28483
28548
  }
28484
28549
  }
28485
28550
  const contextName = `${this.contextName}${contextNameSuffix}_${index}`;
28486
- const name = `${contextName}_Template`;
28551
+ // Note: For the unique name, we don't include an unique suffix, unless really needed.
28552
+ // This keeps the generated output more clean as most of the time, we don't expect conflicts.
28553
+ const name = this.constantPool.uniqueName(`${contextName}_Template`, /** alwaysIncludeSuffix */ false);
28487
28554
  // Create the template function
28488
28555
  const visitor = new TemplateDefinitionBuilder(this.constantPool, this._bindingScope, this.level + 1, contextName, this.i18n, index, name, this._namespace, this.fileBasedI18nSuffix, this.i18nUseExternalIds, this.deferBlocks, this.elementLocations, this.allDeferrableDepsFn, this._constants);
28489
28556
  // Nested templates must not be visited until after their parent templates have completed
@@ -28800,7 +28867,9 @@ class TemplateDefinitionBuilder {
28800
28867
  for (const deferredDep of metadata.deps) {
28801
28868
  if (deferredDep.isDeferrable) {
28802
28869
  // Callback function, e.g. `m () => m.MyCmp;`.
28803
- const innerFn = arrowFn([new FnParam('m', DYNAMIC_TYPE)], variable('m').prop(deferredDep.symbolName));
28870
+ const innerFn = arrowFn([new FnParam('m', DYNAMIC_TYPE)],
28871
+ // Default imports are always accessed through the `default` property.
28872
+ variable('m').prop(deferredDep.isDefaultImport ? 'default' : deferredDep.symbolName));
28804
28873
  // Dynamic import, e.g. `import('./a').then(...)`.
28805
28874
  const importExpr = (new DynamicImportExpr(deferredDep.importPath)).prop('then').callFn([innerFn]);
28806
28875
  dependencyExp.push(importExpr);
@@ -30142,9 +30211,9 @@ function compileDirectiveFromMetadata(meta, constantPool, bindingParser) {
30142
30211
  function createDeferredDepsFunction(constantPool, name, deps) {
30143
30212
  // This defer block has deps for which we need to generate dynamic imports.
30144
30213
  const dependencyExp = [];
30145
- for (const [symbolName, importPath] of deps) {
30214
+ for (const [symbolName, { importPath, isDefaultImport }] of deps) {
30146
30215
  // Callback function, e.g. `m () => m.MyCmp;`.
30147
- const innerFn = arrowFn([new FnParam('m', DYNAMIC_TYPE)], variable('m').prop(symbolName));
30216
+ const innerFn = arrowFn([new FnParam('m', DYNAMIC_TYPE)], variable('m').prop(isDefaultImport ? 'default' : symbolName));
30148
30217
  // Dynamic import, e.g. `import('./a').then(...)`.
30149
30218
  const importExpr = (new DynamicImportExpr(importPath)).prop('then').callFn([innerFn]);
30150
30219
  dependencyExp.push(importExpr);
@@ -30173,16 +30242,16 @@ function compileComponentFromMetadata(meta, constantPool, bindingParser) {
30173
30242
  // e.g. `template: function MyComponent_Template(_ctx, _cm) {...}`
30174
30243
  const templateTypeName = meta.name;
30175
30244
  const templateName = templateTypeName ? `${templateTypeName}_Template` : null;
30245
+ let allDeferrableDepsFn = null;
30246
+ if (meta.deferBlocks.size > 0 && meta.deferrableTypes.size > 0 &&
30247
+ meta.deferBlockDepsEmitMode === 1 /* DeferBlockDepsEmitMode.PerComponent */) {
30248
+ const fnName = `${templateTypeName}_DeferFn`;
30249
+ allDeferrableDepsFn = createDeferredDepsFunction(constantPool, fnName, meta.deferrableTypes);
30250
+ }
30176
30251
  // Template compilation is currently conditional as we're in the process of rewriting it.
30177
30252
  if (!USE_TEMPLATE_PIPELINE) {
30178
30253
  // This is the main path currently used in compilation, which compiles the template with the
30179
30254
  // legacy `TemplateDefinitionBuilder`.
30180
- let allDeferrableDepsFn = null;
30181
- if (meta.deferBlocks.size > 0 && meta.deferrableTypes.size > 0 &&
30182
- meta.deferBlockDepsEmitMode === 1 /* DeferBlockDepsEmitMode.PerComponent */) {
30183
- const fnName = `${templateTypeName}_DeferFn`;
30184
- allDeferrableDepsFn = createDeferredDepsFunction(constantPool, fnName, meta.deferrableTypes);
30185
- }
30186
30255
  const template = meta.template;
30187
30256
  const templateBuilder = new TemplateDefinitionBuilder(constantPool, BindingScope.createRootScope(), 0, templateTypeName, null, null, templateName, Identifiers.namespaceHTML, meta.relativeContextFilePath, meta.i18nUseExternalIds, meta.deferBlocks, new Map(), allDeferrableDepsFn);
30188
30257
  const templateFunctionExpression = templateBuilder.buildTemplateFunction(template.nodes, []);
@@ -30219,7 +30288,7 @@ function compileComponentFromMetadata(meta, constantPool, bindingParser) {
30219
30288
  else {
30220
30289
  // This path compiles the template using the prototype template pipeline. First the template is
30221
30290
  // ingested into IR:
30222
- const tpl = ingestComponent(meta.name, meta.template.nodes, constantPool, meta.relativeContextFilePath, meta.i18nUseExternalIds, meta.deferBlocks);
30291
+ const tpl = ingestComponent(meta.name, meta.template.nodes, constantPool, meta.relativeContextFilePath, meta.i18nUseExternalIds, meta.deferBlocks, allDeferrableDepsFn);
30223
30292
  // Then the IR is transformed to prepare it for cod egeneration.
30224
30293
  transform(tpl, CompilationJobKind.Tmpl);
30225
30294
  // Finally we emit the template function:
@@ -32315,7 +32384,7 @@ function publishFacade(global) {
32315
32384
  * @description
32316
32385
  * Entry point for all public APIs of the compiler package.
32317
32386
  */
32318
- const VERSION = new Version('17.1.1');
32387
+ const VERSION = new Version('17.1.3');
32319
32388
 
32320
32389
  class CompilerConfig {
32321
32390
  constructor({ defaultEncapsulation = ViewEncapsulation.Emulated, preserveWhitespaces, strictInjectionParameters } = {}) {
@@ -33816,9 +33885,11 @@ function compileComponentClassMetadata(metadata, deferrableTypes) {
33816
33885
  }
33817
33886
  const dynamicImports = [];
33818
33887
  const importedSymbols = [];
33819
- for (const [symbolName, importPath] of deferrableTypes) {
33888
+ for (const [symbolName, { importPath, isDefaultImport }] of deferrableTypes) {
33820
33889
  // e.g. `(m) => m.CmpA`
33821
- const innerFn = arrowFn([new FnParam('m', DYNAMIC_TYPE)], variable('m').prop(symbolName));
33890
+ const innerFn =
33891
+ // Default imports are always accessed through the `default` property.
33892
+ arrowFn([new FnParam('m', DYNAMIC_TYPE)], variable('m').prop(isDefaultImport ? 'default' : symbolName));
33822
33893
  // e.g. `import('./cmp-a').then(...)`
33823
33894
  const importExpr = (new DynamicImportExpr(importPath)).prop('then').callFn([innerFn]);
33824
33895
  dynamicImports.push(importExpr);
@@ -33881,7 +33952,7 @@ const MINIMUM_PARTIAL_LINKER_VERSION$5 = '12.0.0';
33881
33952
  function compileDeclareClassMetadata(metadata) {
33882
33953
  const definitionMap = new DefinitionMap();
33883
33954
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$5));
33884
- definitionMap.set('version', literal('17.1.1'));
33955
+ definitionMap.set('version', literal('17.1.3'));
33885
33956
  definitionMap.set('ngImport', importExpr(Identifiers.core));
33886
33957
  definitionMap.set('type', metadata.type);
33887
33958
  definitionMap.set('decorators', metadata.decorators);
@@ -33977,7 +34048,7 @@ function createDirectiveDefinitionMap(meta) {
33977
34048
  const definitionMap = new DefinitionMap();
33978
34049
  const minVersion = getMinimumVersionForPartialOutput(meta);
33979
34050
  definitionMap.set('minVersion', literal(minVersion));
33980
- definitionMap.set('version', literal('17.1.1'));
34051
+ definitionMap.set('version', literal('17.1.3'));
33981
34052
  // e.g. `type: MyDirective`
33982
34053
  definitionMap.set('type', meta.type.value);
33983
34054
  if (meta.isStandalone) {
@@ -34361,7 +34432,7 @@ const MINIMUM_PARTIAL_LINKER_VERSION$4 = '12.0.0';
34361
34432
  function compileDeclareFactoryFunction(meta) {
34362
34433
  const definitionMap = new DefinitionMap();
34363
34434
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$4));
34364
- definitionMap.set('version', literal('17.1.1'));
34435
+ definitionMap.set('version', literal('17.1.3'));
34365
34436
  definitionMap.set('ngImport', importExpr(Identifiers.core));
34366
34437
  definitionMap.set('type', meta.type.value);
34367
34438
  definitionMap.set('deps', compileDependencies(meta.deps));
@@ -34396,7 +34467,7 @@ function compileDeclareInjectableFromMetadata(meta) {
34396
34467
  function createInjectableDefinitionMap(meta) {
34397
34468
  const definitionMap = new DefinitionMap();
34398
34469
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$3));
34399
- definitionMap.set('version', literal('17.1.1'));
34470
+ definitionMap.set('version', literal('17.1.3'));
34400
34471
  definitionMap.set('ngImport', importExpr(Identifiers.core));
34401
34472
  definitionMap.set('type', meta.type.value);
34402
34473
  // Only generate providedIn property if it has a non-null value
@@ -34447,7 +34518,7 @@ function compileDeclareInjectorFromMetadata(meta) {
34447
34518
  function createInjectorDefinitionMap(meta) {
34448
34519
  const definitionMap = new DefinitionMap();
34449
34520
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$2));
34450
- definitionMap.set('version', literal('17.1.1'));
34521
+ definitionMap.set('version', literal('17.1.3'));
34451
34522
  definitionMap.set('ngImport', importExpr(Identifiers.core));
34452
34523
  definitionMap.set('type', meta.type.value);
34453
34524
  definitionMap.set('providers', meta.providers);
@@ -34480,7 +34551,7 @@ function createNgModuleDefinitionMap(meta) {
34480
34551
  throw new Error('Invalid path! Local compilation mode should not get into the partial compilation path');
34481
34552
  }
34482
34553
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$1));
34483
- definitionMap.set('version', literal('17.1.1'));
34554
+ definitionMap.set('version', literal('17.1.3'));
34484
34555
  definitionMap.set('ngImport', importExpr(Identifiers.core));
34485
34556
  definitionMap.set('type', meta.type.value);
34486
34557
  // We only generate the keys in the metadata if the arrays contain values.
@@ -34531,7 +34602,7 @@ function compileDeclarePipeFromMetadata(meta) {
34531
34602
  function createPipeDefinitionMap(meta) {
34532
34603
  const definitionMap = new DefinitionMap();
34533
34604
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION));
34534
- definitionMap.set('version', literal('17.1.1'));
34605
+ definitionMap.set('version', literal('17.1.3'));
34535
34606
  definitionMap.set('ngImport', importExpr(Identifiers.core));
34536
34607
  // e.g. `type: MyPipe`
34537
34608
  definitionMap.set('type', meta.type.value);