@angular/core 20.0.0-next.0 → 20.0.0-next.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/fesm2022/core.mjs +6448 -6198
  2. package/fesm2022/core.mjs.map +1 -1
  3. package/fesm2022/primitives/di.mjs +45 -0
  4. package/fesm2022/primitives/di.mjs.map +1 -0
  5. package/fesm2022/primitives/event-dispatch.mjs +2 -2
  6. package/fesm2022/primitives/signals.mjs +2 -2
  7. package/fesm2022/rxjs-interop.mjs +2 -2
  8. package/fesm2022/testing.mjs +280 -119
  9. package/fesm2022/testing.mjs.map +1 -1
  10. package/index.d.ts +138 -51
  11. package/package.json +11 -1
  12. package/primitives/di/index.d.ts +99 -0
  13. package/primitives/event-dispatch/index.d.ts +2 -2
  14. package/primitives/signals/index.d.ts +2 -2
  15. package/rxjs-interop/index.d.ts +2 -2
  16. package/schematics/bundles/{apply_import_manager-0959b78c.js → apply_import_manager-e2a7fe5b.js} +4 -4
  17. package/schematics/bundles/{checker-cf6f7980.js → checker-af521da6.js} +346 -234
  18. package/schematics/bundles/cleanup-unused-imports.js +8 -8
  19. package/schematics/bundles/{compiler_host-cc1379e9.js → compiler_host-5a29293c.js} +3 -3
  20. package/schematics/bundles/control-flow-migration.js +4 -4
  21. package/schematics/bundles/explicit-standalone-flag.js +6 -6
  22. package/schematics/bundles/{imports-31a38653.js → imports-047fbbc8.js} +2 -2
  23. package/schematics/bundles/{index-42d84d69.js → index-1bef3025.js} +5 -5
  24. package/schematics/bundles/{index-6675d6bc.js → index-ef1bffbb.js} +5 -5
  25. package/schematics/bundles/inject-migration.js +8 -8
  26. package/schematics/bundles/{leading_space-6e7a8ec6.js → leading_space-f8944434.js} +2 -2
  27. package/schematics/bundles/{migrate_ts_type_references-5089e4ef.js → migrate_ts_type_references-2a3e9e6b.js} +13 -15
  28. package/schematics/bundles/{ng_decorators-6878e227.js → ng_decorators-b0d8b324.js} +3 -3
  29. package/schematics/bundles/{nodes-ffdce442.js → nodes-7758dbf6.js} +2 -2
  30. package/schematics/bundles/output-migration.js +8 -8
  31. package/schematics/bundles/pending-tasks.js +6 -6
  32. package/schematics/bundles/{program-362689f0.js → program-a449f9bf.js} +14 -14
  33. package/schematics/bundles/{project_paths-7d2daa1e.js → project_paths-17dc204d.js} +4 -4
  34. package/schematics/bundles/{project_tsconfig_paths-6c9cde78.js → project_tsconfig_paths-b558633b.js} +2 -2
  35. package/schematics/bundles/{property_name-42030525.js → property_name-ac18447e.js} +2 -2
  36. package/schematics/bundles/provide-initializer.js +6 -6
  37. package/schematics/bundles/route-lazy-loading.js +6 -6
  38. package/schematics/bundles/self-closing-tags-migration.js +44 -28
  39. package/schematics/bundles/signal-input-migration.js +10 -10
  40. package/schematics/bundles/signal-queries-migration.js +10 -10
  41. package/schematics/bundles/signals.js +10 -10
  42. package/schematics/bundles/standalone-migration.js +10 -10
  43. package/testing/index.d.ts +25 -14
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
  /**
3
- * @license Angular v20.0.0-next.0
4
- * (c) 2010-2024 Google LLC. https://angular.io/
3
+ * @license Angular v20.0.0-next.1
4
+ * (c) 2010-2025 Google LLC. https://angular.io/
5
5
  * License: MIT
6
6
  */
7
7
  'use strict';
