@angular/language-service 13.0.0-next.3 → 13.0.0-next.7

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.
package/bundles/ivy.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Angular v13.0.0-next.3
2
+ * @license Angular v13.0.0-next.7
3
3
  * Copyright Google LLC All Rights Reserved.
4
4
  * License: MIT
5
5
  */
@@ -1193,9 +1193,6 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
1193
1193
  key(index, type, sourceSpan) {
1194
1194
  return new ReadKeyExpr(this, index, type, sourceSpan);
1195
1195
  }
1196
- callMethod(name, params, sourceSpan) {
1197
- return new InvokeMethodExpr(this, name, params, null, sourceSpan);
1198
- }
1199
1196
  callFn(params, sourceSpan, pure) {
1200
1197
  return new InvokeFunctionExpr(this, params, null, sourceSpan, pure);
1201
1198
  }
@@ -1397,31 +1394,6 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
1397
1394
  BuiltinMethod[BuiltinMethod["SubscribeObservable"] = 1] = "SubscribeObservable";
1398
1395
  BuiltinMethod[BuiltinMethod["Bind"] = 2] = "Bind";
1399
1396
  })(BuiltinMethod || (BuiltinMethod = {}));
1400
- class InvokeMethodExpr extends Expression {
1401
- constructor(receiver, method, args, type, sourceSpan) {
1402
- super(type, sourceSpan);
1403
- this.receiver = receiver;
1404
- this.args = args;
1405
- if (typeof method === 'string') {
1406
- this.name = method;
1407
- this.builtin = null;
1408
- }
1409
- else {
1410
- this.name = null;
1411
- this.builtin = method;
1412
- }
1413
- }
1414
- isEquivalent(e) {
1415
- return e instanceof InvokeMethodExpr && this.receiver.isEquivalent(e.receiver) &&
1416
- this.name === e.name && this.builtin === e.builtin && areAllEquivalent(this.args, e.args);
1417
- }
1418
- isConstant() {
1419
- return false;
1420
- }
1421
- visitExpression(visitor, context) {
1422
- return visitor.visitInvokeMethodExpr(this, context);
1423
- }
1424
- }
1425
1397
  class InvokeFunctionExpr extends Expression {
1426
1398
  constructor(fn, args, type, sourceSpan, pure = false) {
1427
1399
  super(type, sourceSpan);
@@ -2298,7 +2270,6 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
2298
2270
  this.visitWriteVarExpr = invalid;
2299
2271
  this.visitWriteKeyExpr = invalid;
2300
2272
  this.visitWritePropExpr = invalid;
2301
- this.visitInvokeMethodExpr = invalid;
2302
2273
  this.visitInvokeFunctionExpr = invalid;
2303
2274
  this.visitTaggedTemplateExpr = invalid;
2304
2275
  this.visitInstantiateExpr = invalid;
@@ -4395,21 +4366,6 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
4395
4366
  }
4396
4367
  return null;
4397
4368
  }
4398
- visitInvokeMethodExpr(expr, ctx) {
4399
- expr.receiver.visitExpression(this, ctx);
4400
- let name = expr.name;
4401
- if (expr.builtin != null) {
4402
- name = this.getBuiltinMethodName(expr.builtin);
4403
- if (name == null) {
4404
- // some builtins just mean to skip the call.
4405
- return null;
4406
- }
4407
- }
4408
- ctx.print(expr, `.${name}(`);
4409
- this.visitAllExpressions(expr.args, ctx, `,`);
4410
- ctx.print(expr, `)`);
4411
- return null;
4412
- }
4413
4369
  visitInvokeFunctionExpr(expr, ctx) {
4414
4370
  expr.fn.visitExpression(this, ctx);
4415
4371
  ctx.print(expr, `(`);
@@ -5051,7 +5007,7 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
5051
5007
  return createFactoryFunction(unwrappedType);
5052
5008
  }
5053
5009
  function createFactoryFunction(type) {
5054
- return fn([new FnParam('t', DYNAMIC_TYPE)], [new ReturnStatement(type.callMethod('ɵfac', [variable('t')]))]);
5010
+ return fn([new FnParam('t', DYNAMIC_TYPE)], [new ReturnStatement(type.prop('ɵfac').callFn([variable('t')]))]);
5055
5011
  }
5056
5012
 
5057
5013
  /**
@@ -6384,38 +6340,15 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
6384
6340
  return visitor.visitNonNullAssert(this, context);
6385
6341
  }
6386
6342
  }
6387
- class MethodCall extends ASTWithName {
6388
- constructor(span, sourceSpan, nameSpan, receiver, name, args, argumentSpan) {
6389
- super(span, sourceSpan, nameSpan);
6390
- this.receiver = receiver;
6391
- this.name = name;
6392
- this.args = args;
6393
- this.argumentSpan = argumentSpan;
6394
- }
6395
- visit(visitor, context = null) {
6396
- return visitor.visitMethodCall(this, context);
6397
- }
6398
- }
6399
- class SafeMethodCall extends ASTWithName {
6400
- constructor(span, sourceSpan, nameSpan, receiver, name, args, argumentSpan) {
6401
- super(span, sourceSpan, nameSpan);
6343
+ class Call extends AST {
6344
+ constructor(span, sourceSpan, receiver, args, argumentSpan) {
6345
+ super(span, sourceSpan);
6402
6346
  this.receiver = receiver;
6403
- this.name = name;
6404
6347
  this.args = args;
6405
6348
  this.argumentSpan = argumentSpan;
6406
6349
  }
6407
6350
  visit(visitor, context = null) {
6408
- return visitor.visitSafeMethodCall(this, context);
6409
- }
6410
- }
6411
- class FunctionCall extends AST {
6412
- constructor(span, sourceSpan, target, args) {
6413
- super(span, sourceSpan);
6414
- this.target = target;
6415
- this.args = args;
6416
- }
6417
- visit(visitor, context = null) {
6418
- return visitor.visitFunctionCall(this, context);
6351
+ return visitor.visitCall(this, context);
6419
6352
  }
6420
6353
  }
6421
6354
  /**
@@ -6501,12 +6434,6 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
6501
6434
  this.visit(ast.exp, context);
6502
6435
  this.visitAll(ast.args, context);
6503
6436
  }
6504
- visitFunctionCall(ast, context) {
6505
- if (ast.target) {
6506
- this.visit(ast.target, context);
6507
- }
6508
- this.visitAll(ast.args, context);
6509
- }
6510
6437
  visitImplicitReceiver(ast, context) { }
6511
6438
  visitThisReceiver(ast, context) { }
6512
6439
  visitInterpolation(ast, context) {
@@ -6528,10 +6455,6 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
6528
6455
  this.visitAll(ast.values, context);
6529
6456
  }
6530
6457
  visitLiteralPrimitive(ast, context) { }
6531
- visitMethodCall(ast, context) {
6532
- this.visit(ast.receiver, context);
6533
- this.visitAll(ast.args, context);
6534
- }
6535
6458
  visitPrefixNot(ast, context) {
6536
6459
  this.visit(ast.expression, context);
6537
6460
  }
@@ -6548,14 +6471,14 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
6548
6471
  visitSafePropertyRead(ast, context) {
6549
6472
  this.visit(ast.receiver, context);
6550
6473
  }
6551
- visitSafeMethodCall(ast, context) {
6552
- this.visit(ast.receiver, context);
6553
- this.visitAll(ast.args, context);
6554
- }
6555
6474
  visitSafeKeyedRead(ast, context) {
6556
6475
  this.visit(ast.receiver, context);
6557
6476
  this.visit(ast.key, context);
6558
6477
  }
6478
+ visitCall(ast, context) {
6479
+ this.visit(ast.receiver, context);
6480
+ this.visitAll(ast.args, context);
6481
+ }
6559
6482
  visitQuote(ast, context) { }
6560
6483
  // This is not part of the AstVisitor interface, just a helper method
6561
6484
  visitAll(asts, context) {
@@ -6586,15 +6509,6 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
6586
6509
  visitSafePropertyRead(ast, context) {
6587
6510
  return new SafePropertyRead(ast.span, ast.sourceSpan, ast.nameSpan, ast.receiver.visit(this), ast.name);
6588
6511
  }
6589
- visitMethodCall(ast, context) {
6590
- return new MethodCall(ast.span, ast.sourceSpan, ast.nameSpan, ast.receiver.visit(this), ast.name, this.visitAll(ast.args), ast.argumentSpan);
6591
- }
6592
- visitSafeMethodCall(ast, context) {
6593
- return new SafeMethodCall(ast.span, ast.sourceSpan, ast.nameSpan, ast.receiver.visit(this), ast.name, this.visitAll(ast.args), ast.argumentSpan);
6594
- }
6595
- visitFunctionCall(ast, context) {
6596
- return new FunctionCall(ast.span, ast.sourceSpan, ast.target.visit(this), this.visitAll(ast.args));
6597
- }
6598
6512
  visitLiteralArray(ast, context) {
6599
6513
  return new LiteralArray(ast.span, ast.sourceSpan, this.visitAll(ast.expressions));
6600
6514
  }
@@ -6632,6 +6546,9 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
6632
6546
  visitKeyedWrite(ast, context) {
6633
6547
  return new KeyedWrite(ast.span, ast.sourceSpan, ast.receiver.visit(this), ast.key.visit(this), ast.value.visit(this));
6634
6548
  }
6549
+ visitCall(ast, context) {
6550
+ return new Call(ast.span, ast.sourceSpan, ast.receiver.visit(this), this.visitAll(ast.args), ast.argumentSpan);
6551
+ }
6635
6552
  visitAll(asts) {
6636
6553
  const res = [];
6637
6554
  for (let i = 0; i < asts.length; ++i) {
@@ -6689,30 +6606,6 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
6689
6606
  }
6690
6607
  return ast;
6691
6608
  }
6692
- visitMethodCall(ast, context) {
6693
- const receiver = ast.receiver.visit(this);
6694
- const args = this.visitAll(ast.args);
6695
- if (receiver !== ast.receiver || args !== ast.args) {
6696
- return new MethodCall(ast.span, ast.sourceSpan, ast.nameSpan, receiver, ast.name, args, ast.argumentSpan);
6697
- }
6698
- return ast;
6699
- }
6700
- visitSafeMethodCall(ast, context) {
6701
- const receiver = ast.receiver.visit(this);
6702
- const args = this.visitAll(ast.args);
6703
- if (receiver !== ast.receiver || args !== ast.args) {
6704
- return new SafeMethodCall(ast.span, ast.sourceSpan, ast.nameSpan, receiver, ast.name, args, ast.argumentSpan);
6705
- }
6706
- return ast;
6707
- }
6708
- visitFunctionCall(ast, context) {
6709
- const target = ast.target && ast.target.visit(this);
6710
- const args = this.visitAll(ast.args);
6711
- if (target !== ast.target || args !== ast.args) {
6712
- return new FunctionCall(ast.span, ast.sourceSpan, target, args);
6713
- }
6714
- return ast;
6715
- }
6716
6609
  visitLiteralArray(ast, context) {
6717
6610
  const expressions = this.visitAll(ast.expressions);
6718
6611
  if (expressions !== ast.expressions) {
@@ -6815,6 +6708,14 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
6815
6708
  }
6816
6709
  return ast;
6817
6710
  }
6711
+ visitCall(ast, context) {
6712
+ const receiver = ast.receiver.visit(this);
6713
+ const args = this.visitAll(ast.args);
6714
+ if (receiver !== ast.receiver || args !== ast.args) {
6715
+ return new Call(ast.span, ast.sourceSpan, receiver, args, ast.argumentSpan);
6716
+ }
6717
+ return ast;
6718
+ }
6818
6719
  visitQuote(ast, context) {
6819
6720
  return ast;
6820
6721
  }
@@ -7341,18 +7242,6 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
7341
7242
  visitPipe(ast, mode) {
7342
7243
  throw new Error(`Illegal state: Pipes should have been converted into functions. Pipe: ${ast.name}`);
7343
7244
  }
7344
- visitFunctionCall(ast, mode) {
7345
- const convertedArgs = this.visitAll(ast.args, _Mode.Expression);
7346
- let fnResult;
7347
- if (ast instanceof BuiltinFunctionCall) {
7348
- fnResult = ast.converter(convertedArgs);
7349
- }
7350
- else {
7351
- fnResult = this._visit(ast.target, _Mode.Expression)
7352
- .callFn(convertedArgs, this.convertSourceSpan(ast.span));
7353
- }
7354
- return convertToStatementIfNeeded(mode, fnResult);
7355
- }
7356
7245
  visitImplicitReceiver(ast, mode) {
7357
7246
  ensureExpressionMode(mode, ast);
7358
7247
  this.usesImplicitReceiver = true;
@@ -7417,40 +7306,6 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
7417
7306
  }
7418
7307
  return this._localResolver.getLocal(name);
7419
7308
  }
7420
- visitMethodCall(ast, mode) {
7421
- if (ast.receiver instanceof ImplicitReceiver &&
7422
- !(ast.receiver instanceof ThisReceiver) && ast.name === '$any') {
7423
- const args = this.visitAll(ast.args, _Mode.Expression);
7424
- if (args.length != 1) {
7425
- throw new Error(`Invalid call to $any, expected 1 argument but received ${args.length || 'none'}`);
7426
- }
7427
- return args[0].cast(DYNAMIC_TYPE, this.convertSourceSpan(ast.span));
7428
- }
7429
- const leftMostSafe = this.leftMostSafeNode(ast);
7430
- if (leftMostSafe) {
7431
- return this.convertSafeAccess(ast, leftMostSafe, mode);
7432
- }
7433
- else {
7434
- const args = this.visitAll(ast.args, _Mode.Expression);
7435
- const prevUsesImplicitReceiver = this.usesImplicitReceiver;
7436
- let result = null;
7437
- const receiver = this._visit(ast.receiver, _Mode.Expression);
7438
- if (receiver === this._implicitReceiver) {
7439
- const varExpr = this._getLocal(ast.name, ast.receiver);
7440
- if (varExpr) {
7441
- // Restore the previous "usesImplicitReceiver" state since the implicit
7442
- // receiver has been replaced with a resolved local expression.
7443
- this.usesImplicitReceiver = prevUsesImplicitReceiver;
7444
- result = varExpr.callFn(args);
7445
- this.addImplicitReceiverAccess(ast.name);
7446
- }
7447
- }
7448
- if (result == null) {
7449
- result = receiver.callMethod(ast.name, args, this.convertSourceSpan(ast.span));
7450
- }
7451
- return convertToStatementIfNeeded(mode, result);
7452
- }
7453
- }
7454
7309
  visitPrefixNot(ast, mode) {
7455
7310
  return convertToStatementIfNeeded(mode, not(this._visit(ast.expression, _Mode.Expression)));
7456
7311
  }
@@ -7476,7 +7331,7 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
7476
7331
  }
7477
7332
  }
7478
7333
  if (result == null) {
7479
- result = receiver.prop(ast.name);
7334
+ result = receiver.prop(ast.name, this.convertSourceSpan(ast.span));
7480
7335
  }
7481
7336
  return convertToStatementIfNeeded(mode, result);
7482
7337
  }
@@ -7509,16 +7364,13 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
7509
7364
  // If no local expression could be produced, use the original receiver's
7510
7365
  // property as the target.
7511
7366
  if (varExpr === null) {
7512
- varExpr = receiver.prop(ast.name);
7367
+ varExpr = receiver.prop(ast.name, this.convertSourceSpan(ast.span));
7513
7368
  }
7514
7369
  return convertToStatementIfNeeded(mode, varExpr.set(this._visit(ast.value, _Mode.Expression)));
7515
7370
  }
7516
7371
  visitSafePropertyRead(ast, mode) {
7517
7372
  return this.convertSafeAccess(ast, this.leftMostSafeNode(ast), mode);
7518
7373
  }
7519
- visitSafeMethodCall(ast, mode) {
7520
- return this.convertSafeAccess(ast, this.leftMostSafeNode(ast), mode);
7521
- }
7522
7374
  visitSafeKeyedRead(ast, mode) {
7523
7375
  return this.convertSafeAccess(ast, this.leftMostSafeNode(ast), mode);
7524
7376
  }
@@ -7529,6 +7381,29 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
7529
7381
  throw new Error(`Quotes are not supported for evaluation!
7530
7382
  Statement: ${ast.uninterpretedExpression} located at ${ast.location}`);
7531
7383
  }
7384
+ visitCall(ast, mode) {
7385
+ const convertedArgs = this.visitAll(ast.args, _Mode.Expression);
7386
+ if (ast instanceof BuiltinFunctionCall) {
7387
+ return convertToStatementIfNeeded(mode, ast.converter(convertedArgs));
7388
+ }
7389
+ const receiver = ast.receiver;
7390
+ if (receiver instanceof PropertyRead &&
7391
+ receiver.receiver instanceof ImplicitReceiver &&
7392
+ !(receiver.receiver instanceof ThisReceiver) && receiver.name === '$any') {
7393
+ if (convertedArgs.length !== 1) {
7394
+ throw new Error(`Invalid call to $any, expected 1 argument but received ${convertedArgs.length || 'none'}`);
7395
+ }
7396
+ return convertedArgs[0]
7397
+ .cast(DYNAMIC_TYPE, this.convertSourceSpan(ast.span));
7398
+ }
7399
+ const leftMostSafe = this.leftMostSafeNode(ast);
7400
+ if (leftMostSafe) {
7401
+ return this.convertSafeAccess(ast, leftMostSafe, mode);
7402
+ }
7403
+ const call = this._visit(receiver, _Mode.Expression)
7404
+ .callFn(convertedArgs, this.convertSourceSpan(ast.span));
7405
+ return convertToStatementIfNeeded(mode, call);
7406
+ }
7532
7407
  _visit(ast, mode) {
7533
7408
  const result = this._resultMap.get(ast);
7534
7409
  if (result)
@@ -7585,10 +7460,7 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
7585
7460
  const condition = guardedExpression.isBlank();
7586
7461
  // Convert the ast to an unguarded access to the receiver's member. The map will substitute
7587
7462
  // leftMostNode with its unguarded version in the call to `this.visit()`.
7588
- if (leftMostSafe instanceof SafeMethodCall) {
7589
- this._nodeMap.set(leftMostSafe, new MethodCall(leftMostSafe.span, leftMostSafe.sourceSpan, leftMostSafe.nameSpan, leftMostSafe.receiver, leftMostSafe.name, leftMostSafe.args, leftMostSafe.argumentSpan));
7590
- }
7591
- else if (leftMostSafe instanceof SafeKeyedRead) {
7463
+ if (leftMostSafe instanceof SafeKeyedRead) {
7592
7464
  this._nodeMap.set(leftMostSafe, new KeyedRead(leftMostSafe.span, leftMostSafe.sourceSpan, leftMostSafe.receiver, leftMostSafe.key));
7593
7465
  }
7594
7466
  else {
@@ -7644,8 +7516,8 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
7644
7516
  visitConditional(ast) {
7645
7517
  return null;
7646
7518
  },
7647
- visitFunctionCall(ast) {
7648
- return null;
7519
+ visitCall(ast) {
7520
+ return visit(this, ast.receiver);
7649
7521
  },
7650
7522
  visitImplicitReceiver(ast) {
7651
7523
  return null;
@@ -7671,9 +7543,6 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
7671
7543
  visitLiteralPrimitive(ast) {
7672
7544
  return null;
7673
7545
  },
7674
- visitMethodCall(ast) {
7675
- return visit(this, ast.receiver);
7676
- },
7677
7546
  visitPipe(ast) {
7678
7547
  return null;
7679
7548
  },
@@ -7692,9 +7561,6 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
7692
7561
  visitQuote(ast) {
7693
7562
  return null;
7694
7563
  },
7695
- visitSafeMethodCall(ast) {
7696
- return visit(this, ast.receiver) || ast;
7697
- },
7698
7564
  visitSafePropertyRead(ast) {
7699
7565
  return visit(this, ast.receiver) || ast;
7700
7566
  },
@@ -7726,7 +7592,7 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
7726
7592
  visitConditional(ast) {
7727
7593
  return visit(this, ast.condition) || visit(this, ast.trueExp) || visit(this, ast.falseExp);
7728
7594
  },
7729
- visitFunctionCall(ast) {
7595
+ visitCall(ast) {
7730
7596
  return true;
7731
7597
  },
7732
7598
  visitImplicitReceiver(ast) {
@@ -7753,9 +7619,6 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
7753
7619
  visitLiteralPrimitive(ast) {
7754
7620
  return false;
7755
7621
  },
7756
- visitMethodCall(ast) {
7757
- return true;
7758
- },
7759
7622
  visitPipe(ast) {
7760
7623
  return true;
7761
7624
  },
@@ -7774,9 +7637,6 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
7774
7637
  visitQuote(ast) {
7775
7638
  return false;
7776
7639
  },
7777
- visitSafeMethodCall(ast) {
7778
- return true;
7779
- },
7780
7640
  visitSafePropertyRead(ast) {
7781
7641
  return false;
7782
7642
  },
@@ -7861,9 +7721,9 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
7861
7721
  }
7862
7722
  return null;
7863
7723
  }
7864
- class BuiltinFunctionCall extends FunctionCall {
7724
+ class BuiltinFunctionCall extends Call {
7865
7725
  constructor(span, sourceSpan, args, converter) {
7866
- super(span, sourceSpan, null, args);
7726
+ super(span, sourceSpan, new EmptyExpr(span, sourceSpan), args, null);
7867
7727
  this.converter = converter;
7868
7728
  }
7869
7729
  }
@@ -8443,7 +8303,7 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
8443
8303
  const _polyfillHostRe = /-shadowcsshost/gim;
8444
8304
  const _colonHostRe = /:host/gim;
8445
8305
  const _colonHostContextRe = /:host-context/gim;
8446
- const _commentRe = /\/\*\s*[\s\S]*?\*\//g;
8306
+ const _commentRe = /\/\*[\s\S]*?\*\//g;
8447
8307
  function stripComments(input) {
8448
8308
  return input.replace(_commentRe, '');
8449
8309
  }
@@ -8654,9 +8514,10 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
8654
8514
  }
8655
8515
  }
8656
8516
  class Text$2 extends NodeWithI18n {
8657
- constructor(value, sourceSpan, i18n) {
8517
+ constructor(value, sourceSpan, tokens, i18n) {
8658
8518
  super(sourceSpan, i18n);
8659
8519
  this.value = value;
8520
+ this.tokens = tokens;
8660
8521
  }
8661
8522
  visit(visitor, context) {
8662
8523
  return visitor.visitText(this, context);
@@ -8687,12 +8548,13 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
8687
8548
  }
8688
8549
  }
8689
8550
  class Attribute extends NodeWithI18n {
8690
- constructor(name, value, sourceSpan, keySpan, valueSpan, i18n) {
8551
+ constructor(name, value, sourceSpan, keySpan, valueSpan, valueTokens, i18n) {
8691
8552
  super(sourceSpan, i18n);
8692
8553
  this.name = name;
8693
8554
  this.value = value;
8694
8555
  this.keySpan = keySpan;
8695
8556
  this.valueSpan = valueSpan;
8557
+ this.valueTokens = valueTokens;
8696
8558
  }
8697
8559
  visit(visitor, context) {
8698
8560
  return visitor.visitAttribute(this, context);
@@ -10884,38 +10746,6 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
10884
10746
  * Use of this source code is governed by an MIT-style license that can be
10885
10747
  * found in the LICENSE file at https://angular.io/license
10886
10748
  */
10887
- var TokenType;
10888
- (function (TokenType) {
10889
- TokenType[TokenType["TAG_OPEN_START"] = 0] = "TAG_OPEN_START";
10890
- TokenType[TokenType["TAG_OPEN_END"] = 1] = "TAG_OPEN_END";
10891
- TokenType[TokenType["TAG_OPEN_END_VOID"] = 2] = "TAG_OPEN_END_VOID";
10892
- TokenType[TokenType["TAG_CLOSE"] = 3] = "TAG_CLOSE";
10893
- TokenType[TokenType["INCOMPLETE_TAG_OPEN"] = 4] = "INCOMPLETE_TAG_OPEN";
10894
- TokenType[TokenType["TEXT"] = 5] = "TEXT";
10895
- TokenType[TokenType["ESCAPABLE_RAW_TEXT"] = 6] = "ESCAPABLE_RAW_TEXT";
10896
- TokenType[TokenType["RAW_TEXT"] = 7] = "RAW_TEXT";
10897
- TokenType[TokenType["COMMENT_START"] = 8] = "COMMENT_START";
10898
- TokenType[TokenType["COMMENT_END"] = 9] = "COMMENT_END";
10899
- TokenType[TokenType["CDATA_START"] = 10] = "CDATA_START";
10900
- TokenType[TokenType["CDATA_END"] = 11] = "CDATA_END";
10901
- TokenType[TokenType["ATTR_NAME"] = 12] = "ATTR_NAME";
10902
- TokenType[TokenType["ATTR_QUOTE"] = 13] = "ATTR_QUOTE";
10903
- TokenType[TokenType["ATTR_VALUE"] = 14] = "ATTR_VALUE";
10904
- TokenType[TokenType["DOC_TYPE"] = 15] = "DOC_TYPE";
10905
- TokenType[TokenType["EXPANSION_FORM_START"] = 16] = "EXPANSION_FORM_START";
10906
- TokenType[TokenType["EXPANSION_CASE_VALUE"] = 17] = "EXPANSION_CASE_VALUE";
10907
- TokenType[TokenType["EXPANSION_CASE_EXP_START"] = 18] = "EXPANSION_CASE_EXP_START";
10908
- TokenType[TokenType["EXPANSION_CASE_EXP_END"] = 19] = "EXPANSION_CASE_EXP_END";
10909
- TokenType[TokenType["EXPANSION_FORM_END"] = 20] = "EXPANSION_FORM_END";
10910
- TokenType[TokenType["EOF"] = 21] = "EOF";
10911
- })(TokenType || (TokenType = {}));
10912
- class Token {
10913
- constructor(type, parts, sourceSpan) {
10914
- this.type = type;
10915
- this.parts = parts;
10916
- this.sourceSpan = sourceSpan;
10917
- }
10918
- }
10919
10749
  class TokenError extends ParseError {
10920
10750
  constructor(errorMsg, tokenType, span) {
10921
10751
  super(span, errorMsg);
@@ -11022,14 +10852,16 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
11022
10852
  }
11023
10853
  }
11024
10854
  else if (!(this._tokenizeIcu && this._tokenizeExpansionForm())) {
11025
- this._consumeText();
10855
+ // In (possibly interpolated) text the end of the text is given by `isTextEnd()`, while
10856
+ // the premature end of an interpolation is given by the start of a new HTML element.
10857
+ this._consumeWithInterpolation(5 /* TEXT */, 8 /* INTERPOLATION */, () => this._isTextEnd(), () => this._isTagStart());
11026
10858
  }
11027
10859
  }
11028
10860
  catch (e) {
11029
10861
  this.handleError(e);
11030
10862
  }
11031
10863
  }
11032
- this._beginToken(TokenType.EOF);
10864
+ this._beginToken(24 /* EOF */);
11033
10865
  this._endToken([]);
11034
10866
  }
11035
10867
  /**
@@ -11068,7 +10900,11 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
11068
10900
  if (this._currentTokenType === null) {
11069
10901
  throw new TokenError('Programming error - attempted to end a token which has no token type', null, this._cursor.getSpan(this._currentTokenStart));
11070
10902
  }
11071
- const token = new Token(this._currentTokenType, parts, this._cursor.getSpan(this._currentTokenStart, this._leadingTriviaCodePoints));
10903
+ const token = {
10904
+ type: this._currentTokenType,
10905
+ parts,
10906
+ sourceSpan: (end !== null && end !== void 0 ? end : this._cursor).getSpan(this._currentTokenStart, this._leadingTriviaCodePoints),
10907
+ };
11072
10908
  this.tokens.push(token);
11073
10909
  this._currentTokenStart = null;
11074
10910
  this._currentTokenType = null;
@@ -11161,19 +10997,15 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
11161
10997
  this._cursor.advance();
11162
10998
  }
11163
10999
  }
11164
- _readChar(decodeEntities) {
11165
- if (decodeEntities && this._cursor.peek() === $AMPERSAND) {
11166
- return this._decodeEntity();
11167
- }
11168
- else {
11169
- // Don't rely upon reading directly from `_input` as the actual char value
11170
- // may have been generated from an escape sequence.
11171
- const char = String.fromCodePoint(this._cursor.peek());
11172
- this._cursor.advance();
11173
- return char;
11174
- }
11000
+ _readChar() {
11001
+ // Don't rely upon reading directly from `_input` as the actual char value
11002
+ // may have been generated from an escape sequence.
11003
+ const char = String.fromCodePoint(this._cursor.peek());
11004
+ this._cursor.advance();
11005
+ return char;
11175
11006
  }
11176
- _decodeEntity() {
11007
+ _consumeEntity(textTokenType) {
11008
+ this._beginToken(9 /* ENCODED_ENTITY */);
11177
11009
  const start = this._cursor.clone();
11178
11010
  this._cursor.advance();