@@ -999,11 +999,11 @@ class Expression {
999
999
  and(rhs, sourceSpan) {
1000
1000
  return new BinaryOperatorExpr(BinaryOperator.And, this, rhs, null, sourceSpan);
1001
1001
  }
1002
- bitwiseOr(rhs, sourceSpan, parens = true) {
1003
- return new BinaryOperatorExpr(BinaryOperator.BitwiseOr, this, rhs, null, sourceSpan, parens);
1002
+ bitwiseOr(rhs, sourceSpan) {
1003
+ return new BinaryOperatorExpr(BinaryOperator.BitwiseOr, this, rhs, null, sourceSpan);
1004
1004
  }
1005
- bitwiseAnd(rhs, sourceSpan, parens = true) {
1006
- return new BinaryOperatorExpr(BinaryOperator.BitwiseAnd, this, rhs, null, sourceSpan, parens);
1005
+ bitwiseAnd(rhs, sourceSpan) {
1006
+ return new BinaryOperatorExpr(BinaryOperator.BitwiseAnd, this, rhs, null, sourceSpan);
1007
1007
  }
1008
1008
  or(rhs, sourceSpan) {
1009
1009
  return new BinaryOperatorExpr(BinaryOperator.Or, this, rhs, null, sourceSpan);
@@ -1676,16 +1676,34 @@ class UnaryOperatorExpr extends Expression {
1676
1676
  return new UnaryOperatorExpr(this.operator, this.expr.clone(), this.type, this.sourceSpan, this.parens);
1677
1677
  }
1678
1678
  }
1679
+ class ParenthesizedExpr extends Expression {
1680
+ expr;
1681
+ constructor(expr, type, sourceSpan) {
1682
+ super(type, sourceSpan);
1683
+ this.expr = expr;
1684
+ }
1685
+ visitExpression(visitor, context) {
1686
+ return visitor.visitParenthesizedExpr(this, context);
1687
+ }
1688
+ isEquivalent(e) {
1689
+ // TODO: should this ignore paren depth? i.e. is `(1)` equivalent to `1`?
1690
+ return e instanceof ParenthesizedExpr && e.expr.isEquivalent(this.expr);
1691
+ }
1692
+ isConstant() {
1693
+ return this.expr.isConstant();
1694
+ }
1695
+ clone() {
1696
+ return new ParenthesizedExpr(this.expr.clone());
1697
+ }
1698
+ }
1679
1699
  class BinaryOperatorExpr extends Expression {
1680
1700
  operator;
1681
1701
  rhs;
1682
- parens;
1683
1702
  lhs;
1684
- constructor(operator, lhs, rhs, type, sourceSpan, parens = true) {
1703
+ constructor(operator, lhs, rhs, type, sourceSpan) {
1685
1704
  super(type || lhs.type, sourceSpan);
1686
1705
  this.operator = operator;
1687
1706
  this.rhs = rhs;
1688
- this.parens = parens;
1689
1707
  this.lhs = lhs;
1690
1708
  }
1691
1709
  isEquivalent(e) {
@@ -1701,7 +1719,7 @@ class BinaryOperatorExpr extends Expression {
1701
1719
  return visitor.visitBinaryOperatorExpr(this, context);
1702
1720
  }
1703
1721
  clone() {
1704
- return new BinaryOperatorExpr(this.operator, this.lhs.clone(), this.rhs.clone(), this.type, this.sourceSpan, this.parens);
1722
+ return new BinaryOperatorExpr(this.operator, this.lhs.clone(), this.rhs.clone(), this.type, this.sourceSpan);
1705
1723
  }
1706
1724
  }
1707
1725
  class ReadPropExpr extends Expression {
@@ -1986,12 +2004,6 @@ class RecursiveAstVisitor$1 {
1986
2004
  visitWrappedNodeExpr(ast, context) {
1987
2005
  return ast;
1988
2006
  }
1989
- visitTypeofExpr(ast, context) {
1990
- return this.visitExpression(ast, context);
1991
- }
1992
- visitVoidExpr(ast, context) {
1993
- return this.visitExpression(ast, context);
1994
- }
1995
2007
  visitReadVarExpr(ast, context) {
1996
2008
  return this.visitExpression(ast, context);
1997
2009
  }
@@ -2069,6 +2081,14 @@ class RecursiveAstVisitor$1 {
2069
2081
  ast.expr.visitExpression(this, context);
2070
2082
  return this.visitExpression(ast, context);
2071
2083
  }
2084
+ visitTypeofExpr(ast, context) {
2085
+ ast.expr.visitExpression(this, context);
2086
+ return this.visitExpression(ast, context);
2087
+ }
2088
+ visitVoidExpr(ast, context) {
2089
+ ast.expr.visitExpression(this, context);
2090
+ return this.visitExpression(ast, context);
2091
+ }
2072
2092
  visitBinaryOperatorExpr(ast, context) {
2073
2093
  ast.lhs.visitExpression(this, context);
2074
2094
  ast.rhs.visitExpression(this, context);
@@ -2103,6 +2123,10 @@ class RecursiveAstVisitor$1 {
2103
2123
  visitTemplateLiteralElementExpr(ast, context) {
2104
2124
  return this.visitExpression(ast, context);
2105
2125
  }
2126
+ visitParenthesizedExpr(ast, context) {
2127
+ ast.expr.visitExpression(this, context);
2128
+ return this.visitExpression(ast, context);
2129
+ }
2106
2130
  visitAllExpressions(exprs, context) {
2107
2131
  exprs.forEach((expr) => expr.visitExpression(this, context));
2108
2132
  }
@@ -3397,6 +3421,7 @@ class EmitterVisitorContext {
3397
3421
  }
3398
3422
  class AbstractEmitterVisitor {
3399
3423
  _escapeDollarInStrings;
3424
+ lastIfCondition = null;
3400
3425
  constructor(_escapeDollarInStrings) {
3401
3426
  this._escapeDollarInStrings = _escapeDollarInStrings;
3402
3427
  }
@@ -3436,7 +3461,9 @@ class AbstractEmitterVisitor {
3436
3461
  visitIfStmt(stmt, ctx) {
3437
3462
  this.printLeadingComments(stmt, ctx);
3438
3463
  ctx.print(stmt, `if (`);
3464
+ this.lastIfCondition = stmt.condition; // We can skip redundant parentheses for the condition.
3439
3465
  stmt.condition.visitExpression(this, ctx);
3466
+ this.lastIfCondition = null;
3440
3467
  ctx.print(stmt, `) {`);
3441
3468
  const hasElseCase = stmt.falseCase != null && stmt.falseCase.length > 0;
3442
3469
  if (stmt.trueCase.length <= 1 && !hasElseCase) {
@@ -3609,11 +3636,12 @@ class AbstractEmitterVisitor {
3609
3636
  default:
3610
3637
  throw new Error(`Unknown operator ${ast.operator}`);
3611
3638
  }
3612
- if (ast.parens)
3639
+ const parens = ast !== this.lastIfCondition;
3640
+ if (parens)
3613
3641
  ctx.print(ast, `(`);
3614
3642
  ctx.print(ast, opStr);
3615
3643
  ast.expr.visitExpression(this, ctx);
3616
- if (ast.parens)
3644
+ if (parens)
3617
3645
  ctx.print(ast, `)`);
3618
3646
  return null;
3619
3647
  }
@@ -3680,12 +3708,13 @@ class AbstractEmitterVisitor {
3680
3708
  default:
3681
3709
  throw new Error(`Unknown operator ${ast.operator}`);
3682
3710
  }
3683
- if (ast.parens)
3711
+ const parens = ast !== this.lastIfCondition;
3712
+ if (parens)
3684
3713
  ctx.print(ast, `(`);
3685
3714
  ast.lhs.visitExpression(this, ctx);
3686
3715
  ctx.print(ast, ` ${opStr} `);
3687
3716
  ast.rhs.visitExpression(this, ctx);
3688
- if (ast.parens)
3717
+ if (parens)
3689
3718
  ctx.print(ast, `)`);
3690
3719
  return null;
3691
3720
  }
@@ -3723,6 +3752,12 @@ class AbstractEmitterVisitor {
3723
3752
  ctx.print(ast, ')');
3724
3753
  return null;
3725
3754
  }
3755
+ visitParenthesizedExpr(ast, ctx) {
3756
+ // We parenthesize everything regardless of an explicit ParenthesizedExpr, so we can just visit
3757
+ // the inner expression.
3758
+ // TODO: Do we *need* to parenthesize everything?
3759
+ ast.expr.visitExpression(this, ctx);
3760
+ }
3726
3761
  visitAllExpressions(expressions, ctx, separator) {
3727
3762
  this.visitAllObjects((expr) => expr.visitExpression(this, ctx), expressions, ctx, separator);
3728
3763
  }
@@ -3809,7 +3844,7 @@ function guardedExpression(guard, expr) {
3809
3844
  const guardNotDefined = new BinaryOperatorExpr(BinaryOperator.Identical, new TypeofExpr(guardExpr), literal$1('undefined'));
3810
3845
  const guardUndefinedOrTrue = new BinaryOperatorExpr(BinaryOperator.Or, guardNotDefined, guardExpr,
3811
3846
  /* type */ undefined,
3812
- /* sourceSpan */ undefined, true);
3847
+ /* sourceSpan */ undefined);
3813
3848
  return new BinaryOperatorExpr(BinaryOperator.And, guardUndefinedOrTrue, expr);
3814
3849
  }
3815
3850
  function wrapReference(value) {
@@ -4402,6 +4437,18 @@ class SafeCall extends AST {
4402
4437
  return visitor.visitSafeCall(this, context);
4403
4438
  }
4404
4439
  }
4440
+ class TaggedTemplateLiteral extends AST {
4441
+ tag;
4442
+ template;
4443
+ constructor(span, sourceSpan, tag, template) {
4444
+ super(span, sourceSpan);
4445
+ this.tag = tag;
4446
+ this.template = template;
4447
+ }
4448
+ visit(visitor, context) {
4449
+ return visitor.visitTaggedTemplateLiteral(this, context);
4450
+ }
4451
+ }
4405
4452
  class TemplateLiteral extends AST {
4406
4453
  elements;
4407
4454
  expressions;
@@ -4586,6 +4633,10 @@ class RecursiveAstVisitor {
4586
4633
  }
4587
4634
  }
4588
4635
  visitTemplateLiteralElement(ast, context) { }
4636
+ visitTaggedTemplateLiteral(ast, context) {
4637
+ this.visit(ast.tag, context);
4638
+ this.visit(ast.template, context);
4639
+ }
4589
4640
  // This is not part of the AstVisitor interface, just a helper method
4590
4641
  visitAll(asts, context) {
4591
4642
  for (const ast of asts) {
@@ -10326,6 +10377,9 @@ function transformExpressionsInExpression(expr, transform, flags) {
10326
10377
  expr.expressions[i] = transformExpressionsInExpression(expr.expressions[i], transform, flags);
10327
10378
  }
10328
10379
  }
10380
+ else if (expr instanceof ParenthesizedExpr) {
10381
+ expr.expr = transformExpressionsInExpression(expr.expr, transform, flags);
10382
+ }
10329
10383
  else if (expr instanceof ReadVarExpr ||
10330
10384
  expr instanceof ExternalExpr ||
10331
10385
  expr instanceof LiteralExpr) ;
@@ -11398,6 +11452,33 @@ function assignI18nSlotDependencies(job) {
11398
11452
  }
11399
11453
  }
11400
11454
 
11455
+ /**
11456
+ * Locates all of the elements defined in a creation block and outputs an op
11457
+ * that will expose their definition location in the DOM.
11458
+ */
11459
+ function attachSourceLocations(job) {
11460
+ if (!job.enableDebugLocations || job.relativeTemplatePath === null) {
11461
+ return;
11462
+ }
11463
+ for (const unit of job.units) {
11464
+ const locations = [];
11465
+ for (const op of unit.create) {
11466
+ if (op.kind === OpKind.ElementStart || op.kind === OpKind.Element) {
11467
+ const start = op.startSourceSpan.start;
11468
+ locations.push({
11469
+ targetSlot: op.handle,
11470
+ offset: start.offset,
11471
+ line: start.line,
11472
+ column: start.col,
11473
+ });
11474
+ }
11475
+ }
11476
+ if (locations.length > 0) {
11477
+ unit.create.push(createSourceLocationOp(job.relativeTemplatePath, locations));
11478
+ }
11479
+ }
11480
+ }
11481
+
11401
11482
  /**
11402
11483
  * Gets a map of all elements in the given view by their xref id.
11403
11484
  */
@@ -12088,29 +12169,6 @@ function convertI18nBindings(job) {
12088
12169
  }
12089
12170
  }
12090
12171
 
12091
- /**
12092
- * Resolve the dependency function of a deferred block.
12093
- */
12094
- function resolveDeferDepsFns(job) {
12095
- for (const unit of job.units) {
12096
- for (const op of unit.create) {
12097
- if (op.kind === OpKind.Defer) {
12098
- if (op.resolverFn !== null) {
12099
- continue;
12100
- }
12101
- if (op.ownResolverFn !== null) {
12102
- if (op.handle.slot === null) {
12103
- throw new Error('AssertionError: slot must be assigned before extracting defer deps functions');
12104
- }
12105
- const fullPathName = unit.fnName?.replace('_Template', '');
12106
- op.resolverFn = job.pool.getSharedFunctionReference(op.ownResolverFn, `${fullPathName}_Defer_${op.handle.slot}_DepsFn`,
12107
- /* Don't use unique names for TDB compatibility */ false);
12108
- }
12109
- }
12110
- }
12111
- }
12112
- }
12113
-
12114
12172
  /**
12115
12173
  * Create one helper context op per i18n block (including generate descending blocks).
12116
12174
  *
@@ -12853,6 +12911,27 @@ function generateAdvance(job) {
12853
12911
  }
12854
12912
  }
12855
12913
 
12914
+ /**
12915
+ * Replaces the `storeLet` ops with variables that can be
12916
+ * used to reference the value within the same view.
12917
+ */
12918
+ function generateLocalLetReferences(job) {
12919
+ for (const unit of job.units) {
12920
+ for (const op of unit.update) {
12921
+ if (op.kind !== OpKind.StoreLet) {
12922
+ continue;
12923
+ }
12924
+ const variable = {
12925
+ kind: SemanticVariableKind.Identifier,
12926
+ name: null,
12927
+ identifier: op.declaredName,
12928
+ local: true,
12929
+ };
12930
+ OpList.replace(op, createVariableOp(job.allocateXrefId(), variable, new StoreLetExpr(op.target, op.value, op.sourceSpan), VariableFlags.None));
12931
+ }
12932
+ }
12933
+ }
12934
+
12856
12935
  /**
12857
12936
  * Locate projection slots, populate the each component's `ngContentSelectors` literal field,
12858
12937
  * populate `project` arguments, and generate the required `projectionDef` instruction for the job's
@@ -18677,7 +18756,7 @@ class _ParseAST {
18677
18756
  this.error('Unary operator used immediately before exponentiation expression. Parenthesis must be used to disambiguate operator precedence');
18678
18757
  }
18679
18758
  this.advance();
18680
- const right = this.parsePrefix();
18759
+ const right = this.parseExponentiation();
18681
18760
  result = new Binary(this.span(start), this.sourceSpan(start), '**', result, right);
18682
18761
  }
18683
18762
  return result;
@@ -18742,6 +18821,12 @@ class _ParseAST {
18742
18821
  else if (this.consumeOptionalOperator('!')) {
18743
18822
  result = new NonNullAssert(this.span(start), this.sourceSpan(start), result);
18744
18823
  }
18824
+ else if (this.next.isTemplateLiteralEnd()) {
18825
+ result = this.parseNoInterpolationTaggedTemplateLiteral(result, start);
18826
+ }
18827
+ else if (this.next.isTemplateLiteralPart()) {
18828
+ result = this.parseTaggedTemplateLiteral(result, start);
18829
+ }
18745
18830
  else {
18746
18831
  return result;
18747
18832
  }
@@ -18796,7 +18881,7 @@ class _ParseAST {
18796
18881
  return new LiteralPrimitive(this.span(start), this.sourceSpan(start), value);
18797
18882
  }
18798
18883
  else if (this.next.isTemplateLiteralEnd()) {
18799
- return this.parseNoInterpolationTemplateLiteral(start);
18884
+ return this.parseNoInterpolationTemplateLiteral();
18800
18885
  }
18801
18886
  else if (this.next.isTemplateLiteralPart()) {
18802
18887
  return this.parseTemplateLiteral();
@@ -19126,17 +19211,25 @@ class _ParseAST {
19126
19211
  const sourceSpan = new AbsoluteSourceSpan(spanStart, this.currentAbsoluteOffset);
19127
19212
  return new VariableBinding(sourceSpan, key, value);
19128
19213
  }
19129
- parseNoInterpolationTemplateLiteral(start) {
19214
+ parseNoInterpolationTaggedTemplateLiteral(tag, start) {
19215
+ const template = this.parseNoInterpolationTemplateLiteral();
19216
+ return new TaggedTemplateLiteral(this.span(start), this.sourceSpan(start), tag, template);
19217
+ }
19218
+ parseNoInterpolationTemplateLiteral() {
19130
19219
  const text = this.next.strValue;
19131
19220
  this.advance();
19132
- const span = this.span(start);
19133
- const sourceSpan = this.sourceSpan(start);
19221
+ const span = this.span(this.inputIndex);
19222
+ const sourceSpan = this.sourceSpan(this.inputIndex);
19134
19223
  return new TemplateLiteral(span, sourceSpan, [new TemplateLiteralElement(span, sourceSpan, text)], []);
19135
19224
  }
19225
+ parseTaggedTemplateLiteral(tag, start) {
19226
+ const template = this.parseTemplateLiteral();
19227
+ return new TaggedTemplateLiteral(this.span(start), this.sourceSpan(start), tag, template);
19228
+ }
19136
19229
  parseTemplateLiteral() {
19137
- const start = this.inputIndex;
19138
19230
  const elements = [];
19139
19231
  const expressions = [];
19232
+ const start = this.inputIndex;
19140
19233
  while (this.next !== EOF) {
19141
19234
  const token = this.next;
19142
19235
  if (token.isTemplateLiteralPart() || token.isTemplateLiteralEnd()) {
@@ -19397,6 +19490,9 @@ class SerializeExpressionVisitor {
19397
19490
  visitTemplateLiteralElement(ast, context) {
19398
19491
  return ast.text;
19399
19492
  }
19493
+ visitTaggedTemplateLiteral(ast, context) {
19494
+ return ast.tag.visit(this, context) + ast.template.visit(this, context);
19495
+ }
19400
19496
  }
19401
19497
  /** Zips the two input arrays into a single array of pairs of elements at the same index. */
19402
19498
  function zip(left, right) {
@@ -21946,30 +22042,6 @@ function disableBindings$1(job) {
21946
22042
  }
21947
22043
  }
21948
22044
 
21949
- /**
21950
- * Nullish coalescing expressions such as `a ?? b` have different semantics in Angular templates as
21951
- * compared to JavaScript. In particular, they default to `null` instead of `undefined`. Therefore,
21952
- * we replace them with ternary expressions, assigning temporaries as needed to avoid re-evaluating
21953
- * the same sub-expression multiple times.
21954
- */
21955
- function generateNullishCoalesceExpressions(job) {
21956
- for (const unit of job.units) {
21957
- for (const op of unit.ops()) {
21958
- transformExpressionsInOp(op, (expr) => {
21959
- if (!(expr instanceof BinaryOperatorExpr) ||
21960
- expr.operator !== BinaryOperator.NullishCoalesce) {
21961
- return expr;
21962
- }
21963
- const assignment = new AssignTemporaryExpr(expr.lhs.clone(), job.allocateXrefId());
21964
- const read = new ReadTemporaryExpr(assignment.xref);
21965
- // TODO: When not in compatibility mode for TemplateDefinitionBuilder, we can just emit
21966
- // `t != null` instead of including an undefined check as well.
21967
- return new ConditionalExpr(new BinaryOperatorExpr(BinaryOperator.And, new BinaryOperatorExpr(BinaryOperator.NotIdentical, assignment, NULL_EXPR), new BinaryOperatorExpr(BinaryOperator.NotIdentical, read, new LiteralExpr(undefined))), read.clone(), expr.rhs);
21968
- }, VisitorContextFlag.None);
21969
- }
21970
- }
21971
- }
21972
-
21973
22045
  function kindTest(kind) {
21974
22046
  return (op) => op.kind === kind;
21975
22047
  }
@@ -23488,6 +23560,33 @@ function removeI18nContexts(job) {
23488
23560
  }
23489
23561
  }
23490
23562
 
23563
+ /**
23564
+ * It's not allowed to access a `@let` declaration before it has been defined. This is enforced
23565
+ * already via template type checking, however it can trip some of the assertions in the pipeline.
23566
+ * E.g. the naming phase can fail because we resolved the variable here, but the variable doesn't
23567
+ * exist anymore because the optimization phase removed it since it's invalid. To avoid surfacing
23568
+ * confusing errors to users in the case where template type checking isn't running (e.g. in JIT
23569
+ * mode) this phase detects illegal forward references and replaces them with `undefined`.
23570
+ * Eventually users will see the proper error from the template type checker.
23571
+ */
23572
+ function removeIllegalLetReferences(job) {
23573
+ for (const unit of job.units) {
23574
+ for (const op of unit.update) {
23575
+ if (op.kind !== OpKind.Variable ||
23576
+ op.variable.kind !== SemanticVariableKind.Identifier ||
23577
+ !(op.initializer instanceof StoreLetExpr)) {
23578
+ continue;
23579
+ }
23580
+ const name = op.variable.identifier;
23581
+ let current = op;
23582
+ while (current && current.kind !== OpKind.ListEnd) {
23583
+ transformExpressionsInOp(current, (expr) => expr instanceof LexicalReadExpr && expr.name === name ? literal$1(undefined) : expr, VisitorContextFlag.None);
23584
+ current = current.prev;
23585
+ }
23586
+ }
23587
+ }
23588
+ }
23589
+
23491
23590
  /**
23492
23591
  * i18nAttributes ops will be generated for each i18n attribute. However, not all i18n attribues
23493
23592
  * will contain dynamic content, and so some of these i18nAttributes ops may be unnecessary.
@@ -23513,6 +23612,57 @@ function removeUnusedI18nAttributesOps(job) {
23513
23612
  }
23514
23613
  }
23515
23614
 
23615
+ // TODO: create AST for parentheses when parsing, then we can remove the unnecessary ones instead of
23616
+ // adding them out of thin air. This should simplify the parsing and give us valid spans for the
23617
+ // parentheses.
23618
+ /**
23619
+ * In some cases we need to add parentheses to expressions for them to be considered valid
23620
+ * JavaScript. This phase adds parentheses to cover such cases. Currently these cases are:
23621
+ *
23622
+ * 1. Unary operators in the base of an exponentiation expression. For example, `-2 ** 3` is not
23623
+ * valid JavaScript, but `(-2) ** 3` is.
23624
+ * 2. When mixing nullish coalescing (`??`) and logical and/or operators (`&&`, `||`), we need to
23625
+ * add parentheses. For example, `a ?? b && c` is not valid JavaScript, but `a ?? (b && c)` is.
23626
+ * 3. Safe property access that has been down-leveled into a ternary expression needs parentheses
23627
+ * when used with nullish coalescing.
23628
+ */
23629
+ function requiredParentheses(job) {
23630
+ for (const unit of job.units) {
23631
+ for (const op of unit.ops()) {
23632
+ transformExpressionsInOp(op, (expr) => {
23633
+ if (expr instanceof BinaryOperatorExpr) {
23634
+ switch (expr.operator) {
23635
+ case BinaryOperator.Exponentiation:
23636
+ parenthesizeExponentiation(expr);
23637
+ break;
23638
+ case BinaryOperator.NullishCoalesce:
23639
+ parenthesizeNullishCoalescing(expr);
23640
+ break;
23641
+ }
23642
+ }
23643
+ return expr;
23644
+ }, VisitorContextFlag.None);
23645
+ }
23646
+ }
23647
+ }
23648
+ function parenthesizeExponentiation(expr) {
23649
+ if (expr.lhs instanceof UnaryOperatorExpr) {
23650
+ expr.lhs = new ParenthesizedExpr(expr.lhs);
23651
+ }
23652
+ }
23653
+ function parenthesizeNullishCoalescing(expr) {
23654
+ if (isLogicalAndOr(expr.lhs) || expr.lhs instanceof ConditionalExpr) {
23655
+ expr.lhs = new ParenthesizedExpr(expr.lhs);
23656
+ }
23657
+ if (isLogicalAndOr(expr.rhs) || expr.rhs instanceof ConditionalExpr) {
23658
+ expr.rhs = new ParenthesizedExpr(expr.rhs);
23659
+ }
23660
+ }
23661
+ function isLogicalAndOr(expr) {
23662
+ return (expr instanceof BinaryOperatorExpr &&
23663
+ (expr.operator === BinaryOperator.And || expr.operator === BinaryOperator.Or));
23664
+ }
23665
+
23516
23666
  /**
23517
23667
  * Resolves `ir.ContextExpr` expressions (which represent embedded view or component contexts) to
23518
23668
  * either the `ctx` parameter to component functions (for the current view context) or to variables
@@ -23569,6 +23719,29 @@ function processLexicalScope$1(view, ops) {
23569
23719
  }
23570
23720
  }
23571
23721
 
23722
+ /**
23723
+ * Resolve the dependency function of a deferred block.
23724
+ */
23725
+ function resolveDeferDepsFns(job) {
23726
+ for (const unit of job.units) {
23727
+ for (const op of unit.create) {
23728
+ if (op.kind === OpKind.Defer) {
23729
+ if (op.resolverFn !== null) {
23730
+ continue;
23731
+ }
23732
+ if (op.ownResolverFn !== null) {
23733
+ if (op.handle.slot === null) {
23734
+ throw new Error('AssertionError: slot must be assigned before extracting defer deps functions');
23735
+ }
23736
+ const fullPathName = unit.fnName?.replace('_Template', '');
23737
+ op.resolverFn = job.pool.getSharedFunctionReference(op.ownResolverFn, `${fullPathName}_Defer_${op.handle.slot}_DepsFn`,
23738
+ /* Don't use unique names for TDB compatibility */ false);
23739
+ }
23740
+ }
23741
+ }
23742
+ }
23743
+ }
23744
+
23572
23745
  /**
23573
23746
  * Any variable inside a listener with the name `$event` will be transformed into a output lexical
23574
23747
  * read immediately, and does not participate in any of the normal logic for handling variables.
@@ -24145,39 +24318,6 @@ function getOnlySecurityContext(securityContext) {
24145
24318
  return securityContext;
24146
24319
  }
24147
24320
 
24148
- /**
24149
- * Transforms a `TwoWayBindingSet` expression into an expression that either
24150
- * sets a value through the `twoWayBindingSet` instruction or falls back to setting
24151
- * the value directly. E.g. the expression `TwoWayBindingSet(target, value)` becomes:
24152
- * `ng.twoWayBindingSet(target, value) || (target = value)`.
24153
- */
24154
- function transformTwoWayBindingSet(job) {
24155
- for (const unit of job.units) {
24156
- for (const op of unit.create) {
24157
- if (op.kind === OpKind.TwoWayListener) {
24158
- transformExpressionsInOp(op, (expr) => {
24159
- if (!(expr instanceof TwoWayBindingSetExpr)) {
24160
- return expr;
24161
- }
24162
- const { target, value } = expr;
24163
- if (target instanceof ReadPropExpr || target instanceof ReadKeyExpr) {
24164
- return twoWayBindingSet(target, value).or(target.set(value));
24165
- }
24166
- // ASSUMPTION: here we're assuming that `ReadVariableExpr` will be a reference
24167
- // to a local template variable. This appears to be the case at the time of writing.
24168
- // If the expression is targeting a variable read, we only emit the `twoWayBindingSet`
24169
- // since the fallback would be attempting to write into a constant. Invalid usages will be
24170
- // flagged during template type checking.
24171
- if (target instanceof ReadVariableExpr) {
24172
- return twoWayBindingSet(target, value);
24173
- }
24174
- throw new Error(`Unsupported expression in two-way action binding.`);
24175
- }, VisitorContextFlag.InChildOperation);
24176
- }
24177
- }
24178
- }
24179
- }
24180
-
24181
24321
  /**
24182
24322
  * When inside of a listener, we may need access to one or more enclosing views. Therefore, each
24183
24323
  * view should save the current view, and each listener must have the ability to restore the
@@ -24287,6 +24427,40 @@ function allocateSlots(job) {
24287
24427
  }
24288
24428
  }
24289
24429
 
24430
+ /*!
24431
+ * @license
24432
+ * Copyright Google LLC All Rights Reserved.
24433
+ *
24434
+ * Use of this source code is governed by an MIT-style license that can be
24435
+ * found in the LICENSE file at https://angular.dev/license
24436
+ */
24437
+ /**
24438
+ * Removes any `storeLet` calls that aren't referenced outside of the current view.
24439
+ */
24440
+ function optimizeStoreLet(job) {
24441
+ const letUsedExternally = new Set();
24442
+ // Since `@let` declarations can be referenced in child views, both in
24443
+ // the creation block (via listeners) and in the update block, we have
24444
+ // to look through all the ops to find the references.
24445
+ for (const unit of job.units) {
24446
+ for (const op of unit.ops()) {
24447
+ visitExpressionsInOp(op, (expr) => {
24448
+ if (expr instanceof ContextLetReferenceExpr) {
24449
+ letUsedExternally.add(expr.target);
24450
+ }
24451
+ });
24452
+ }
24453
+ }
24454
+ // TODO(crisbeto): potentially remove the unused calls completely, pending discussion.
24455
+ for (const unit of job.units) {
24456
+ for (const op of unit.update) {
24457
+ transformExpressionsInOp(op, (expression) => expression instanceof StoreLetExpr && !letUsedExternally.has(expression.target)
24458
+ ? expression.value
24459
+ : expression, VisitorContextFlag.None);
24460
+ }
24461
+ }
24462
+ }
24463
+
24290
24464
  /**
24291
24465
  * Transforms special-case bindings with 'style' or 'class' in their names. Must run before the
24292
24466
  * main binding specialization pass.
@@ -24514,6 +24688,39 @@ function generateTrackVariables(job) {
24514
24688
  }
24515
24689
  }
24516
24690
 
24691
+ /**
24692
+ * Transforms a `TwoWayBindingSet` expression into an expression that either
24693
+ * sets a value through the `twoWayBindingSet` instruction or falls back to setting
24694
+ * the value directly. E.g. the expression `TwoWayBindingSet(target, value)` becomes:
24695
+ * `ng.twoWayBindingSet(target, value) || (target = value)`.
24696
+ */
24697
+ function transformTwoWayBindingSet(job) {
24698
+ for (const unit of job.units) {
24699
+ for (const op of unit.create) {
24700
+ if (op.kind === OpKind.TwoWayListener) {
24701
+ transformExpressionsInOp(op, (expr) => {
24702
+ if (!(expr instanceof TwoWayBindingSetExpr)) {
24703
+ return expr;
24704
+ }
24705
+ const { target, value } = expr;
24706
+ if (target instanceof ReadPropExpr || target instanceof ReadKeyExpr) {
24707
+ return twoWayBindingSet(target, value).or(target.set(value));
24708
+ }
24709
+ // ASSUMPTION: here we're assuming that `ReadVariableExpr` will be a reference
24710
+ // to a local template variable. This appears to be the case at the time of writing.
24711
+ // If the expression is targeting a variable read, we only emit the `twoWayBindingSet`
24712
+ // since the fallback would be attempting to write into a constant. Invalid usages will be
24713
+ // flagged during template type checking.
24714
+ if (target instanceof ReadVariableExpr) {
24715
+ return twoWayBindingSet(target, value);
24716
+ }
24717
+ throw new Error(`Unsupported expression in two-way action binding.`);
24718
+ }, VisitorContextFlag.InChildOperation);
24719
+ }
24720
+ }
24721
+ }
24722
+ }
24723
+
24517
24724
  /**
24518
24725
  * Counts the number of variable slots used within each view, and stores that on the view itself, as
24519
24726
  * well as propagates it to the `ir.TemplateOp` for embedded views.
@@ -25113,115 +25320,6 @@ function wrapI18nIcus(job) {
25113
25320
  }
25114
25321
  }
25115
25322
 
25116
- /*!
25117
- * @license
25118
- * Copyright Google LLC All Rights Reserved.
25119
- *
25120
- * Use of this source code is governed by an MIT-style license that can be
25121
- * found in the LICENSE file at https://angular.dev/license
25122
- */
25123
- /**
25124
- * Removes any `storeLet` calls that aren't referenced outside of the current view.
25125
- */
25126
- function optimizeStoreLet(job) {
25127
- const letUsedExternally = new Set();
25128
- // Since `@let` declarations can be referenced in child views, both in
25129
- // the creation block (via listeners) and in the update block, we have
25130
- // to look through all the ops to find the references.
25131
- for (const unit of job.units) {
25132
- for (const op of unit.ops()) {
25133
- visitExpressionsInOp(op, (expr) => {
25134
- if (expr instanceof ContextLetReferenceExpr) {
25135
- letUsedExternally.add(expr.target);
25136
- }
25137
- });
25138
- }
25139
- }
25140
- // TODO(crisbeto): potentially remove the unused calls completely, pending discussion.
25141
- for (const unit of job.units) {
25142
- for (const op of unit.update) {
25143
- transformExpressionsInOp(op, (expression) => expression instanceof StoreLetExpr && !letUsedExternally.has(expression.target)
25144
- ? expression.value
25145
- : expression, VisitorContextFlag.None);
25146
- }
25147
- }
25148
- }
25149
-
25150
- /**
25151
- * It's not allowed to access a `@let` declaration before it has been defined. This is enforced
25152
- * already via template type checking, however it can trip some of the assertions in the pipeline.
25153
- * E.g. the naming phase can fail because we resolved the variable here, but the variable doesn't
25154
- * exist anymore because the optimization phase removed it since it's invalid. To avoid surfacing
25155
- * confusing errors to users in the case where template type checking isn't running (e.g. in JIT
25156
- * mode) this phase detects illegal forward references and replaces them with `undefined`.
25157
- * Eventually users will see the proper error from the template type checker.
25158
- */
25159
- function removeIllegalLetReferences(job) {
25160
- for (const unit of job.units) {
25161
- for (const op of unit.update) {
25162
- if (op.kind !== OpKind.Variable ||
25163
- op.variable.kind !== SemanticVariableKind.Identifier ||
25164
- !(op.initializer instanceof StoreLetExpr)) {
25165
- continue;
25166
- }
25167
- const name = op.variable.identifier;
25168
- let current = op;
25169
- while (current && current.kind !== OpKind.ListEnd) {
25170
- transformExpressionsInOp(current, (expr) => expr instanceof LexicalReadExpr && expr.name === name ? literal$1(undefined) : expr, VisitorContextFlag.None);
25171
- current = current.prev;
25172
- }
25173
- }
25174
- }
25175
- }
25176
-
25177
- /**
25178
- * Replaces the `storeLet` ops with variables that can be
25179
- * used to reference the value within the same view.
25180
- */
25181
- function generateLocalLetReferences(job) {
25182
- for (const unit of job.units) {
25183
- for (const op of unit.update) {
25184
- if (op.kind !== OpKind.StoreLet) {
25185
- continue;
25186
- }
25187
- const variable = {
25188
- kind: SemanticVariableKind.Identifier,
25189
- name: null,
25190
- identifier: op.declaredName,
25191
- local: true,
25192
- };
25193
- OpList.replace(op, createVariableOp(job.allocateXrefId(), variable, new StoreLetExpr(op.target, op.value, op.sourceSpan), VariableFlags.None));
25194
- }
25195
- }
25196
- }
25197
-
25198
- /**
25199
- * Locates all of the elements defined in a creation block and outputs an op
25200
- * that will expose their definition location in the DOM.
25201
- */
25202
- function attachSourceLocations(job) {
25203
- if (!job.enableDebugLocations || job.relativeTemplatePath === null) {
25204
- return;
25205
- }
25206
- for (const unit of job.units) {
25207
- const locations = [];
25208
- for (const op of unit.create) {
25209
- if (op.kind === OpKind.ElementStart || op.kind === OpKind.Element) {
25210
- const start = op.startSourceSpan.start;
25211
- locations.push({
25212
- targetSlot: op.handle,
25213
- offset: start.offset,
25214
- line: start.line,
25215
- column: start.col,
25216
- });
25217
- }
25218
- }
25219
- if (locations.length > 0) {
25220
- unit.create.push(createSourceLocationOp(job.relativeTemplatePath, locations));
25221
- }
25222
- }
25223
- }
25224
-
25225
25323
  /**
25226
25324
  *
25227
25325
  * @license
@@ -25270,8 +25368,8 @@ const phases = [
25270
25368
  { kind: CompilationJobKind.Both, fn: resolveContexts },
25271
25369
  { kind: CompilationJobKind.Both, fn: resolveSanitizers },
25272
25370
  { kind: CompilationJobKind.Tmpl, fn: liftLocalRefs },
25273
- { kind: CompilationJobKind.Both, fn: generateNullishCoalesceExpressions },
25274
25371
  { kind: CompilationJobKind.Both, fn: expandSafeReads },
25372
+ { kind: CompilationJobKind.Both, fn: requiredParentheses },
25275
25373
  { kind: CompilationJobKind.Both, fn: generateTemporaryVariables },
25276
25374
  { kind: CompilationJobKind.Both, fn: optimizeVariables },
25277
25375
  { kind: CompilationJobKind.Both, fn: optimizeStoreLet },
@@ -26065,14 +26163,20 @@ function convertAst(ast, job, baseSourceSpan) {
26065
26163
  return new VoidExpr(convertAst(ast.expression, job, baseSourceSpan), undefined, convertSourceSpan(ast.span, baseSourceSpan));
26066
26164
  }
26067
26165
  else if (ast instanceof TemplateLiteral) {
26068
- return new TemplateLiteralExpr(ast.elements.map((el) => {
26069
- return new TemplateLiteralElementExpr(el.text, convertSourceSpan(el.span, baseSourceSpan));
26070
- }), ast.expressions.map((expr) => convertAst(expr, job, baseSourceSpan)), convertSourceSpan(ast.span, baseSourceSpan));
26166
+ return convertTemplateLiteral(ast, job, baseSourceSpan);
26167
+ }
26168
+ else if (ast instanceof TaggedTemplateLiteral) {
26169
+ return new TaggedTemplateLiteralExpr(convertAst(ast.tag, job, baseSourceSpan), convertTemplateLiteral(ast.template, job, baseSourceSpan), undefined, convertSourceSpan(ast.span, baseSourceSpan));
26071
26170
  }
26072
26171
  else {
26073
26172
  throw new Error(`Unhandled expression type "${ast.constructor.name}" in file "${baseSourceSpan?.start.file.url}"`);
26074
26173
  }
26075
26174
  }
26175
+ function convertTemplateLiteral(ast, job, baseSourceSpan) {
26176
+ return new TemplateLiteralExpr(ast.elements.map((el) => {
26177
+ return new TemplateLiteralElementExpr(el.text, convertSourceSpan(el.span, baseSourceSpan));
26178
+ }), ast.expressions.map((expr) => convertAst(expr, job, baseSourceSpan)), convertSourceSpan(ast.span, baseSourceSpan));
26179
+ }
26076
26180
  function convertAstWithInterpolation(job, value, i18nMeta, sourceSpan) {
26077
26181
  let expression;
26078
26182
  if (value instanceof Interpolation$1) {
@@ -26464,7 +26568,7 @@ function getTemplateSourceLocationsEnabled() {
26464
26568
 
26465
26569
  // if (rf & flags) { .. }
26466
26570
  function renderFlagCheckIfStmt(flags, statements) {
26467
- return ifStmt(variable(RENDER_FLAGS).bitwiseAnd(literal$1(flags), null, false), statements);
26571
+ return ifStmt(variable(RENDER_FLAGS).bitwiseAnd(literal$1(flags), null), statements);
26468
26572
  }
26469
26573
  /**
26470
26574
  * Translates query flags into `TQueryFlags` type in
@@ -31284,7 +31388,7 @@ var FactoryTarget;
31284
31388
  * @description
31285
31389
  * Entry point for all public APIs of the compiler package.
31286
31390
  */
31287
- new Version('20.0.0-next.0');
31391
+ new Version('20.0.0-next.1');
31288
31392
 
31289
31393
  //////////////////////////////////////
31290
31394
  // This file only reexports content of the `src` folder. Keep it that way.
@@ -32216,7 +32320,7 @@ class NodeJSPathManipulation {
32216
32320
  // G3-ESM-MARKER: G3 uses CommonJS, but externally everything in ESM.
32217
32321
  // CommonJS/ESM interop for determining the current file name and containing dir.
32218
32322
  const isCommonJS = typeof __filename !== 'undefined';
32219
- const currentFileUrl = isCommonJS ? null : (typeof document === 'undefined' ? new (require('u' + 'rl').URL)('file:' + __filename).href : (document.currentScript && document.currentScript.tagName.toUpperCase() === 'SCRIPT' && document.currentScript.src || new URL('checker-cf6f7980.js', document.baseURI).href));
32323
+ const currentFileUrl = isCommonJS ? null : (typeof document === 'undefined' ? new (require('u' + 'rl').URL)('file:' + __filename).href : (document.currentScript && document.currentScript.tagName.toUpperCase() === 'SCRIPT' && document.currentScript.src || new URL('checker-af521da6.js', document.baseURI).href));
32220
32324
  const currentFileName = isCommonJS ? __filename : url.fileURLToPath(currentFileUrl);
32221
32325
  /**
32222
32326
  * A wrapper around the Node.js file-system that supports readonly operations and path manipulation.
@@ -36972,6 +37076,9 @@ class ExpressionTranslatorVisitor {
36972
37076
  }
36973
37077
  return this.factory.createUnaryExpression(UNARY_OPERATORS$1.get(ast.operator), ast.expr.visitExpression(this, context));
36974
37078
  }
37079
+ visitParenthesizedExpr(ast, context) {
37080
+ return this.factory.createParenthesizedExpression(ast.expr.visitExpression(this, context));
37081
+ }
36975
37082
  visitStatements(statements, context) {
36976
37083
  return statements
36977
37084
  .map((stmt) => stmt.visitStatement(this, context))
@@ -37385,6 +37492,9 @@ class TypeTranslatorVisitor {
37385
37492
  visitVoidExpr(ast, context) {
37386
37493
  throw new Error('Method not implemented.');
37387
37494
  }
37495
+ visitParenthesizedExpr(ast, context) {
37496
+ throw new Error('Method not implemented.');
37497
+ }
37388
37498
  translateType(type, context) {
37389
37499
  const typeNode = type.visitType(this, context);
37390
37500
  if (!ts__default["default"].isTypeNode(typeNode)) {
@@ -38382,20 +38492,16 @@ function parseTemplateAsSourceFile(fileName, template) {
38382
38492
  /* setParentNodes */ false, ts__default["default"].ScriptKind.JSX);
38383
38493
  }
38384
38494
 
38385
- const TEMPLATE_ID = Symbol('ngTemplateId');
38386
- const NEXT_TEMPLATE_ID = Symbol('ngNextTemplateId');
38495
+ const TEMPLATE_ID_MAP = Symbol('ngTemplateId');
38387
38496
  function getTemplateId$1(clazz) {
38388
- const node = clazz;
38389
- if (node[TEMPLATE_ID] === undefined) {
38390
- node[TEMPLATE_ID] = allocateTemplateId(node.getSourceFile());
38497
+ const sf = clazz.getSourceFile();
38498
+ if (sf[TEMPLATE_ID_MAP] === undefined) {
38499
+ sf[TEMPLATE_ID_MAP] = new Map();
38391
38500
  }
38392
- return node[TEMPLATE_ID];
38393
- }
38394
- function allocateTemplateId(sf) {
38395
- if (sf[NEXT_TEMPLATE_ID] === undefined) {
38396
- sf[NEXT_TEMPLATE_ID] = 1;
38501
+ if (sf[TEMPLATE_ID_MAP].get(clazz) === undefined) {
38502
+ sf[TEMPLATE_ID_MAP].set(clazz, `tcb${sf[TEMPLATE_ID_MAP].size + 1}`);
38397
38503
  }
38398
- return `tcb${sf[NEXT_TEMPLATE_ID]++}`;
38504
+ return sf[TEMPLATE_ID_MAP].get(clazz);
38399
38505
  }
38400
38506
 
38401
38507
  const parseSpanComment = /^(\d+),(\d+)$/;
@@ -41668,6 +41774,9 @@ class AstTranslator {
41668
41774
  visitTemplateLiteralElement(ast, context) {
41669
41775
  throw new Error('Method not implemented');
41670
41776
  }
41777
+ visitTaggedTemplateLiteral(ast) {
41778
+ return ts__default["default"].factory.createTaggedTemplateExpression(this.translate(ast.tag), undefined, this.visitTemplateLiteral(ast.template));
41779
+ }
41671
41780
  convertToSafeCall(ast, expr, args) {
41672
41781
  if (this.config.strictSafeNavigationTypes) {
41673
41782
  // "a?.method(...)" becomes (0 as any ? a!.method(...) : undefined)
@@ -41776,6 +41885,9 @@ class VeSafeLhsInferenceBugDetector {
41776
41885
  visitTemplateLiteralElement(ast, context) {
41777
41886
  return false;
41778
41887
  }
41888
+ visitTaggedTemplateLiteral(ast, context) {
41889
+ return false;
41890
+ }
41779
41891
  }
41780
41892
 
41781
41893
  /**