11179
11011
  if (this._attemptCharCode($HASH)) {
@@ -11191,7 +11023,7 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
11191
11023
  this._cursor.advance();
11192
11024
  try {
11193
11025
  const charCode = parseInt(strNum, isHex ? 16 : 10);
11194
- return String.fromCharCode(charCode);
11026
+ this._endToken([String.fromCharCode(charCode), this._cursor.getChars(start)]);
11195
11027
  }
11196
11028
  catch (_a) {
11197
11029
  throw this._createError(_unknownEntityErrorMsg(this._cursor.getChars(start)), this._cursor.getSpan());
@@ -11201,20 +11033,25 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
11201
11033
  const nameStart = this._cursor.clone();
11202
11034
  this._attemptCharCodeUntilFn(isNamedEntityEnd);
11203
11035
  if (this._cursor.peek() != $SEMICOLON) {
11036
+ // No semicolon was found so abort the encoded entity token that was in progress, and treat
11037
+ // this as a text token
11038
+ this._beginToken(textTokenType, start);
11204
11039
  this._cursor = nameStart;
11205
- return '&';
11040
+ this._endToken(['&']);
11206
11041
  }
11207
- const name = this._cursor.getChars(nameStart);
11208
- this._cursor.advance();
11209
- const char = NAMED_ENTITIES[name];
11210
- if (!char) {
11211
- throw this._createError(_unknownEntityErrorMsg(name), this._cursor.getSpan(start));
11042
+ else {
11043
+ const name = this._cursor.getChars(nameStart);
11044
+ this._cursor.advance();
11045
+ const char = NAMED_ENTITIES[name];
11046
+ if (!char) {
11047
+ throw this._createError(_unknownEntityErrorMsg(name), this._cursor.getSpan(start));
11048
+ }
11049
+ this._endToken([char, `&${name};`]);
11212
11050
  }
11213
- return char;
11214
11051
  }
11215
11052
  }
11216
- _consumeRawText(decodeEntities, endMarkerPredicate) {
11217
- this._beginToken(decodeEntities ? TokenType.ESCAPABLE_RAW_TEXT : TokenType.RAW_TEXT);
11053
+ _consumeRawText(consumeEntities, endMarkerPredicate) {
11054
+ this._beginToken(consumeEntities ? 6 /* ESCAPABLE_RAW_TEXT */ : 7 /* RAW_TEXT */);
11218
11055
  const parts = [];
11219
11056
  while (true) {
11220
11057
  const tagCloseStart = this._cursor.clone();
@@ -11223,30 +11060,38 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
11223
11060
  if (foundEndMarker) {
11224
11061
  break;
11225
11062
  }
11226
- parts.push(this._readChar(decodeEntities));
11063
+ if (consumeEntities && this._cursor.peek() === $AMPERSAND) {
11064
+ this._endToken([this._processCarriageReturns(parts.join(''))]);
11065
+ parts.length = 0;
11066
+ this._consumeEntity(6 /* ESCAPABLE_RAW_TEXT */);
11067
+ this._beginToken(6 /* ESCAPABLE_RAW_TEXT */);
11068
+ }
11069
+ else {
11070
+ parts.push(this._readChar());
11071
+ }
11227
11072
  }
11228
- return this._endToken([this._processCarriageReturns(parts.join(''))]);
11073
+ this._endToken([this._processCarriageReturns(parts.join(''))]);
11229
11074
  }
11230
11075
  _consumeComment(start) {
11231
- this._beginToken(TokenType.COMMENT_START, start);
11076
+ this._beginToken(10 /* COMMENT_START */, start);
11232
11077
  this._requireCharCode($MINUS);
11233
11078
  this._endToken([]);
11234
11079
  this._consumeRawText(false, () => this._attemptStr('-->'));
11235
- this._beginToken(TokenType.COMMENT_END);
11080
+ this._beginToken(11 /* COMMENT_END */);
11236
11081
  this._requireStr('-->');
11237
11082
  this._endToken([]);
11238
11083
  }
11239
11084
  _consumeCdata(start) {
11240
- this._beginToken(TokenType.CDATA_START, start);
11085
+ this._beginToken(12 /* CDATA_START */, start);
11241
11086
  this._requireStr('CDATA[');
11242
11087
  this._endToken([]);
11243
11088
  this._consumeRawText(false, () => this._attemptStr(']]>'));
11244
- this._beginToken(TokenType.CDATA_END);
11089
+ this._beginToken(13 /* CDATA_END */);
11245
11090
  this._requireStr(']]>');
11246
11091
  this._endToken([]);
11247
11092
  }
11248
11093
  _consumeDocType(start) {
11249
- this._beginToken(TokenType.DOC_TYPE, start);
11094
+ this._beginToken(18 /* DOC_TYPE */, start);
11250
11095
  const contentStart = this._cursor.clone();
11251
11096
  this._attemptUntilChar($GT);
11252
11097
  const content = this._cursor.getChars(contentStart);
@@ -11300,12 +11145,12 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
11300
11145
  if (e instanceof _ControlFlowError) {
11301
11146
  if (openTagToken) {
11302
11147
  // We errored before we could close the opening tag, so it is incomplete.
11303
- openTagToken.type = TokenType.INCOMPLETE_TAG_OPEN;
11148
+ openTagToken.type = 4 /* INCOMPLETE_TAG_OPEN */;
11304
11149
  }
11305
11150
  else {
11306
11151
  // When the start tag is invalid, assume we want a "<" as text.
11307
11152
  // Back to back text tokens are merged at the end.
11308
- this._beginToken(TokenType.TEXT, start);
11153
+ this._beginToken(5 /* TEXT */, start);
11309
11154
  this._endToken(['<']);
11310
11155
  }
11311
11156
  return;
@@ -11320,8 +11165,8 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
11320
11165
  this._consumeRawTextWithTagClose(prefix, tagName, true);
11321
11166
  }
11322
11167
  }
11323
- _consumeRawTextWithTagClose(prefix, tagName, decodeEntities) {
11324
- this._consumeRawText(decodeEntities, () => {
11168
+ _consumeRawTextWithTagClose(prefix, tagName, consumeEntities) {
11169
+ this._consumeRawText(consumeEntities, () => {
11325
11170
  if (!this._attemptCharCode($LT))
11326
11171
  return false;
11327
11172
  if (!this._attemptCharCode($SLASH))
@@ -11332,13 +11177,13 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
11332
11177
  this._attemptCharCodeUntilFn(isNotWhitespace);
11333
11178
  return this._attemptCharCode($GT);
11334
11179
  });
11335
- this._beginToken(TokenType.TAG_CLOSE);
11180
+ this._beginToken(3 /* TAG_CLOSE */);
11336
11181
  this._requireCharCodeUntilFn(code => code === $GT, 3);
11337
11182
  this._cursor.advance(); // Consume the `>`
11338
11183
  this._endToken([prefix, tagName]);
11339
11184
  }
11340
11185
  _consumeTagOpenStart(start) {
11341
- this._beginToken(TokenType.TAG_OPEN_START, start);
11186
+ this._beginToken(0 /* TAG_OPEN_START */, start);
11342
11187
  const parts = this._consumePrefixAndName();
11343
11188
  return this._endToken(parts);
11344
11189
  }
@@ -11347,44 +11192,38 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
11347
11192
  if (attrNameStart === $SQ || attrNameStart === $DQ) {
11348
11193
  throw this._createError(_unexpectedCharacterErrorMsg(attrNameStart), this._cursor.getSpan());
11349
11194
  }
11350
- this._beginToken(TokenType.ATTR_NAME);
11195
+ this._beginToken(14 /* ATTR_NAME */);
11351
11196
  const prefixAndName = this._consumePrefixAndName();
11352
11197
  this._endToken(prefixAndName);
11353
11198
  }
11354
11199
  _consumeAttributeValue() {
11355
- let value;
11356
11200
  if (this._cursor.peek() === $SQ || this._cursor.peek() === $DQ) {
11357
- this._beginToken(TokenType.ATTR_QUOTE);
11358
11201
  const quoteChar = this._cursor.peek();
11359
- this._cursor.advance();
11360
- this._endToken([String.fromCodePoint(quoteChar)]);
11361
- this._beginToken(TokenType.ATTR_VALUE);
11362
- const parts = [];
11363
- while (this._cursor.peek() !== quoteChar) {
11364
- parts.push(this._readChar(true));
11365
- }
11366
- value = parts.join('');
11367
- this._endToken([this._processCarriageReturns(value)]);
11368
- this._beginToken(TokenType.ATTR_QUOTE);
11369
- this._cursor.advance();
11370
- this._endToken([String.fromCodePoint(quoteChar)]);
11202
+ this._consumeQuote(quoteChar);
11203
+ // In an attribute then end of the attribute value and the premature end to an interpolation
11204
+ // are both triggered by the `quoteChar`.
11205
+ const endPredicate = () => this._cursor.peek() === quoteChar;
11206
+ this._consumeWithInterpolation(16 /* ATTR_VALUE_TEXT */, 17 /* ATTR_VALUE_INTERPOLATION */, endPredicate, endPredicate);
11207
+ this._consumeQuote(quoteChar);
11371
11208
  }
11372
11209
  else {
11373
- this._beginToken(TokenType.ATTR_VALUE);
11374
- const valueStart = this._cursor.clone();
11375
- this._requireCharCodeUntilFn(isNameEnd, 1);
11376
- value = this._cursor.getChars(valueStart);
11377
- this._endToken([this._processCarriageReturns(value)]);
11210
+ const endPredicate = () => isNameEnd(this._cursor.peek());
11211
+ this._consumeWithInterpolation(16 /* ATTR_VALUE_TEXT */, 17 /* ATTR_VALUE_INTERPOLATION */, endPredicate, endPredicate);
11378
11212
  }
11379
11213
  }
11214
+ _consumeQuote(quoteChar) {
11215
+ this._beginToken(15 /* ATTR_QUOTE */);
11216
+ this._requireCharCode(quoteChar);
11217
+ this._endToken([String.fromCodePoint(quoteChar)]);
11218
+ }
11380
11219
  _consumeTagOpenEnd() {
11381
- const tokenType = this._attemptCharCode($SLASH) ? TokenType.TAG_OPEN_END_VOID : TokenType.TAG_OPEN_END;
11220
+ const tokenType = this._attemptCharCode($SLASH) ? 2 /* TAG_OPEN_END_VOID */ : 1 /* TAG_OPEN_END */;
11382
11221
  this._beginToken(tokenType);
11383
11222
  this._requireCharCode($GT);
11384
11223
  this._endToken([]);
11385
11224
  }
11386
11225
  _consumeTagClose(start) {
11387
- this._beginToken(TokenType.TAG_CLOSE, start);
11226
+ this._beginToken(3 /* TAG_CLOSE */, start);
11388
11227
  this._attemptCharCodeUntilFn(isNotWhitespace);
11389
11228
  const prefixAndName = this._consumePrefixAndName();
11390
11229
  this._attemptCharCodeUntilFn(isNotWhitespace);
@@ -11392,11 +11231,11 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
11392
11231
  this._endToken(prefixAndName);
11393
11232
  }
11394
11233
  _consumeExpansionFormStart() {
11395
- this._beginToken(TokenType.EXPANSION_FORM_START);
11234
+ this._beginToken(19 /* EXPANSION_FORM_START */);
11396
11235
  this._requireCharCode($LBRACE);
11397
11236
  this._endToken([]);
11398
- this._expansionCaseStack.push(TokenType.EXPANSION_FORM_START);
11399
- this._beginToken(TokenType.RAW_TEXT);
11237
+ this._expansionCaseStack.push(19 /* EXPANSION_FORM_START */);
11238
+ this._beginToken(7 /* RAW_TEXT */);
11400
11239
  const condition = this._readUntil($COMMA);
11401
11240
  const normalizedCondition = this._processCarriageReturns(condition);
11402
11241
  if (this._i18nNormalizeLineEndingsInICUs) {
@@ -11412,59 +11251,139 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
11412
11251
  }
11413
11252
  this._requireCharCode($COMMA);
11414
11253
  this._attemptCharCodeUntilFn(isNotWhitespace);
11415
- this._beginToken(TokenType.RAW_TEXT);
11254
+ this._beginToken(7 /* RAW_TEXT */);
11416
11255
  const type = this._readUntil($COMMA);
11417
11256
  this._endToken([type]);
11418
11257
  this._requireCharCode($COMMA);
11419
11258
  this._attemptCharCodeUntilFn(isNotWhitespace);
11420
11259
  }
11421
11260
  _consumeExpansionCaseStart() {
11422
- this._beginToken(TokenType.EXPANSION_CASE_VALUE);
11261
+ this._beginToken(20 /* EXPANSION_CASE_VALUE */);
11423
11262
  const value = this._readUntil($LBRACE).trim();
11424
11263
  this._endToken([value]);
11425
11264
  this._attemptCharCodeUntilFn(isNotWhitespace);
11426
- this._beginToken(TokenType.EXPANSION_CASE_EXP_START);
11265
+ this._beginToken(21 /* EXPANSION_CASE_EXP_START */);
11427
11266
  this._requireCharCode($LBRACE);
11428
11267
  this._endToken([]);
11429
11268
  this._attemptCharCodeUntilFn(isNotWhitespace);
11430
- this._expansionCaseStack.push(TokenType.EXPANSION_CASE_EXP_START);
11269
+ this._expansionCaseStack.push(21 /* EXPANSION_CASE_EXP_START */);
11431
11270
  }
11432
11271
  _consumeExpansionCaseEnd() {
11433
- this._beginToken(TokenType.EXPANSION_CASE_EXP_END);
11272
+ this._beginToken(22 /* EXPANSION_CASE_EXP_END */);
11434
11273
  this._requireCharCode($RBRACE);
11435
11274
  this._endToken([]);
11436
11275
  this._attemptCharCodeUntilFn(isNotWhitespace);
11437
11276
  this._expansionCaseStack.pop();
11438
11277
  }
11439
11278
  _consumeExpansionFormEnd() {
11440
- this._beginToken(TokenType.EXPANSION_FORM_END);
11279
+ this._beginToken(23 /* EXPANSION_FORM_END */);
11441
11280
  this._requireCharCode($RBRACE);
11442
11281
  this._endToken([]);
11443
11282
  this._expansionCaseStack.pop();
11444
11283
  }
11445
- _consumeText() {
11446
- const start = this._cursor.clone();
11447
- this._beginToken(TokenType.TEXT, start);
11284
+ /**
11285
+ * Consume a string that may contain interpolation expressions.
11286
+ *
11287
+ * The first token consumed will be of `tokenType` and then there will be alternating
11288
+ * `interpolationTokenType` and `tokenType` tokens until the `endPredicate()` returns true.
11289
+ *
11290
+ * If an interpolation token ends prematurely it will have no end marker in its `parts` array.
11291
+ *
11292
+ * @param textTokenType the kind of tokens to interleave around interpolation tokens.
11293
+ * @param interpolationTokenType the kind of tokens that contain interpolation.
11294
+ * @param endPredicate a function that should return true when we should stop consuming.
11295
+ * @param endInterpolation a function that should return true if there is a premature end to an
11296
+ * interpolation expression - i.e. before we get to the normal interpolation closing marker.
11297
+ */
11298
+ _consumeWithInterpolation(textTokenType, interpolationTokenType, endPredicate, endInterpolation) {
11299
+ this._beginToken(textTokenType);
11448
11300
  const parts = [];
11449
- do {
11301
+ while (!endPredicate()) {
11302
+ const current = this._cursor.clone();
11450
11303
  if (this._interpolationConfig && this._attemptStr(this._interpolationConfig.start)) {
11451
- parts.push(this._interpolationConfig.start);
11452
- this._inInterpolation = true;
11304
+ this._endToken([this._processCarriageReturns(parts.join(''))], current);
11305
+ parts.length = 0;
11306
+ this._consumeInterpolation(interpolationTokenType, current, endInterpolation);
11307
+ this._beginToken(textTokenType);
11453
11308
  }
11454
- else if (this._interpolationConfig && this._inInterpolation &&
11455
- this._attemptStr(this._interpolationConfig.end)) {
11456
- parts.push(this._interpolationConfig.end);
11457
- this._inInterpolation = false;
11309
+ else if (this._cursor.peek() === $AMPERSAND) {
11310
+ this._endToken([this._processCarriageReturns(parts.join(''))]);
11311
+ parts.length = 0;
11312
+ this._consumeEntity(textTokenType);
11313
+ this._beginToken(textTokenType);
11458
11314
  }
11459
11315
  else {
11460
- parts.push(this._readChar(true));
11316
+ parts.push(this._readChar());
11461
11317
  }
11462
- } while (!this._isTextEnd());
11318
+ }
11463
11319
  // It is possible that an interpolation was started but not ended inside this text token.
11464
11320
  // Make sure that we reset the state of the lexer correctly.
11465
11321
  this._inInterpolation = false;
11466
11322
  this._endToken([this._processCarriageReturns(parts.join(''))]);
11467
11323
  }
11324
+ /**
11325
+ * Consume a block of text that has been interpreted as an Angular interpolation.
11326
+ *
11327
+ * @param interpolationTokenType the type of the interpolation token to generate.
11328
+ * @param interpolationStart a cursor that points to the start of this interpolation.
11329
+ * @param prematureEndPredicate a function that should return true if the next characters indicate
11330
+ * an end to the interpolation before its normal closing marker.
11331
+ */
11332
+ _consumeInterpolation(interpolationTokenType, interpolationStart, prematureEndPredicate) {
11333
+ const parts = [];
11334
+ this._beginToken(interpolationTokenType, interpolationStart);
11335
+ parts.push(this._interpolationConfig.start);
11336
+ // Find the end of the interpolation, ignoring content inside quotes.
11337
+ const expressionStart = this._cursor.clone();
11338
+ let inQuote = null;
11339
+ let inComment = false;
11340
+ while (this._cursor.peek() !== $EOF &&
11341
+ (prematureEndPredicate === null || !prematureEndPredicate())) {
11342
+ const current = this._cursor.clone();
11343
+ if (this._isTagStart()) {
11344
+ // We are starting what looks like an HTML element in the middle of this interpolation.
11345
+ // Reset the cursor to before the `<` character and end the interpolation token.
11346
+ // (This is actually wrong but here for backward compatibility).
11347
+ this._cursor = current;
11348
+ parts.push(this._getProcessedChars(expressionStart, current));
11349
+ this._endToken(parts);
11350
+ return;
11351
+ }
11352
+ if (inQuote === null) {
11353
+ if (this._attemptStr(this._interpolationConfig.end)) {
11354
+ // We are not in a string, and we hit the end interpolation marker
11355
+ parts.push(this._getProcessedChars(expressionStart, current));
11356
+ parts.push(this._interpolationConfig.end);
11357
+ this._endToken(parts);
11358
+ return;
11359
+ }
11360
+ else if (this._attemptStr('//')) {
11361
+ // Once we are in a comment we ignore any quotes
11362
+ inComment = true;
11363
+ }
11364
+ }
11365
+ const char = this._cursor.peek();
11366
+ this._cursor.advance();
11367
+ if (char === $BACKSLASH) {
11368
+ // Skip the next character because it was escaped.
11369
+ this._cursor.advance();
11370
+ }
11371
+ else if (char === inQuote) {
11372
+ // Exiting the current quoted string
11373
+ inQuote = null;
11374
+ }
11375
+ else if (!inComment && inQuote === null && isQuote(char)) {
11376
+ // Entering a new quoted string
11377
+ inQuote = char;
11378
+ }
11379
+ }
11380
+ // We hit EOF without finding a closing interpolation marker
11381
+ parts.push(this._getProcessedChars(expressionStart, this._cursor));
11382
+ this._endToken(parts);
11383
+ }
11384
+ _getProcessedChars(start, end) {
11385
+ return this._processCarriageReturns(end.getChars(start));
11386
+ }
11468
11387
  _isTextEnd() {
11469
11388
  if (this._isTagStart() || this._cursor.peek() === $EOF) {
11470
11389
  return true;
@@ -11507,12 +11426,12 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
11507
11426
  _isInExpansionCase() {
11508
11427
  return this._expansionCaseStack.length > 0 &&
11509
11428
  this._expansionCaseStack[this._expansionCaseStack.length - 1] ===
11510
- TokenType.EXPANSION_CASE_EXP_START;
11429
+ 21 /* EXPANSION_CASE_EXP_START */;
11511
11430
  }
11512
11431
  _isInExpansionForm() {
11513
11432
  return this._expansionCaseStack.length > 0 &&
11514
11433
  this._expansionCaseStack[this._expansionCaseStack.length - 1] ===
11515
- TokenType.EXPANSION_FORM_START;
11434
+ 19 /* EXPANSION_FORM_START */;
11516
11435
  }
11517
11436
  isExpansionFormStart() {
11518
11437
  if (this._cursor.peek() !== $LBRACE) {
@@ -11559,7 +11478,9 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
11559
11478
  let lastDstToken = undefined;
11560
11479
  for (let i = 0; i < srcTokens.length; i++) {
11561
11480
  const token = srcTokens[i];
11562
- if (lastDstToken && lastDstToken.type === TokenType.TEXT && token.type === TokenType.TEXT) {
11481
+ if ((lastDstToken && lastDstToken.type === 5 /* TEXT */ && token.type === 5 /* TEXT */) ||
11482
+ (lastDstToken && lastDstToken.type === 16 /* ATTR_VALUE_TEXT */ &&
11483
+ token.type === 16 /* ATTR_VALUE_TEXT */)) {
11563
11484
  lastDstToken.parts[0] += token.parts[0];
11564
11485
  lastDstToken.sourceSpan.end = token.sourceSpan.end;
11565
11486
  }
@@ -11852,28 +11773,28 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
11852
11773
  this._advance();
11853
11774
  }
11854
11775
  build() {
11855
- while (this._peek.type !== TokenType.EOF) {
11856
- if (this._peek.type === TokenType.TAG_OPEN_START ||
11857
- this._peek.type === TokenType.INCOMPLETE_TAG_OPEN) {
11776
+ while (this._peek.type !== 24 /* EOF */) {
11777
+ if (this._peek.type === 0 /* TAG_OPEN_START */ ||
11778
+ this._peek.type === 4 /* INCOMPLETE_TAG_OPEN */) {
11858
11779
  this._consumeStartTag(this._advance());
11859
11780
  }
11860
- else if (this._peek.type === TokenType.TAG_CLOSE) {
11781
+ else if (this._peek.type === 3 /* TAG_CLOSE */) {
11861
11782
  this._consumeEndTag(this._advance());
11862
11783
  }
11863
- else if (this._peek.type === TokenType.CDATA_START) {
11784
+ else if (this._peek.type === 12 /* CDATA_START */) {
11864
11785
  this._closeVoidElement();
11865
11786
  this._consumeCdata(this._advance());
11866
11787
  }
11867
- else if (this._peek.type === TokenType.COMMENT_START) {
11788
+ else if (this._peek.type === 10 /* COMMENT_START */) {
11868
11789
  this._closeVoidElement();
11869
11790
  this._consumeComment(this._advance());
11870
11791
  }
11871
- else if (this._peek.type === TokenType.TEXT || this._peek.type === TokenType.RAW_TEXT ||
11872
- this._peek.type === TokenType.ESCAPABLE_RAW_TEXT) {
11792
+ else if (this._peek.type === 5 /* TEXT */ || this._peek.type === 7 /* RAW_TEXT */ ||
11793
+ this._peek.type === 6 /* ESCAPABLE_RAW_TEXT */) {
11873
11794
  this._closeVoidElement();
11874
11795
  this._consumeText(this._advance());
11875
11796
  }
11876
- else if (this._peek.type === TokenType.EXPANSION_FORM_START) {
11797
+ else if (this._peek.type === 19 /* EXPANSION_FORM_START */) {
11877
11798
  this._consumeExpansion(this._advance());
11878
11799
  }
11879
11800
  else {
@@ -11899,11 +11820,11 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
11899
11820
  }
11900
11821
  _consumeCdata(_startToken) {
11901
11822
  this._consumeText(this._advance());
11902
- this._advanceIf(TokenType.CDATA_END);
11823
+ this._advanceIf(13 /* CDATA_END */);
11903
11824
  }
11904
11825
  _consumeComment(token) {
11905
- const text = this._advanceIf(TokenType.RAW_TEXT);
11906
- this._advanceIf(TokenType.COMMENT_END);
11826
+ const text = this._advanceIf(7 /* RAW_TEXT */);
11827
+ this._advanceIf(11 /* COMMENT_END */);
11907
11828
  const value = text != null ? text.parts[0].trim() : null;
11908
11829
  this._addToParent(new Comment$1(value, token.sourceSpan));
11909
11830
  }
@@ -11912,14 +11833,14 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
11912
11833
  const type = this._advance();
11913
11834
  const cases = [];
11914
11835
  // read =
11915
- while (this._peek.type === TokenType.EXPANSION_CASE_VALUE) {
11836
+ while (this._peek.type === 20 /* EXPANSION_CASE_VALUE */) {
11916
11837
  const expCase = this._parseExpansionCase();
11917
11838
  if (!expCase)
11918
11839
  return; // error
11919
11840
  cases.push(expCase);
11920
11841
  }
11921
11842
  // read the final }
11922
- if (this._peek.type !== TokenType.EXPANSION_FORM_END) {
11843
+ if (this._peek.type !== 23 /* EXPANSION_FORM_END */) {
11923
11844
  this.errors.push(TreeError.create(null, this._peek.sourceSpan, `Invalid ICU message. Missing '}'.`));
11924
11845
  return;
11925
11846
  }
@@ -11930,7 +11851,7 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
11930
11851
  _parseExpansionCase() {
11931
11852
  const value = this._advance();
11932
11853
  // read {
11933
- if (this._peek.type !== TokenType.EXPANSION_CASE_EXP_START) {
11854
+ if (this._peek.type !== 21 /* EXPANSION_CASE_EXP_START */) {
11934
11855
  this.errors.push(TreeError.create(null, this._peek.sourceSpan, `Invalid ICU message. Missing '{'.`));
11935
11856
  return null;
11936
11857
  }
@@ -11940,7 +11861,7 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
11940
11861
  if (!exp)
11941
11862
  return null;
11942
11863
  const end = this._advance();
11943
- exp.push(new Token(TokenType.EOF, [], end.sourceSpan));
11864
+ exp.push({ type: 24 /* EOF */, parts: [], sourceSpan: end.sourceSpan });
11944
11865
  // parse everything in between { and }
11945
11866
  const expansionCaseParser = new _TreeBuilder(exp, this.getTagDefinition);
11946
11867
  expansionCaseParser.build();
@@ -11954,14 +11875,14 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
11954
11875
  }
11955
11876
  _collectExpansionExpTokens(start) {
11956
11877
  const exp = [];
11957
- const expansionFormStack = [TokenType.EXPANSION_CASE_EXP_START];
11878
+ const expansionFormStack = [21 /* EXPANSION_CASE_EXP_START */];
11958
11879
  while (true) {
11959
- if (this._peek.type === TokenType.EXPANSION_FORM_START ||
11960
- this._peek.type === TokenType.EXPANSION_CASE_EXP_START) {
11880
+ if (this._peek.type === 19 /* EXPANSION_FORM_START */ ||
11881
+ this._peek.type === 21 /* EXPANSION_CASE_EXP_START */) {
11961
11882
  expansionFormStack.push(this._peek.type);
11962
11883
  }
11963
- if (this._peek.type === TokenType.EXPANSION_CASE_EXP_END) {
11964
- if (lastOnStack(expansionFormStack, TokenType.EXPANSION_CASE_EXP_START)) {
11884
+ if (this._peek.type === 22 /* EXPANSION_CASE_EXP_END */) {
11885
+ if (lastOnStack(expansionFormStack, 21 /* EXPANSION_CASE_EXP_START */)) {
11965
11886
  expansionFormStack.pop();
11966
11887
  if (expansionFormStack.length === 0)
11967
11888
  return exp;
@@ -11971,8 +11892,8 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
11971
11892
  return null;
11972
11893
  }
11973
11894
  }
11974
- if (this._peek.type === TokenType.EXPANSION_FORM_END) {
11975
- if (lastOnStack(expansionFormStack, TokenType.EXPANSION_FORM_START)) {
11895
+ if (this._peek.type === 23 /* EXPANSION_FORM_END */) {
11896
+ if (lastOnStack(expansionFormStack, 19 /* EXPANSION_FORM_START */)) {
11976
11897
  expansionFormStack.pop();
11977
11898
  }
11978
11899
  else {
@@ -11980,7 +11901,7 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
11980
11901
  return null;
11981
11902
  }
11982
11903
  }
11983
- if (this._peek.type === TokenType.EOF) {
11904
+ if (this._peek.type === 24 /* EOF */) {
11984
11905
  this.errors.push(TreeError.create(null, start.sourceSpan, `Invalid ICU message. Missing '}'.`));
11985
11906
  return null;
11986
11907
  }
@@ -11988,16 +11909,38 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
11988
11909
  }
11989
11910
  }
11990
11911
  _consumeText(token) {
11912
+ const tokens = [token];
11913
+ const startSpan = token.sourceSpan;
11991
11914
  let text = token.parts[0];
11992
11915
  if (text.length > 0 && text[0] === '\n') {
11993
11916
  const parent = this._getParentElement();
11994
11917
  if (parent != null && parent.children.length === 0 &&
11995
11918
  this.getTagDefinition(parent.name).ignoreFirstLf) {
11996
11919
  text = text.substring(1);
11920
+ tokens[0] = { type: token.type, sourceSpan: token.sourceSpan, parts: [text] };
11921
+ }
11922
+ }
11923
+ while (this._peek.type === 8 /* INTERPOLATION */ || this._peek.type === 5 /* TEXT */ ||
11924
+ this._peek.type === 9 /* ENCODED_ENTITY */) {
11925
+ token = this._advance();
11926
+ tokens.push(token);
11927
+ if (token.type === 8 /* INTERPOLATION */) {
11928
+ // For backward compatibility we decode HTML entities that appear in interpolation
11929
+ // expressions. This is arguably a bug, but it could be a considerable breaking change to
11930
+ // fix it. It should be addressed in a larger project to refactor the entire parser/lexer
11931
+ // chain after View Engine has been removed.
11932
+ text += token.parts.join('').replace(/&([^;]+);/g, decodeEntity);
11933
+ }
11934
+ else if (token.type === 9 /* ENCODED_ENTITY */) {
11935
+ text += token.parts[0];
11936
+ }
11937
+ else {
11938
+ text += token.parts.join('');
11997
11939
  }
11998
11940
  }
11999
11941
  if (text.length > 0) {
12000
- this._addToParent(new Text$2(text, token.sourceSpan));
11942
+ const endSpan = token.sourceSpan;
11943
+ this._addToParent(new Text$2(text, new ParseSourceSpan(startSpan.start, endSpan.end, startSpan.fullStart, startSpan.details), tokens));
12001
11944
  }
12002
11945
  }
12003
11946
  _closeVoidElement() {
@@ -12009,14 +11952,14 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
12009
11952
  _consumeStartTag(startTagToken) {
12010
11953
  const [prefix, name] = startTagToken.parts;
12011
11954
  const attrs = [];
12012
- while (this._peek.type === TokenType.ATTR_NAME) {
11955
+ while (this._peek.type === 14 /* ATTR_NAME */) {
12013
11956
  attrs.push(this._consumeAttr(this._advance()));
12014
11957
  }
12015
11958
  const fullName = this._getElementFullName(prefix, name, this._getParentElement());
12016
11959
  let selfClosing = false;
12017
11960
  // Note: There could have been a tokenizer error
12018
11961
  // so that we don't get a token for the end tag...
12019
- if (this._peek.type === TokenType.TAG_OPEN_END_VOID) {
11962
+ if (this._peek.type === 2 /* TAG_OPEN_END_VOID */) {
12020
11963
  this._advance();
12021
11964
  selfClosing = true;
12022
11965
  const tagDef = this.getTagDefinition(fullName);
@@ -12024,7 +11967,7 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
12024
11967
  this.errors.push(TreeError.create(fullName, startTagToken.sourceSpan, `Only void and foreign elements can be self closed "${startTagToken.parts[1]}"`));
12025
11968
  }
12026
11969
  }
12027
- else if (this._peek.type === TokenType.TAG_OPEN_END) {
11970
+ else if (this._peek.type === 1 /* TAG_OPEN_END */) {
12028
11971
  this._advance();
12029
11972
  selfClosing = false;
12030
11973
  }
@@ -12039,7 +11982,7 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
12039
11982
  // element start tag also represents the end tag.
12040
11983
  this._popElement(fullName, span);
12041
11984
  }
12042
- else if (startTagToken.type === TokenType.INCOMPLETE_TAG_OPEN) {
11985
+ else if (startTagToken.type === 4 /* INCOMPLETE_TAG_OPEN */) {
12043
11986
  // We already know the opening tag is not complete, so it is unlikely it has a corresponding
12044
11987
  // close tag. Let's optimistically parse it as a full element and emit an error.
12045
11988
  this._popElement(fullName, null);
@@ -12094,24 +12037,53 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
12094
12037
  }
12095
12038
  _consumeAttr(attrName) {
12096
12039
  const fullName = mergeNsAndName(attrName.parts[0], attrName.parts[1]);
12097
- let end = attrName.sourceSpan.end;
12098
- let value = '';
12099
- let valueSpan = undefined;
12100
- if (this._peek.type === TokenType.ATTR_QUOTE) {
12040
+ let attrEnd = attrName.sourceSpan.end;
12041
+ // Consume any quote
12042
+ if (this._peek.type === 15 /* ATTR_QUOTE */) {
12101
12043
  this._advance();
12102
12044
  }
12103
- if (this._peek.type === TokenType.ATTR_VALUE) {
12104
- const valueToken = this._advance();
12105
- value = valueToken.parts[0];
12106
- end = valueToken.sourceSpan.end;
12107
- valueSpan = valueToken.sourceSpan;
12045
+ // Consume the attribute value
12046
+ let value = '';
12047
+ const valueTokens = [];
12048
+ let valueStartSpan = undefined;
12049
+ let valueEnd = undefined;
12050
+ // NOTE: We need to use a new variable `nextTokenType` here to hide the actual type of
12051
+ // `_peek.type` from TS. Otherwise TS will narrow the type of `_peek.type` preventing it from
12052
+ // being able to consider `ATTR_VALUE_INTERPOLATION` as an option. This is because TS is not
12053
+ // able to see that `_advance()` will actually mutate `_peek`.
12054
+ const nextTokenType = this._peek.type;
12055
+ if (nextTokenType === 16 /* ATTR_VALUE_TEXT */) {
12056
+ valueStartSpan = this._peek.sourceSpan;
12057
+ valueEnd = this._peek.sourceSpan.end;
12058
+ while (this._peek.type === 16 /* ATTR_VALUE_TEXT */ ||
12059
+ this._peek.type === 17 /* ATTR_VALUE_INTERPOLATION */ ||
12060
+ this._peek.type === 9 /* ENCODED_ENTITY */) {
12061
+ const valueToken = this._advance();
12062
+ valueTokens.push(valueToken);
12063
+ if (valueToken.type === 17 /* ATTR_VALUE_INTERPOLATION */) {
12064
+ // For backward compatibility we decode HTML entities that appear in interpolation
12065
+ // expressions. This is arguably a bug, but it could be a considerable breaking change to
12066
+ // fix it. It should be addressed in a larger project to refactor the entire parser/lexer
12067
+ // chain after View Engine has been removed.
12068
+ value += valueToken.parts.join('').replace(/&([^;]+);/g, decodeEntity);
12069
+ }
12070
+ else if (valueToken.type === 9 /* ENCODED_ENTITY */) {
12071
+ value += valueToken.parts[0];
12072
+ }
12073
+ else {
12074
+ value += valueToken.parts.join('');
12075
+ }
12076
+ valueEnd = attrEnd = valueToken.sourceSpan.end;
12077
+ }
12108
12078
  }
12109
- if (this._peek.type === TokenType.ATTR_QUOTE) {
12079
+ // Consume any quote
12080
+ if (this._peek.type === 15 /* ATTR_QUOTE */) {
12110
12081
  const quoteToken = this._advance();
12111
- end = quoteToken.sourceSpan.end;
12082
+ attrEnd = quoteToken.sourceSpan.end;
12112
12083
  }
12113
- const keySpan = new ParseSourceSpan(attrName.sourceSpan.start, attrName.sourceSpan.end);
12114
- return new Attribute(fullName, value, new ParseSourceSpan(attrName.sourceSpan.start, end, attrName.sourceSpan.fullStart), keySpan, valueSpan);
12084
+ const valueSpan = valueStartSpan && valueEnd &&
12085
+ new ParseSourceSpan(valueStartSpan.start, valueEnd, valueStartSpan.fullStart);
12086
+ return new Attribute(fullName, value, new ParseSourceSpan(attrName.sourceSpan.start, attrEnd, attrName.sourceSpan.fullStart), attrName.sourceSpan, valueSpan, valueTokens.length > 0 ? valueTokens : undefined, undefined);
12115
12087
  }
12116
12088
  _getParentElement() {
12117
12089
  return this._elementStack.length > 0 ? this._elementStack[this._elementStack.length - 1] : null;
@@ -12142,6 +12114,23 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
12142
12114
  function lastOnStack(stack, element) {
12143
12115
  return stack.length > 0 && stack[stack.length - 1] === element;
12144
12116
  }
12117
+ /**
12118
+ * Decode the `entity` string, which we believe is the contents of an HTML entity.
12119
+ *
12120
+ * If the string is not actually a valid/known entity then just return the original `match` string.
12121
+ */
12122
+ function decodeEntity(match, entity) {
12123
+ if (NAMED_ENTITIES[entity] !== undefined) {
12124
+ return NAMED_ENTITIES[entity] || match;
12125
+ }
12126
+ if (/^#x[a-f0-9]+$/i.test(entity)) {
12127
+ return String.fromCodePoint(parseInt(entity.slice(2), 16));
12128
+ }
12129
+ if (/^#\d+$/.test(entity)) {
12130
+ return String.fromCodePoint(parseInt(entity.slice(1), 10));
12131
+ }
12132
+ return match;
12133
+ }
12145
12134
 
12146
12135
  /**
12147
12136
  * @license
@@ -12217,7 +12206,11 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
12217
12206
  const hasExpansionSibling = context &&
12218
12207
  (context.prev instanceof Expansion || context.next instanceof Expansion);
12219
12208
  if (isNotBlank || hasExpansionSibling) {
12220
- return new Text$2(replaceNgsp(text.value).replace(WS_REPLACE_REGEXP, ' '), text.sourceSpan, text.i18n);
12209
+ // Process the whitespace in the tokens of this Text node
12210
+ const tokens = text.tokens.map(token => token.type === 5 /* TEXT */ ? createWhitespaceProcessedTextToken(token) : token);
12211
+ // Process the whitespace of the value of this Text node
12212
+ const value = processWhitespace(text.value);
12213
+ return new Text$2(value, text.sourceSpan, tokens, text.i18n);
12221
12214
  }
12222
12215
  return null;
12223
12216
  }
@@ -12231,6 +12224,12 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
12231
12224
  return expansionCase;
12232
12225
  }
12233
12226
  }
12227
+ function createWhitespaceProcessedTextToken({ type, parts, sourceSpan }) {
12228
+ return { type, parts: [processWhitespace(parts[0])], sourceSpan };
12229
+ }
12230
+ function processWhitespace(text) {
12231
+ return replaceNgsp(text).replace(WS_REPLACE_REGEXP, ' ');
12232
+ }
12234
12233
  function visitAllWithSiblings(visitor, nodes) {
12235
12234
  const result = [];
12236
12235
  nodes.forEach((ast, i) => {
@@ -13481,7 +13480,7 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
13481
13480
  * Use of this source code is governed by an MIT-style license that can be
13482
13481
  * found in the LICENSE file at https://angular.io/license
13483
13482
  */
13484
- var TokenType$1;
13483
+ var TokenType;
13485
13484
  (function (TokenType) {
13486
13485
  TokenType[TokenType["Character"] = 0] = "Character";
13487
13486
  TokenType[TokenType["Identifier"] = 1] = "Identifier";
@@ -13491,7 +13490,7 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
13491
13490
  TokenType[TokenType["Operator"] = 5] = "Operator";
13492
13491
  TokenType[TokenType["Number"] = 6] = "Number";
13493
13492
  TokenType[TokenType["Error"] = 7] = "Error";
13494
- })(TokenType$1 || (TokenType$1 = {}));
13493
+ })(TokenType || (TokenType = {}));
13495
13494
  const KEYWORDS = ['var', 'let', 'as', 'null', 'undefined', 'true', 'false', 'if', 'else', 'this'];
13496
13495
  class Lexer {
13497
13496
  tokenize(text) {
@@ -13505,7 +13504,7 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
13505
13504
  return tokens;
13506
13505
  }
13507
13506
  }
13508
- class Token$1 {
13507
+ class Token {
13509
13508
  constructor(index, end, type, numValue, strValue) {
13510
13509
  this.index = index;
13511
13510
  this.end = end;
@@ -13514,64 +13513,64 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
13514
13513
  this.strValue = strValue;
13515
13514
  }
13516
13515
  isCharacter(code) {
13517
- return this.type == TokenType$1.Character && this.numValue == code;
13516
+ return this.type == TokenType.Character && this.numValue == code;
13518
13517
  }
13519
13518
  isNumber() {
13520
- return this.type == TokenType$1.Number;
13519
+ return this.type == TokenType.Number;
13521
13520
  }
13522
13521
  isString() {
13523
- return this.type == TokenType$1.String;
13522
+ return this.type == TokenType.String;
13524
13523
  }
13525
13524
  isOperator(operator) {
13526
- return this.type == TokenType$1.Operator && this.strValue == operator;
13525
+ return this.type == TokenType.Operator && this.strValue == operator;
13527
13526
  }
13528
13527
  isIdentifier() {
13529
- return this.type == TokenType$1.Identifier;
13528
+ return this.type == TokenType.Identifier;
13530
13529
  }
13531
13530
  isPrivateIdentifier() {
13532
- return this.type == TokenType$1.PrivateIdentifier;
13531
+ return this.type == TokenType.PrivateIdentifier;
13533
13532
  }
13534
13533
  isKeyword() {
13535
- return this.type == TokenType$1.Keyword;
13534
+ return this.type == TokenType.Keyword;
13536
13535
  }
13537
13536
  isKeywordLet() {
13538
- return this.type == TokenType$1.Keyword && this.strValue == 'let';
13537
+ return this.type == TokenType.Keyword && this.strValue == 'let';
13539
13538
  }
13540
13539
  isKeywordAs() {
13541
- return this.type == TokenType$1.Keyword && this.strValue == 'as';
13540
+ return this.type == TokenType.Keyword && this.strValue == 'as';
13542
13541
  }
13543
13542
  isKeywordNull() {
13544
- return this.type == TokenType$1.Keyword && this.strValue == 'null';
13543
+ return this.type == TokenType.Keyword && this.strValue == 'null';
13545
13544
  }
13546
13545
  isKeywordUndefined() {
13547
- return this.type == TokenType$1.Keyword && this.strValue == 'undefined';
13546
+ return this.type == TokenType.Keyword && this.strValue == 'undefined';
13548
13547
  }
13549
13548
  isKeywordTrue() {
13550
- return this.type == TokenType$1.Keyword && this.strValue == 'true';
13549
+ return this.type == TokenType.Keyword && this.strValue == 'true';
13551
13550
  }
13552
13551
  isKeywordFalse() {
13553
- return this.type == TokenType$1.Keyword && this.strValue == 'false';
13552
+ return this.type == TokenType.Keyword && this.strValue == 'false';
13554
13553
  }
13555
13554
  isKeywordThis() {
13556
- return this.type == TokenType$1.Keyword && this.strValue == 'this';
13555
+ return this.type == TokenType.Keyword && this.strValue == 'this';
13557
13556
  }
13558
13557
  isError() {
13559
- return this.type == TokenType$1.Error;
13558
+ return this.type == TokenType.Error;
13560
13559
  }
13561
13560
  toNumber() {
13562
- return this.type == TokenType$1.Number ? this.numValue : -1;
13561
+ return this.type == TokenType.Number ? this.numValue : -1;
13563
13562
  }
13564
13563
  toString() {
13565
13564
  switch (this.type) {
13566
- case TokenType$1.Character:
13567
- case TokenType$1.Identifier:
13568
- case TokenType$1.Keyword:
13569
- case TokenType$1.Operator:
13570
- case TokenType$1.PrivateIdentifier:
13571
- case TokenType$1.String:
13572
- case TokenType$1.Error:
13565
+ case TokenType.Character:
13566
+ case TokenType.Identifier:
13567
+ case TokenType.Keyword:
13568
+ case TokenType.Operator:
13569
+ case TokenType.PrivateIdentifier:
13570
+ case TokenType.String:
13571
+ case TokenType.Error:
13573
13572
  return this.strValue;
13574
- case TokenType$1.Number:
13573
+ case TokenType.Number:
13575
13574
  return this.numValue.toString();
13576
13575
  default:
13577
13576
  return null;
@@ -13579,30 +13578,30 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
13579
13578
  }
13580
13579
  }
13581
13580
  function newCharacterToken(index, end, code) {
13582
- return new Token$1(index, end, TokenType$1.Character, code, String.fromCharCode(code));
13581
+ return new Token(index, end, TokenType.Character, code, String.fromCharCode(code));
13583
13582
  }
13584
13583
  function newIdentifierToken(index, end, text) {
13585
- return new Token$1(index, end, TokenType$1.Identifier, 0, text);
13584
+ return new Token(index, end, TokenType.Identifier, 0, text);
13586
13585
  }
13587
13586
  function newPrivateIdentifierToken(index, end, text) {
13588
- return new Token$1(index, end, TokenType$1.PrivateIdentifier, 0, text);
13587
+ return new Token(index, end, TokenType.PrivateIdentifier, 0, text);
13589
13588
  }
13590
13589
  function newKeywordToken(index, end, text) {
13591
- return new Token$1(index, end, TokenType$1.Keyword, 0, text);
13590
+ return new Token(index, end, TokenType.Keyword, 0, text);
13592
13591
  }
13593
13592
  function newOperatorToken(index, end, text) {
13594
- return new Token$1(index, end, TokenType$1.Operator, 0, text);
13593
+ return new Token(index, end, TokenType.Operator, 0, text);
13595
13594
  }
13596
13595
  function newStringToken(index, end, text) {
13597
- return new Token$1(index, end, TokenType$1.String, 0, text);
13596
+ return new Token(index, end, TokenType.String, 0, text);
13598
13597
  }
13599
13598
  function newNumberToken(index, end, n) {
13600
- return new Token$1(index, end, TokenType$1.Number, n, '');
13599
+ return new Token(index, end, TokenType.Number, n, '');
13601
13600
  }
13602
13601
  function newErrorToken(index, end, message) {
13603
- return new Token$1(index, end, TokenType$1.Error, 0, message);
13602
+ return new Token(index, end, TokenType.Error, 0, message);
13604
13603
  }
13605
- const EOF = new Token$1(-1, -1, TokenType$1.Character, 0, '');
13604
+ const EOF = new Token(-1, -1, TokenType.Character, 0, '');
13606
13605
  class _Scanner {
13607
13606
  constructor(input) {
13608
13607
  this.input = input;
@@ -14509,7 +14508,7 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
14509
14508
  // '==','!=','===','!=='
14510
14509
  const start = this.inputIndex;
14511
14510
  let result = this.parseRelational();
14512
- while (this.next.type == TokenType$1.Operator) {
14511
+ while (this.next.type == TokenType.Operator) {
14513
14512
  const operator = this.next.strValue;
14514
14513
  switch (operator) {
14515
14514
  case '==':
@@ -14529,7 +14528,7 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
14529
14528
  // '<', '>', '<=', '>='
14530
14529
  const start = this.inputIndex;
14531
14530
  let result = this.parseAdditive();
14532
- while (this.next.type == TokenType$1.Operator) {
14531
+ while (this.next.type == TokenType.Operator) {
14533
14532
  const operator = this.next.strValue;
14534
14533
  switch (operator) {
14535
14534
  case '<':
@@ -14549,7 +14548,7 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
14549
14548
  // '+', '-'
14550
14549
  const start = this.inputIndex;
14551
14550
  let result = this.parseMultiplicative();
14552
- while (this.next.type == TokenType$1.Operator) {
14551
+ while (this.next.type == TokenType.Operator) {
14553
14552
  const operator = this.next.strValue;
14554
14553
  switch (operator) {
14555
14554
  case '+':
@@ -14567,7 +14566,7 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
14567
14566
  // '*', '%', '/'
14568
14567
  const start = this.inputIndex;
14569
14568
  let result = this.parsePrefix();
14570
- while (this.next.type == TokenType$1.Operator) {
14569
+ while (this.next.type == TokenType.Operator) {
14571
14570
  const operator = this.next.strValue;
14572
14571
  switch (operator) {
14573
14572
  case '*':
@@ -14583,7 +14582,7 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
14583
14582
  return result;
14584
14583
  }
14585
14584
  parsePrefix() {
14586
- if (this.next.type == TokenType$1.Operator) {
14585
+ if (this.next.type == TokenType.Operator) {
14587
14586
  const start = this.inputIndex;
14588
14587
  const operator = this.next.strValue;
14589
14588
  let result;
@@ -14609,22 +14608,24 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
14609
14608
  let result = this.parsePrimary();
14610
14609
  while (true) {
14611
14610
  if (this.consumeOptionalCharacter($PERIOD)) {
14612
- result = this.parseAccessMemberOrMethodCall(result, start, false);
14611
+ result = this.parseAccessMemberOrCall(result, start, false);
14613
14612
  }
14614
14613
  else if (this.consumeOptionalOperator('?.')) {
14615
14614
  result = this.consumeOptionalCharacter($LBRACKET) ?
14616
14615
  this.parseKeyedReadOrWrite(result, start, true) :
14617
- this.parseAccessMemberOrMethodCall(result, start, true);
14616
+ this.parseAccessMemberOrCall(result, start, true);
14618
14617
  }
14619
14618
  else if (this.consumeOptionalCharacter($LBRACKET)) {
14620
14619
  result = this.parseKeyedReadOrWrite(result, start, false);
14621
14620
  }
14622
14621
  else if (this.consumeOptionalCharacter($LPAREN)) {
14622
+ const argumentStart = this.inputIndex;
14623
14623
  this.rparensExpected++;
14624
14624
  const args = this.parseCallArguments();
14625
+ const argumentSpan = this.span(argumentStart, this.inputIndex).toAbsolute(this.absoluteOffset);
14625
14626
  this.rparensExpected--;
14626
14627
  this.expectCharacter($RPAREN);
14627
- result = new FunctionCall(this.span(start), this.sourceSpan(start), result, args);
14628
+ result = new Call(this.span(start), this.sourceSpan(start), result, args, argumentSpan);
14628
14629
  }
14629
14630
  else if (this.consumeOptionalOperator('!')) {
14630
14631
  result = new NonNullAssert(this.span(start), this.sourceSpan(start), result);
@@ -14674,7 +14675,7 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
14674
14675
  return this.parseLiteralMap();
14675
14676
  }
14676
14677
  else if (this.next.isIdentifier()) {
14677
- return this.parseAccessMemberOrMethodCall(new ImplicitReceiver(this.span(start), this.sourceSpan(start)), start, false);
14678
+ return this.parseAccessMemberOrCall(new ImplicitReceiver(this.span(start), this.sourceSpan(start)), start, false);
14678
14679
  }
14679
14680
  else if (this.next.isNumber()) {
14680
14681
  const value = this.next.toNumber();
@@ -14742,17 +14743,41 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
14742
14743
  }
14743
14744
  return new LiteralMap(this.span(start), this.sourceSpan(start), keys, values);
14744
14745
  }
14745
- parseAccessMemberOrMethodCall(receiver, start, isSafe) {
14746
+ parseAccessMemberOrCall(readReceiver, start, isSafe) {
14746
14747
  const nameStart = this.inputIndex;
14747
14748
  const id = this.withContext(ParseContextFlags.Writable, () => {
14748
14749
  var _a;
14749
14750
  const id = (_a = this.expectIdentifierOrKeyword()) !== null && _a !== void 0 ? _a : '';
14750
14751
  if (id.length === 0) {
14751
- this.error(`Expected identifier for property access`, receiver.span.end);
14752
+ this.error(`Expected identifier for property access`, readReceiver.span.end);
14752
14753
  }
14753
14754
  return id;
14754
14755
  });
14755
14756
  const nameSpan = this.sourceSpan(nameStart);
14757
+ let receiver;
14758
+ if (isSafe) {
14759
+ if (this.consumeOptionalOperator('=')) {
14760
+ this.error('The \'?.\' operator cannot be used in the assignment');
14761
+ receiver = new EmptyExpr(this.span(start), this.sourceSpan(start));
14762
+ }
14763
+ else {
14764
+ receiver = new SafePropertyRead(this.span(start), this.sourceSpan(start), nameSpan, readReceiver, id);
14765
+ }
14766
+ }
14767
+ else {
14768
+ if (this.consumeOptionalOperator('=')) {
14769
+ if (!this.parseAction) {
14770
+ this.error('Bindings cannot contain assignments');
14771
+ return new EmptyExpr(this.span(start), this.sourceSpan(start));
14772
+ }
14773
+ const value = this.parseConditional();
14774
+ receiver = new PropertyWrite(this.span(start), this.sourceSpan(start), nameSpan, readReceiver, id, value);
14775
+ }
14776
+ else {
14777
+ receiver =
14778
+ new PropertyRead(this.span(start), this.sourceSpan(start), nameSpan, readReceiver, id);
14779
+ }
14780
+ }
14756
14781
  if (this.consumeOptionalCharacter($LPAREN)) {
14757
14782
  const argumentStart = this.inputIndex;
14758
14783
  this.rparensExpected++;
@@ -14762,34 +14787,9 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
14762
14787
  this.rparensExpected--;
14763
14788
  const span = this.span(start);
14764
14789
  const sourceSpan = this.sourceSpan(start);
14765
- return isSafe ?
14766
- new SafeMethodCall(span, sourceSpan, nameSpan, receiver, id, args, argumentSpan) :
14767
- new MethodCall(span, sourceSpan, nameSpan, receiver, id, args, argumentSpan);
14768
- }
14769
- else {
14770
- if (isSafe) {
14771
- if (this.consumeOptionalOperator('=')) {
14772
- this.error('The \'?.\' operator cannot be used in the assignment');
14773
- return new EmptyExpr(this.span(start), this.sourceSpan(start));
14774
- }
14775
- else {
14776
- return new SafePropertyRead(this.span(start), this.sourceSpan(start), nameSpan, receiver, id);
14777
- }
14778
- }
14779
- else {
14780
- if (this.consumeOptionalOperator('=')) {
14781
- if (!this.parseAction) {
14782
- this.error('Bindings cannot contain assignments');
14783
- return new EmptyExpr(this.span(start), this.sourceSpan(start));
14784
- }
14785
- const value = this.parseConditional();
14786
- return new PropertyWrite(this.span(start), this.sourceSpan(start), nameSpan, receiver, id, value);
14787
- }
14788
- else {
14789
- return new PropertyRead(this.span(start), this.sourceSpan(start), nameSpan, receiver, id);
14790
- }
14791
- }
14790
+ return new Call(span, sourceSpan, receiver, args, argumentSpan);
14792
14791
  }
14792
+ return receiver;
14793
14793
  }
14794
14794
  parseCallArguments() {
14795
14795
  if (this.next.isCharacter($RPAREN))
@@ -15085,9 +15085,7 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
15085
15085
  visitPropertyRead(ast, context) { }
15086
15086
  visitPropertyWrite(ast, context) { }
15087
15087
  visitSafePropertyRead(ast, context) { }
15088
- visitMethodCall(ast, context) { }
15089
- visitSafeMethodCall(ast, context) { }
15090
- visitFunctionCall(ast, context) { }
15088
+ visitCall(ast, context) { }
15091
15089
  visitLiteralArray(ast, context) {
15092
15090
  this.visitAll(ast.expressions, context);
15093
15091
  }
@@ -16515,11 +16513,15 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
16515
16513
  return context.visitNodeFn(el, node);
16516
16514
  }
16517
16515
  visitAttribute(attribute, context) {
16518
- const node = this._visitTextWithInterpolation(attribute.value, attribute.valueSpan || attribute.sourceSpan, context, attribute.i18n);
16516
+ const node = attribute.valueTokens === undefined || attribute.valueTokens.length === 1 ?
16517
+ new Text$1(attribute.value, attribute.valueSpan || attribute.sourceSpan) :
16518
+ this._visitTextWithInterpolation(attribute.valueTokens, attribute.valueSpan || attribute.sourceSpan, context, attribute.i18n);
16519
16519
  return context.visitNodeFn(attribute, node);
16520
16520
  }
16521
16521
  visitText(text, context) {
16522
- const node = this._visitTextWithInterpolation(text.value, text.sourceSpan, context, text.i18n);
16522
+ const node = text.tokens.length === 1 ?
16523
+ new Text$1(text.value, text.sourceSpan) :
16524
+ this._visitTextWithInterpolation(text.tokens, text.sourceSpan, context, text.i18n);
16523
16525
  return context.visitNodeFn(text, node);
16524
16526
  }
16525
16527
  visitComment(comment, context) {
@@ -16558,61 +16560,58 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
16558
16560
  throw new Error('Unreachable code');
16559
16561
  }
16560
16562
  /**
16561
- * Split the, potentially interpolated, text up into text and placeholder pieces.
16563
+ * Convert, text and interpolated tokens up into text and placeholder pieces.
16562
16564
  *
16563
- * @param text The potentially interpolated string to be split.
16565
+ * @param tokens The text and interpolated tokens.
16564
16566
  * @param sourceSpan The span of the whole of the `text` string.
16565
16567
  * @param context The current context of the visitor, used to compute and store placeholders.
16566
16568
  * @param previousI18n Any i18n metadata associated with this `text` from a previous pass.
16567
16569
  */
16568
- _visitTextWithInterpolation(text, sourceSpan, context, previousI18n) {
16569
- const { strings, expressions } = this._expressionParser.splitInterpolation(text, sourceSpan.start.toString(), this._interpolationConfig);
16570
- // No expressions, return a single text.
16571
- if (expressions.length === 0) {
16572
- return new Text$1(text, sourceSpan);
16573
- }
16570
+ _visitTextWithInterpolation(tokens, sourceSpan, context, previousI18n) {
16574
16571
  // Return a sequence of `Text` and `Placeholder` nodes grouped in a `Container`.
16575
16572
  const nodes = [];
16576
- for (let i = 0; i < strings.length - 1; i++) {
16577
- this._addText(nodes, strings[i], sourceSpan);
16578
- this._addPlaceholder(nodes, context, expressions[i], sourceSpan);
16573
+ // We will only create a container if there are actually interpolations,
16574
+ // so this flag tracks that.
16575
+ let hasInterpolation = false;
16576
+ for (const token of tokens) {
16577
+ switch (token.type) {
16578
+ case 8 /* INTERPOLATION */:
16579
+ case 17 /* ATTR_VALUE_INTERPOLATION */:
16580
+ hasInterpolation = true;
16581
+ const expression = token.parts[1];
16582
+ const baseName = extractPlaceholderName(expression) || 'INTERPOLATION';
16583
+ const phName = context.placeholderRegistry.getPlaceholderName(baseName, expression);
16584
+ context.placeholderToContent[phName] = {
16585
+ text: token.parts.join(''),
16586
+ sourceSpan: token.sourceSpan
16587
+ };
16588
+ nodes.push(new Placeholder(expression, phName, token.sourceSpan));
16589
+ break;
16590
+ default:
16591
+ if (token.parts[0].length > 0) {
16592
+ // This token is text or an encoded entity.
16593
+ // If it is following on from a previous text node then merge it into that node
16594
+ // Otherwise, if it is following an interpolation, then add a new node.
16595
+ const previous = nodes[nodes.length - 1];
16596
+ if (previous instanceof Text$1) {
16597
+ previous.value += token.parts[0];
16598
+ previous.sourceSpan = new ParseSourceSpan(previous.sourceSpan.start, token.sourceSpan.end, previous.sourceSpan.fullStart, previous.sourceSpan.details);
16599
+ }
16600
+ else {
16601
+ nodes.push(new Text$1(token.parts[0], token.sourceSpan));
16602
+ }
16603
+ }
16604
+ break;
16605
+ }
16579
16606
  }
16580
- // The last index contains no expression
16581
- this._addText(nodes, strings[strings.length - 1], sourceSpan);
16582
- // Whitespace removal may have invalidated the interpolation source-spans.
16583
- reusePreviousSourceSpans(nodes, previousI18n);
16584
- return new Container(nodes, sourceSpan);
16585
- }
16586
- /**
16587
- * Create a new `Text` node from the `textPiece` and add it to the `nodes` collection.
16588
- *
16589
- * @param nodes The nodes to which the created `Text` node should be added.
16590
- * @param textPiece The text and relative span information for this `Text` node.
16591
- * @param interpolationSpan The span of the whole interpolated text.
16592
- */
16593
- _addText(nodes, textPiece, interpolationSpan) {
16594
- if (textPiece.text.length > 0) {
16595
- // No need to add empty strings
16596
- const stringSpan = getOffsetSourceSpan(interpolationSpan, textPiece);
16597
- nodes.push(new Text$1(textPiece.text, stringSpan));
16607
+ if (hasInterpolation) {
16608
+ // Whitespace removal may have invalidated the interpolation source-spans.
16609
+ reusePreviousSourceSpans(nodes, previousI18n);
16610
+ return new Container(nodes, sourceSpan);
16611
+ }
16612
+ else {
16613
+ return nodes[0];
16598
16614
  }
16599
- }
16600
- /**
16601
- * Create a new `Placeholder` node from the `expression` and add it to the `nodes` collection.
16602
- *
16603
- * @param nodes The nodes to which the created `Text` node should be added.
16604
- * @param context The current context of the visitor, used to compute and store placeholders.
16605
- * @param expression The expression text and relative span information for this `Placeholder`
16606
- * node.
16607
- * @param interpolationSpan The span of the whole interpolated text.
16608
- */
16609
- _addPlaceholder(nodes, context, expression, interpolationSpan) {
16610
- const sourceSpan = getOffsetSourceSpan(interpolationSpan, expression);
16611
- const baseName = extractPlaceholderName(expression.text) || 'INTERPOLATION';
16612
- const phName = context.placeholderRegistry.getPlaceholderName(baseName, expression.text);
16613
- const text = this._interpolationConfig.start + expression.text + this._interpolationConfig.end;
16614
- context.placeholderToContent[phName] = { text, sourceSpan };
16615
- nodes.push(new Placeholder(expression.text, phName, sourceSpan));
16616
16615
  }
16617
16616
  }
16618
16617
  /**
@@ -16634,7 +16633,7 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
16634
16633
  }
16635
16634
  if (previousI18n instanceof Container) {
16636
16635
  // The `previousI18n` is a `Container`, which means that this is a second i18n extraction pass
16637
- // after whitespace has been removed from the AST ndoes.
16636
+ // after whitespace has been removed from the AST nodes.
16638
16637
  assertEquivalentNodes(previousI18n.children, nodes);
16639
16638
  // Reuse the source-spans from the first pass.
16640
16639
  for (let i = 0; i < nodes.length; i++) {
@@ -16663,12 +16662,6 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
16663
16662
  throw new Error('The types of the i18n message children changed between first and second pass.');
16664
16663
  }
16665
16664
  }
16666
- /**
16667
- * Create a new `ParseSourceSpan` from the `sourceSpan`, offset by the `start` and `end` values.
16668
- */
16669
- function getOffsetSourceSpan(sourceSpan, { start, end }) {
16670
- return new ParseSourceSpan(sourceSpan.fullStart.moveBy(start), sourceSpan.fullStart.moveBy(end));
16671
- }
16672
16665
  const _CUSTOM_PH_EXP = /\/\/[\s\S]*i18n[\s\S]*\([\s\S]*ph[\s\S]*=[\s\S]*("|')([\s\S]*?)\1[\s\S]*\)/g;
16673
16666
  function extractPlaceholderName(input) {
16674
16667
  return input.split(_CUSTOM_PH_EXP)[2];
@@ -16988,7 +16981,8 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
16988
16981
  context[context.length - 1].text += text.value;
16989
16982
  }
16990
16983
  else {
16991
- context.push(new LiteralPiece(text.value, text.sourceSpan));
16984
+ const sourceSpan = new ParseSourceSpan(text.sourceSpan.fullStart, text.sourceSpan.end, text.sourceSpan.fullStart, text.sourceSpan.details);
16985
+ context.push(new LiteralPiece(text.value, sourceSpan));
16992
16986
  }
16993
16987
  }
16994
16988
  visitContainer(container, context) {
@@ -17032,7 +17026,7 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
17032
17026
  function getSourceSpan(message) {
17033
17027
  const startNode = message.nodes[0];
17034
17028
  const endNode = message.nodes[message.nodes.length - 1];
17035
- return new ParseSourceSpan(startNode.sourceSpan.start, endNode.sourceSpan.end, startNode.sourceSpan.fullStart, startNode.sourceSpan.details);
17029
+ return new ParseSourceSpan(startNode.sourceSpan.fullStart, endNode.sourceSpan.end, startNode.sourceSpan.fullStart, startNode.sourceSpan.details);
17036
17030
  }
17037
17031
  /**
17038
17032
  * Convert the list of serialized MessagePieces into two arrays.
@@ -18266,11 +18260,11 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
18266
18260
  const convertedArgs = isVarLength ?
18267
18261
  this.visitAll([new LiteralArray(pipe.span, pipe.sourceSpan, args)]) :
18268
18262
  this.visitAll(args);
18269
- const pipeBindExpr = new FunctionCall(pipe.span, pipe.sourceSpan, target, [
18263
+ const pipeBindExpr = new Call(pipe.span, pipe.sourceSpan, target, [
18270
18264
  new LiteralPrimitive(pipe.span, pipe.sourceSpan, slot),
18271
18265
  new LiteralPrimitive(pipe.span, pipe.sourceSpan, pureFunctionSlot),
18272
18266
  ...convertedArgs,
18273
- ]);
18267
+ ], null);
18274
18268
  this._pipeBindExprs.push(pipeBindExpr);
18275
18269
  return pipeBindExpr;
18276
18270
  }
@@ -19065,7 +19059,7 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
19065
19059
  return fn([], [new ReturnStatement(list)]);
19066
19060
  case 2 /* ClosureResolved */:
19067
19061
  // directives: function () { return [MyDir].map(ng.resolveForwardRef); }
19068
- const resolvedList = list.callMethod('map', [importExpr(Identifiers.resolveForwardRef)]);
19062
+ const resolvedList = list.prop('map').callFn([importExpr(Identifiers.resolveForwardRef)]);
19069
19063
  return fn([], [new ReturnStatement(resolvedList)]);
19070
19064
  }
19071
19065
  }
@@ -19938,7 +19932,7 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
19938
19932
  * Use of this source code is governed by an MIT-style license that can be
19939
19933
  * found in the LICENSE file at https://angular.io/license
19940
19934
  */
19941
- const VERSION$1 = new Version('13.0.0-next.3');
19935
+ const VERSION$1 = new Version('13.0.0-next.7');
19942
19936
 
19943
19937
  /**
19944
19938
  * @license
@@ -20436,14 +20430,6 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
20436
20430
  this.maybeMap(context, ast, ast.name);
20437
20431
  return super.visitPropertyWrite(ast, context);
20438
20432
  }
20439
- visitMethodCall(ast, context) {
20440
- this.maybeMap(context, ast, ast.name);
20441
- return super.visitMethodCall(ast, context);
20442
- }
20443
- visitSafeMethodCall(ast, context) {
20444
- this.maybeMap(context, ast, ast.name);
20445
- return super.visitSafeMethodCall(ast, context);
20446
- }
20447
20433
  maybeMap(scope, ast, name) {
20448
20434
  // If the receiver of the expression isn't the `ImplicitReceiver`, this isn't the root of an
20449
20435
  // `AST` expression that maps to a `Variable` or `Reference`.
@@ -20577,7 +20563,7 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
20577
20563
  function compileDeclareClassMetadata(metadata) {
20578
20564
  const definitionMap = new DefinitionMap();
20579
20565
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION));
20580
- definitionMap.set('version', literal('13.0.0-next.3'));
20566
+ definitionMap.set('version', literal('13.0.0-next.7'));
20581
20567
  definitionMap.set('ngImport', importExpr(Identifiers.core));
20582
20568
  definitionMap.set('type', metadata.type);
20583
20569
  definitionMap.set('decorators', metadata.decorators);
@@ -20617,7 +20603,7 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
20617
20603
  function createDirectiveDefinitionMap(meta) {
20618
20604
  const definitionMap = new DefinitionMap();
20619
20605
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$1));
20620
- definitionMap.set('version', literal('13.0.0-next.3'));
20606
+ definitionMap.set('version', literal('13.0.0-next.7'));
20621
20607
  // e.g. `type: MyDirective`
20622
20608
  definitionMap.set('type', meta.internalType);
20623
20609
  // e.g. `selector: 'some-dir'`
@@ -20834,7 +20820,7 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
20834
20820
  function compileDeclareFactoryFunction(meta) {
20835
20821
  const definitionMap = new DefinitionMap();
20836
20822
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$2));
20837
- definitionMap.set('version', literal('13.0.0-next.3'));
20823
+ definitionMap.set('version', literal('13.0.0-next.7'));
20838
20824
  definitionMap.set('ngImport', importExpr(Identifiers.core));
20839
20825
  definitionMap.set('type', meta.internalType);
20840
20826
  definitionMap.set('deps', compileDependencies(meta.deps));
@@ -20876,7 +20862,7 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
20876
20862
  function createInjectableDefinitionMap(meta) {
20877
20863
  const definitionMap = new DefinitionMap();
20878
20864
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$3));
20879
- definitionMap.set('version', literal('13.0.0-next.3'));
20865
+ definitionMap.set('version', literal('13.0.0-next.7'));
20880
20866
  definitionMap.set('ngImport', importExpr(Identifiers.core));
20881
20867
  definitionMap.set('type', meta.internalType);
20882
20868
  // Only generate providedIn property if it has a non-null value
@@ -20955,7 +20941,7 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
20955
20941
  function createInjectorDefinitionMap(meta) {
20956
20942
  const definitionMap = new DefinitionMap();
20957
20943
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$4));
20958
- definitionMap.set('version', literal('13.0.0-next.3'));
20944
+ definitionMap.set('version', literal('13.0.0-next.7'));
20959
20945
  definitionMap.set('ngImport', importExpr(Identifiers.core));
20960
20946
  definitionMap.set('type', meta.internalType);
20961
20947
  definitionMap.set('providers', meta.providers);
@@ -20992,7 +20978,7 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
20992
20978
  function createNgModuleDefinitionMap(meta) {
20993
20979
  const definitionMap = new DefinitionMap();
20994
20980
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$5));
20995
- definitionMap.set('version', literal('13.0.0-next.3'));
20981
+ definitionMap.set('version', literal('13.0.0-next.7'));
20996
20982
  definitionMap.set('ngImport', importExpr(Identifiers.core));
20997
20983
  definitionMap.set('type', meta.internalType);
20998
20984
  // We only generate the keys in the metadata if the arrays contain values.
@@ -21050,7 +21036,7 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
21050
21036
  function createPipeDefinitionMap(meta) {
21051
21037
  const definitionMap = new DefinitionMap();
21052
21038
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$6));
21053
- definitionMap.set('version', literal('13.0.0-next.3'));
21039
+ definitionMap.set('version', literal('13.0.0-next.7'));
21054
21040
  definitionMap.set('ngImport', importExpr(Identifiers.core));
21055
21041
  // e.g. `type: MyPipe`
21056
21042
  definitionMap.set('type', meta.internalType);
@@ -21082,7 +21068,7 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
21082
21068
  * Use of this source code is governed by an MIT-style license that can be
21083
21069
  * found in the LICENSE file at https://angular.io/license
21084
21070
  */
21085
- const VERSION$2 = new Version('13.0.0-next.3');
21071
+ const VERSION$2 = new Version('13.0.0-next.7');
21086
21072
 
21087
21073
  /**
21088
21074
  * @license
@@ -21294,6 +21280,15 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
21294
21280
  * ```
21295
21281
  */
21296
21282
  ErrorCode[ErrorCode["INVALID_BANANA_IN_BOX"] = 8101] = "INVALID_BANANA_IN_BOX";
21283
+ /**
21284
+ * The left side of a nullish coalescing operation is not nullable.
21285
+ *
21286
+ * ```
21287
+ * {{ foo ?? bar }}
21288
+ * ```
21289
+ * When the type of foo doesn't include `null` or `undefined`.
21290
+ */
21291
+ ErrorCode[ErrorCode["NULLISH_COALESCING_NOT_NULLABLE"] = 8102] = "NULLISH_COALESCING_NOT_NULLABLE";
21297
21292
  /**
21298
21293
  * The template type-checking engine would need to generate an inline type check block for a
21299
21294
  * component, but the current type-checking environment doesn't support it.
@@ -23210,11 +23205,11 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
23210
23205
  getAdjacentNameOfClass(clazz) {
23211
23206
  return clazz.name;
23212
23207
  }
23213
- isStaticallyExported(clazz) {
23214
- // First check if there's an `export` modifier directly on the class declaration.
23215
- let topLevel = clazz;
23216
- if (ts$1.isVariableDeclaration(clazz) && ts$1.isVariableDeclarationList(clazz.parent)) {
23217
- topLevel = clazz.parent.parent;
23208
+ isStaticallyExported(decl) {
23209
+ // First check if there's an `export` modifier directly on the declaration.
23210
+ let topLevel = decl;
23211
+ if (ts$1.isVariableDeclaration(decl) && ts$1.isVariableDeclarationList(decl.parent)) {
23212
+ topLevel = decl.parent.parent;
23218
23213
  }
23219
23214
  if (topLevel.modifiers !== undefined &&
23220
23215
  topLevel.modifiers.some(modifier => modifier.kind === ts$1.SyntaxKind.ExportKeyword)) {
@@ -23233,8 +23228,8 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
23233
23228
  if (topLevel.parent === undefined || !ts$1.isSourceFile(topLevel.parent)) {
23234
23229
  return false;
23235
23230
  }
23236
- const localExports = this.getLocalExportedClassesOfSourceFile(clazz.getSourceFile());
23237
- return localExports.has(clazz);
23231
+ const localExports = this.getLocalExportedDeclarationsOfSourceFile(decl.getSourceFile());
23232
+ return localExports.has(decl);
23238
23233
  }
23239
23234
  getDirectImportOfIdentifier(id) {
23240
23235
  const symbol = this.checker.getSymbolAtLocation(id);
@@ -23437,16 +23432,16 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
23437
23432
  };
23438
23433
  }
23439
23434
  /**
23440
- * Get the set of classes declared in `file` which are exported.
23435
+ * Get the set of declarations declared in `file` which are exported.
23441
23436
  */
23442
- getLocalExportedClassesOfSourceFile(file) {
23437
+ getLocalExportedDeclarationsOfSourceFile(file) {
23443
23438
  const cacheSf = file;
23444
- if (cacheSf[LocalExportedClasses] !== undefined) {
23439
+ if (cacheSf[LocalExportedDeclarations] !== undefined) {
23445
23440
  // TS does not currently narrow symbol-keyed fields, hence the non-null assert is needed.
23446
- return cacheSf[LocalExportedClasses];
23441
+ return cacheSf[LocalExportedDeclarations];
23447
23442
  }
23448
23443
  const exportSet = new Set();
23449
- cacheSf[LocalExportedClasses] = exportSet;
23444
+ cacheSf[LocalExportedDeclarations] = exportSet;
23450
23445
  const sfSymbol = this.checker.getSymbolAtLocation(cacheSf);
23451
23446
  if (sfSymbol === undefined || sfSymbol.exports === undefined) {
23452
23447
  return exportSet;
@@ -23471,8 +23466,7 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
23471
23466
  exportedSymbol = this.checker.getAliasedSymbol(exportedSymbol);
23472
23467
  }
23473
23468
  if (exportedSymbol.valueDeclaration !== undefined &&
23474
- exportedSymbol.valueDeclaration.getSourceFile() === file &&
23475
- this.isClass(exportedSymbol.valueDeclaration)) {
23469
+ exportedSymbol.valueDeclaration.getSourceFile() === file) {
23476
23470
  exportSet.add(exportedSymbol.valueDeclaration);
23477
23471
  }
23478
23472
  item = iter.next();
@@ -23631,7 +23625,7 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
23631
23625
  (decl.propertyName !== undefined ? decl.propertyName : decl.name).text :
23632
23626
  originalId.text;
23633
23627
  }
23634
- const LocalExportedClasses = Symbol('LocalExportedClasses');
23628
+ const LocalExportedDeclarations = Symbol('LocalExportedDeclarations');
23635
23629
 
23636
23630
  /**
23637
23631
  * @license
@@ -26858,11 +26852,6 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
26858
26852
  const target = this.factory.createPropertyAccess(expr.receiver.visitExpression(this, context), expr.name);
26859
26853
  return this.factory.createAssignment(target, expr.value.visitExpression(this, context));
26860
26854
  }
26861
- visitInvokeMethodExpr(ast, context) {
26862
- const target = ast.receiver.visitExpression(this, context);
26863
- return this.setSourceMapRange(this.factory.createCallExpression(ast.name !== null ? this.factory.createPropertyAccess(target, ast.name) : target, ast.args.map(arg => arg.visitExpression(this, context)),
26864
- /* pure */ false), ast.sourceSpan);
26865
- }
26866
26855
  visitInvokeFunctionExpr(ast, context) {
26867
26856
  return this.setSourceMapRange(this.factory.createCallExpression(ast.fn.visitExpression(this, context), ast.args.map(arg => arg.visitExpression(this, context)), ast.pure), ast.sourceSpan);
26868
26857
  }
@@ -27157,9 +27146,6 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
27157
27146
  visitWritePropExpr(expr, context) {
27158
27147
  throw new Error('Method not implemented.');
27159
27148
  }
27160
- visitInvokeMethodExpr(ast, context) {
27161
- throw new Error('Method not implemented.');
27162
- }
27163
27149
  visitInvokeFunctionExpr(ast, context) {
27164
27150
  throw new Error('Method not implemented.');
27165
27151
  }
@@ -32868,10 +32854,6 @@ Either add the @Injectable() decorator to '${provider.node.name
32868
32854
  visit(ast) {
32869
32855
  ast.visit(this);
32870
32856
  }
32871
- visitMethodCall(ast, context) {
32872
- this.visitIdentifier(ast, IdentifierKind.Method);
32873
- super.visitMethodCall(ast, context);
32874
- }
32875
32857
  visitPropertyRead(ast, context) {
32876
32858
  this.visitIdentifier(ast, IdentifierKind.Property);
32877
32859
  super.visitPropertyRead(ast, context);
@@ -34992,15 +34974,14 @@ Either add the @Injectable() decorator to '${provider.node.name
34992
34974
  }
34993
34975
  // Completion works inside property reads and method calls.
34994
34976
  let tsExpr = null;
34995
- if (expr instanceof PropertyRead || expr instanceof MethodCall ||
34996
- expr instanceof PropertyWrite) {
34977
+ if (expr instanceof PropertyRead || expr instanceof PropertyWrite) {
34997
34978
  // Non-safe navigation operations are trivial: `foo.bar` or `foo.bar()`
34998
34979
  tsExpr = findFirstMatchingNode(this.tcb, {
34999
34980
  filter: ts$1.isPropertyAccessExpression,
35000
34981
  withSpan: expr.nameSpan,
35001
34982
  });
35002
34983
  }
35003
- else if (expr instanceof SafePropertyRead || expr instanceof SafeMethodCall) {
34984
+ else if (expr instanceof SafePropertyRead) {
35004
34985
  // Safe navigation operations are a little more complex, and involve a ternary. Completion
35005
34986
  // happens in the "true" case of the ternary.
35006
34987
  const ternaryExpr = findFirstMatchingNode(this.tcb, {
@@ -35011,11 +34992,10 @@ Either add the @Injectable() decorator to '${provider.node.name
35011
34992
  return null;
35012
34993
  }
35013
34994
  const whenTrue = ternaryExpr.expression.whenTrue;
35014
- if (expr instanceof SafePropertyRead && ts$1.isPropertyAccessExpression(whenTrue)) {
34995
+ if (ts$1.isPropertyAccessExpression(whenTrue)) {
35015
34996
  tsExpr = whenTrue;
35016
34997
  }
35017
- else if (expr instanceof SafeMethodCall && ts$1.isCallExpression(whenTrue) &&
35018
- ts$1.isPropertyAccessExpression(whenTrue.expression)) {
34998
+ else if (ts$1.isCallExpression(whenTrue) && ts$1.isPropertyAccessExpression(whenTrue.expression)) {
35019
34999
  tsExpr = whenTrue.expression;
35020
35000
  }
35021
35001
  }
@@ -35524,15 +35504,20 @@ Either add the @Injectable() decorator to '${provider.node.name
35524
35504
  resolutionContext: type.getSourceFile().fileName,
35525
35505
  };
35526
35506
  }
35527
- // If no owning module is known, the reference needs to be exported to be able to emit an import
35507
+ // The declaration needs to be exported as a top-level export to be able to emit an import
35528
35508
  // statement for it. If the declaration is not exported, null is returned to prevent emit.
35529
- if (owningModule === null && !this.isStaticallyExported(declaration.node)) {
35509
+ if (!this.isTopLevelExport(declaration.node)) {
35530
35510
  return null;
35531
35511
  }
35532
35512
  return new Reference$1(declaration.node, owningModule);
35533
35513
  }
35534
- isStaticallyExported(decl) {
35535
- return isNamedClassDeclaration(decl) && this.reflector.isStaticallyExported(decl);
35514
+ isTopLevelExport(decl) {
35515
+ if (decl.parent === undefined || !ts$1.isSourceFile(decl.parent)) {
35516
+ // The declaration has to exist at the top-level, as the reference emitters are not capable of
35517
+ // generating imports to classes declared in a namespace.
35518
+ return false;
35519
+ }
35520
+ return this.reflector.isStaticallyExported(decl);
35536
35521
  }
35537
35522
  isLocalTypeParameter(decl) {
35538
35523
  // Checking for local type parameters only occurs during resolution of type parameters, so it is
@@ -36414,13 +36399,6 @@ Either add the @Injectable() decorator to '${provider.node.name
36414
36399
  addParseSpanInfo(node, ast.sourceSpan);
36415
36400
  return node;
36416
36401
  }
36417
- visitFunctionCall(ast) {
36418
- const receiver = wrapForDiagnostics(this.translate(ast.target));
36419
- const args = ast.args.map(expr => this.translate(expr));
36420
- const node = ts$1.createCall(receiver, undefined, args);
36421
- addParseSpanInfo(node, ast.sourceSpan);
36422
- return node;
36423
- }
36424
36402
  visitImplicitReceiver(ast) {
36425
36403
  throw new Error('Method not implemented.');
36426
36404
  }
@@ -36483,15 +36461,6 @@ Either add the @Injectable() decorator to '${provider.node.name
36483
36461
  addParseSpanInfo(node, ast.sourceSpan);
36484
36462
  return node;
36485
36463
  }
36486
- visitMethodCall(ast) {
36487
- const receiver = wrapForDiagnostics(this.translate(ast.receiver));
36488
- const method = ts$1.createPropertyAccess(receiver, ast.name);
36489
- addParseSpanInfo(method, ast.nameSpan);
36490
- const args = ast.args.map(expr => this.translate(expr));
36491
- const node = ts$1.createCall(method, undefined, args);
36492
- addParseSpanInfo(node, ast.sourceSpan);
36493
- return node;
36494
- }
36495
36464
  visitNonNullAssert(ast) {
36496
36465
  const expr = wrapForDiagnostics(this.translate(ast.expression));
36497
36466
  const node = ts$1.createNonNullExpression(expr);
@@ -36541,33 +36510,6 @@ Either add the @Injectable() decorator to '${provider.node.name
36541
36510
  visitQuote(ast) {
36542
36511
  return NULL_AS_ANY;
36543
36512
  }
36544
- visitSafeMethodCall(ast) {
36545
- // See the comments in SafePropertyRead above for an explanation of the cases here.
36546
- let node;
36547
- const receiver = wrapForDiagnostics(this.translate(ast.receiver));
36548
- const args = ast.args.map(expr => this.translate(expr));
36549
- if (this.config.strictSafeNavigationTypes) {
36550
- // "a?.method(...)" becomes (null as any ? a!.method(...) : undefined)
36551
- const method = ts$1.createPropertyAccess(ts$1.createNonNullExpression(receiver), ast.name);
36552
- addParseSpanInfo(method, ast.nameSpan);
36553
- const call = ts$1.createCall(method, undefined, args);
36554
- node = ts$1.createParen(ts$1.createConditional(NULL_AS_ANY, call, UNDEFINED));
36555
- }
36556
- else if (VeSafeLhsInferenceBugDetector.veWillInferAnyFor(ast)) {
36557
- // "a?.method(...)" becomes (a as any).method(...)
36558
- const method = ts$1.createPropertyAccess(tsCastToAny(receiver), ast.name);
36559
- addParseSpanInfo(method, ast.nameSpan);
36560
- node = ts$1.createCall(method, undefined, args);
36561
- }
36562
- else {
36563
- // "a?.method(...)" becomes (a!.method(...) as any)
36564
- const method = ts$1.createPropertyAccess(ts$1.createNonNullExpression(receiver), ast.name);
36565
- addParseSpanInfo(method, ast.nameSpan);
36566
- node = tsCastToAny(ts$1.createCall(method, undefined, args));
36567
- }
36568
- addParseSpanInfo(node, ast.sourceSpan);
36569
- return node;
36570
- }
36571
36513
  visitSafePropertyRead(ast) {
36572
36514
  let node;
36573
36515
  const receiver = wrapForDiagnostics(this.translate(ast.receiver));
@@ -36624,6 +36566,33 @@ Either add the @Injectable() decorator to '${provider.node.name
36624
36566
  addParseSpanInfo(node, ast.sourceSpan);
36625
36567
  return node;
36626
36568
  }
36569
+ visitCall(ast) {
36570
+ const args = ast.args.map(expr => this.translate(expr));
36571
+ const expr = wrapForDiagnostics(this.translate(ast.receiver));
36572
+ let node;
36573
+ // Safe property/keyed reads will produce a ternary whose value is nullable.
36574
+ // We have to generate a similar ternary around the call.
36575
+ if (ast.receiver instanceof SafePropertyRead || ast.receiver instanceof SafeKeyedRead) {
36576
+ if (this.config.strictSafeNavigationTypes) {
36577
+ // "a?.method(...)" becomes (null as any ? a!.method(...) : undefined)
36578
+ const call = ts$1.createCall(ts$1.createNonNullExpression(expr), undefined, args);
36579
+ node = ts$1.createParen(ts$1.createConditional(NULL_AS_ANY, call, UNDEFINED));
36580
+ }
36581
+ else if (VeSafeLhsInferenceBugDetector.veWillInferAnyFor(ast)) {
36582
+ // "a?.method(...)" becomes (a as any).method(...)
36583
+ node = ts$1.createCall(tsCastToAny(expr), undefined, args);
36584
+ }
36585
+ else {
36586
+ // "a?.method(...)" becomes (a!.method(...) as any)
36587
+ node = tsCastToAny(ts$1.createCall(ts$1.createNonNullExpression(expr), undefined, args));
36588
+ }
36589
+ }
36590
+ else {
36591
+ node = ts$1.createCall(expr, undefined, args);
36592
+ }
36593
+ addParseSpanInfo(node, ast.sourceSpan);
36594
+ return node;
36595
+ }
36627
36596
  }
36628
36597
  /**
36629
36598
  * Checks whether View Engine will infer a type of 'any' for the left-hand side of a safe navigation
@@ -36641,7 +36610,7 @@ Either add the @Injectable() decorator to '${provider.node.name
36641
36610
  class VeSafeLhsInferenceBugDetector {
36642
36611
  static veWillInferAnyFor(ast) {
36643
36612
  const visitor = VeSafeLhsInferenceBugDetector.SINGLETON;
36644
- return ast instanceof SafeKeyedRead ? ast.receiver.visit(visitor) : ast.receiver.visit(visitor);
36613
+ return ast instanceof Call ? ast.visit(visitor) : ast.receiver.visit(visitor);
36645
36614
  }
36646
36615
  visitUnary(ast) {
36647
36616
  return ast.expr.visit(this);
@@ -36655,7 +36624,7 @@ Either add the @Injectable() decorator to '${provider.node.name
36655
36624
  visitConditional(ast) {
36656
36625
  return ast.condition.visit(this) || ast.trueExp.visit(this) || ast.falseExp.visit(this);
36657
36626
  }
36658
- visitFunctionCall(ast) {
36627
+ visitCall(ast) {
36659
36628
  return true;
36660
36629
  }
36661
36630
  visitImplicitReceiver(ast) {
@@ -36682,9 +36651,6 @@ Either add the @Injectable() decorator to '${provider.node.name
36682
36651
  visitLiteralPrimitive(ast) {
36683
36652
  return false;
36684
36653
  }
36685
- visitMethodCall(ast) {
36686
- return true;
36687
- }
36688
36654
  visitPipe(ast) {
36689
36655
  return true;
36690
36656
  }
@@ -36703,9 +36669,6 @@ Either add the @Injectable() decorator to '${provider.node.name
36703
36669
  visitQuote(ast) {
36704
36670
  return false;
36705
36671
  }
36706
- visitSafeMethodCall(ast) {
36707
- return true;
36708
- }
36709
36672
  visitSafePropertyRead(ast) {
36710
36673
  return false;
36711
36674
  }
@@ -38287,15 +38250,15 @@ Either add the @Injectable() decorator to '${provider.node.name
38287
38250
  else if (ast instanceof ImplicitReceiver) {
38288
38251
  // AST instances representing variables and references look very similar to property reads
38289
38252
  // or method calls from the component context: both have the shape
38290
- // PropertyRead(ImplicitReceiver, 'propName') or MethodCall(ImplicitReceiver, 'methodName').
38253
+ // PropertyRead(ImplicitReceiver, 'propName') or Call(ImplicitReceiver, 'methodName').
38291
38254
  //
38292
- // `translate` will first try to `resolve` the outer PropertyRead/MethodCall. If this works,
38255
+ // `translate` will first try to `resolve` the outer PropertyRead/Call. If this works,
38293
38256
  // it's because the `BoundTarget` found an expression target for the whole expression, and
38294
38257
  // therefore `translate` will never attempt to `resolve` the ImplicitReceiver of that
38295
- // PropertyRead/MethodCall.
38258
+ // PropertyRead/Call.
38296
38259
  //
38297
38260
  // Therefore if `resolve` is called on an `ImplicitReceiver`, it's because no outer
38298
- // PropertyRead/MethodCall resolved to a variable or reference, and therefore this is a
38261
+ // PropertyRead/Call resolved to a variable or reference, and therefore this is a
38299
38262
  // property read or method call on the component context itself.
38300
38263
  return ts$1.createIdentifier('ctx');
38301
38264
  }
@@ -38326,11 +38289,12 @@ Either add the @Injectable() decorator to '${provider.node.name
38326
38289
  addParseSpanInfo(result, ast.sourceSpan);
38327
38290
  return result;
38328
38291
  }
38329
- else if (ast instanceof MethodCall && ast.receiver instanceof ImplicitReceiver &&
38330
- !(ast.receiver instanceof ThisReceiver)) {
38292
+ else if (ast instanceof Call &&
38293
+ (ast.receiver instanceof PropertyRead || ast.receiver instanceof SafePropertyRead) &&
38294
+ !(ast.receiver.receiver instanceof ThisReceiver)) {
38331
38295
  // Resolve the special `$any(expr)` syntax to insert a cast of the argument to type `any`.
38332
38296
  // `$any(expr)` -> `expr as any`
38333
- if (ast.name === '$any' && ast.args.length === 1) {
38297
+ if (ast.receiver.name === '$any' && ast.args.length === 1) {
38334
38298
  const expr = this.translate(ast.args[0]);
38335
38299
  const exprAsAny = ts$1.createAsExpression(expr, ts$1.createKeywordTypeNode(ts$1.SyntaxKind.AnyKeyword));
38336
38300
  const result = ts$1.createParen(exprAsAny);
@@ -38346,7 +38310,7 @@ Either add the @Injectable() decorator to '${provider.node.name
38346
38310
  return null;
38347
38311
  }
38348
38312
  const method = wrapForDiagnostics(receiver);
38349
- addParseSpanInfo(method, ast.nameSpan);
38313
+ addParseSpanInfo(method, ast.receiver.nameSpan);
38350
38314
  const args = ast.args.map(arg => this.translate(arg));
38351
38315
  const node = ts$1.createCall(method, undefined, args);
38352
38316
  addParseSpanInfo(node, ast.sourceSpan);
@@ -39471,11 +39435,15 @@ Either add the @Injectable() decorator to '${provider.node.name
39471
39435
  if (expressionTarget !== null) {
39472
39436
  return this.getSymbol(expressionTarget);
39473
39437
  }
39474
- // The `name` part of a `PropertyWrite` and `MethodCall` does not have its own
39438
+ let withSpan = expression.sourceSpan;
39439
+ // The `name` part of a `PropertyWrite` and a non-safe `Call` does not have its own
39475
39440
  // AST so there is no way to retrieve a `Symbol` for just the `name` via a specific node.
39476
- const withSpan = (expression instanceof PropertyWrite || expression instanceof MethodCall) ?
39477
- expression.nameSpan :
39478
- expression.sourceSpan;
39441
+ if (expression instanceof PropertyWrite) {
39442
+ withSpan = expression.nameSpan;
39443
+ }
39444
+ else if (expression instanceof Call && expression.receiver instanceof PropertyRead) {
39445
+ withSpan = expression.receiver.nameSpan;
39446
+ }
39479
39447
  let node = null;
39480
39448
  // Property reads in templates usually map to a `PropertyAccessExpression`
39481
39449
  // (e.g. `ctx.foo`) so try looking for one first.
@@ -39497,9 +39465,10 @@ Either add the @Injectable() decorator to '${provider.node.name
39497
39465
  // - If our expression is a pipe binding ("a | test:b:c"), we want the Symbol for the
39498
39466
  // `transform` on the pipe.
39499
39467
  // - Otherwise, we retrieve the symbol for the node itself with no special considerations
39500
- if ((expression instanceof SafePropertyRead || expression instanceof SafeMethodCall) &&
39468
+ if ((expression instanceof SafePropertyRead ||
39469
+ (expression instanceof Call && expression.receiver instanceof SafePropertyRead)) &&
39501
39470
  ts$1.isConditionalExpression(node)) {
39502
- const whenTrueSymbol = (expression instanceof SafeMethodCall && ts$1.isCallExpression(node.whenTrue)) ?
39471
+ const whenTrueSymbol = (expression instanceof Call && ts$1.isCallExpression(node.whenTrue)) ?
39503
39472
  this.getSymbolOfTsNode(node.whenTrue.expression) :
39504
39473
  this.getSymbolOfTsNode(node.whenTrue);
39505
39474
  if (whenTrueSymbol === null) {
@@ -40165,12 +40134,11 @@ Either add the @Injectable() decorator to '${provider.node.name
40165
40134
  */
40166
40135
  class ExtendedTemplateCheckerImpl {
40167
40136
  constructor(templateTypeChecker, typeChecker, templateChecks) {
40168
- this.templateTypeChecker = templateTypeChecker;
40169
- this.typeChecker = typeChecker;
40170
40137
  this.templateChecks = templateChecks;
40138
+ this.ctx = { templateTypeChecker: templateTypeChecker, typeChecker: typeChecker };
40171
40139
  }
40172
40140
  getDiagnosticsForComponent(component) {
40173
- const template = this.templateTypeChecker.getTemplate(component);
40141
+ const template = this.ctx.templateTypeChecker.getTemplate(component);
40174
40142
  // Skip checks if component has no template. This can happen if the user writes a
40175
40143
  // `@Component()` but doesn't add the template, could happen in the language service
40176
40144
  // when users are in the middle of typing code.
@@ -40178,66 +40146,100 @@ Either add the @Injectable() decorator to '${provider.node.name
40178
40146
  return [];
40179
40147
  }
40180
40148
  const diagnostics = [];
40181
- const ctx = {
40182
- templateTypeChecker: this.templateTypeChecker,
40183
- typeChecker: this.typeChecker,
40184
- component
40185
- };
40186
40149
  for (const check of this.templateChecks) {
40187
- diagnostics.push(...deduplicateDiagnostics(check.run(ctx, template)));
40150
+ diagnostics.push(...check.run(this.ctx, component, template));
40188
40151
  }
40189
40152
  return diagnostics;
40190
40153
  }
40191
40154
  }
40192
- // Filter out duplicated diagnostics, this is possible due to the way the compiler
40193
- // handles desugaring and produces `AST`s. Ex.
40194
- //
40195
- // ```
40196
- // <div *ngIf="true" (foo)="bar">test</div>
40197
- // ```
40198
- //
40199
- // Would result in the following AST:
40200
- //
40201
- // ```
40202
- // Template {
40203
- // outputs: [
40204
- // BoundEvent {
40205
- // name: 'foo',
40206
- // /.../
40207
- // }
40208
- // ],
40209
- // children: [
40210
- // Element {
40211
- // outputs: [
40212
- // BoundEvent {
40213
- // name: 'foo',
40214
- // /.../
40215
- // }
40216
- // ]
40217
- // }
40218
- // ],
40219
- // /.../
40220
- // }
40221
- // ```
40222
- //
40223
- // In this case a duplicated diagnostic could be generated for the output `foo`.
40224
- // TODO(danieltrevino): handle duplicated diagnostics when they are being generated
40225
- // to avoid extra work (could be directly in the visitor).
40226
- // https://github.com/angular/angular/pull/42984#discussion_r684823926
40227
- function deduplicateDiagnostics(diagnostics) {
40228
- const result = [];
40229
- for (const newDiag of diagnostics) {
40230
- const isDuplicateDiag = result.some(existingDiag => areDiagnosticsEqual(newDiag, existingDiag));
40231
- if (!isDuplicateDiag) {
40232
- result.push(newDiag);
40233
- }
40155
+
40156
+ /**
40157
+ * @license
40158
+ * Copyright Google LLC All Rights Reserved.
40159
+ *
40160
+ * Use of this source code is governed by an MIT-style license that can be
40161
+ * found in the LICENSE file at https://angular.io/license
40162
+ */
40163
+ /**
40164
+ * This abstract class provides a base implementation for the run method.
40165
+ */
40166
+ class TemplateCheckWithVisitor {
40167
+ /**
40168
+ * Base implementation for run function, visits all nodes in template and calls
40169
+ * `visitNode()` for each one.
40170
+ */
40171
+ run(ctx, component, template) {
40172
+ const visitor = new TemplateVisitor$1(ctx, component, this);
40173
+ return visitor.getDiagnostics(template);
40234
40174
  }
40235
- return result;
40236
40175
  }
40237
- function areDiagnosticsEqual(first, second) {
40238
- var _a, _b;
40239
- return ((_a = first.file) === null || _a === void 0 ? void 0 : _a.fileName) === ((_b = second.file) === null || _b === void 0 ? void 0 : _b.fileName) && first.start === second.start &&
40240
- first.length === second.length && first.code === second.code;
40176
+ /**
40177
+ * Visits all nodes in a template (TmplAstNode and AST) and calls `visitNode` for each one.
40178
+ */
40179
+ class TemplateVisitor$1 extends RecursiveAstVisitor {
40180
+ constructor(ctx, component, check) {
40181
+ super();
40182
+ this.ctx = ctx;
40183
+ this.component = component;
40184
+ this.check = check;
40185
+ this.diagnostics = [];
40186
+ }
40187
+ visit(node, context) {
40188
+ this.diagnostics.push(...this.check.visitNode(this.ctx, this.component, node));
40189
+ node.visit(this);
40190
+ }
40191
+ visitAllNodes(nodes) {
40192
+ for (const node of nodes) {
40193
+ this.visit(node);
40194
+ }
40195
+ }
40196
+ visitAst(ast) {
40197
+ if (ast instanceof ASTWithSource) {
40198
+ ast = ast.ast;
40199
+ }
40200
+ this.visit(ast);
40201
+ }
40202
+ visitElement(element) {
40203
+ this.visitAllNodes(element.attributes);
40204
+ this.visitAllNodes(element.inputs);
40205
+ this.visitAllNodes(element.outputs);
40206
+ this.visitAllNodes(element.references);
40207
+ this.visitAllNodes(element.children);
40208
+ }
40209
+ visitTemplate(template) {
40210
+ this.visitAllNodes(template.attributes);
40211
+ if (template.tagName === 'ng-template') {
40212
+ // Only visit input/outputs/templateAttrs if this isn't an inline template node
40213
+ // generated for a structural directive (like `<div *ngIf></div>`). These nodes
40214
+ // would be visited when the underlying element of an inline template node is processed.
40215
+ this.visitAllNodes(template.inputs);
40216
+ this.visitAllNodes(template.outputs);
40217
+ this.visitAllNodes(template.templateAttrs);
40218
+ }
40219
+ this.visitAllNodes(template.variables);
40220
+ this.visitAllNodes(template.references);
40221
+ this.visitAllNodes(template.children);
40222
+ }
40223
+ visitContent(content) { }
40224
+ visitVariable(variable) { }
40225
+ visitReference(reference) { }
40226
+ visitTextAttribute(attribute) { }
40227
+ visitBoundAttribute(attribute) {
40228
+ this.visitAst(attribute.value);
40229
+ }
40230
+ visitBoundEvent(attribute) {
40231
+ this.visitAst(attribute.handler);
40232
+ }
40233
+ visitText(text) { }
40234
+ visitBoundText(text) {
40235
+ this.visitAst(text.value);
40236
+ }
40237
+ visitIcu(icu) { }
40238
+ getDiagnostics(template) {
40239
+ this.diagnostics = [];
40240
+ this.visitAllNodes(template);
40241
+ return this.diagnostics;
40242
+ }
40241
40243
  }
40242
40244
 
40243
40245
  /**
@@ -40252,42 +40254,63 @@ Either add the @Injectable() decorator to '${provider.node.name
40252
40254
  * Parentheses should be inside the brackets "[()]".
40253
40255
  * Will return diagnostic information when "([])" is found.
40254
40256
  */
40255
- class InvalidBananaInBoxCheck {
40257
+ class InvalidBananaInBoxCheck extends TemplateCheckWithVisitor {
40256
40258
  constructor() {
40257
- this.code = 8101;
40259
+ super(...arguments);
40260
+ this.code = ErrorCode.INVALID_BANANA_IN_BOX;
40258
40261
  }
40259
- run(ctx, template) {
40260
- const visitor = new BananaVisitor(ctx);
40261
- return visitor.getDiagnostics(template);
40262
+ visitNode(ctx, component, node) {
40263
+ if (!(node instanceof BoundEvent))
40264
+ return [];
40265
+ const name = node.name;
40266
+ if (!name.startsWith('[') || !name.endsWith(']'))
40267
+ return [];
40268
+ const boundSyntax = node.sourceSpan.toString();
40269
+ const expectedBoundSyntax = boundSyntax.replace(`(${name})`, `[(${name.slice(1, -1)})]`);
40270
+ const diagnostic = ctx.templateTypeChecker.makeTemplateDiagnostic(component, node.sourceSpan, ts$1.DiagnosticCategory.Warning, ErrorCode.INVALID_BANANA_IN_BOX, `In the two-way binding syntax the parentheses should be inside the brackets, ex. '${expectedBoundSyntax}'.
40271
+ Find more at https://angular.io/guide/two-way-binding`);
40272
+ return [diagnostic];
40262
40273
  }
40263
40274
  }
40264
- class BananaVisitor extends RecursiveVisitor {
40265
- constructor(ctx) {
40266
- super();
40267
- this.ctx = ctx;
40268
- this.diagnostics = [];
40275
+
40276
+ /**
40277
+ * @license
40278
+ * Copyright Google LLC All Rights Reserved.
40279
+ *
40280
+ * Use of this source code is governed by an MIT-style license that can be
40281
+ * found in the LICENSE file at https://angular.io/license
40282
+ */
40283
+ /**
40284
+ * Ensures the left side of a nullish coalescing operation is nullable.
40285
+ * Returns diagnostics for the cases where the operator is useless.
40286
+ * This check should only be use if `strictNullChecks` is enabled,
40287
+ * otherwise it would produce inaccurate results.
40288
+ */
40289
+ class NullishCoalescingNotNullableCheck extends TemplateCheckWithVisitor {
40290
+ constructor() {
40291
+ super(...arguments);
40292
+ this.code = ErrorCode.NULLISH_COALESCING_NOT_NULLABLE;
40269
40293
  }
40270
- /**
40271
- * Check for outputs with names surrounded in brackets "[]".
40272
- * The syntax '([foo])="bar"' would be interpreted as an @Output()
40273
- * with name '[foo]'. Just like '(foo)="bar"' would have the name 'foo'.
40274
- * Generate diagnostic information for the cases found.
40275
- */
40276
- visitBoundEvent(boundEvent) {
40277
- const name = boundEvent.name;
40278
- if (name.startsWith('[') && name.endsWith(']')) {
40279
- const boundSyntax = boundEvent.sourceSpan.toString();
40280
- const expectedBoundSyntax = boundSyntax.replace(`(${name})`, `[(${name.slice(1, -1)})]`);
40281
- this.diagnostics.push(this.ctx.templateTypeChecker.makeTemplateDiagnostic(this.ctx.component, boundEvent.sourceSpan, ts$1.DiagnosticCategory.Warning, ErrorCode.INVALID_BANANA_IN_BOX, `In the two-way binding syntax the parentheses should be inside the brackets, ex. '${expectedBoundSyntax}'.
40282
- Find more at https://angular.io/guide/two-way-binding`));
40294
+ visitNode(ctx, component, node) {
40295
+ if (!(node instanceof Binary) || node.operation !== '??')
40296
+ return [];
40297
+ const symbolLeft = ctx.templateTypeChecker.getSymbolOfNode(node.left, component);
40298
+ if (symbolLeft === null || symbolLeft.kind !== SymbolKind.Expression) {
40299
+ return [];
40283
40300
  }
40284
- }
40285
- getDiagnostics(template) {
40286
- this.diagnostics = [];
40287
- for (const node of template) {
40288
- node.visit(this);
40301
+ const typeLeft = symbolLeft.tsType;
40302
+ // If the left operand's type is different from its non-nullable self, then it must
40303
+ // contain a null or undefined so this nullish coalescing operator is useful. No diagnostic to
40304
+ // report.
40305
+ if (typeLeft.getNonNullableType() !== typeLeft)
40306
+ return [];
40307
+ const symbol = ctx.templateTypeChecker.getSymbolOfNode(node, component);
40308
+ if (symbol.kind !== SymbolKind.Expression) {
40309
+ return [];
40289
40310
  }
40290
- return this.diagnostics;
40311
+ const span = ctx.templateTypeChecker.getTemplateMappingAtShimLocation(symbol.shimLocation).span;
40312
+ const diagnostic = ctx.templateTypeChecker.makeTemplateDiagnostic(component, span, ts$1.DiagnosticCategory.Warning, ErrorCode.NULLISH_COALESCING_NOT_NULLABLE, `The left side of this nullish coalescing operation does not include 'null' or 'undefined' in its type, therefore the '??' operator can be safely removed.`);
40313
+ return [diagnostic];
40291
40314
  }
40292
40315
  }
40293
40316
 
@@ -41074,6 +41097,9 @@ Either add the @Injectable() decorator to '${provider.node.name
41074
41097
  });
41075
41098
  const templateTypeChecker = new TemplateTypeCheckerImpl(this.inputProgram, notifyingDriver, traitCompiler, this.getTypeCheckingConfig(), refEmitter, reflector, this.adapter, this.incrementalCompilation, scopeRegistry, typeCheckScopeRegistry, this.delegatingPerfRecorder);
41076
41099
  const templateChecks = [new InvalidBananaInBoxCheck()];
41100
+ if (this.options.strictNullChecks) {
41101
+ templateChecks.push(new NullishCoalescingNotNullableCheck());
41102
+ }
41077
41103
  const extendedTemplateChecker = new ExtendedTemplateCheckerImpl(templateTypeChecker, checker, templateChecks);
41078
41104
  return {
41079
41105
  isCore,
@@ -41591,11 +41617,10 @@ https://v9.angular.io/guide/template-typecheck#template-type-checking`,
41591
41617
  if (isTemplateNodeWithKeyAndValue(node)) {
41592
41618
  return toTextSpan(node.keySpan);
41593
41619
  }
41594
- else if (node instanceof PropertyWrite || node instanceof MethodCall ||
41595
- node instanceof BindingPipe || node instanceof PropertyRead) {
41596
- // The `name` part of a `PropertyWrite`, `MethodCall`, and `BindingPipe` does not
41597
- // have its own AST so there is no way to retrieve a `Symbol` for just the `name` via a specific
41598
- // node.
41620
+ else if (node instanceof PropertyWrite || node instanceof BindingPipe ||
41621
+ node instanceof PropertyRead) {
41622
+ // The `name` part of a `PropertyWrite` and `BindingPipe` does not have its own AST
41623
+ // so there is no way to retrieve a `Symbol` for just the `name` via a specific node.
41599
41624
  return toTextSpan(node.nameSpan);
41600
41625
  }
41601
41626
  else {
@@ -42498,7 +42523,7 @@ https://v9.angular.io/guide/template-typecheck#template-type-checking`,
42498
42523
  var TargetNodeKind;
42499
42524
  (function (TargetNodeKind) {
42500
42525
  TargetNodeKind[TargetNodeKind["RawExpression"] = 0] = "RawExpression";
42501
- TargetNodeKind[TargetNodeKind["MethodCallExpressionInArgContext"] = 1] = "MethodCallExpressionInArgContext";
42526
+ TargetNodeKind[TargetNodeKind["CallExpressionInArgContext"] = 1] = "CallExpressionInArgContext";
42502
42527
  TargetNodeKind[TargetNodeKind["RawTemplateNode"] = 2] = "RawTemplateNode";
42503
42528
  TargetNodeKind[TargetNodeKind["ElementInTagContext"] = 3] = "ElementInTagContext";
42504
42529
  TargetNodeKind[TargetNodeKind["ElementInBodyContext"] = 4] = "ElementInBodyContext";
@@ -42544,10 +42569,9 @@ https://v9.angular.io/guide/template-typecheck#template-type-checking`,
42544
42569
  }
42545
42570
  // Given the candidate node, determine the full targeted context.
42546
42571
  let nodeInContext;
42547
- if ((candidate instanceof MethodCall || candidate instanceof SafeMethodCall) &&
42548
- isWithin(position, candidate.argumentSpan)) {
42572
+ if (candidate instanceof Call && isWithin(position, candidate.argumentSpan)) {
42549
42573
  nodeInContext = {
42550
- kind: TargetNodeKind.MethodCallExpressionInArgContext,
42574
+ kind: TargetNodeKind.CallExpressionInArgContext,
42551
42575
  node: candidate,
42552
42576
  };
42553
42577
  }
@@ -42950,8 +42974,7 @@ https://v9.angular.io/guide/template-typecheck#template-type-checking`,
42950
42974
  * expressions.
42951
42975
  */
42952
42976
  isPropertyExpressionCompletion() {
42953
- return this.node instanceof PropertyRead || this.node instanceof MethodCall ||
42954
- this.node instanceof SafePropertyRead || this.node instanceof SafeMethodCall ||
42977
+ return this.node instanceof PropertyRead || this.node instanceof SafePropertyRead ||
42955
42978
  this.node instanceof PropertyWrite || this.node instanceof EmptyExpr ||
42956
42979
  // BoundEvent nodes only count as property completions if in an EventValue context.
42957
42980
  (this.node instanceof BoundEvent && this.nodeContext === CompletionNodeContext.EventValue);
@@ -42975,7 +42998,7 @@ https://v9.angular.io/guide/template-typecheck#template-type-checking`,
42975
42998
  }
42976
42999
  const replacementSpan = makeReplacementSpanFromAst(this.node);
42977
43000
  if (!(this.node.receiver instanceof ImplicitReceiver) &&
42978
- (options === null || options === void 0 ? void 0 : options.includeCompletionsWithInsertText) &&
43001
+ !(this.node instanceof SafePropertyRead) && (options === null || options === void 0 ? void 0 : options.includeCompletionsWithInsertText) &&
42979
43002
  options.includeAutomaticOptionalChainCompletions !== false) {
42980
43003
  const symbol = this.templateTypeChecker.getSymbolOfNode(this.node.receiver, this.component);
42981
43004
  if ((symbol === null || symbol === void 0 ? void 0 : symbol.kind) === SymbolKind.Expression) {
@@ -43705,9 +43728,8 @@ https://v9.angular.io/guide/template-typecheck#template-type-checking`,
43705
43728
  return { text: node.valueSpan.toString(), span: toTextSpan(node.valueSpan) };
43706
43729
  }
43707
43730
  }
43708
- if (node instanceof PropertyRead || node instanceof MethodCall || node instanceof PropertyWrite ||
43709
- node instanceof SafePropertyRead || node instanceof SafeMethodCall ||
43710
- node instanceof BindingPipe) {
43731
+ if (node instanceof PropertyRead || node instanceof PropertyWrite ||
43732
+ node instanceof SafePropertyRead || node instanceof BindingPipe) {
43711
43733
  return { text: node.name, span: toTextSpan(node.nameSpan) };
43712
43734
  }
43713
43735
  else if (node instanceof LiteralPrimitive) {
@@ -44046,19 +44068,27 @@ https://v9.angular.io/guide/template-typecheck#template-type-checking`,
44046
44068
  * found in the LICENSE file at https://angular.io/license
44047
44069
  */
44048
44070
  class QuickInfoBuilder {
44049
- constructor(tsLS, compiler, component, node) {
44071
+ constructor(tsLS, compiler, component, node, parent) {
44050
44072
  this.tsLS = tsLS;
44051
44073
  this.compiler = compiler;
44052
44074
  this.component = component;
44053
44075
  this.node = node;
44076
+ this.parent = parent;
44054
44077
  this.typeChecker = this.compiler.getCurrentProgram().getTypeChecker();
44055
44078
  }
44056
44079
  get() {
44057
44080
  const symbol = this.compiler.getTemplateTypeChecker().getSymbolOfNode(this.node, this.component);
44058
- if (symbol === null) {
44059
- return isDollarAny(this.node) ? createDollarAnyQuickInfo(this.node) : undefined;
44081
+ if (symbol !== null) {
44082
+ return this.getQuickInfoForSymbol(symbol);
44083
+ }
44084
+ if (isDollarAny(this.node)) {
44085
+ return createDollarAnyQuickInfo(this.node);
44086
+ }
44087
+ // If the cursor lands on the receiver of a method call, we have to look
44088
+ // at the entire call in order to figure out if it's a call to `$any`.
44089
+ if (this.parent !== null && isDollarAny(this.parent) && this.parent.receiver === this.node) {
44090
+ return createDollarAnyQuickInfo(this.parent);
44060
44091
  }
44061
- return this.getQuickInfoForSymbol(symbol);
44062
44092
  }
44063
44093
  getQuickInfoForSymbol(symbol) {
44064
44094
  switch (symbol.kind) {
@@ -44181,11 +44211,13 @@ https://v9.angular.io/guide/template-typecheck#template-type-checking`,
44181
44211
  return a.text === b.text && a.kind === b.kind;
44182
44212
  }
44183
44213
  function isDollarAny(node) {
44184
- return node instanceof MethodCall && node.receiver instanceof ImplicitReceiver &&
44185
- !(node.receiver instanceof ThisReceiver) && node.name === '$any' && node.args.length === 1;
44214
+ return node instanceof Call && node.receiver instanceof PropertyRead &&
44215
+ node.receiver.receiver instanceof ImplicitReceiver &&
44216
+ !(node.receiver.receiver instanceof ThisReceiver) && node.receiver.name === '$any' &&
44217
+ node.args.length === 1;
44186
44218
  }
44187
44219
  function createDollarAnyQuickInfo(node) {
44188
- return createQuickInfo('$any', DisplayInfoKind.METHOD, getTextSpanOfNode(node),
44220
+ return createQuickInfo('$any', DisplayInfoKind.METHOD, getTextSpanOfNode(node.receiver),
44189
44221
  /** containerName */ undefined, 'any', [{
44190
44222
  kind: SYMBOL_TEXT,
44191
44223
  text: 'function to cast an expression to the `any` type',
@@ -44560,7 +44592,7 @@ https://v9.angular.io/guide/template-typecheck#template-type-checking`,
44560
44592
  return undefined;
44561
44593
  }
44562
44594
  if (targetInfo.context.kind !== TargetNodeKind.RawExpression &&
44563
- targetInfo.context.kind !== TargetNodeKind.MethodCallExpressionInArgContext) {
44595
+ targetInfo.context.kind !== TargetNodeKind.CallExpressionInArgContext) {
44564
44596
  // Signature completions are only available in expressions.
44565
44597
  return undefined;
44566
44598
  }
@@ -44569,38 +44601,37 @@ https://v9.angular.io/guide/template-typecheck#template-type-checking`,
44569
44601
  return undefined;
44570
44602
  }
44571
44603
  // Determine a shim position to use in the request to the TypeScript Language Service.
44572
- // Additionally, extract the `MethodCall` or `SafeMethodCall` node for which signature help is
44573
- // being queried, as this is needed to construct the correct span for the results later.
44604
+ // Additionally, extract the `Call` node for which signature help is being queried, as this
44605
+ // is needed to construct the correct span for the results later.
44574
44606
  let shimPosition;
44575
44607
  let expr;
44576
44608
  switch (targetInfo.context.kind) {
44577
44609
  case TargetNodeKind.RawExpression:
44578
44610
  // For normal expressions, just use the primary TCB position of the expression.
44579
44611
  shimPosition = symbol.shimLocation.positionInShimFile;
44580
- // Walk up the parents of this expression and try to find a `MethodCall` or `SafeMethodCall`
44581
- // for which signature information is being fetched.
44612
+ // Walk up the parents of this expression and try to find a
44613
+ // `Call` for which signature information is being fetched.
44582
44614
  let callExpr = null;
44583
44615
  const parents = targetInfo.context.parents;
44584
44616
  for (let i = parents.length - 1; i >= 0; i--) {
44585
44617
  const parent = parents[i];
44586
- if (parent instanceof MethodCall || parent instanceof SafeMethodCall) {
44618
+ if (parent instanceof Call) {
44587
44619
  callExpr = parent;
44588
44620
  break;
44589
44621
  }
44590
44622
  }
44591
- // If no MethodCall or SafeMethodCall node could be found, then this query cannot be safely
44623
+ // If no Call node could be found, then this query cannot be safely
44592
44624
  // answered as a correct span for the results will not be obtainable.
44593
44625
  if (callExpr === null) {
44594
44626
  return undefined;
44595
44627
  }
44596
44628
  expr = callExpr;
44597
44629
  break;
44598
- case TargetNodeKind.MethodCallExpressionInArgContext:
44599
- // The `Symbol` points to a `MethodCall` or `SafeMethodCall` expression in the TCB (where it
44600
- // will be represented as a `ts.CallExpression`) *and* the template position was within the
44601
- // argument list of the method call. This happens when there was no narrower expression inside
44602
- // the argument list that matched the template position, such as when the call has no
44603
- // arguments: `foo(|)`.
44630
+ case TargetNodeKind.CallExpressionInArgContext:
44631
+ // The `Symbol` points to a `Call` expression in the TCB (where it will be represented as a
44632
+ // `ts.CallExpression`) *and* the template position was within the argument list of the method
44633
+ // call. This happens when there was no narrower expression inside the argument list that
44634
+ // matched the template position, such as when the call has no arguments: `foo(|)`.
44604
44635
  //
44605
44636
  // The `Symbol`'s shim position is to the start of the call expression (`|foo()`) and
44606
44637
  // therefore wouldn't return accurate signature help from the TS language service. For that, a
@@ -44636,8 +44667,7 @@ https://v9.angular.io/guide/template-typecheck#template-type-checking`,
44636
44667
  }
44637
44668
  // The TS language service results are almost returnable as-is. However, they contain an
44638
44669
  // `applicableSpan` which marks the entire argument list, and that span is in the context of the
44639
- // TCB's `ts.CallExpression`. It needs to be replaced with the span for the `MethodCall` (or
44640
- // `SafeMethodCall`) argument list.
44670
+ // TCB's `ts.CallExpression`. It needs to be replaced with the span for the `Call` argument list.
44641
44671
  return Object.assign(Object.assign({}, res), { applicableSpan: {
44642
44672
  start: expr.argumentSpan.start,
44643
44673
  length: expr.argumentSpan.end - expr.argumentSpan.start,
@@ -44752,7 +44782,8 @@ https://v9.angular.io/guide/template-typecheck#template-type-checking`,
44752
44782
  const node = positionDetails.context.kind === TargetNodeKind.TwoWayBindingContext ?
44753
44783
  positionDetails.context.nodes[0] :
44754
44784
  positionDetails.context.node;
44755
- return new QuickInfoBuilder(this.tsLS, compiler, templateInfo.component, node).get();
44785
+ return new QuickInfoBuilder(this.tsLS, compiler, templateInfo.component, node, positionDetails.parent)
44786
+ .get();
44756
44787
  }
44757
44788
  getReferencesAtPosition(fileName, position) {
44758
44789
  return this.withCompilerAndPerfTracing(PerfPhase.LsReferencesAndRenames, (compiler) => {