@angular/core 10.0.6 → 10.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/bundles/core-testing.umd.js +1 -1
  2. package/bundles/core-testing.umd.min.js +1 -1
  3. package/bundles/core-testing.umd.min.js.map +1 -1
  4. package/bundles/core.umd.js +1678 -1387
  5. package/bundles/core.umd.js.map +1 -1
  6. package/bundles/core.umd.min.js +152 -124
  7. package/bundles/core.umd.min.js.map +1 -1
  8. package/core.d.ts +258 -58
  9. package/core.metadata.json +1 -1
  10. package/esm2015/core.js +3 -3
  11. package/esm2015/src/application_module.js +2 -2
  12. package/esm2015/src/application_ref.js +2 -2
  13. package/esm2015/src/core_render3_private_export.js +2 -1
  14. package/esm2015/src/metadata/di.js +1 -1
  15. package/esm2015/src/r3_symbols.js +2 -1
  16. package/esm2015/src/reflection/reflection_capabilities.js +38 -8
  17. package/esm2015/src/render3/bindings.js +3 -3
  18. package/esm2015/src/render3/component.js +3 -3
  19. package/esm2015/src/render3/di.js +1 -1
  20. package/esm2015/src/render3/i18n/i18n_apply.js +445 -0
  21. package/esm2015/src/render3/i18n/i18n_debug.js +170 -0
  22. package/esm2015/src/render3/i18n/i18n_locale_id.js +37 -0
  23. package/esm2015/src/render3/i18n/i18n_parse.js +635 -0
  24. package/esm2015/src/render3/i18n/i18n_postprocess.js +121 -0
  25. package/esm2015/src/render3/index.js +3 -2
  26. package/esm2015/src/render3/instructions/advance.js +3 -3
  27. package/esm2015/src/render3/instructions/element.js +3 -3
  28. package/esm2015/src/render3/instructions/element_container.js +3 -3
  29. package/esm2015/src/render3/instructions/i18n.js +164 -0
  30. package/esm2015/src/render3/instructions/listener.js +3 -3
  31. package/esm2015/src/render3/instructions/lview_debug.js +54 -213
  32. package/esm2015/src/render3/instructions/shared.js +54 -38
  33. package/esm2015/src/render3/instructions/text.js +3 -3
  34. package/esm2015/src/render3/interfaces/i18n.js +12 -3
  35. package/esm2015/src/render3/interfaces/node.js +13 -1
  36. package/esm2015/src/render3/interfaces/view.js +1 -1
  37. package/esm2015/src/render3/jit/directive.js +33 -10
  38. package/esm2015/src/render3/ng_module_ref.js +2 -2
  39. package/esm2015/src/render3/node_manipulation.js +1 -11
  40. package/esm2015/src/render3/pure_function.js +3 -3
  41. package/esm2015/src/render3/query.js +14 -12
  42. package/esm2015/src/render3/styling/style_binding_list.js +3 -3
  43. package/esm2015/src/render3/styling/styling_parser.js +3 -2
  44. package/esm2015/src/render3/util/debug_utils.js +31 -2
  45. package/esm2015/src/render3/util/discovery_utils.js +1 -1
  46. package/esm2015/src/render3/util/view_utils.js +5 -5
  47. package/esm2015/src/render3/view_engine_compatibility.js +13 -4
  48. package/esm2015/src/util/assert.js +2 -2
  49. package/esm2015/src/util/char_code.js +1 -1
  50. package/esm2015/src/version.js +1 -1
  51. package/fesm2015/core.js +1652 -1364
  52. package/fesm2015/core.js.map +1 -1
  53. package/fesm2015/testing.js +1 -1
  54. package/package.json +1 -1
  55. package/src/r3_symbols.d.ts +13 -1
  56. package/testing/testing.d.ts +1 -1
  57. package/testing.d.ts +1 -1
  58. package/esm2015/src/render3/i18n.js +0 -1225
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Angular v10.0.6
2
+ * @license Angular v10.0.10
3
3
  * (c) 2010-2020 Google LLC. https://angular.io/
4
4
  * License: MIT
5
5
  */
@@ -1403,7 +1403,7 @@
1403
1403
  (typeof node === 'object' && node != null &&
1404
1404
  node.constructor.name === 'WebWorkerRenderNode'), true, "The provided value must be an instance of a DOM Node but got " + stringify(node));
1405
1405
  }
1406
- function assertDataInRange(arr, index) {
1406
+ function assertIndexInRange(arr, index) {
1407
1407
  var maxLen = arr ? arr.length : 0;
1408
1408
  assertLessThan(index, maxLen, "Index expected to be less than " + maxLen + " but got " + index);
1409
1409
  }
@@ -2618,7 +2618,7 @@
2618
2618
  */
2619
2619
  function getNativeByTNode(tNode, lView) {
2620
2620
  ngDevMode && assertTNodeForLView(tNode, lView);
2621
- ngDevMode && assertDataInRange(lView, tNode.index);
2621
+ ngDevMode && assertIndexInRange(lView, tNode.index);
2622
2622
  var node = unwrapRNode(lView[tNode.index]);
2623
2623
  ngDevMode && !isProceduralRenderer(lView[RENDERER]) && assertDomNode(node);
2624
2624
  return node;
@@ -2648,12 +2648,12 @@
2648
2648
  }
2649
2649
  /** Retrieves a value from any `LView` or `TData`. */
2650
2650
  function load(view, index) {
2651
- ngDevMode && assertDataInRange(view, index + HEADER_OFFSET);
2651
+ ngDevMode && assertIndexInRange(view, index + HEADER_OFFSET);
2652
2652
  return view[index + HEADER_OFFSET];
2653
2653
  }
2654
2654
  function getComponentLViewByIndex(nodeIndex, hostView) {
2655
2655
  // Could be an LView or an LContainer. If LContainer, unwrap to find LView.
2656
- ngDevMode && assertDataInRange(hostView, nodeIndex);
2656
+ ngDevMode && assertIndexInRange(hostView, nodeIndex);
2657
2657
  var slotValue = hostView[nodeIndex];
2658
2658
  var lView = isLView(slotValue) ? slotValue : slotValue[HOST];
2659
2659
  return lView;
@@ -5852,6 +5852,18 @@
5852
5852
  return { propName: undefined, oldValue: oldValue, newValue: newValue };
5853
5853
  }
5854
5854
 
5855
+ /**
5856
+ * Converts `TNodeType` into human readable text.
5857
+ * Make sure this matches with `TNodeType`
5858
+ */
5859
+ var TNodeTypeAsString = [
5860
+ 'Container',
5861
+ 'Projection',
5862
+ 'View',
5863
+ 'Element',
5864
+ 'ElementContainer',
5865
+ 'IcuContainer' // 5
5866
+ ];
5855
5867
  // Note: This hack is necessary so we don't erroneously get a circular dependency
5856
5868
  // failure based on types.
5857
5869
  var unusedValueExportToPlacateAjd$4 = 1;
@@ -6486,7 +6498,7 @@
6486
6498
  }
6487
6499
  function selectIndexInternal(tView, lView, index, checkNoChangesMode) {
6488
6500
  ngDevMode && assertGreaterThan(index, -1, 'Invalid index');
6489
- ngDevMode && assertDataInRange(lView, index + HEADER_OFFSET);
6501
+ ngDevMode && assertIndexInRange(lView, index + HEADER_OFFSET);
6490
6502
  // Flush the initial hooks for elements in the view that have been added up to this point.
6491
6503
  // PERF WARNING: do NOT extract this to a separate function without running benchmarks
6492
6504
  if (!checkNoChangesMode) {
@@ -6511,33 +6523,6 @@
6511
6523
  setSelectedIndex(index);
6512
6524
  }
6513
6525
 
6514
- /**
6515
- * @license
6516
- * Copyright Google LLC All Rights Reserved.
6517
- *
6518
- * Use of this source code is governed by an MIT-style license that can be
6519
- * found in the LICENSE file at https://angular.io/license
6520
- */
6521
- /**
6522
- * Marks that the next string is for element.
6523
- *
6524
- * See `I18nMutateOpCodes` documentation.
6525
- */
6526
- var ELEMENT_MARKER = {
6527
- marker: 'element'
6528
- };
6529
- /**
6530
- * Marks that the next string is for comment.
6531
- *
6532
- * See `I18nMutateOpCodes` documentation.
6533
- */
6534
- var COMMENT_MARKER = {
6535
- marker: 'comment'
6536
- };
6537
- // Note: This hack is necessary so we don't erroneously get a circular dependency
6538
- // failure based on types.
6539
- var unusedValueExportToPlacateAjd$6 = 1;
6540
-
6541
6526
  /**
6542
6527
  * @license
6543
6528
  * Copyright Google LLC All Rights Reserved.
@@ -6601,8 +6586,37 @@
6601
6586
  * Use of this source code is governed by an MIT-style license that can be
6602
6587
  * found in the LICENSE file at https://angular.io/license
6603
6588
  */
6589
+ /**
6590
+ * Patch a `debug` property on top of the existing object.
6591
+ *
6592
+ * NOTE: always call this method with `ngDevMode && attachDebugObject(...)`
6593
+ *
6594
+ * @param obj Object to patch
6595
+ * @param debug Value to patch
6596
+ */
6604
6597
  function attachDebugObject(obj, debug) {
6605
- Object.defineProperty(obj, 'debug', { value: debug, enumerable: false });
6598
+ if (ngDevMode) {
6599
+ Object.defineProperty(obj, 'debug', { value: debug, enumerable: false });
6600
+ }
6601
+ else {
6602
+ throw new Error('This method should be guarded with `ngDevMode` so that it can be tree shaken in production!');
6603
+ }
6604
+ }
6605
+ /**
6606
+ * Patch a `debug` property getter on top of the existing object.
6607
+ *
6608
+ * NOTE: always call this method with `ngDevMode && attachDebugObject(...)`
6609
+ *
6610
+ * @param obj Object to patch
6611
+ * @param debugGetter Getter returning a value to patch
6612
+ */
6613
+ function attachDebugGetter(obj, debugGetter) {
6614
+ if (ngDevMode) {
6615
+ Object.defineProperty(obj, 'debug', { get: debugGetter, enumerable: false });
6616
+ }
6617
+ else {
6618
+ throw new Error('This method should be guarded with `ngDevMode` so that it can be tree shaken in production!');
6619
+ }
6606
6620
  }
6607
6621
 
6608
6622
  /**
@@ -6723,8 +6737,9 @@
6723
6737
  firstChild, //
6724
6738
  schemas, //
6725
6739
  consts, //
6726
- incompleteFirstPass //
6727
- ) {
6740
+ incompleteFirstPass, //
6741
+ _decls, //
6742
+ _vars) {
6728
6743
  this.type = type;
6729
6744
  this.id = id;
6730
6745
  this.blueprint = blueprint;
@@ -6756,6 +6771,8 @@
6756
6771
  this.schemas = schemas;
6757
6772
  this.consts = consts;
6758
6773
  this.incompleteFirstPass = incompleteFirstPass;
6774
+ this._decls = _decls;
6775
+ this._vars = _vars;
6759
6776
  }
6760
6777
  Object.defineProperty(TView.prototype, "template_", {
6761
6778
  get: function () {
@@ -7002,19 +7019,23 @@
7002
7019
  if (includeChildren === void 0) { includeChildren = false; }
7003
7020
  var node = unwrapRNode(value);
7004
7021
  if (node) {
7005
- var isTextNode = node.nodeType === Node.TEXT_NODE;
7006
- var outerHTML = (isTextNode ? node.textContent : node.outerHTML) || '';
7007
- if (includeChildren || isTextNode) {
7008
- return outerHTML;
7009
- }
7010
- else {
7011
- var innerHTML = '>' + node.innerHTML + '<';
7012
- return (outerHTML.split(innerHTML)[0]) + '>';
7022
+ switch (node.nodeType) {
7023
+ case Node.TEXT_NODE:
7024
+ return node.textContent;
7025
+ case Node.COMMENT_NODE:
7026
+ return "<!--" + node.textContent + "-->";
7027
+ case Node.ELEMENT_NODE:
7028
+ var outerHTML = node.outerHTML;
7029
+ if (includeChildren) {
7030
+ return outerHTML;
7031
+ }
7032
+ else {
7033
+ var innerHTML = '>' + node.innerHTML + '<';
7034
+ return (outerHTML.split(innerHTML)[0]) + '>';
7035
+ }
7013
7036
  }
7014
7037
  }
7015
- else {
7016
- return null;
7017
- }
7038
+ return null;
7018
7039
  }
7019
7040
  var LViewDebug = /** @class */ (function () {
7020
7041
  function LViewDebug(_raw_lView) {
@@ -7049,7 +7070,7 @@
7049
7070
  enumerable: false,
7050
7071
  configurable: true
7051
7072
  });
7052
- Object.defineProperty(LViewDebug.prototype, "host", {
7073
+ Object.defineProperty(LViewDebug.prototype, "hostHTML", {
7053
7074
  get: function () {
7054
7075
  return toHtml(this._raw_lView[HOST], true);
7055
7076
  },
@@ -7073,8 +7094,7 @@
7073
7094
  Object.defineProperty(LViewDebug.prototype, "nodes", {
7074
7095
  /**
7075
7096
  * The tree of nodes associated with the current `LView`. The nodes have been normalized into
7076
- * a
7077
- * tree structure with relevant details pulled out for readability.
7097
+ * a tree structure with relevant details pulled out for readability.
7078
7098
  */
7079
7099
  get: function () {
7080
7100
  var lView = this._raw_lView;
@@ -7168,6 +7188,41 @@
7168
7188
  enumerable: false,
7169
7189
  configurable: true
7170
7190
  });
7191
+ Object.defineProperty(LViewDebug.prototype, "decls", {
7192
+ get: function () {
7193
+ var tView = this.tView;
7194
+ var start = HEADER_OFFSET;
7195
+ return toLViewRange(this.tView, this._raw_lView, start, start + tView._decls);
7196
+ },
7197
+ enumerable: false,
7198
+ configurable: true
7199
+ });
7200
+ Object.defineProperty(LViewDebug.prototype, "vars", {
7201
+ get: function () {
7202
+ var tView = this.tView;
7203
+ var start = HEADER_OFFSET + tView._decls;
7204
+ return toLViewRange(this.tView, this._raw_lView, start, start + tView._vars);
7205
+ },
7206
+ enumerable: false,
7207
+ configurable: true
7208
+ });
7209
+ Object.defineProperty(LViewDebug.prototype, "i18n", {
7210
+ get: function () {
7211
+ var tView = this.tView;
7212
+ var start = HEADER_OFFSET + tView._decls + tView._vars;
7213
+ return toLViewRange(this.tView, this._raw_lView, start, this.tView.expandoStartIndex);
7214
+ },
7215
+ enumerable: false,
7216
+ configurable: true
7217
+ });
7218
+ Object.defineProperty(LViewDebug.prototype, "expando", {
7219
+ get: function () {
7220
+ var tView = this.tView;
7221
+ return toLViewRange(this.tView, this._raw_lView, this.tView.expandoStartIndex, this._raw_lView.length);
7222
+ },
7223
+ enumerable: false,
7224
+ configurable: true
7225
+ });
7171
7226
  Object.defineProperty(LViewDebug.prototype, "childViews", {
7172
7227
  /**
7173
7228
  * Normalized view of child views (and containers) attached at this location.
@@ -7186,6 +7241,13 @@
7186
7241
  });
7187
7242
  return LViewDebug;
7188
7243
  }());
7244
+ function toLViewRange(tView, lView, start, end) {
7245
+ var content = [];
7246
+ for (var index = start; index < end; index++) {
7247
+ content.push({ index: index, t: tView.data[index], l: lView[index] });
7248
+ }
7249
+ return { start: start, end: end, length: end - start, content: content };
7250
+ }
7189
7251
  /**
7190
7252
  * Turns a flat list of nodes into a tree by walking the associated `TNode` tree.
7191
7253
  *
@@ -7203,18 +7265,17 @@
7203
7265
  return debugNodes;
7204
7266
  }
7205
7267
  else {
7206
- return null;
7268
+ return [];
7207
7269
  }
7208
7270
  }
7209
7271
  function buildDebugNode(tNode, lView, nodeIndex) {
7210
7272
  var rawValue = lView[nodeIndex];
7211
7273
  var native = unwrapRNode(rawValue);
7212
- var componentLViewDebug = toDebug(readLViewValue(rawValue));
7213
7274
  return {
7214
7275
  html: toHtml(native),
7276
+ type: TNodeTypeAsString[tNode.type],
7215
7277
  native: native,
7216
- nodes: toDebugNodes(tNode.child, lView),
7217
- component: componentLViewDebug,
7278
+ children: toDebugNodes(tNode.child, lView),
7218
7279
  };
7219
7280
  }
7220
7281
  var LContainerDebug = /** @class */ (function () {
@@ -7288,211 +7349,6 @@
7288
7349
  }
7289
7350
  return null;
7290
7351
  }
7291
- var I18NDebugItem = /** @class */ (function () {
7292
- function I18NDebugItem(__raw_opCode, _lView, nodeIndex, type) {
7293
- this.__raw_opCode = __raw_opCode;
7294
- this._lView = _lView;
7295
- this.nodeIndex = nodeIndex;
7296
- this.type = type;
7297
- }
7298
- Object.defineProperty(I18NDebugItem.prototype, "tNode", {
7299
- get: function () {
7300
- return getTNode(this._lView[TVIEW], this.nodeIndex);
7301
- },
7302
- enumerable: false,
7303
- configurable: true
7304
- });
7305
- return I18NDebugItem;
7306
- }());
7307
- /**
7308
- * Turns a list of "Create" & "Update" OpCodes into a human-readable list of operations for
7309
- * debugging purposes.
7310
- * @param mutateOpCodes mutation opCodes to read
7311
- * @param updateOpCodes update opCodes to read
7312
- * @param icus list of ICU expressions
7313
- * @param lView The view the opCodes are acting on
7314
- */
7315
- function attachI18nOpCodesDebug(mutateOpCodes, updateOpCodes, icus, lView) {
7316
- attachDebugObject(mutateOpCodes, new I18nMutateOpCodesDebug(mutateOpCodes, lView));
7317
- attachDebugObject(updateOpCodes, new I18nUpdateOpCodesDebug(updateOpCodes, icus, lView));
7318
- if (icus) {
7319
- icus.forEach(function (icu) {
7320
- icu.create.forEach(function (icuCase) {
7321
- attachDebugObject(icuCase, new I18nMutateOpCodesDebug(icuCase, lView));
7322
- });
7323
- icu.update.forEach(function (icuCase) {
7324
- attachDebugObject(icuCase, new I18nUpdateOpCodesDebug(icuCase, icus, lView));
7325
- });
7326
- });
7327
- }
7328
- }
7329
- var I18nMutateOpCodesDebug = /** @class */ (function () {
7330
- function I18nMutateOpCodesDebug(__raw_opCodes, __lView) {
7331
- this.__raw_opCodes = __raw_opCodes;
7332
- this.__lView = __lView;
7333
- }
7334
- Object.defineProperty(I18nMutateOpCodesDebug.prototype, "operations", {
7335
- /**
7336
- * A list of operation information about how the OpCodes will act on the view.
7337
- */
7338
- get: function () {
7339
- var _a = this, __lView = _a.__lView, __raw_opCodes = _a.__raw_opCodes;
7340
- var results = [];
7341
- for (var i = 0; i < __raw_opCodes.length; i++) {
7342
- var opCode = __raw_opCodes[i];
7343
- var result = void 0;
7344
- if (typeof opCode === 'string') {
7345
- result = {
7346
- __raw_opCode: opCode,
7347
- type: 'Create Text Node',
7348
- nodeIndex: __raw_opCodes[++i],
7349
- text: opCode,
7350
- };
7351
- }
7352
- if (typeof opCode === 'number') {
7353
- switch (opCode & 7 /* MASK_OPCODE */) {
7354
- case 1 /* AppendChild */:
7355
- var destinationNodeIndex = opCode >>> 17 /* SHIFT_PARENT */;
7356
- result = new I18NDebugItem(opCode, __lView, destinationNodeIndex, 'AppendChild');
7357
- break;
7358
- case 0 /* Select */:
7359
- var nodeIndex = opCode >>> 3 /* SHIFT_REF */;
7360
- result = new I18NDebugItem(opCode, __lView, nodeIndex, 'Select');
7361
- break;
7362
- case 5 /* ElementEnd */:
7363
- var elementIndex = opCode >>> 3 /* SHIFT_REF */;
7364
- result = new I18NDebugItem(opCode, __lView, elementIndex, 'ElementEnd');
7365
- break;
7366
- case 4 /* Attr */:
7367
- elementIndex = opCode >>> 3 /* SHIFT_REF */;
7368
- result = new I18NDebugItem(opCode, __lView, elementIndex, 'Attr');
7369
- result['attrName'] = __raw_opCodes[++i];
7370
- result['attrValue'] = __raw_opCodes[++i];
7371
- break;
7372
- }
7373
- }
7374
- if (!result) {
7375
- switch (opCode) {
7376
- case COMMENT_MARKER:
7377
- result = {
7378
- __raw_opCode: opCode,
7379
- type: 'COMMENT_MARKER',
7380
- commentValue: __raw_opCodes[++i],
7381
- nodeIndex: __raw_opCodes[++i],
7382
- };
7383
- break;
7384
- case ELEMENT_MARKER:
7385
- result = {
7386
- __raw_opCode: opCode,
7387
- type: 'ELEMENT_MARKER',
7388
- };
7389
- break;
7390
- }
7391
- }
7392
- if (!result) {
7393
- result = {
7394
- __raw_opCode: opCode,
7395
- type: 'Unknown Op Code',
7396
- code: opCode,
7397
- };
7398
- }
7399
- results.push(result);
7400
- }
7401
- return results;
7402
- },
7403
- enumerable: false,
7404
- configurable: true
7405
- });
7406
- return I18nMutateOpCodesDebug;
7407
- }());
7408
- var I18nUpdateOpCodesDebug = /** @class */ (function () {
7409
- function I18nUpdateOpCodesDebug(__raw_opCodes, icus, __lView) {
7410
- this.__raw_opCodes = __raw_opCodes;
7411
- this.icus = icus;
7412
- this.__lView = __lView;
7413
- }
7414
- Object.defineProperty(I18nUpdateOpCodesDebug.prototype, "operations", {
7415
- /**
7416
- * A list of operation information about how the OpCodes will act on the view.
7417
- */
7418
- get: function () {
7419
- var _a = this, __lView = _a.__lView, __raw_opCodes = _a.__raw_opCodes, icus = _a.icus;
7420
- var results = [];
7421
- for (var i = 0; i < __raw_opCodes.length; i++) {
7422
- // bit code to check if we should apply the next update
7423
- var checkBit = __raw_opCodes[i];
7424
- // Number of opCodes to skip until next set of update codes
7425
- var skipCodes = __raw_opCodes[++i];
7426
- var value = '';
7427
- for (var j = i + 1; j <= (i + skipCodes); j++) {
7428
- var opCode = __raw_opCodes[j];
7429
- if (typeof opCode === 'string') {
7430
- value += opCode;
7431
- }
7432
- else if (typeof opCode == 'number') {
7433
- if (opCode < 0) {
7434
- // It's a binding index whose value is negative
7435
- // We cannot know the value of the binding so we only show the index
7436
- value += "\uFFFD" + (-opCode - 1) + "\uFFFD";
7437
- }
7438
- else {
7439
- var nodeIndex = opCode >>> 2 /* SHIFT_REF */;
7440
- var tIcuIndex = void 0;
7441
- var tIcu = void 0;
7442
- switch (opCode & 3 /* MASK_OPCODE */) {
7443
- case 1 /* Attr */:
7444
- var attrName = __raw_opCodes[++j];
7445
- var sanitizeFn = __raw_opCodes[++j];
7446
- results.push({
7447
- __raw_opCode: opCode,
7448
- checkBit: checkBit,
7449
- type: 'Attr',
7450
- attrValue: value,
7451
- attrName: attrName,
7452
- sanitizeFn: sanitizeFn,
7453
- });
7454
- break;
7455
- case 0 /* Text */:
7456
- results.push({
7457
- __raw_opCode: opCode,
7458
- checkBit: checkBit,
7459
- type: 'Text',
7460
- nodeIndex: nodeIndex,
7461
- text: value,
7462
- });
7463
- break;
7464
- case 2 /* IcuSwitch */:
7465
- tIcuIndex = __raw_opCodes[++j];
7466
- tIcu = icus[tIcuIndex];
7467
- var result = new I18NDebugItem(opCode, __lView, nodeIndex, 'IcuSwitch');
7468
- result['tIcuIndex'] = tIcuIndex;
7469
- result['checkBit'] = checkBit;
7470
- result['mainBinding'] = value;
7471
- result['tIcu'] = tIcu;
7472
- results.push(result);
7473
- break;
7474
- case 3 /* IcuUpdate */:
7475
- tIcuIndex = __raw_opCodes[++j];
7476
- tIcu = icus[tIcuIndex];
7477
- result = new I18NDebugItem(opCode, __lView, nodeIndex, 'IcuUpdate');
7478
- result['tIcuIndex'] = tIcuIndex;
7479
- result['checkBit'] = checkBit;
7480
- result['tIcu'] = tIcu;
7481
- results.push(result);
7482
- break;
7483
- }
7484
- }
7485
- }
7486
- }
7487
- i += skipCodes;
7488
- }
7489
- return results;
7490
- },
7491
- enumerable: false,
7492
- configurable: true
7493
- });
7494
- return I18nUpdateOpCodesDebug;
7495
- }());
7496
7352
 
7497
7353
  var ɵ0$4 = function () { return Promise.resolve(null); };
7498
7354
  /**
@@ -8014,7 +7870,7 @@
8014
7870
  // that has a host binding, we will update the blueprint with that def's hostVars count.
8015
7871
  var initialViewLength = bindingStartIndex + vars;
8016
7872
  var blueprint = createViewBlueprint(bindingStartIndex, initialViewLength);
8017
- return blueprint[TVIEW] = ngDevMode ?
7873
+ var tView = blueprint[TVIEW] = ngDevMode ?
8018
7874
  new TViewConstructor(type, viewIndex, // id: number,
8019
7875
  blueprint, // blueprint: LView,
8020
7876
  templateFn, // template: ComponentTemplate<{}>|null,
@@ -8046,8 +7902,9 @@
8046
7902
  null, // firstChild: TNode|null,
8047
7903
  schemas, // schemas: SchemaMetadata[]|null,
8048
7904
  consts, // consts: TConstants|null
8049
- false // incompleteFirstPass: boolean
8050
- ) :
7905
+ false, // incompleteFirstPass: boolean
7906
+ decls, // ngDevMode only: decls
7907
+ vars) :
8051
7908
  {
8052
7909
  type: type,
8053
7910
  id: viewIndex,
@@ -8081,6 +7938,13 @@
8081
7938
  consts: consts,
8082
7939
  incompleteFirstPass: false
8083
7940
  };
7941
+ if (ngDevMode) {
7942
+ // For performance reasons it is important that the tView retains the same shape during runtime.
7943
+ // (To make sure that all of the code is monomorphic.) For this reason we seal the object to
7944
+ // prevent class transitions.
7945
+ Object.seal(tView);
7946
+ }
7947
+ return tView;
8084
7948
  }
8085
7949
  function createViewBlueprint(bindingStartIndex, initialViewLength) {
8086
7950
  var blueprint = ngDevMode ? new LViewBlueprint() : [];
@@ -8154,37 +8018,38 @@
8154
8018
  function createTNode(tView, tParent, type, adjustedIndex, tagName, attrs) {
8155
8019
  ngDevMode && ngDevMode.tNode++;
8156
8020
  var injectorIndex = tParent ? tParent.injectorIndex : -1;
8157
- return ngDevMode ? new TNodeDebug(tView, // tView_: TView
8158
- type, // type: TNodeType
8159
- adjustedIndex, // index: number
8160
- injectorIndex, // injectorIndex: number
8161
- -1, // directiveStart: number
8162
- -1, // directiveEnd: number
8163
- -1, // directiveStylingLast: number
8164
- null, // propertyBindings: number[]|null
8165
- 0, // flags: TNodeFlags
8166
- 0, // providerIndexes: TNodeProviderIndexes
8167
- tagName, // tagName: string|null
8168
- attrs, // attrs: (string|AttributeMarker|(string|SelectorFlags)[])[]|null
8169
- null, // mergedAttrs
8170
- null, // localNames: (string|number)[]|null
8171
- undefined, // initialInputs: (string[]|null)[]|null|undefined
8172
- null, // inputs: PropertyAliases|null
8173
- null, // outputs: PropertyAliases|null
8174
- null, // tViews: ITView|ITView[]|null
8175
- null, // next: ITNode|null
8176
- null, // projectionNext: ITNode|null
8177
- null, // child: ITNode|null
8178
- tParent, // parent: TElementNode|TContainerNode|null
8179
- null, // projection: number|(ITNode|RNode[])[]|null
8180
- null, // styles: string|null
8181
- null, // stylesWithoutHost: string|null
8182
- undefined, // residualStyles: string|null
8183
- null, // classes: string|null
8184
- null, // classesWithoutHost: string|null
8185
- undefined, // residualClasses: string|null
8186
- 0, // classBindings: TStylingRange;
8187
- 0) :
8021
+ var tNode = ngDevMode ?
8022
+ new TNodeDebug(tView, // tView_: TView
8023
+ type, // type: TNodeType
8024
+ adjustedIndex, // index: number
8025
+ injectorIndex, // injectorIndex: number
8026
+ -1, // directiveStart: number
8027
+ -1, // directiveEnd: number
8028
+ -1, // directiveStylingLast: number
8029
+ null, // propertyBindings: number[]|null
8030
+ 0, // flags: TNodeFlags
8031
+ 0, // providerIndexes: TNodeProviderIndexes
8032
+ tagName, // tagName: string|null
8033
+ attrs, // attrs: (string|AttributeMarker|(string|SelectorFlags)[])[]|null
8034
+ null, // mergedAttrs
8035
+ null, // localNames: (string|number)[]|null
8036
+ undefined, // initialInputs: (string[]|null)[]|null|undefined
8037
+ null, // inputs: PropertyAliases|null
8038
+ null, // outputs: PropertyAliases|null
8039
+ null, // tViews: ITView|ITView[]|null
8040
+ null, // next: ITNode|null
8041
+ null, // projectionNext: ITNode|null
8042
+ null, // child: ITNode|null
8043
+ tParent, // parent: TElementNode|TContainerNode|null
8044
+ null, // projection: number|(ITNode|RNode[])[]|null
8045
+ null, // styles: string|null
8046
+ null, // stylesWithoutHost: string|null
8047
+ undefined, // residualStyles: string|null
8048
+ null, // classes: string|null
8049
+ null, // classesWithoutHost: string|null
8050
+ undefined, // residualClasses: string|null
8051
+ 0, // classBindings: TStylingRange;
8052
+ 0) :
8188
8053
  {
8189
8054
  type: type,
8190
8055
  index: adjustedIndex,
@@ -8217,6 +8082,13 @@
8217
8082
  classBindings: 0,
8218
8083
  styleBindings: 0,
8219
8084
  };
8085
+ if (ngDevMode) {
8086
+ // For performance reasons it is important that the tNode retains the same shape during runtime.
8087
+ // (To make sure that all of the code is monomorphic.) For this reason we seal the object to
8088
+ // prevent class transitions.
8089
+ Object.seal(tNode);
8090
+ }
8091
+ return tNode;
8220
8092
  }
8221
8093
  function generatePropertyAliases(inputAliasMap, directiveDefIdx, propStore) {
8222
8094
  for (var publicName in inputAliasMap) {
@@ -9257,7 +9129,7 @@
9257
9129
  var index = inputs[i++];
9258
9130
  var privateName = inputs[i++];
9259
9131
  var instance = lView[index];
9260
- ngDevMode && assertDataInRange(lView, index);
9132
+ ngDevMode && assertIndexInRange(lView, index);
9261
9133
  var def = tView.data[index];
9262
9134
  if (def.setInput !== null) {
9263
9135
  def.setInput(instance, value, publicName, privateName);
@@ -9272,7 +9144,7 @@
9272
9144
  */
9273
9145
  function textBindingInternal(lView, index, value) {
9274
9146
  ngDevMode && assertNotSame(value, NO_CHANGE, 'value should not be NO_CHANGE');
9275
- ngDevMode && assertDataInRange(lView, index + HEADER_OFFSET);
9147
+ ngDevMode && assertIndexInRange(lView, index + HEADER_OFFSET);
9276
9148
  var element = getNativeByIndex(index, lView);
9277
9149
  ngDevMode && assertDefined(element, 'native element should exist');
9278
9150
  ngDevMode && ngDevMode.rendererSetText++;
@@ -9553,16 +9425,6 @@
9553
9425
  }
9554
9426
  return viewToDetach;
9555
9427
  }
9556
- /**
9557
- * Removes a view from a container, i.e. detaches it and then destroys the underlying LView.
9558
- *
9559
- * @param lContainer The container from which to remove a view
9560
- * @param removeIndex The index of the view to remove
9561
- */
9562
- function removeView(lContainer, removeIndex) {
9563
- var detachedView = detachView(lContainer, removeIndex);
9564
- detachedView && destroyLView(detachedView[TVIEW], detachedView);
9565
- }
9566
9428
  /**
9567
9429
  * A standalone function which destroys an LView,
9568
9430
  * conducting clean up (e.g. removing listeners, calling onDestroys).
@@ -10818,8 +10680,17 @@
10818
10680
  ViewContainerRef.prototype.remove = function (index) {
10819
10681
  this.allocateContainerIfNeeded();
10820
10682
  var adjustedIdx = this._adjustIndex(index, -1);
10821
- removeView(this._lContainer, adjustedIdx);
10822
- removeFromArray(this._lContainer[VIEW_REFS], adjustedIdx);
10683
+ var detachedView = detachView(this._lContainer, adjustedIdx);
10684
+ if (detachedView) {
10685
+ // Before destroying the view, remove it from the container's array of `ViewRef`s.
10686
+ // This ensures the view container length is updated before calling
10687
+ // `destroyLView`, which could recursively call view container methods that
10688
+ // rely on an accurate container length.
10689
+ // (e.g. a method on this view container being called by a child directive's OnDestroy
10690
+ // lifecycle hook)
10691
+ removeFromArray(this._lContainer[VIEW_REFS], adjustedIdx);
10692
+ destroyLView(detachedView[TVIEW], detachedView);
10693
+ }
10823
10694
  };
10824
10695
  ViewContainerRef.prototype.detach = function (index) {
10825
10696
  this.allocateContainerIfNeeded();
@@ -11035,13 +10906,42 @@
11035
10906
  return typeof v === 'function';
11036
10907
  }
11037
10908
 
10909
+ /*
10910
+ * #########################
10911
+ * Attention: These Regular expressions have to hold even if the code is minified!
10912
+ * ##########################
10913
+ */
10914
+ /**
10915
+ * Regular expression that detects pass-through constructors for ES5 output. This Regex
10916
+ * intends to capture the common delegation pattern emitted by TypeScript and Babel. Also
10917
+ * it intends to capture the pattern where existing constructors have been downleveled from
10918
+ * ES2015 to ES5 using TypeScript w/ downlevel iteration. e.g.
10919
+ *
10920
+ * ```
10921
+ * function MyClass() {
10922
+ * var _this = _super.apply(this, arguments) || this;
10923
+ * ```
10924
+ *
10925
+ * ```
10926
+ * function MyClass() {
10927
+ * var _this = _super.apply(this, __spread(arguments)) || this;
10928
+ * ```
10929
+ *
10930
+ * More details can be found in: https://github.com/angular/angular/issues/38453.
10931
+ */
10932
+ var ES5_DELEGATE_CTOR = /^function\s+\S+\(\)\s*{[\s\S]+\.apply\(this,\s*(arguments|[^()]+\(arguments\))\)/;
10933
+ /** Regular expression that detects ES2015 classes which extend from other classes. */
10934
+ var ES2015_INHERITED_CLASS = /^class\s+[A-Za-z\d$_]*\s*extends\s+[^{]+{/;
10935
+ /**
10936
+ * Regular expression that detects ES2015 classes which extend from other classes and
10937
+ * have an explicit constructor defined.
10938
+ */
10939
+ var ES2015_INHERITED_CLASS_WITH_CTOR = /^class\s+[A-Za-z\d$_]*\s*extends\s+[^{]+{[\s\S]*constructor\s*\(/;
11038
10940
  /**
11039
- * Attention: These regex has to hold even if the code is minified!
10941
+ * Regular expression that detects ES2015 classes which extend from other classes
10942
+ * and inherit a constructor.
11040
10943
  */
11041
- var DELEGATE_CTOR = /^function\s+\S+\(\)\s*{[\s\S]+\.apply\(this,\s*arguments\)/;
11042
- var INHERITED_CLASS = /^class\s+[A-Za-z\d$_]*\s*extends\s+[^{]+{/;
11043
- var INHERITED_CLASS_WITH_CTOR = /^class\s+[A-Za-z\d$_]*\s*extends\s+[^{]+{[\s\S]*constructor\s*\(/;
11044
- var INHERITED_CLASS_WITH_DELEGATE_CTOR = /^class\s+[A-Za-z\d$_]*\s*extends\s+[^{]+{[\s\S]*constructor\s*\(\)\s*{\s*super\(\.\.\.arguments\)/;
10944
+ var ES2015_INHERITED_CLASS_WITH_DELEGATE_CTOR = /^class\s+[A-Za-z\d$_]*\s*extends\s+[^{]+{[\s\S]*constructor\s*\(\)\s*{\s*super\(\.\.\.arguments\)/;
11045
10945
  /**
11046
10946
  * Determine whether a stringified type is a class which delegates its constructor
11047
10947
  * to its parent.
@@ -11051,8 +10951,9 @@
11051
10951
  * an initialized instance property.
11052
10952
  */
11053
10953
  function isDelegateCtor(typeStr) {
11054
- return DELEGATE_CTOR.test(typeStr) || INHERITED_CLASS_WITH_DELEGATE_CTOR.test(typeStr) ||
11055
- (INHERITED_CLASS.test(typeStr) && !INHERITED_CLASS_WITH_CTOR.test(typeStr));
10954
+ return ES5_DELEGATE_CTOR.test(typeStr) ||
10955
+ ES2015_INHERITED_CLASS_WITH_DELEGATE_CTOR.test(typeStr) ||
10956
+ (ES2015_INHERITED_CLASS.test(typeStr) && !ES2015_INHERITED_CLASS_WITH_CTOR.test(typeStr));
11056
10957
  }
11057
10958
  var ReflectionCapabilities = /** @class */ (function () {
11058
10959
  function ReflectionCapabilities(reflect) {
@@ -13647,7 +13548,7 @@
13647
13548
  }
13648
13549
  /** Gets the current binding value. */
13649
13550
  function getBinding(lView, bindingIndex) {
13650
- ngDevMode && assertDataInRange(lView, bindingIndex);
13551
+ ngDevMode && assertIndexInRange(lView, bindingIndex);
13651
13552
  ngDevMode &&
13652
13553
  assertNotSame(lView[bindingIndex], NO_CHANGE, 'Stored value should never be NO_CHANGE.');
13653
13554
  return lView[bindingIndex];
@@ -14542,7 +14443,7 @@
14542
14443
  ngDevMode &&
14543
14444
  assertEqual(getBindingIndex(), tView.bindingStartIndex, 'elements should be created before any bindings');
14544
14445
  ngDevMode && ngDevMode.rendererCreateElement++;
14545
- ngDevMode && assertDataInRange(lView, adjustedIndex);
14446
+ ngDevMode && assertIndexInRange(lView, adjustedIndex);
14546
14447
  var renderer = lView[RENDERER];
14547
14448
  var native = lView[adjustedIndex] = elementCreate(name, renderer, getNamespace());
14548
14449
  var tNode = tView.firstCreatePass ?
@@ -14702,7 +14603,7 @@
14702
14603
  var lView = getLView();
14703
14604
  var tView = getTView();
14704
14605
  var adjustedIndex = index + HEADER_OFFSET;
14705
- ngDevMode && assertDataInRange(lView, adjustedIndex);
14606
+ ngDevMode && assertIndexInRange(lView, adjustedIndex);
14706
14607
  ngDevMode &&
14707
14608
  assertEqual(getBindingIndex(), tView.bindingStartIndex, 'element containers should be created before any bindings');
14708
14609
  var tNode = tView.firstCreatePass ?
@@ -14969,7 +14870,7 @@
14969
14870
  if (propsLength) {
14970
14871
  for (var i = 0; i < propsLength; i += 2) {
14971
14872
  var index = props[i];
14972
- ngDevMode && assertDataInRange(lView, index);
14873
+ ngDevMode && assertIndexInRange(lView, index);
14973
14874
  var minifiedName = props[i + 1];
14974
14875
  var directiveInstance = lView[index];
14975
14876
  var output = directiveInstance[minifiedName];
@@ -16029,7 +15930,7 @@
16029
15930
  // - we are a map in which case we have to continue searching even after we find what we were
16030
15931
  // looking for since we are a wild card and everything needs to be flipped to duplicate.
16031
15932
  while (cursor !== 0 && (foundDuplicate === false || isMap)) {
16032
- ngDevMode && assertDataInRange(tData, cursor);
15933
+ ngDevMode && assertIndexInRange(tData, cursor);
16033
15934
  var tStylingValueAtCursor = tData[cursor];
16034
15935
  var tStyleRangeAtCursor = tData[cursor + 1];
16035
15936
  if (isStylingMatch(tStylingValueAtCursor, tStylingKey)) {
@@ -16252,7 +16153,8 @@
16252
16153
  var ch;
16253
16154
  while (startIndex < endIndex &&
16254
16155
  ((ch = text.charCodeAt(startIndex)) === 45 /* DASH */ || ch === 95 /* UNDERSCORE */ ||
16255
- ((ch & -33 /* UPPER_CASE */) >= 65 /* A */ && (ch & -33 /* UPPER_CASE */) <= 90 /* Z */))) {
16156
+ ((ch & -33 /* UPPER_CASE */) >= 65 /* A */ && (ch & -33 /* UPPER_CASE */) <= 90 /* Z */) ||
16157
+ (ch >= 48 /* ZERO */ && ch <= 57 /* NINE */))) {
16256
16158
  startIndex++;
16257
16159
  }
16258
16160
  return startIndex;
@@ -17146,7 +17048,7 @@
17146
17048
  var adjustedIndex = index + HEADER_OFFSET;
17147
17049
  ngDevMode &&
17148
17050
  assertEqual(getBindingIndex(), tView.bindingStartIndex, 'text nodes should be created before any bindings');
17149
- ngDevMode && assertDataInRange(lView, adjustedIndex);
17051
+ ngDevMode && assertIndexInRange(lView, adjustedIndex);
17150
17052
  var tNode = tView.firstCreatePass ?
17151
17053
  getOrCreateTNode(tView, lView[T_HOST], index, 3 /* Element */, null, null) :
17152
17054
  tView.data[adjustedIndex];
@@ -19009,7 +18911,7 @@
19009
18911
  */
19010
18912
  function createRootComponentView(rNode, def, rootView, rendererFactory, hostRenderer, sanitizer) {
19011
18913
  var tView = rootView[TVIEW];
19012
- ngDevMode && assertDataInRange(rootView, 0 + HEADER_OFFSET);
18914
+ ngDevMode && assertIndexInRange(rootView, 0 + HEADER_OFFSET);
19013
18915
  rootView[0 + HEADER_OFFSET] = rNode;
19014
18916
  var tNode = getOrCreateTNode(tView, null, 0, 3 /* Element */, null, null);
19015
18917
  var mergedAttrs = tNode.mergedAttrs = def.hostAttrs;
@@ -19915,7 +19817,7 @@
19915
19817
  /**
19916
19818
  * @publicApi
19917
19819
  */
19918
- var VERSION = new Version('10.0.6');
19820
+ var VERSION = new Version('10.0.10');
19919
19821
 
19920
19822
  /**
19921
19823
  * @license
@@ -23059,30 +22961,6 @@
23059
22961
  return ComponentRef;
23060
22962
  }(ComponentRef));
23061
22963
 
23062
- /**
23063
- * @license
23064
- * Copyright Google LLC All Rights Reserved.
23065
- *
23066
- * Use of this source code is governed by an MIT-style license that can be
23067
- * found in the LICENSE file at https://angular.io/license
23068
- */
23069
- /**
23070
- * NOTE: changes to the `ngI18nClosureMode` name must be synced with `compiler-cli/src/tooling.ts`.
23071
- */
23072
- if (typeof ngI18nClosureMode === 'undefined') {
23073
- // These property accesses can be ignored because ngI18nClosureMode will be set to false
23074
- // when optimizing code and the whole if statement will be dropped.
23075
- // Make sure to refer to ngI18nClosureMode as ['ngI18nClosureMode'] for closure.
23076
- // NOTE: we need to have it in IIFE so that the tree-shaker is happy.
23077
- (function () {
23078
- // tslint:disable-next-line:no-toplevel-property-access
23079
- _global['ngI18nClosureMode'] =
23080
- // TODO(FW-1250): validate that this actually, you know, works.
23081
- // tslint:disable-next-line:no-toplevel-property-access
23082
- typeof goog !== 'undefined' && typeof goog.getMsg === 'function';
23083
- })();
23084
- }
23085
-
23086
22964
  /**
23087
22965
  * @license
23088
22966
  * Copyright Google LLC All Rights Reserved.
@@ -23285,405 +23163,401 @@
23285
23163
  */
23286
23164
  var USD_CURRENCY_CODE = 'USD';
23287
23165
 
23288
- var MARKER = "\uFFFD";
23289
- var ICU_BLOCK_REGEXP = /^\s*(�\d+:?\d*�)\s*,\s*(select|plural)\s*,/;
23290
- var SUBTEMPLATE_REGEXP = /�\/?\*(\d+:\d+)�/gi;
23291
- var PH_REGEXP = /�(\/?[#*!]\d+):?\d*�/gi;
23292
- var BINDING_REGEXP = /�(\d+):?\d*�/gi;
23293
- var ICU_REGEXP = /({\s*�\d+:?\d*�\s*,\s*\S{6}\s*,[\s\S]*})/gi;
23294
- // i18nPostprocess consts
23295
- var ROOT_TEMPLATE_ID = 0;
23296
- var PP_MULTI_VALUE_PLACEHOLDERS_REGEXP = /\[(�.+?�?)\]/;
23297
- var PP_PLACEHOLDERS_REGEXP = /\[(�.+?�?)\]|(�\/?\*\d+:\d+�)/g;
23298
- var PP_ICU_VARS_REGEXP = /({\s*)(VAR_(PLURAL|SELECT)(_\d+)?)(\s*,)/g;
23299
- var PP_ICU_PLACEHOLDERS_REGEXP = /{([A-Z0-9_]+)}/g;
23300
- var PP_ICUS_REGEXP = /�I18N_EXP_(ICU(_\d+)?)�/g;
23301
- var PP_CLOSE_TEMPLATE_REGEXP = /\/\*/;
23302
- var PP_TEMPLATE_ID_REGEXP = /\d+\:(\d+)/;
23303
23166
  /**
23304
- * Breaks pattern into strings and top level {...} blocks.
23305
- * Can be used to break a message into text and ICU expressions, or to break an ICU expression into
23306
- * keys and cases.
23307
- * Original code from closure library, modified for Angular.
23308
- *
23309
- * @param pattern (sub)Pattern to be broken.
23167
+ * @license
23168
+ * Copyright Google LLC All Rights Reserved.
23310
23169
  *
23170
+ * Use of this source code is governed by an MIT-style license that can be
23171
+ * found in the LICENSE file at https://angular.io/license
23311
23172
  */
23312
- function extractParts(pattern) {
23313
- if (!pattern) {
23314
- return [];
23315
- }
23316
- var prevPos = 0;
23317
- var braceStack = [];
23318
- var results = [];
23319
- var braces = /[{}]/g;
23320
- // lastIndex doesn't get set to 0 so we have to.
23321
- braces.lastIndex = 0;
23322
- var match;
23323
- while (match = braces.exec(pattern)) {
23324
- var pos = match.index;
23325
- if (match[0] == '}') {
23326
- braceStack.pop();
23327
- if (braceStack.length == 0) {
23328
- // End of the block.
23329
- var block = pattern.substring(prevPos, pos);
23330
- if (ICU_BLOCK_REGEXP.test(block)) {
23331
- results.push(parseICUBlock(block));
23332
- }
23333
- else {
23334
- results.push(block);
23335
- }
23336
- prevPos = pos + 1;
23337
- }
23338
- }
23339
- else {
23340
- if (braceStack.length == 0) {
23341
- var substring_1 = pattern.substring(prevPos, pos);
23342
- results.push(substring_1);
23343
- prevPos = pos + 1;
23344
- }
23345
- braceStack.push('{');
23346
- }
23347
- }
23348
- var substring = pattern.substring(prevPos);
23349
- results.push(substring);
23350
- return results;
23351
- }
23352
23173
  /**
23353
- * Parses text containing an ICU expression and produces a JSON object for it.
23354
- * Original code from closure library, modified for Angular.
23355
- *
23356
- * @param pattern Text containing an ICU expression that needs to be parsed.
23357
- *
23174
+ * The locale id that the application is currently using (for translations and ICU expressions).
23175
+ * This is the ivy version of `LOCALE_ID` that was defined as an injection token for the view engine
23176
+ * but is now defined as a global value.
23358
23177
  */
23359
- function parseICUBlock(pattern) {
23360
- var cases = [];
23361
- var values = [];
23362
- var icuType = 1 /* plural */;
23363
- var mainBinding = 0;
23364
- pattern = pattern.replace(ICU_BLOCK_REGEXP, function (str, binding, type) {
23365
- if (type === 'select') {
23366
- icuType = 0 /* select */;
23367
- }
23368
- else {
23369
- icuType = 1 /* plural */;
23370
- }
23371
- mainBinding = parseInt(binding.substr(1), 10);
23372
- return '';
23373
- });
23374
- var parts = extractParts(pattern);
23375
- // Looking for (key block)+ sequence. One of the keys has to be "other".
23376
- for (var pos = 0; pos < parts.length;) {
23377
- var key = parts[pos++].trim();
23378
- if (icuType === 1 /* plural */) {
23379
- // Key can be "=x", we just want "x"
23380
- key = key.replace(/\s*(?:=)?(\w+)\s*/, '$1');
23381
- }
23382
- if (key.length) {
23383
- cases.push(key);
23384
- }
23385
- var blocks = extractParts(parts[pos++]);
23386
- if (cases.length > values.length) {
23387
- values.push(blocks);
23388
- }
23178
+ var LOCALE_ID = DEFAULT_LOCALE_ID;
23179
+ /**
23180
+ * Sets the locale id that will be used for translations and ICU expressions.
23181
+ * This is the ivy version of `LOCALE_ID` that was defined as an injection token for the view engine
23182
+ * but is now defined as a global value.
23183
+ *
23184
+ * @param localeId
23185
+ */
23186
+ function setLocaleId(localeId) {
23187
+ assertDefined(localeId, "Expected localeId to be defined");
23188
+ if (typeof localeId === 'string') {
23189
+ LOCALE_ID = localeId.toLowerCase().replace(/_/g, '-');
23389
23190
  }
23390
- // TODO(ocombe): support ICU expressions in attributes, see #21615
23391
- return { type: icuType, mainBinding: mainBinding, cases: cases, values: values };
23392
23191
  }
23393
23192
  /**
23394
- * Removes everything inside the sub-templates of a message.
23193
+ * Gets the locale id that will be used for translations and ICU expressions.
23194
+ * This is the ivy version of `LOCALE_ID` that was defined as an injection token for the view engine
23195
+ * but is now defined as a global value.
23395
23196
  */
23396
- function removeInnerTemplateTranslation(message) {
23397
- var match;
23398
- var res = '';
23399
- var index = 0;
23400
- var inTemplate = false;
23401
- var tagMatched;
23402
- while ((match = SUBTEMPLATE_REGEXP.exec(message)) !== null) {
23403
- if (!inTemplate) {
23404
- res += message.substring(index, match.index + match[0].length);
23405
- tagMatched = match[1];
23406
- inTemplate = true;
23407
- }
23408
- else {
23409
- if (match[0] === MARKER + "/*" + tagMatched + MARKER) {
23410
- index = match.index;
23411
- inTemplate = false;
23412
- }
23413
- }
23414
- }
23415
- ngDevMode &&
23416
- assertEqual(inTemplate, false, "Tag mismatch: unable to find the end of the sub-template in the translation \"" + message + "\"");
23417
- res += message.substr(index);
23418
- return res;
23197
+ function getLocaleId() {
23198
+ return LOCALE_ID;
23419
23199
  }
23200
+
23420
23201
  /**
23421
- * Extracts a part of a message and removes the rest.
23422
- *
23423
- * This method is used for extracting a part of the message associated with a template. A translated
23424
- * message can span multiple templates.
23425
- *
23426
- * Example:
23427
- * ```
23428
- * <div i18n>Translate <span *ngIf>me</span>!</div>
23429
- * ```
23202
+ * @license
23203
+ * Copyright Google LLC All Rights Reserved.
23430
23204
  *
23431
- * @param message The message to crop
23432
- * @param subTemplateIndex Index of the sub-template to extract. If undefined it returns the
23433
- * external template and removes all sub-templates.
23205
+ * Use of this source code is governed by an MIT-style license that can be
23206
+ * found in the LICENSE file at https://angular.io/license
23434
23207
  */
23435
- function getTranslationForTemplate(message, subTemplateIndex) {
23436
- if (isRootTemplateMessage(subTemplateIndex)) {
23437
- // We want the root template message, ignore all sub-templates
23438
- return removeInnerTemplateTranslation(message);
23439
- }
23440
- else {
23441
- // We want a specific sub-template
23442
- var start = message.indexOf(":" + subTemplateIndex + MARKER) + 2 + subTemplateIndex.toString().length;
23443
- var end = message.search(new RegExp(MARKER + "\\/\\*\\d+:" + subTemplateIndex + MARKER));
23444
- return removeInnerTemplateTranslation(message.substring(start, end));
23445
- }
23208
+ /**
23209
+ * NOTE: changes to the `ngI18nClosureMode` name must be synced with `compiler-cli/src/tooling.ts`.
23210
+ */
23211
+ if (typeof ngI18nClosureMode === 'undefined') {
23212
+ // These property accesses can be ignored because ngI18nClosureMode will be set to false
23213
+ // when optimizing code and the whole if statement will be dropped.
23214
+ // Make sure to refer to ngI18nClosureMode as ['ngI18nClosureMode'] for closure.
23215
+ // NOTE: we need to have it in IIFE so that the tree-shaker is happy.
23216
+ (function () {
23217
+ // tslint:disable-next-line:no-toplevel-property-access
23218
+ _global['ngI18nClosureMode'] =
23219
+ // TODO(FW-1250): validate that this actually, you know, works.
23220
+ // tslint:disable-next-line:no-toplevel-property-access
23221
+ typeof goog !== 'undefined' && typeof goog.getMsg === 'function';
23222
+ })();
23446
23223
  }
23224
+
23447
23225
  /**
23448
- * Generate the OpCodes to update the bindings of a string.
23226
+ * @license
23227
+ * Copyright Google LLC All Rights Reserved.
23449
23228
  *
23450
- * @param str The string containing the bindings.
23451
- * @param destinationNode Index of the destination node which will receive the binding.
23452
- * @param attrName Name of the attribute, if the string belongs to an attribute.
23453
- * @param sanitizeFn Sanitization function used to sanitize the string after update, if necessary.
23229
+ * Use of this source code is governed by an MIT-style license that can be
23230
+ * found in the LICENSE file at https://angular.io/license
23454
23231
  */
23455
- function generateBindingUpdateOpCodes(str, destinationNode, attrName, sanitizeFn) {
23456
- if (sanitizeFn === void 0) { sanitizeFn = null; }
23457
- var updateOpCodes = [null, null]; // Alloc space for mask and size
23458
- var textParts = str.split(BINDING_REGEXP);
23459
- var mask = 0;
23460
- for (var j = 0; j < textParts.length; j++) {
23461
- var textValue = textParts[j];
23462
- if (j & 1) {
23463
- // Odd indexes are bindings
23464
- var bindingIndex = parseInt(textValue, 10);
23465
- updateOpCodes.push(-1 - bindingIndex);
23466
- mask = mask | toMaskBit(bindingIndex);
23467
- }
23468
- else if (textValue !== '') {
23469
- // Even indexes are text
23470
- updateOpCodes.push(textValue);
23471
- }
23472
- }
23473
- updateOpCodes.push(destinationNode << 2 /* SHIFT_REF */ |
23474
- (attrName ? 1 /* Attr */ : 0 /* Text */));
23475
- if (attrName) {
23476
- updateOpCodes.push(attrName, sanitizeFn);
23477
- }
23478
- updateOpCodes[0] = mask;
23479
- updateOpCodes[1] = updateOpCodes.length - 2;
23480
- return updateOpCodes;
23232
+ function getParentFromI18nMutateOpCode(mergedCode) {
23233
+ return mergedCode >>> 17 /* SHIFT_PARENT */;
23481
23234
  }
23482
- function getBindingMask(icuExpression, mask) {
23483
- if (mask === void 0) { mask = 0; }
23484
- mask = mask | toMaskBit(icuExpression.mainBinding);
23485
- var match;
23486
- for (var i = 0; i < icuExpression.values.length; i++) {
23487
- var valueArr = icuExpression.values[i];
23488
- for (var j = 0; j < valueArr.length; j++) {
23489
- var value = valueArr[j];
23490
- if (typeof value === 'string') {
23491
- while (match = BINDING_REGEXP.exec(value)) {
23492
- mask = mask | toMaskBit(parseInt(match[1], 10));
23493
- }
23494
- }
23495
- else {
23496
- mask = getBindingMask(value, mask);
23497
- }
23498
- }
23499
- }
23500
- return mask;
23235
+ function getRefFromI18nMutateOpCode(mergedCode) {
23236
+ return (mergedCode & 131064 /* MASK_REF */) >>> 3 /* SHIFT_REF */;
23237
+ }
23238
+ function getInstructionFromI18nMutateOpCode(mergedCode) {
23239
+ return mergedCode & 7 /* MASK_INSTRUCTION */;
23501
23240
  }
23502
- var i18nIndexStack = [];
23503
- var i18nIndexStackPointer = -1;
23504
23241
  /**
23505
- * Convert binding index to mask bit.
23242
+ * Marks that the next string is an element name.
23506
23243
  *
23507
- * Each index represents a single bit on the bit-mask. Because bit-mask only has 32 bits, we make
23508
- * the 32nd bit share all masks for all bindings higher than 32. Since it is extremely rare to have
23509
- * more than 32 bindings this will be hit very rarely. The downside of hitting this corner case is
23510
- * that we will execute binding code more often than necessary. (penalty of performance)
23244
+ * See `I18nMutateOpCodes` documentation.
23511
23245
  */
23512
- function toMaskBit(bindingIndex) {
23513
- return 1 << Math.min(bindingIndex, 31);
23514
- }
23515
- var parentIndexStack = [];
23246
+ var ELEMENT_MARKER = {
23247
+ marker: 'element'
23248
+ };
23516
23249
  /**
23517
- * Marks a block of text as translatable.
23518
- *
23519
- * The instructions `i18nStart` and `i18nEnd` mark the translation block in the template.
23520
- * The translation `message` is the value which is locale specific. The translation string may
23521
- * contain placeholders which associate inner elements and sub-templates within the translation.
23250
+ * Marks that the next string is comment text.
23522
23251
  *
23523
- * The translation `message` placeholders are:
23524
- * - `�{index}(:{block})�`: *Binding Placeholder*: Marks a location where an expression will be
23525
- * interpolated into. The placeholder `index` points to the expression binding index. An optional
23526
- * `block` that matches the sub-template in which it was declared.
23527
- * - `�#{index}(:{block})�`/`�/#{index}(:{block})�`: *Element Placeholder*: Marks the beginning
23528
- * and end of DOM element that were embedded in the original translation block. The placeholder
23529
- * `index` points to the element index in the template instructions set. An optional `block` that
23530
- * matches the sub-template in which it was declared.
23531
- * - `�!{index}(:{block})�`/`�/!{index}(:{block})�`: *Projection Placeholder*: Marks the
23532
- * beginning and end of <ng-content> that was embedded in the original translation block.
23533
- * The placeholder `index` points to the element index in the template instructions set.
23534
- * An optional `block` that matches the sub-template in which it was declared.
23535
- * - `�*{index}:{block}�`/`�/*{index}:{block}�`: *Sub-template Placeholder*: Sub-templates must be
23536
- * split up and translated separately in each angular template function. The `index` points to the
23537
- * `template` instruction index. A `block` that matches the sub-template in which it was declared.
23538
- *
23539
- * @param index A unique index of the translation in the static block.
23540
- * @param message The translation message.
23541
- * @param subTemplateIndex Optional sub-template index in the `message`.
23252
+ * See `I18nMutateOpCodes` documentation.
23253
+ */
23254
+ var COMMENT_MARKER = {
23255
+ marker: 'comment'
23256
+ };
23257
+ // Note: This hack is necessary so we don't erroneously get a circular dependency
23258
+ // failure based on types.
23259
+ var unusedValueExportToPlacateAjd$6 = 1;
23260
+
23261
+ /**
23262
+ * @license
23263
+ * Copyright Google LLC All Rights Reserved.
23542
23264
  *
23543
- * @codeGenApi
23265
+ * Use of this source code is governed by an MIT-style license that can be
23266
+ * found in the LICENSE file at https://angular.io/license
23544
23267
  */
23545
- function ɵɵi18nStart(index, message, subTemplateIndex) {
23546
- var tView = getTView();
23547
- ngDevMode && assertDefined(tView, "tView should be defined");
23268
+ var i18nIndexStack = [];
23269
+ var i18nIndexStackPointer = -1;
23270
+ function popI18nIndex() {
23271
+ return i18nIndexStack[i18nIndexStackPointer--];
23272
+ }
23273
+ function pushI18nIndex(index) {
23548
23274
  i18nIndexStack[++i18nIndexStackPointer] = index;
23549
- // We need to delay projections until `i18nEnd`
23550
- setDelayProjection(true);
23551
- if (tView.firstCreatePass && tView.data[index + HEADER_OFFSET] === null) {
23552
- i18nStartFirstPass(getLView(), tView, index, message, subTemplateIndex);
23553
- }
23554
23275
  }
23555
- // Count for the number of vars that will be allocated for each i18n block.
23556
- // It is global because this is used in multiple functions that include loops and recursive calls.
23557
- // This is reset to 0 when `i18nStartFirstPass` is called.
23558
- var i18nVarsCount;
23559
- function allocNodeIndex(startIndex) {
23560
- return startIndex + i18nVarsCount++;
23276
+ var changeMask = 0;
23277
+ var shiftsCounter = 0;
23278
+ function setMaskBit(bit) {
23279
+ if (bit) {
23280
+ changeMask = changeMask | (1 << shiftsCounter);
23281
+ }
23282
+ shiftsCounter++;
23561
23283
  }
23562
- /**
23563
- * See `i18nStart` above.
23564
- */
23565
- function i18nStartFirstPass(lView, tView, index, message, subTemplateIndex) {
23566
- var startIndex = tView.blueprint.length - HEADER_OFFSET;
23567
- i18nVarsCount = 0;
23568
- var previousOrParentTNode = getPreviousOrParentTNode();
23569
- var parentTNode = getIsParent() ? previousOrParentTNode : previousOrParentTNode && previousOrParentTNode.parent;
23570
- var parentIndex = parentTNode && parentTNode !== lView[T_HOST] ? parentTNode.index - HEADER_OFFSET : index;
23571
- var parentIndexPointer = 0;
23572
- parentIndexStack[parentIndexPointer] = parentIndex;
23573
- var createOpCodes = [];
23574
- // If the previous node wasn't the direct parent then we have a translation without top level
23575
- // element and we need to keep a reference of the previous element if there is one. We should also
23576
- // keep track whether an element was a parent node or not, so that the logic that consumes
23577
- // the generated `I18nMutateOpCode`s can leverage this information to properly set TNode state
23578
- // (whether it's a parent or sibling).
23579
- if (index > 0 && previousOrParentTNode !== parentTNode) {
23580
- var previousTNodeIndex = previousOrParentTNode.index - HEADER_OFFSET;
23581
- // If current TNode is a sibling node, encode it using a negative index. This information is
23582
- // required when the `Select` action is processed (see the `readCreateOpCodes` function).
23583
- if (!getIsParent()) {
23584
- previousTNodeIndex = ~previousTNodeIndex;
23284
+ function applyI18n(tView, lView, index) {
23285
+ if (shiftsCounter > 0) {
23286
+ ngDevMode && assertDefined(tView, "tView should be defined");
23287
+ var tI18n = tView.data[index + HEADER_OFFSET];
23288
+ var updateOpCodes = void 0;
23289
+ var tIcus = null;
23290
+ if (Array.isArray(tI18n)) {
23291
+ updateOpCodes = tI18n;
23585
23292
  }
23586
- // Create an OpCode to select the previous TNode
23587
- createOpCodes.push(previousTNodeIndex << 3 /* SHIFT_REF */ | 0 /* Select */);
23588
- }
23589
- var updateOpCodes = [];
23590
- var icuExpressions = [];
23591
- if (message === '' && isRootTemplateMessage(subTemplateIndex)) {
23592
- // If top level translation is an empty string, do not invoke additional processing
23593
- // and just create op codes for empty text node instead.
23594
- createOpCodes.push(message, allocNodeIndex(startIndex), parentIndex << 17 /* SHIFT_PARENT */ | 1 /* AppendChild */);
23293
+ else {
23294
+ updateOpCodes = tI18n.update;
23295
+ tIcus = tI18n.icus;
23296
+ }
23297
+ var bindingsStartIndex = getBindingIndex() - shiftsCounter - 1;
23298
+ applyUpdateOpCodes(tView, tIcus, lView, updateOpCodes, bindingsStartIndex, changeMask);
23299
+ // Reset changeMask & maskBit to default for the next update cycle
23300
+ changeMask = 0;
23301
+ shiftsCounter = 0;
23595
23302
  }
23596
- else {
23597
- var templateTranslation = getTranslationForTemplate(message, subTemplateIndex);
23598
- var msgParts = replaceNgsp(templateTranslation).split(PH_REGEXP);
23599
- for (var i = 0; i < msgParts.length; i++) {
23600
- var value = msgParts[i];
23601
- if (i & 1) {
23602
- // Odd indexes are placeholders (elements and sub-templates)
23603
- if (value.charAt(0) === '/') {
23604
- // It is a closing tag
23605
- if (value.charAt(1) === "#" /* ELEMENT */) {
23606
- var phIndex = parseInt(value.substr(2), 10);
23607
- parentIndex = parentIndexStack[--parentIndexPointer];
23608
- createOpCodes.push(phIndex << 3 /* SHIFT_REF */ | 5 /* ElementEnd */);
23303
+ }
23304
+ /**
23305
+ * Apply `I18nMutateOpCodes` OpCodes.
23306
+ *
23307
+ * @param tView Current `TView`
23308
+ * @param rootIndex Pointer to the root (parent) tNode for the i18n.
23309
+ * @param createOpCodes OpCodes to process
23310
+ * @param lView Current `LView`
23311
+ */
23312
+ function applyCreateOpCodes(tView, rootindex, createOpCodes, lView) {
23313
+ var renderer = lView[RENDERER];
23314
+ var currentTNode = null;
23315
+ var previousTNode = null;
23316
+ var visitedNodes = [];
23317
+ for (var i = 0; i < createOpCodes.length; i++) {
23318
+ var opCode = createOpCodes[i];
23319
+ if (typeof opCode == 'string') {
23320
+ var textRNode = createTextNode(opCode, renderer);
23321
+ var textNodeIndex = createOpCodes[++i];
23322
+ ngDevMode && ngDevMode.rendererCreateTextNode++;
23323
+ previousTNode = currentTNode;
23324
+ currentTNode =
23325
+ createDynamicNodeAtIndex(tView, lView, textNodeIndex, 3 /* Element */, textRNode, null);
23326
+ visitedNodes.push(textNodeIndex);
23327
+ setIsNotParent();
23328
+ }
23329
+ else if (typeof opCode == 'number') {
23330
+ switch (opCode & 7 /* MASK_INSTRUCTION */) {
23331
+ case 1 /* AppendChild */:
23332
+ var destinationNodeIndex = opCode >>> 17 /* SHIFT_PARENT */;
23333
+ var destinationTNode = void 0;
23334
+ if (destinationNodeIndex === rootindex) {
23335
+ // If the destination node is `i18nStart`, we don't have a
23336
+ // top-level node and we should use the host node instead
23337
+ destinationTNode = lView[T_HOST];
23609
23338
  }
23610
- }
23611
- else {
23612
- var phIndex = parseInt(value.substr(1), 10);
23613
- var isElement = value.charAt(0) === "#" /* ELEMENT */;
23614
- // The value represents a placeholder that we move to the designated index.
23615
- // Note: positive indicies indicate that a TNode with a given index should also be marked
23616
- // as parent while executing `Select` instruction.
23617
- createOpCodes.push((isElement ? phIndex : ~phIndex) << 3 /* SHIFT_REF */ |
23618
- 0 /* Select */, parentIndex << 17 /* SHIFT_PARENT */ | 1 /* AppendChild */);
23619
- if (isElement) {
23620
- parentIndexStack[++parentIndexPointer] = parentIndex = phIndex;
23339
+ else {
23340
+ destinationTNode = getTNode(tView, destinationNodeIndex);
23621
23341
  }
23622
- }
23342
+ ngDevMode &&
23343
+ assertDefined(currentTNode, "You need to create or select a node before you can insert it into the DOM");
23344
+ previousTNode =
23345
+ appendI18nNode(tView, currentTNode, destinationTNode, previousTNode, lView);
23346
+ break;
23347
+ case 0 /* Select */:
23348
+ // Negative indices indicate that a given TNode is a sibling node, not a parent node
23349
+ // (see `i18nStartFirstPass` for additional information).
23350
+ var isParent = opCode >= 0;
23351
+ // FIXME(misko): This SHIFT_REF looks suspect as it does not have mask.
23352
+ var nodeIndex = (isParent ? opCode : ~opCode) >>> 3 /* SHIFT_REF */;
23353
+ visitedNodes.push(nodeIndex);
23354
+ previousTNode = currentTNode;
23355
+ currentTNode = getTNode(tView, nodeIndex);
23356
+ if (currentTNode) {
23357
+ setPreviousOrParentTNode(currentTNode, isParent);
23358
+ }
23359
+ break;
23360
+ case 5 /* ElementEnd */:
23361
+ var elementIndex = opCode >>> 3 /* SHIFT_REF */;
23362
+ previousTNode = currentTNode = getTNode(tView, elementIndex);
23363
+ setPreviousOrParentTNode(currentTNode, false);
23364
+ break;
23365
+ case 4 /* Attr */:
23366
+ var elementNodeIndex = opCode >>> 3 /* SHIFT_REF */;
23367
+ var attrName = createOpCodes[++i];
23368
+ var attrValue = createOpCodes[++i];
23369
+ // This code is used for ICU expressions only, since we don't support
23370
+ // directives/components in ICUs, we don't need to worry about inputs here
23371
+ elementAttributeInternal(getTNode(tView, elementNodeIndex), lView, attrName, attrValue, null, null);
23372
+ break;
23373
+ default:
23374
+ throw new Error("Unable to determine the type of mutate operation for \"" + opCode + "\"");
23623
23375
  }
23624
- else {
23625
- // Even indexes are text (including bindings & ICU expressions)
23626
- var parts = extractParts(value);
23627
- for (var j = 0; j < parts.length; j++) {
23628
- if (j & 1) {
23629
- // Odd indexes are ICU expressions
23630
- var icuExpression = parts[j];
23631
- // Verify that ICU expression has the right shape. Translations might contain invalid
23632
- // constructions (while original messages were correct), so ICU parsing at runtime may
23633
- // not succeed (thus `icuExpression` remains a string).
23634
- if (typeof icuExpression !== 'object') {
23635
- throw new Error("Unable to parse ICU expression in \"" + templateTranslation + "\" message.");
23636
- }
23637
- // Create the comment node that will anchor the ICU expression
23638
- var icuNodeIndex = allocNodeIndex(startIndex);
23639
- createOpCodes.push(COMMENT_MARKER, ngDevMode ? "ICU " + icuNodeIndex : '', icuNodeIndex, parentIndex << 17 /* SHIFT_PARENT */ | 1 /* AppendChild */);
23640
- // Update codes for the ICU expression
23641
- var mask = getBindingMask(icuExpression);
23642
- icuStart(icuExpressions, icuExpression, icuNodeIndex, icuNodeIndex);
23643
- // Since this is recursive, the last TIcu that was pushed is the one we want
23644
- var tIcuIndex = icuExpressions.length - 1;
23645
- updateOpCodes.push(toMaskBit(icuExpression.mainBinding), // mask of the main binding
23646
- 3, // skip 3 opCodes if not changed
23647
- -1 - icuExpression.mainBinding, icuNodeIndex << 2 /* SHIFT_REF */ | 2 /* IcuSwitch */, tIcuIndex, mask, // mask of all the bindings of this ICU expression
23648
- 2, // skip 2 opCodes if not changed
23649
- icuNodeIndex << 2 /* SHIFT_REF */ | 3 /* IcuUpdate */, tIcuIndex);
23376
+ }
23377
+ else {
23378
+ switch (opCode) {
23379
+ case COMMENT_MARKER:
23380
+ var commentValue = createOpCodes[++i];
23381
+ var commentNodeIndex = createOpCodes[++i];
23382
+ ngDevMode &&
23383
+ assertEqual(typeof commentValue, 'string', "Expected \"" + commentValue + "\" to be a comment node value");
23384
+ var commentRNode = renderer.createComment(commentValue);
23385
+ ngDevMode && ngDevMode.rendererCreateComment++;
23386
+ previousTNode = currentTNode;
23387
+ currentTNode = createDynamicNodeAtIndex(tView, lView, commentNodeIndex, 5 /* IcuContainer */, commentRNode, null);
23388
+ visitedNodes.push(commentNodeIndex);
23389
+ attachPatchData(commentRNode, lView);
23390
+ // We will add the case nodes later, during the update phase
23391
+ setIsNotParent();
23392
+ break;
23393
+ case ELEMENT_MARKER:
23394
+ var tagNameValue = createOpCodes[++i];
23395
+ var elementNodeIndex = createOpCodes[++i];
23396
+ ngDevMode &&
23397
+ assertEqual(typeof tagNameValue, 'string', "Expected \"" + tagNameValue + "\" to be an element node tag name");
23398
+ var elementRNode = renderer.createElement(tagNameValue);
23399
+ ngDevMode && ngDevMode.rendererCreateElement++;
23400
+ previousTNode = currentTNode;
23401
+ currentTNode = createDynamicNodeAtIndex(tView, lView, elementNodeIndex, 3 /* Element */, elementRNode, tagNameValue);
23402
+ visitedNodes.push(elementNodeIndex);
23403
+ break;
23404
+ default:
23405
+ throw new Error("Unable to determine the type of mutate operation for \"" + opCode + "\"");
23406
+ }
23407
+ }
23408
+ }
23409
+ setIsNotParent();
23410
+ return visitedNodes;
23411
+ }
23412
+ /**
23413
+ * Apply `I18nUpdateOpCodes` OpCodes
23414
+ *
23415
+ * @param tView Current `TView`
23416
+ * @param tIcus If ICUs present than this contains them.
23417
+ * @param lView Current `LView`
23418
+ * @param updateOpCodes OpCodes to process
23419
+ * @param bindingsStartIndex Location of the first `ɵɵi18nApply`
23420
+ * @param changeMask Each bit corresponds to a `ɵɵi18nExp` (Counting backwards from
23421
+ * `bindingsStartIndex`)
23422
+ */
23423
+ function applyUpdateOpCodes(tView, tIcus, lView, updateOpCodes, bindingsStartIndex, changeMask) {
23424
+ var caseCreated = false;
23425
+ for (var i = 0; i < updateOpCodes.length; i++) {
23426
+ // bit code to check if we should apply the next update
23427
+ var checkBit = updateOpCodes[i];
23428
+ // Number of opCodes to skip until next set of update codes
23429
+ var skipCodes = updateOpCodes[++i];
23430
+ if (checkBit & changeMask) {
23431
+ // The value has been updated since last checked
23432
+ var value = '';
23433
+ for (var j = i + 1; j <= (i + skipCodes); j++) {
23434
+ var opCode = updateOpCodes[j];
23435
+ if (typeof opCode == 'string') {
23436
+ value += opCode;
23437
+ }
23438
+ else if (typeof opCode == 'number') {
23439
+ if (opCode < 0) {
23440
+ // Negative opCode represent `i18nExp` values offset.
23441
+ value += renderStringify(lView[bindingsStartIndex - opCode]);
23650
23442
  }
23651
- else if (parts[j] !== '') {
23652
- var text = parts[j];
23653
- // Even indexes are text (including bindings)
23654
- var hasBinding = text.match(BINDING_REGEXP);
23655
- // Create text nodes
23656
- var textNodeIndex = allocNodeIndex(startIndex);
23657
- createOpCodes.push(
23658
- // If there is a binding, the value will be set during update
23659
- hasBinding ? '' : text, textNodeIndex, parentIndex << 17 /* SHIFT_PARENT */ | 1 /* AppendChild */);
23660
- if (hasBinding) {
23661
- addAllToArray(generateBindingUpdateOpCodes(text, textNodeIndex), updateOpCodes);
23443
+ else {
23444
+ var nodeIndex = opCode >>> 2 /* SHIFT_REF */;
23445
+ switch (opCode & 3 /* MASK_OPCODE */) {
23446
+ case 1 /* Attr */:
23447
+ var propName = updateOpCodes[++j];
23448
+ var sanitizeFn = updateOpCodes[++j];
23449
+ elementPropertyInternal(tView, getTNode(tView, nodeIndex), lView, propName, value, lView[RENDERER], sanitizeFn, false);
23450
+ break;
23451
+ case 0 /* Text */:
23452
+ textBindingInternal(lView, nodeIndex, value);
23453
+ break;
23454
+ case 2 /* IcuSwitch */:
23455
+ caseCreated =
23456
+ applyIcuSwitchCase(tView, tIcus, updateOpCodes[++j], lView, value);
23457
+ break;
23458
+ case 3 /* IcuUpdate */:
23459
+ applyIcuUpdateCase(tView, tIcus, updateOpCodes[++j], bindingsStartIndex, lView, caseCreated);
23460
+ break;
23662
23461
  }
23663
23462
  }
23664
23463
  }
23665
23464
  }
23666
23465
  }
23466
+ i += skipCodes;
23667
23467
  }
23668
- if (i18nVarsCount > 0) {
23669
- allocExpando(tView, lView, i18nVarsCount);
23468
+ }
23469
+ /**
23470
+ * Apply OpCodes associated with updating an existing ICU.
23471
+ *
23472
+ * @param tView Current `TView`
23473
+ * @param tIcus ICUs active at this location.
23474
+ * @param tIcuIndex Index into `tIcus` to process.
23475
+ * @param bindingsStartIndex Location of the first `ɵɵi18nApply`
23476
+ * @param lView Current `LView`
23477
+ * @param changeMask Each bit corresponds to a `ɵɵi18nExp` (Counting backwards from
23478
+ * `bindingsStartIndex`)
23479
+ */
23480
+ function applyIcuUpdateCase(tView, tIcus, tIcuIndex, bindingsStartIndex, lView, caseCreated) {
23481
+ ngDevMode && assertIndexInRange(tIcus, tIcuIndex);
23482
+ var tIcu = tIcus[tIcuIndex];
23483
+ ngDevMode && assertIndexInRange(lView, tIcu.currentCaseLViewIndex);
23484
+ var activeCaseIndex = lView[tIcu.currentCaseLViewIndex];
23485
+ if (activeCaseIndex !== null) {
23486
+ var mask = caseCreated ?
23487
+ -1 : // -1 is same as all bits on, which simulates creation since it marks all bits dirty
23488
+ changeMask;
23489
+ applyUpdateOpCodes(tView, tIcus, lView, tIcu.update[activeCaseIndex], bindingsStartIndex, mask);
23670
23490
  }
23671
- ngDevMode &&
23672
- attachI18nOpCodesDebug(createOpCodes, updateOpCodes, icuExpressions.length ? icuExpressions : null, lView);
23673
- // NOTE: local var needed to properly assert the type of `TI18n`.
23674
- var tI18n = {
23675
- vars: i18nVarsCount,
23676
- create: createOpCodes,
23677
- update: updateOpCodes,
23678
- icus: icuExpressions.length ? icuExpressions : null,
23679
- };
23680
- tView.data[index + HEADER_OFFSET] = tI18n;
23681
23491
  }
23682
- function appendI18nNode(tView, tNode, parentTNode, previousTNode, lView) {
23683
- ngDevMode && ngDevMode.rendererMoveNode++;
23684
- var nextNode = tNode.next;
23685
- if (!previousTNode) {
23686
- previousTNode = parentTNode;
23492
+ /**
23493
+ * Apply OpCodes associated with switching a case on ICU.
23494
+ *
23495
+ * This involves tearing down existing case and than building up a new case.
23496
+ *
23497
+ * @param tView Current `TView`
23498
+ * @param tIcus ICUs active at this location.
23499
+ * @param tICuIndex Index into `tIcus` to process.
23500
+ * @param lView Current `LView`
23501
+ * @param value Value of the case to update to.
23502
+ * @returns true if a new case was created (needed so that the update executes regardless of the
23503
+ * bitmask)
23504
+ */
23505
+ function applyIcuSwitchCase(tView, tIcus, tICuIndex, lView, value) {
23506
+ applyIcuSwitchCaseRemove(tView, tIcus, tICuIndex, lView);
23507
+ // Rebuild a new case for this ICU
23508
+ var caseCreated = false;
23509
+ var tIcu = tIcus[tICuIndex];
23510
+ var caseIndex = getCaseIndex(tIcu, value);
23511
+ lView[tIcu.currentCaseLViewIndex] = caseIndex !== -1 ? caseIndex : null;
23512
+ if (caseIndex > -1) {
23513
+ // Add the nodes for the new case
23514
+ applyCreateOpCodes(tView, -1, // -1 means we don't have parent node
23515
+ tIcu.create[caseIndex], lView);
23516
+ caseCreated = true;
23517
+ }
23518
+ return caseCreated;
23519
+ }
23520
+ /**
23521
+ * Apply OpCodes associated with tearing down of DOM.
23522
+ *
23523
+ * This involves tearing down existing case and than building up a new case.
23524
+ *
23525
+ * @param tView Current `TView`
23526
+ * @param tIcus ICUs active at this location.
23527
+ * @param tIcuIndex Index into `tIcus` to process.
23528
+ * @param lView Current `LView`
23529
+ * @returns true if a new case was created (needed so that the update executes regardless of the
23530
+ * bitmask)
23531
+ */
23532
+ function applyIcuSwitchCaseRemove(tView, tIcus, tIcuIndex, lView) {
23533
+ ngDevMode && assertIndexInRange(tIcus, tIcuIndex);
23534
+ var tIcu = tIcus[tIcuIndex];
23535
+ var activeCaseIndex = lView[tIcu.currentCaseLViewIndex];
23536
+ if (activeCaseIndex !== null) {
23537
+ var removeCodes = tIcu.remove[activeCaseIndex];
23538
+ for (var k = 0; k < removeCodes.length; k++) {
23539
+ var removeOpCode = removeCodes[k];
23540
+ var nodeOrIcuIndex = removeOpCode >>> 3 /* SHIFT_REF */;
23541
+ switch (removeOpCode & 7 /* MASK_INSTRUCTION */) {
23542
+ case 3 /* Remove */:
23543
+ // FIXME(misko): this comment is wrong!
23544
+ // Remove DOM element, but do *not* mark TNode as detached, since we are
23545
+ // just switching ICU cases (while keeping the same TNode), so a DOM element
23546
+ // representing a new ICU case will be re-created.
23547
+ removeNode(tView, lView, nodeOrIcuIndex, /* markAsDetached */ false);
23548
+ break;
23549
+ case 6 /* RemoveNestedIcu */:
23550
+ applyIcuSwitchCaseRemove(tView, tIcus, nodeOrIcuIndex, lView);
23551
+ break;
23552
+ }
23553
+ }
23554
+ }
23555
+ }
23556
+ function appendI18nNode(tView, tNode, parentTNode, previousTNode, lView) {
23557
+ ngDevMode && ngDevMode.rendererMoveNode++;
23558
+ var nextNode = tNode.next;
23559
+ if (!previousTNode) {
23560
+ previousTNode = parentTNode;
23687
23561
  }
23688
23562
  // Re-organize node tree to put this node in the correct position.
23689
23563
  if (previousTNode === parentTNode && tNode !== parentTNode.child) {
@@ -23721,9 +23595,901 @@
23721
23595
  }
23722
23596
  return tNode;
23723
23597
  }
23724
- function isRootTemplateMessage(subTemplateIndex) {
23725
- return subTemplateIndex === undefined;
23598
+ /**
23599
+ * See `i18nEnd` above.
23600
+ */
23601
+ function i18nEndFirstPass(tView, lView) {
23602
+ ngDevMode &&
23603
+ assertEqual(getBindingIndex(), tView.bindingStartIndex, 'i18nEnd should be called before any binding');
23604
+ var rootIndex = popI18nIndex();
23605
+ var tI18n = tView.data[rootIndex + HEADER_OFFSET];
23606
+ ngDevMode && assertDefined(tI18n, "You should call i18nStart before i18nEnd");
23607
+ // Find the last node that was added before `i18nEnd`
23608
+ var lastCreatedNode = getPreviousOrParentTNode();
23609
+ // Read the instructions to insert/move/remove DOM elements
23610
+ var visitedNodes = applyCreateOpCodes(tView, rootIndex, tI18n.create, lView);
23611
+ // Remove deleted nodes
23612
+ var index = rootIndex + 1;
23613
+ while (index <= lastCreatedNode.index - HEADER_OFFSET) {
23614
+ if (visitedNodes.indexOf(index) === -1) {
23615
+ removeNode(tView, lView, index, /* markAsDetached */ true);
23616
+ }
23617
+ // Check if an element has any local refs and skip them
23618
+ var tNode = getTNode(tView, index);
23619
+ if (tNode &&
23620
+ (tNode.type === 0 /* Container */ || tNode.type === 3 /* Element */ ||
23621
+ tNode.type === 4 /* ElementContainer */) &&
23622
+ tNode.localNames !== null) {
23623
+ // Divide by 2 to get the number of local refs,
23624
+ // since they are stored as an array that also includes directive indexes,
23625
+ // i.e. ["localRef", directiveIndex, ...]
23626
+ index += tNode.localNames.length >> 1;
23627
+ }
23628
+ index++;
23629
+ }
23630
+ }
23631
+ function removeNode(tView, lView, index, markAsDetached) {
23632
+ var removedPhTNode = getTNode(tView, index);
23633
+ var removedPhRNode = getNativeByIndex(index, lView);
23634
+ if (removedPhRNode) {
23635
+ nativeRemoveNode(lView[RENDERER], removedPhRNode);
23636
+ }
23637
+ var slotValue = load(lView, index);
23638
+ if (isLContainer(slotValue)) {
23639
+ var lContainer = slotValue;
23640
+ if (removedPhTNode.type !== 0 /* Container */) {
23641
+ nativeRemoveNode(lView[RENDERER], lContainer[NATIVE]);
23642
+ }
23643
+ }
23644
+ if (markAsDetached) {
23645
+ // Define this node as detached to avoid projecting it later
23646
+ removedPhTNode.flags |= 64 /* isDetached */;
23647
+ }
23648
+ ngDevMode && ngDevMode.rendererRemoveNode++;
23649
+ }
23650
+ /**
23651
+ * Creates and stores the dynamic TNode, and unhooks it from the tree for now.
23652
+ */
23653
+ function createDynamicNodeAtIndex(tView, lView, index, type, native, name) {
23654
+ var previousOrParentTNode = getPreviousOrParentTNode();
23655
+ ngDevMode && assertIndexInRange(lView, index + HEADER_OFFSET);
23656
+ lView[index + HEADER_OFFSET] = native;
23657
+ // FIXME(misko): Why does this create A TNode??? I would not expect this to be here.
23658
+ var tNode = getOrCreateTNode(tView, lView[T_HOST], index, type, name, null);
23659
+ // We are creating a dynamic node, the previous tNode might not be pointing at this node.
23660
+ // We will link ourselves into the tree later with `appendI18nNode`.
23661
+ if (previousOrParentTNode && previousOrParentTNode.next === tNode) {
23662
+ previousOrParentTNode.next = null;
23663
+ }
23664
+ return tNode;
23665
+ }
23666
+ /**
23667
+ * Returns the index of the current case of an ICU expression depending on the main binding value
23668
+ *
23669
+ * @param icuExpression
23670
+ * @param bindingValue The value of the main binding used by this ICU expression
23671
+ */
23672
+ function getCaseIndex(icuExpression, bindingValue) {
23673
+ var index = icuExpression.cases.indexOf(bindingValue);
23674
+ if (index === -1) {
23675
+ switch (icuExpression.type) {
23676
+ case 1 /* plural */: {
23677
+ var resolvedCase = getPluralCase(bindingValue, getLocaleId());
23678
+ index = icuExpression.cases.indexOf(resolvedCase);
23679
+ if (index === -1 && resolvedCase !== 'other') {
23680
+ index = icuExpression.cases.indexOf('other');
23681
+ }
23682
+ break;
23683
+ }
23684
+ case 0 /* select */: {
23685
+ index = icuExpression.cases.indexOf('other');
23686
+ break;
23687
+ }
23688
+ }
23689
+ }
23690
+ return index;
23691
+ }
23692
+
23693
+ /**
23694
+ * @license
23695
+ * Copyright Google LLC All Rights Reserved.
23696
+ *
23697
+ * Use of this source code is governed by an MIT-style license that can be
23698
+ * found in the LICENSE file at https://angular.io/license
23699
+ */
23700
+ /**
23701
+ * Converts `I18nUpdateOpCodes` array into a human readable format.
23702
+ *
23703
+ * This function is attached to the `I18nUpdateOpCodes.debug` property if `ngDevMode` is enabled.
23704
+ * This function provides a human readable view of the opcodes. This is useful when debugging the
23705
+ * application as well as writing more readable tests.
23706
+ *
23707
+ * @param this `I18nUpdateOpCodes` if attached as a method.
23708
+ * @param opcodes `I18nUpdateOpCodes` if invoked as a function.
23709
+ */
23710
+ function i18nUpdateOpCodesToString(opcodes) {
23711
+ var parser = new OpCodeParser(opcodes || (Array.isArray(this) ? this : []));
23712
+ var lines = [];
23713
+ function consumeOpCode(value) {
23714
+ var ref = value >>> 2 /* SHIFT_REF */;
23715
+ var opCode = value & 3 /* MASK_OPCODE */;
23716
+ switch (opCode) {
23717
+ case 0 /* Text */:
23718
+ return "(lView[" + ref + "] as Text).textContent = $$$";
23719
+ case 1 /* Attr */:
23720
+ var attrName = parser.consumeString();
23721
+ var sanitizationFn = parser.consumeFunction();
23722
+ var value_1 = sanitizationFn ? "(" + sanitizationFn + ")($$$)" : '$$$';
23723
+ return "(lView[" + ref + "] as Element).setAttribute('" + attrName + "', " + value_1 + ")";
23724
+ case 2 /* IcuSwitch */:
23725
+ return "icuSwitchCase(lView[" + ref + "] as Comment, " + parser.consumeNumber() + ", $$$)";
23726
+ case 3 /* IcuUpdate */:
23727
+ return "icuUpdateCase(lView[" + ref + "] as Comment, " + parser.consumeNumber() + ")";
23728
+ }
23729
+ throw new Error('unexpected OpCode');
23730
+ }
23731
+ while (parser.hasMore()) {
23732
+ var mask = parser.consumeNumber();
23733
+ var size = parser.consumeNumber();
23734
+ var end = parser.i + size;
23735
+ var statements = [];
23736
+ var statement = '';
23737
+ while (parser.i < end) {
23738
+ var value = parser.consumeNumberOrString();
23739
+ if (typeof value === 'string') {
23740
+ statement += value;
23741
+ }
23742
+ else if (value < 0) {
23743
+ // Negative numbers are ref indexes
23744
+ statement += '${lView[' + (0 - value) + ']}';
23745
+ }
23746
+ else {
23747
+ // Positive numbers are operations.
23748
+ var opCodeText = consumeOpCode(value);
23749
+ statements.push(opCodeText.replace('$$$', '`' + statement + '`') + ';');
23750
+ statement = '';
23751
+ }
23752
+ }
23753
+ lines.push("if (mask & 0b" + mask.toString(2) + ") { " + statements.join(' ') + " }");
23754
+ }
23755
+ return lines;
23756
+ }
23757
+ /**
23758
+ * Converts `I18nMutableOpCodes` array into a human readable format.
23759
+ *
23760
+ * This function is attached to the `I18nMutableOpCodes.debug` if `ngDevMode` is enabled. This
23761
+ * function provides a human readable view of the opcodes. This is useful when debugging the
23762
+ * application as well as writing more readable tests.
23763
+ *
23764
+ * @param this `I18nMutableOpCodes` if attached as a method.
23765
+ * @param opcodes `I18nMutableOpCodes` if invoked as a function.
23766
+ */
23767
+ function i18nMutateOpCodesToString(opcodes) {
23768
+ var parser = new OpCodeParser(opcodes || (Array.isArray(this) ? this : []));
23769
+ var lines = [];
23770
+ function consumeOpCode(opCode) {
23771
+ var parent = getParentFromI18nMutateOpCode(opCode);
23772
+ var ref = getRefFromI18nMutateOpCode(opCode);
23773
+ switch (getInstructionFromI18nMutateOpCode(opCode)) {
23774
+ case 0 /* Select */:
23775
+ lastRef = ref;
23776
+ return '';
23777
+ case 1 /* AppendChild */:
23778
+ return "(lView[" + parent + "] as Element).appendChild(lView[" + lastRef + "])";
23779
+ case 3 /* Remove */:
23780
+ return "(lView[" + parent + "] as Element).remove(lView[" + ref + "])";
23781
+ case 4 /* Attr */:
23782
+ return "(lView[" + ref + "] as Element).setAttribute(\"" + parser.consumeString() + "\", \"" + parser.consumeString() + "\")";
23783
+ case 5 /* ElementEnd */:
23784
+ return "setPreviousOrParentTNode(tView.data[" + ref + "] as TNode)";
23785
+ case 6 /* RemoveNestedIcu */:
23786
+ return "removeNestedICU(" + ref + ")";
23787
+ }
23788
+ throw new Error('Unexpected OpCode');
23789
+ }
23790
+ var lastRef = -1;
23791
+ while (parser.hasMore()) {
23792
+ var value = parser.consumeNumberStringOrMarker();
23793
+ if (value === COMMENT_MARKER) {
23794
+ var text = parser.consumeString();
23795
+ lastRef = parser.consumeNumber();
23796
+ lines.push("lView[" + lastRef + "] = document.createComment(\"" + text + "\")");
23797
+ }
23798
+ else if (value === ELEMENT_MARKER) {
23799
+ var text = parser.consumeString();
23800
+ lastRef = parser.consumeNumber();
23801
+ lines.push("lView[" + lastRef + "] = document.createElement(\"" + text + "\")");
23802
+ }
23803
+ else if (typeof value === 'string') {
23804
+ lastRef = parser.consumeNumber();
23805
+ lines.push("lView[" + lastRef + "] = document.createTextNode(\"" + value + "\")");
23806
+ }
23807
+ else if (typeof value === 'number') {
23808
+ var line = consumeOpCode(value);
23809
+ line && lines.push(line);
23810
+ }
23811
+ else {
23812
+ throw new Error('Unexpected value');
23813
+ }
23814
+ }
23815
+ return lines;
23816
+ }
23817
+ var OpCodeParser = /** @class */ (function () {
23818
+ function OpCodeParser(codes) {
23819
+ this.i = 0;
23820
+ this.codes = codes;
23821
+ }
23822
+ OpCodeParser.prototype.hasMore = function () {
23823
+ return this.i < this.codes.length;
23824
+ };
23825
+ OpCodeParser.prototype.consumeNumber = function () {
23826
+ var value = this.codes[this.i++];
23827
+ assertNumber(value, 'expecting number in OpCode');
23828
+ return value;
23829
+ };
23830
+ OpCodeParser.prototype.consumeString = function () {
23831
+ var value = this.codes[this.i++];
23832
+ assertString(value, 'expecting string in OpCode');
23833
+ return value;
23834
+ };
23835
+ OpCodeParser.prototype.consumeFunction = function () {
23836
+ var value = this.codes[this.i++];
23837
+ if (value === null || typeof value === 'function') {
23838
+ return value;
23839
+ }
23840
+ throw new Error('expecting function in OpCode');
23841
+ };
23842
+ OpCodeParser.prototype.consumeNumberOrString = function () {
23843
+ var value = this.codes[this.i++];
23844
+ if (typeof value === 'string') {
23845
+ return value;
23846
+ }
23847
+ assertNumber(value, 'expecting number or string in OpCode');
23848
+ return value;
23849
+ };
23850
+ OpCodeParser.prototype.consumeNumberStringOrMarker = function () {
23851
+ var value = this.codes[this.i++];
23852
+ if (typeof value === 'string' || typeof value === 'number' || value == COMMENT_MARKER ||
23853
+ value == ELEMENT_MARKER) {
23854
+ return value;
23855
+ }
23856
+ assertNumber(value, 'expecting number, string, COMMENT_MARKER or ELEMENT_MARKER in OpCode');
23857
+ return value;
23858
+ };
23859
+ return OpCodeParser;
23860
+ }());
23861
+
23862
+ var BINDING_REGEXP = /�(\d+):?\d*�/gi;
23863
+ var ICU_REGEXP = /({\s*�\d+:?\d*�\s*,\s*\S{6}\s*,[\s\S]*})/gi;
23864
+ var NESTED_ICU = /�(\d+)�/;
23865
+ var ICU_BLOCK_REGEXP = /^\s*(�\d+:?\d*�)\s*,\s*(select|plural)\s*,/;
23866
+ // Count for the number of vars that will be allocated for each i18n block.
23867
+ // It is global because this is used in multiple functions that include loops and recursive calls.
23868
+ // This is reset to 0 when `i18nStartFirstPass` is called.
23869
+ var i18nVarsCount;
23870
+ var parentIndexStack = [];
23871
+ var MARKER = "\uFFFD";
23872
+ var SUBTEMPLATE_REGEXP = /�\/?\*(\d+:\d+)�/gi;
23873
+ var PH_REGEXP = /�(\/?[#*!]\d+):?\d*�/gi;
23874
+ /**
23875
+ * Angular Dart introduced &ngsp; as a placeholder for non-removable space, see:
23876
+ * https://github.com/dart-lang/angular/blob/0bb611387d29d65b5af7f9d2515ab571fd3fbee4/_tests/test/compiler/preserve_whitespace_test.dart#L25-L32
23877
+ * In Angular Dart &ngsp; is converted to the 0xE500 PUA (Private Use Areas) unicode character
23878
+ * and later on replaced by a space. We are re-implementing the same idea here, since translations
23879
+ * might contain this special character.
23880
+ */
23881
+ var NGSP_UNICODE_REGEXP = /\uE500/g;
23882
+ function replaceNgsp(value) {
23883
+ return value.replace(NGSP_UNICODE_REGEXP, ' ');
23726
23884
  }
23885
+ /**
23886
+ * See `i18nStart` above.
23887
+ */
23888
+ function i18nStartFirstPass(lView, tView, index, message, subTemplateIndex) {
23889
+ var startIndex = tView.blueprint.length - HEADER_OFFSET;
23890
+ i18nVarsCount = 0;
23891
+ var previousOrParentTNode = getPreviousOrParentTNode();
23892
+ var parentTNode = getIsParent() ? previousOrParentTNode : previousOrParentTNode && previousOrParentTNode.parent;
23893
+ var parentIndex = parentTNode && parentTNode !== lView[T_HOST] ? parentTNode.index - HEADER_OFFSET : index;
23894
+ var parentIndexPointer = 0;
23895
+ parentIndexStack[parentIndexPointer] = parentIndex;
23896
+ var createOpCodes = [];
23897
+ if (ngDevMode) {
23898
+ attachDebugGetter(createOpCodes, i18nMutateOpCodesToString);
23899
+ }
23900
+ // If the previous node wasn't the direct parent then we have a translation without top level
23901
+ // element and we need to keep a reference of the previous element if there is one. We should also
23902
+ // keep track whether an element was a parent node or not, so that the logic that consumes
23903
+ // the generated `I18nMutateOpCode`s can leverage this information to properly set TNode state
23904
+ // (whether it's a parent or sibling).
23905
+ if (index > 0 && previousOrParentTNode !== parentTNode) {
23906
+ var previousTNodeIndex = previousOrParentTNode.index - HEADER_OFFSET;
23907
+ // If current TNode is a sibling node, encode it using a negative index. This information is
23908
+ // required when the `Select` action is processed (see the `readCreateOpCodes` function).
23909
+ if (!getIsParent()) {
23910
+ previousTNodeIndex = ~previousTNodeIndex;
23911
+ }
23912
+ // Create an OpCode to select the previous TNode
23913
+ createOpCodes.push(previousTNodeIndex << 3 /* SHIFT_REF */ | 0 /* Select */);
23914
+ }
23915
+ var updateOpCodes = [];
23916
+ if (ngDevMode) {
23917
+ attachDebugGetter(updateOpCodes, i18nUpdateOpCodesToString);
23918
+ }
23919
+ var icuExpressions = [];
23920
+ if (message === '' && isRootTemplateMessage(subTemplateIndex)) {
23921
+ // If top level translation is an empty string, do not invoke additional processing
23922
+ // and just create op codes for empty text node instead.
23923
+ createOpCodes.push(message, allocNodeIndex(startIndex), parentIndex << 17 /* SHIFT_PARENT */ | 1 /* AppendChild */);
23924
+ }
23925
+ else {
23926
+ var templateTranslation = getTranslationForTemplate(message, subTemplateIndex);
23927
+ var msgParts = replaceNgsp(templateTranslation).split(PH_REGEXP);
23928
+ for (var i = 0; i < msgParts.length; i++) {
23929
+ var value = msgParts[i];
23930
+ if (i & 1) {
23931
+ // Odd indexes are placeholders (elements and sub-templates)
23932
+ if (value.charAt(0) === '/') {
23933
+ // It is a closing tag
23934
+ if (value.charAt(1) === "#" /* ELEMENT */) {
23935
+ var phIndex = parseInt(value.substr(2), 10);
23936
+ parentIndex = parentIndexStack[--parentIndexPointer];
23937
+ createOpCodes.push(phIndex << 3 /* SHIFT_REF */ | 5 /* ElementEnd */);
23938
+ }
23939
+ }
23940
+ else {
23941
+ var phIndex = parseInt(value.substr(1), 10);
23942
+ var isElement = value.charAt(0) === "#" /* ELEMENT */;
23943
+ // The value represents a placeholder that we move to the designated index.
23944
+ // Note: positive indicies indicate that a TNode with a given index should also be marked
23945
+ // as parent while executing `Select` instruction.
23946
+ createOpCodes.push((isElement ? phIndex : ~phIndex) << 3 /* SHIFT_REF */ |
23947
+ 0 /* Select */, parentIndex << 17 /* SHIFT_PARENT */ | 1 /* AppendChild */);
23948
+ if (isElement) {
23949
+ parentIndexStack[++parentIndexPointer] = parentIndex = phIndex;
23950
+ }
23951
+ }
23952
+ }
23953
+ else {
23954
+ // Even indexes are text (including bindings & ICU expressions)
23955
+ var parts = extractParts(value);
23956
+ for (var j = 0; j < parts.length; j++) {
23957
+ if (j & 1) {
23958
+ // Odd indexes are ICU expressions
23959
+ var icuExpression = parts[j];
23960
+ // Verify that ICU expression has the right shape. Translations might contain invalid
23961
+ // constructions (while original messages were correct), so ICU parsing at runtime may
23962
+ // not succeed (thus `icuExpression` remains a string).
23963
+ if (typeof icuExpression !== 'object') {
23964
+ throw new Error("Unable to parse ICU expression in \"" + templateTranslation + "\" message.");
23965
+ }
23966
+ // Create the comment node that will anchor the ICU expression
23967
+ var icuNodeIndex = allocNodeIndex(startIndex);
23968
+ createOpCodes.push(COMMENT_MARKER, ngDevMode ? "ICU " + icuNodeIndex : '', icuNodeIndex, parentIndex << 17 /* SHIFT_PARENT */ | 1 /* AppendChild */);
23969
+ // Update codes for the ICU expression
23970
+ var mask = getBindingMask(icuExpression);
23971
+ icuStart(icuExpressions, icuExpression, icuNodeIndex, icuNodeIndex);
23972
+ // Since this is recursive, the last TIcu that was pushed is the one we want
23973
+ var tIcuIndex = icuExpressions.length - 1;
23974
+ updateOpCodes.push(toMaskBit(icuExpression.mainBinding), // mask of the main binding
23975
+ 3, // skip 3 opCodes if not changed
23976
+ -1 - icuExpression.mainBinding, icuNodeIndex << 2 /* SHIFT_REF */ | 2 /* IcuSwitch */, tIcuIndex, mask, // mask of all the bindings of this ICU expression
23977
+ 2, // skip 2 opCodes if not changed
23978
+ icuNodeIndex << 2 /* SHIFT_REF */ | 3 /* IcuUpdate */, tIcuIndex);
23979
+ }
23980
+ else if (parts[j] !== '') {
23981
+ var text = parts[j];
23982
+ // Even indexes are text (including bindings)
23983
+ var hasBinding = text.match(BINDING_REGEXP);
23984
+ // Create text nodes
23985
+ var textNodeIndex = allocNodeIndex(startIndex);
23986
+ createOpCodes.push(
23987
+ // If there is a binding, the value will be set during update
23988
+ hasBinding ? '' : text, textNodeIndex, parentIndex << 17 /* SHIFT_PARENT */ | 1 /* AppendChild */);
23989
+ if (hasBinding) {
23990
+ addAllToArray(generateBindingUpdateOpCodes(text, textNodeIndex), updateOpCodes);
23991
+ }
23992
+ }
23993
+ }
23994
+ }
23995
+ }
23996
+ }
23997
+ if (i18nVarsCount > 0) {
23998
+ allocExpando(tView, lView, i18nVarsCount);
23999
+ }
24000
+ // NOTE: local var needed to properly assert the type of `TI18n`.
24001
+ var tI18n = {
24002
+ vars: i18nVarsCount,
24003
+ create: createOpCodes,
24004
+ update: updateOpCodes,
24005
+ icus: icuExpressions.length ? icuExpressions : null,
24006
+ };
24007
+ tView.data[index + HEADER_OFFSET] = tI18n;
24008
+ }
24009
+ /**
24010
+ * See `i18nAttributes` above.
24011
+ */
24012
+ function i18nAttributesFirstPass(lView, tView, index, values) {
24013
+ var previousElement = getPreviousOrParentTNode();
24014
+ var previousElementIndex = previousElement.index - HEADER_OFFSET;
24015
+ var updateOpCodes = [];
24016
+ if (ngDevMode) {
24017
+ attachDebugGetter(updateOpCodes, i18nUpdateOpCodesToString);
24018
+ }
24019
+ for (var i = 0; i < values.length; i += 2) {
24020
+ var attrName = values[i];
24021
+ var message = values[i + 1];
24022
+ var parts = message.split(ICU_REGEXP);
24023
+ for (var j = 0; j < parts.length; j++) {
24024
+ var value = parts[j];
24025
+ if (j & 1) {
24026
+ // Odd indexes are ICU expressions
24027
+ // TODO(ocombe): support ICU expressions in attributes
24028
+ throw new Error('ICU expressions are not yet supported in attributes');
24029
+ }
24030
+ else if (value !== '') {
24031
+ // Even indexes are text (including bindings)
24032
+ var hasBinding = !!value.match(BINDING_REGEXP);
24033
+ if (hasBinding) {
24034
+ if (tView.firstCreatePass && tView.data[index + HEADER_OFFSET] === null) {
24035
+ addAllToArray(generateBindingUpdateOpCodes(value, previousElementIndex, attrName), updateOpCodes);
24036
+ }
24037
+ }
24038
+ else {
24039
+ var tNode = getTNode(tView, previousElementIndex);
24040
+ // Set attributes for Elements only, for other types (like ElementContainer),
24041
+ // only set inputs below
24042
+ if (tNode.type === 3 /* Element */) {
24043
+ elementAttributeInternal(tNode, lView, attrName, value, null, null);
24044
+ }
24045
+ // Check if that attribute is a directive input
24046
+ var dataValue = tNode.inputs !== null && tNode.inputs[attrName];
24047
+ if (dataValue) {
24048
+ setInputsForProperty(tView, lView, dataValue, attrName, value);
24049
+ if (ngDevMode) {
24050
+ var element = getNativeByIndex(previousElementIndex, lView);
24051
+ setNgReflectProperties(lView, element, tNode.type, dataValue, value);
24052
+ }
24053
+ }
24054
+ }
24055
+ }
24056
+ }
24057
+ }
24058
+ if (tView.firstCreatePass && tView.data[index + HEADER_OFFSET] === null) {
24059
+ tView.data[index + HEADER_OFFSET] = updateOpCodes;
24060
+ }
24061
+ }
24062
+ /**
24063
+ * Generate the OpCodes to update the bindings of a string.
24064
+ *
24065
+ * @param str The string containing the bindings.
24066
+ * @param destinationNode Index of the destination node which will receive the binding.
24067
+ * @param attrName Name of the attribute, if the string belongs to an attribute.
24068
+ * @param sanitizeFn Sanitization function used to sanitize the string after update, if necessary.
24069
+ */
24070
+ function generateBindingUpdateOpCodes(str, destinationNode, attrName, sanitizeFn) {
24071
+ if (sanitizeFn === void 0) { sanitizeFn = null; }
24072
+ var updateOpCodes = [null, null]; // Alloc space for mask and size
24073
+ if (ngDevMode) {
24074
+ attachDebugGetter(updateOpCodes, i18nUpdateOpCodesToString);
24075
+ }
24076
+ var textParts = str.split(BINDING_REGEXP);
24077
+ var mask = 0;
24078
+ for (var j = 0; j < textParts.length; j++) {
24079
+ var textValue = textParts[j];
24080
+ if (j & 1) {
24081
+ // Odd indexes are bindings
24082
+ var bindingIndex = parseInt(textValue, 10);
24083
+ updateOpCodes.push(-1 - bindingIndex);
24084
+ mask = mask | toMaskBit(bindingIndex);
24085
+ }
24086
+ else if (textValue !== '') {
24087
+ // Even indexes are text
24088
+ updateOpCodes.push(textValue);
24089
+ }
24090
+ }
24091
+ updateOpCodes.push(destinationNode << 2 /* SHIFT_REF */ |
24092
+ (attrName ? 1 /* Attr */ : 0 /* Text */));
24093
+ if (attrName) {
24094
+ updateOpCodes.push(attrName, sanitizeFn);
24095
+ }
24096
+ updateOpCodes[0] = mask;
24097
+ updateOpCodes[1] = updateOpCodes.length - 2;
24098
+ return updateOpCodes;
24099
+ }
24100
+ function getBindingMask(icuExpression, mask) {
24101
+ if (mask === void 0) { mask = 0; }
24102
+ mask = mask | toMaskBit(icuExpression.mainBinding);
24103
+ var match;
24104
+ for (var i = 0; i < icuExpression.values.length; i++) {
24105
+ var valueArr = icuExpression.values[i];
24106
+ for (var j = 0; j < valueArr.length; j++) {
24107
+ var value = valueArr[j];
24108
+ if (typeof value === 'string') {
24109
+ while (match = BINDING_REGEXP.exec(value)) {
24110
+ mask = mask | toMaskBit(parseInt(match[1], 10));
24111
+ }
24112
+ }
24113
+ else {
24114
+ mask = getBindingMask(value, mask);
24115
+ }
24116
+ }
24117
+ }
24118
+ return mask;
24119
+ }
24120
+ function allocNodeIndex(startIndex) {
24121
+ return startIndex + i18nVarsCount++;
24122
+ }
24123
+ /**
24124
+ * Convert binding index to mask bit.
24125
+ *
24126
+ * Each index represents a single bit on the bit-mask. Because bit-mask only has 32 bits, we make
24127
+ * the 32nd bit share all masks for all bindings higher than 32. Since it is extremely rare to have
24128
+ * more than 32 bindings this will be hit very rarely. The downside of hitting this corner case is
24129
+ * that we will execute binding code more often than necessary. (penalty of performance)
24130
+ */
24131
+ function toMaskBit(bindingIndex) {
24132
+ return 1 << Math.min(bindingIndex, 31);
24133
+ }
24134
+ function isRootTemplateMessage(subTemplateIndex) {
24135
+ return subTemplateIndex === undefined;
24136
+ }
24137
+ /**
24138
+ * Removes everything inside the sub-templates of a message.
24139
+ */
24140
+ function removeInnerTemplateTranslation(message) {
24141
+ var match;
24142
+ var res = '';
24143
+ var index = 0;
24144
+ var inTemplate = false;
24145
+ var tagMatched;
24146
+ while ((match = SUBTEMPLATE_REGEXP.exec(message)) !== null) {
24147
+ if (!inTemplate) {
24148
+ res += message.substring(index, match.index + match[0].length);
24149
+ tagMatched = match[1];
24150
+ inTemplate = true;
24151
+ }
24152
+ else {
24153
+ if (match[0] === MARKER + "/*" + tagMatched + MARKER) {
24154
+ index = match.index;
24155
+ inTemplate = false;
24156
+ }
24157
+ }
24158
+ }
24159
+ ngDevMode &&
24160
+ assertEqual(inTemplate, false, "Tag mismatch: unable to find the end of the sub-template in the translation \"" + message + "\"");
24161
+ res += message.substr(index);
24162
+ return res;
24163
+ }
24164
+ /**
24165
+ * Extracts a part of a message and removes the rest.
24166
+ *
24167
+ * This method is used for extracting a part of the message associated with a template. A translated
24168
+ * message can span multiple templates.
24169
+ *
24170
+ * Example:
24171
+ * ```
24172
+ * <div i18n>Translate <span *ngIf>me</span>!</div>
24173
+ * ```
24174
+ *
24175
+ * @param message The message to crop
24176
+ * @param subTemplateIndex Index of the sub-template to extract. If undefined it returns the
24177
+ * external template and removes all sub-templates.
24178
+ */
24179
+ function getTranslationForTemplate(message, subTemplateIndex) {
24180
+ if (isRootTemplateMessage(subTemplateIndex)) {
24181
+ // We want the root template message, ignore all sub-templates
24182
+ return removeInnerTemplateTranslation(message);
24183
+ }
24184
+ else {
24185
+ // We want a specific sub-template
24186
+ var start = message.indexOf(":" + subTemplateIndex + MARKER) + 2 + subTemplateIndex.toString().length;
24187
+ var end = message.search(new RegExp(MARKER + "\\/\\*\\d+:" + subTemplateIndex + MARKER));
24188
+ return removeInnerTemplateTranslation(message.substring(start, end));
24189
+ }
24190
+ }
24191
+ /**
24192
+ * Generate the OpCodes for ICU expressions.
24193
+ *
24194
+ * @param tIcus
24195
+ * @param icuExpression
24196
+ * @param startIndex
24197
+ * @param expandoStartIndex
24198
+ */
24199
+ function icuStart(tIcus, icuExpression, startIndex, expandoStartIndex) {
24200
+ var createCodes = [];
24201
+ var removeCodes = [];
24202
+ var updateCodes = [];
24203
+ var vars = [];
24204
+ var childIcus = [];
24205
+ var values = icuExpression.values;
24206
+ for (var i = 0; i < values.length; i++) {
24207
+ // Each value is an array of strings & other ICU expressions
24208
+ var valueArr = values[i];
24209
+ var nestedIcus = [];
24210
+ for (var j = 0; j < valueArr.length; j++) {
24211
+ var value = valueArr[j];
24212
+ if (typeof value !== 'string') {
24213
+ // It is an nested ICU expression
24214
+ var icuIndex = nestedIcus.push(value) - 1;
24215
+ // Replace nested ICU expression by a comment node
24216
+ valueArr[j] = "<!--\uFFFD" + icuIndex + "\uFFFD-->";
24217
+ }
24218
+ }
24219
+ var icuCase = parseIcuCase(valueArr.join(''), startIndex, nestedIcus, tIcus, expandoStartIndex);
24220
+ createCodes.push(icuCase.create);
24221
+ removeCodes.push(icuCase.remove);
24222
+ updateCodes.push(icuCase.update);
24223
+ vars.push(icuCase.vars);
24224
+ childIcus.push(icuCase.childIcus);
24225
+ }
24226
+ var tIcu = {
24227
+ type: icuExpression.type,
24228
+ vars: vars,
24229
+ currentCaseLViewIndex: HEADER_OFFSET +
24230
+ expandoStartIndex // expandoStartIndex does not include the header so add it.
24231
+ + 1,
24232
+ childIcus: childIcus,
24233
+ cases: icuExpression.cases,
24234
+ create: createCodes,
24235
+ remove: removeCodes,
24236
+ update: updateCodes
24237
+ };
24238
+ tIcus.push(tIcu);
24239
+ // Adding the maximum possible of vars needed (based on the cases with the most vars)
24240
+ i18nVarsCount += Math.max.apply(Math, __spread(vars));
24241
+ }
24242
+ /**
24243
+ * Parses text containing an ICU expression and produces a JSON object for it.
24244
+ * Original code from closure library, modified for Angular.
24245
+ *
24246
+ * @param pattern Text containing an ICU expression that needs to be parsed.
24247
+ *
24248
+ */
24249
+ function parseICUBlock(pattern) {
24250
+ var cases = [];
24251
+ var values = [];
24252
+ var icuType = 1 /* plural */;
24253
+ var mainBinding = 0;
24254
+ pattern = pattern.replace(ICU_BLOCK_REGEXP, function (str, binding, type) {
24255
+ if (type === 'select') {
24256
+ icuType = 0 /* select */;
24257
+ }
24258
+ else {
24259
+ icuType = 1 /* plural */;
24260
+ }
24261
+ mainBinding = parseInt(binding.substr(1), 10);
24262
+ return '';
24263
+ });
24264
+ var parts = extractParts(pattern);
24265
+ // Looking for (key block)+ sequence. One of the keys has to be "other".
24266
+ for (var pos = 0; pos < parts.length;) {
24267
+ var key = parts[pos++].trim();
24268
+ if (icuType === 1 /* plural */) {
24269
+ // Key can be "=x", we just want "x"
24270
+ key = key.replace(/\s*(?:=)?(\w+)\s*/, '$1');
24271
+ }
24272
+ if (key.length) {
24273
+ cases.push(key);
24274
+ }
24275
+ var blocks = extractParts(parts[pos++]);
24276
+ if (cases.length > values.length) {
24277
+ values.push(blocks);
24278
+ }
24279
+ }
24280
+ // TODO(ocombe): support ICU expressions in attributes, see #21615
24281
+ return { type: icuType, mainBinding: mainBinding, cases: cases, values: values };
24282
+ }
24283
+ /**
24284
+ * Transforms a string template into an HTML template and a list of instructions used to update
24285
+ * attributes or nodes that contain bindings.
24286
+ *
24287
+ * @param unsafeHtml The string to parse
24288
+ * @param parentIndex
24289
+ * @param nestedIcus
24290
+ * @param tIcus
24291
+ * @param expandoStartIndex
24292
+ */
24293
+ function parseIcuCase(unsafeHtml, parentIndex, nestedIcus, tIcus, expandoStartIndex) {
24294
+ var inertBodyHelper = getInertBodyHelper(getDocument());
24295
+ var inertBodyElement = inertBodyHelper.getInertBodyElement(unsafeHtml);
24296
+ if (!inertBodyElement) {
24297
+ throw new Error('Unable to generate inert body element');
24298
+ }
24299
+ var wrapper = getTemplateContent(inertBodyElement) || inertBodyElement;
24300
+ var opCodes = {
24301
+ vars: 1,
24302
+ childIcus: [],
24303
+ create: [],
24304
+ remove: [],
24305
+ update: []
24306
+ };
24307
+ if (ngDevMode) {
24308
+ attachDebugGetter(opCodes.create, i18nMutateOpCodesToString);
24309
+ attachDebugGetter(opCodes.remove, i18nMutateOpCodesToString);
24310
+ attachDebugGetter(opCodes.update, i18nUpdateOpCodesToString);
24311
+ }
24312
+ parseNodes(wrapper.firstChild, opCodes, parentIndex, nestedIcus, tIcus, expandoStartIndex);
24313
+ return opCodes;
24314
+ }
24315
+ /**
24316
+ * Breaks pattern into strings and top level {...} blocks.
24317
+ * Can be used to break a message into text and ICU expressions, or to break an ICU expression into
24318
+ * keys and cases.
24319
+ * Original code from closure library, modified for Angular.
24320
+ *
24321
+ * @param pattern (sub)Pattern to be broken.
24322
+ *
24323
+ */
24324
+ function extractParts(pattern) {
24325
+ if (!pattern) {
24326
+ return [];
24327
+ }
24328
+ var prevPos = 0;
24329
+ var braceStack = [];
24330
+ var results = [];
24331
+ var braces = /[{}]/g;
24332
+ // lastIndex doesn't get set to 0 so we have to.
24333
+ braces.lastIndex = 0;
24334
+ var match;
24335
+ while (match = braces.exec(pattern)) {
24336
+ var pos = match.index;
24337
+ if (match[0] == '}') {
24338
+ braceStack.pop();
24339
+ if (braceStack.length == 0) {
24340
+ // End of the block.
24341
+ var block = pattern.substring(prevPos, pos);
24342
+ if (ICU_BLOCK_REGEXP.test(block)) {
24343
+ results.push(parseICUBlock(block));
24344
+ }
24345
+ else {
24346
+ results.push(block);
24347
+ }
24348
+ prevPos = pos + 1;
24349
+ }
24350
+ }
24351
+ else {
24352
+ if (braceStack.length == 0) {
24353
+ var substring_1 = pattern.substring(prevPos, pos);
24354
+ results.push(substring_1);
24355
+ prevPos = pos + 1;
24356
+ }
24357
+ braceStack.push('{');
24358
+ }
24359
+ }
24360
+ var substring = pattern.substring(prevPos);
24361
+ results.push(substring);
24362
+ return results;
24363
+ }
24364
+ /**
24365
+ * Parses a node, its children and its siblings, and generates the mutate & update OpCodes.
24366
+ *
24367
+ * @param currentNode The first node to parse
24368
+ * @param icuCase The data for the ICU expression case that contains those nodes
24369
+ * @param parentIndex Index of the current node's parent
24370
+ * @param nestedIcus Data for the nested ICU expressions that this case contains
24371
+ * @param tIcus Data for all ICU expressions of the current message
24372
+ * @param expandoStartIndex Expando start index for the current ICU expression
24373
+ */
24374
+ function parseNodes(currentNode, icuCase, parentIndex, nestedIcus, tIcus, expandoStartIndex) {
24375
+ if (currentNode) {
24376
+ var nestedIcusToCreate = [];
24377
+ while (currentNode) {
24378
+ var nextNode = currentNode.nextSibling;
24379
+ var newIndex = expandoStartIndex + ++icuCase.vars;
24380
+ switch (currentNode.nodeType) {
24381
+ case Node.ELEMENT_NODE:
24382
+ var element = currentNode;
24383
+ var tagName = element.tagName.toLowerCase();
24384
+ if (!VALID_ELEMENTS.hasOwnProperty(tagName)) {
24385
+ // This isn't a valid element, we won't create an element for it
24386
+ icuCase.vars--;
24387
+ }
24388
+ else {
24389
+ icuCase.create.push(ELEMENT_MARKER, tagName, newIndex, parentIndex << 17 /* SHIFT_PARENT */ | 1 /* AppendChild */);
24390
+ var elAttrs = element.attributes;
24391
+ for (var i = 0; i < elAttrs.length; i++) {
24392
+ var attr = elAttrs.item(i);
24393
+ var lowerAttrName = attr.name.toLowerCase();
24394
+ var hasBinding_1 = !!attr.value.match(BINDING_REGEXP);
24395
+ // we assume the input string is safe, unless it's using a binding
24396
+ if (hasBinding_1) {
24397
+ if (VALID_ATTRS.hasOwnProperty(lowerAttrName)) {
24398
+ if (URI_ATTRS[lowerAttrName]) {
24399
+ addAllToArray(generateBindingUpdateOpCodes(attr.value, newIndex, attr.name, _sanitizeUrl), icuCase.update);
24400
+ }
24401
+ else if (SRCSET_ATTRS[lowerAttrName]) {
24402
+ addAllToArray(generateBindingUpdateOpCodes(attr.value, newIndex, attr.name, sanitizeSrcset), icuCase.update);
24403
+ }
24404
+ else {
24405
+ addAllToArray(generateBindingUpdateOpCodes(attr.value, newIndex, attr.name), icuCase.update);
24406
+ }
24407
+ }
24408
+ else {
24409
+ ngDevMode &&
24410
+ console.warn("WARNING: ignoring unsafe attribute value " + lowerAttrName + " on element " + tagName + " (see http://g.co/ng/security#xss)");
24411
+ }
24412
+ }
24413
+ else {
24414
+ icuCase.create.push(newIndex << 3 /* SHIFT_REF */ | 4 /* Attr */, attr.name, attr.value);
24415
+ }
24416
+ }
24417
+ // Parse the children of this node (if any)
24418
+ parseNodes(currentNode.firstChild, icuCase, newIndex, nestedIcus, tIcus, expandoStartIndex);
24419
+ // Remove the parent node after the children
24420
+ icuCase.remove.push(newIndex << 3 /* SHIFT_REF */ | 3 /* Remove */);
24421
+ }
24422
+ break;
24423
+ case Node.TEXT_NODE:
24424
+ var value = currentNode.textContent || '';
24425
+ var hasBinding = value.match(BINDING_REGEXP);
24426
+ icuCase.create.push(hasBinding ? '' : value, newIndex, parentIndex << 17 /* SHIFT_PARENT */ | 1 /* AppendChild */);
24427
+ icuCase.remove.push(newIndex << 3 /* SHIFT_REF */ | 3 /* Remove */);
24428
+ if (hasBinding) {
24429
+ addAllToArray(generateBindingUpdateOpCodes(value, newIndex), icuCase.update);
24430
+ }
24431
+ break;
24432
+ case Node.COMMENT_NODE:
24433
+ // Check if the comment node is a placeholder for a nested ICU
24434
+ var match = NESTED_ICU.exec(currentNode.textContent || '');
24435
+ if (match) {
24436
+ var nestedIcuIndex = parseInt(match[1], 10);
24437
+ var newLocal = ngDevMode ? "nested ICU " + nestedIcuIndex : '';
24438
+ // Create the comment node that will anchor the ICU expression
24439
+ icuCase.create.push(COMMENT_MARKER, newLocal, newIndex, parentIndex << 17 /* SHIFT_PARENT */ | 1 /* AppendChild */);
24440
+ var nestedIcu = nestedIcus[nestedIcuIndex];
24441
+ nestedIcusToCreate.push([nestedIcu, newIndex]);
24442
+ }
24443
+ else {
24444
+ // We do not handle any other type of comment
24445
+ icuCase.vars--;
24446
+ }
24447
+ break;
24448
+ default:
24449
+ // We do not handle any other type of element
24450
+ icuCase.vars--;
24451
+ }
24452
+ currentNode = nextNode;
24453
+ }
24454
+ for (var i = 0; i < nestedIcusToCreate.length; i++) {
24455
+ var nestedIcu = nestedIcusToCreate[i][0];
24456
+ var nestedIcuNodeIndex = nestedIcusToCreate[i][1];
24457
+ icuStart(tIcus, nestedIcu, nestedIcuNodeIndex, expandoStartIndex + icuCase.vars);
24458
+ // Since this is recursive, the last TIcu that was pushed is the one we want
24459
+ var nestTIcuIndex = tIcus.length - 1;
24460
+ icuCase.vars += Math.max.apply(Math, __spread(tIcus[nestTIcuIndex].vars));
24461
+ icuCase.childIcus.push(nestTIcuIndex);
24462
+ var mask = getBindingMask(nestedIcu);
24463
+ icuCase.update.push(toMaskBit(nestedIcu.mainBinding), // mask of the main binding
24464
+ 3, // skip 3 opCodes if not changed
24465
+ -1 - nestedIcu.mainBinding, nestedIcuNodeIndex << 2 /* SHIFT_REF */ | 2 /* IcuSwitch */,
24466
+ // FIXME(misko): Index should be part of the opcode
24467
+ nestTIcuIndex, mask, // mask of all the bindings of this ICU expression
24468
+ 2, // skip 2 opCodes if not changed
24469
+ nestedIcuNodeIndex << 2 /* SHIFT_REF */ | 3 /* IcuUpdate */, nestTIcuIndex);
24470
+ icuCase.remove.push(nestTIcuIndex << 3 /* SHIFT_REF */ | 6 /* RemoveNestedIcu */,
24471
+ // FIXME(misko): Index should be part of the opcode
24472
+ nestedIcuNodeIndex << 3 /* SHIFT_REF */ | 3 /* Remove */);
24473
+ }
24474
+ }
24475
+ }
24476
+
24477
+ /**
24478
+ * @license
24479
+ * Copyright Google LLC All Rights Reserved.
24480
+ *
24481
+ * Use of this source code is governed by an MIT-style license that can be
24482
+ * found in the LICENSE file at https://angular.io/license
24483
+ */
24484
+ // i18nPostprocess consts
24485
+ var ROOT_TEMPLATE_ID = 0;
24486
+ var PP_MULTI_VALUE_PLACEHOLDERS_REGEXP = /\[(�.+?�?)\]/;
24487
+ var PP_PLACEHOLDERS_REGEXP = /\[(�.+?�?)\]|(�\/?\*\d+:\d+�)/g;
24488
+ var PP_ICU_VARS_REGEXP = /({\s*)(VAR_(PLURAL|SELECT)(_\d+)?)(\s*,)/g;
24489
+ var PP_ICU_PLACEHOLDERS_REGEXP = /{([A-Z0-9_]+)}/g;
24490
+ var PP_ICUS_REGEXP = /�I18N_EXP_(ICU(_\d+)?)�/g;
24491
+ var PP_CLOSE_TEMPLATE_REGEXP = /\/\*/;
24492
+ var PP_TEMPLATE_ID_REGEXP = /\d+\:(\d+)/;
23727
24493
  /**
23728
24494
  * Handles message string post-processing for internationalization.
23729
24495
  *
@@ -23744,7 +24510,7 @@
23744
24510
  *
23745
24511
  * @codeGenApi
23746
24512
  */
23747
- function ɵɵi18nPostprocess(message, replacements) {
24513
+ function i18nPostprocess(message, replacements) {
23748
24514
  if (replacements === void 0) { replacements = {}; }
23749
24515
  /**
23750
24516
  * Step 1: resolve all multi-value placeholders like [�#5�|�*1:1��#2:1�|�#4:1�]
@@ -23774,337 +24540,73 @@
23774
24540
  }
23775
24541
  if (!placeholders.length) {
23776
24542
  throw new Error("i18n postprocess: unmatched placeholder - " + content);
23777
- }
23778
- var currentTemplateId = templateIdsStack_1[templateIdsStack_1.length - 1];
23779
- var idx = 0;
23780
- // find placeholder index that matches current template id
23781
- for (var i = 0; i < placeholders.length; i++) {
23782
- if (placeholders[i][0] === currentTemplateId) {
23783
- idx = i;
23784
- break;
23785
- }
23786
- }
23787
- // update template id stack based on the current tag extracted
23788
- var _a = __read(placeholders[idx], 3), templateId = _a[0], isCloseTemplateTag = _a[1], placeholder = _a[2];
23789
- if (isCloseTemplateTag) {
23790
- templateIdsStack_1.pop();
23791
- }
23792
- else if (currentTemplateId !== templateId) {
23793
- templateIdsStack_1.push(templateId);
23794
- }
23795
- // remove processed tag from the list
23796
- placeholders.splice(idx, 1);
23797
- return placeholder;
23798
- });
23799
- }
23800
- // return current result if no replacements specified
23801
- if (!Object.keys(replacements).length) {
23802
- return result;
23803
- }
23804
- /**
23805
- * Step 2: replace all ICU vars (like "VAR_PLURAL")
23806
- */
23807
- result = result.replace(PP_ICU_VARS_REGEXP, function (match, start, key, _type, _idx, end) {
23808
- return replacements.hasOwnProperty(key) ? "" + start + replacements[key] + end : match;
23809
- });
23810
- /**
23811
- * Step 3: replace all placeholders used inside ICUs in a form of {PLACEHOLDER}
23812
- */
23813
- result = result.replace(PP_ICU_PLACEHOLDERS_REGEXP, function (match, key) {
23814
- return replacements.hasOwnProperty(key) ? replacements[key] : match;
23815
- });
23816
- /**
23817
- * Step 4: replace all ICU references with corresponding values (like �ICU_EXP_ICU_1�) in case
23818
- * multiple ICUs have the same placeholder name
23819
- */
23820
- result = result.replace(PP_ICUS_REGEXP, function (match, key) {
23821
- if (replacements.hasOwnProperty(key)) {
23822
- var list = replacements[key];
23823
- if (!list.length) {
23824
- throw new Error("i18n postprocess: unmatched ICU - " + match + " with key: " + key);
23825
- }
23826
- return list.shift();
23827
- }
23828
- return match;
23829
- });
23830
- return result;
23831
- }
23832
- /**
23833
- * Translates a translation block marked by `i18nStart` and `i18nEnd`. It inserts the text/ICU nodes
23834
- * into the render tree, moves the placeholder nodes and removes the deleted nodes.
23835
- *
23836
- * @codeGenApi
23837
- */
23838
- function ɵɵi18nEnd() {
23839
- var lView = getLView();
23840
- var tView = getTView();
23841
- ngDevMode && assertDefined(tView, "tView should be defined");
23842
- i18nEndFirstPass(tView, lView);
23843
- // Stop delaying projections
23844
- setDelayProjection(false);
23845
- }
23846
- /**
23847
- * See `i18nEnd` above.
23848
- */
23849
- function i18nEndFirstPass(tView, lView) {
23850
- ngDevMode &&
23851
- assertEqual(getBindingIndex(), tView.bindingStartIndex, 'i18nEnd should be called before any binding');
23852
- var rootIndex = i18nIndexStack[i18nIndexStackPointer--];
23853
- var tI18n = tView.data[rootIndex + HEADER_OFFSET];
23854
- ngDevMode && assertDefined(tI18n, "You should call i18nStart before i18nEnd");
23855
- // Find the last node that was added before `i18nEnd`
23856
- var lastCreatedNode = getPreviousOrParentTNode();
23857
- // Read the instructions to insert/move/remove DOM elements
23858
- var visitedNodes = readCreateOpCodes(rootIndex, tI18n.create, tView, lView);
23859
- // Remove deleted nodes
23860
- var index = rootIndex + 1;
23861
- while (index <= lastCreatedNode.index - HEADER_OFFSET) {
23862
- if (visitedNodes.indexOf(index) === -1) {
23863
- removeNode(tView, lView, index, /* markAsDetached */ true);
23864
- }
23865
- // Check if an element has any local refs and skip them
23866
- var tNode = getTNode(tView, index);
23867
- if (tNode &&
23868
- (tNode.type === 0 /* Container */ || tNode.type === 3 /* Element */ ||
23869
- tNode.type === 4 /* ElementContainer */) &&
23870
- tNode.localNames !== null) {
23871
- // Divide by 2 to get the number of local refs,
23872
- // since they are stored as an array that also includes directive indexes,
23873
- // i.e. ["localRef", directiveIndex, ...]
23874
- index += tNode.localNames.length >> 1;
23875
- }
23876
- index++;
23877
- }
23878
- }
23879
- /**
23880
- * Creates and stores the dynamic TNode, and unhooks it from the tree for now.
23881
- */
23882
- function createDynamicNodeAtIndex(tView, lView, index, type, native, name) {
23883
- var previousOrParentTNode = getPreviousOrParentTNode();
23884
- ngDevMode && assertDataInRange(lView, index + HEADER_OFFSET);
23885
- lView[index + HEADER_OFFSET] = native;
23886
- var tNode = getOrCreateTNode(tView, lView[T_HOST], index, type, name, null);
23887
- // We are creating a dynamic node, the previous tNode might not be pointing at this node.
23888
- // We will link ourselves into the tree later with `appendI18nNode`.
23889
- if (previousOrParentTNode && previousOrParentTNode.next === tNode) {
23890
- previousOrParentTNode.next = null;
23891
- }
23892
- return tNode;
23893
- }
23894
- function readCreateOpCodes(index, createOpCodes, tView, lView) {
23895
- var renderer = lView[RENDERER];
23896
- var currentTNode = null;
23897
- var previousTNode = null;
23898
- var visitedNodes = [];
23899
- for (var i = 0; i < createOpCodes.length; i++) {
23900
- var opCode = createOpCodes[i];
23901
- if (typeof opCode == 'string') {
23902
- var textRNode = createTextNode(opCode, renderer);
23903
- var textNodeIndex = createOpCodes[++i];
23904
- ngDevMode && ngDevMode.rendererCreateTextNode++;
23905
- previousTNode = currentTNode;
23906
- currentTNode =
23907
- createDynamicNodeAtIndex(tView, lView, textNodeIndex, 3 /* Element */, textRNode, null);
23908
- visitedNodes.push(textNodeIndex);
23909
- setIsNotParent();
23910
- }
23911
- else if (typeof opCode == 'number') {
23912
- switch (opCode & 7 /* MASK_OPCODE */) {
23913
- case 1 /* AppendChild */:
23914
- var destinationNodeIndex = opCode >>> 17 /* SHIFT_PARENT */;
23915
- var destinationTNode = void 0;
23916
- if (destinationNodeIndex === index) {
23917
- // If the destination node is `i18nStart`, we don't have a
23918
- // top-level node and we should use the host node instead
23919
- destinationTNode = lView[T_HOST];
23920
- }
23921
- else {
23922
- destinationTNode = getTNode(tView, destinationNodeIndex);
23923
- }
23924
- ngDevMode &&
23925
- assertDefined(currentTNode, "You need to create or select a node before you can insert it into the DOM");
23926
- previousTNode =
23927
- appendI18nNode(tView, currentTNode, destinationTNode, previousTNode, lView);
23928
- break;
23929
- case 0 /* Select */:
23930
- // Negative indicies indicate that a given TNode is a sibling node, not a parent node
23931
- // (see `i18nStartFirstPass` for additional information).
23932
- var isParent = opCode >= 0;
23933
- var nodeIndex = (isParent ? opCode : ~opCode) >>> 3 /* SHIFT_REF */;
23934
- visitedNodes.push(nodeIndex);
23935
- previousTNode = currentTNode;
23936
- currentTNode = getTNode(tView, nodeIndex);
23937
- if (currentTNode) {
23938
- setPreviousOrParentTNode(currentTNode, isParent);
23939
- }
23940
- break;
23941
- case 5 /* ElementEnd */:
23942
- var elementIndex = opCode >>> 3 /* SHIFT_REF */;
23943
- previousTNode = currentTNode = getTNode(tView, elementIndex);
23944
- setPreviousOrParentTNode(currentTNode, false);
23945
- break;
23946
- case 4 /* Attr */:
23947
- var elementNodeIndex = opCode >>> 3 /* SHIFT_REF */;
23948
- var attrName = createOpCodes[++i];
23949
- var attrValue = createOpCodes[++i];
23950
- // This code is used for ICU expressions only, since we don't support
23951
- // directives/components in ICUs, we don't need to worry about inputs here
23952
- elementAttributeInternal(getTNode(tView, elementNodeIndex), lView, attrName, attrValue, null, null);
23953
- break;
23954
- default:
23955
- throw new Error("Unable to determine the type of mutate operation for \"" + opCode + "\"");
23956
- }
23957
- }
23958
- else {
23959
- switch (opCode) {
23960
- case COMMENT_MARKER:
23961
- var commentValue = createOpCodes[++i];
23962
- var commentNodeIndex = createOpCodes[++i];
23963
- ngDevMode &&
23964
- assertEqual(typeof commentValue, 'string', "Expected \"" + commentValue + "\" to be a comment node value");
23965
- var commentRNode = renderer.createComment(commentValue);
23966
- ngDevMode && ngDevMode.rendererCreateComment++;
23967
- previousTNode = currentTNode;
23968
- currentTNode = createDynamicNodeAtIndex(tView, lView, commentNodeIndex, 5 /* IcuContainer */, commentRNode, null);
23969
- visitedNodes.push(commentNodeIndex);
23970
- attachPatchData(commentRNode, lView);
23971
- currentTNode.activeCaseIndex = null;
23972
- // We will add the case nodes later, during the update phase
23973
- setIsNotParent();
23974
- break;
23975
- case ELEMENT_MARKER:
23976
- var tagNameValue = createOpCodes[++i];
23977
- var elementNodeIndex = createOpCodes[++i];
23978
- ngDevMode &&
23979
- assertEqual(typeof tagNameValue, 'string', "Expected \"" + tagNameValue + "\" to be an element node tag name");
23980
- var elementRNode = renderer.createElement(tagNameValue);
23981
- ngDevMode && ngDevMode.rendererCreateElement++;
23982
- previousTNode = currentTNode;
23983
- currentTNode = createDynamicNodeAtIndex(tView, lView, elementNodeIndex, 3 /* Element */, elementRNode, tagNameValue);
23984
- visitedNodes.push(elementNodeIndex);
23985
- break;
23986
- default:
23987
- throw new Error("Unable to determine the type of mutate operation for \"" + opCode + "\"");
23988
- }
23989
- }
23990
- }
23991
- setIsNotParent();
23992
- return visitedNodes;
23993
- }
23994
- function readUpdateOpCodes(updateOpCodes, icus, bindingsStartIndex, changeMask, tView, lView, bypassCheckBit) {
23995
- if (bypassCheckBit === void 0) { bypassCheckBit = false; }
23996
- var caseCreated = false;
23997
- for (var i = 0; i < updateOpCodes.length; i++) {
23998
- // bit code to check if we should apply the next update
23999
- var checkBit = updateOpCodes[i];
24000
- // Number of opCodes to skip until next set of update codes
24001
- var skipCodes = updateOpCodes[++i];
24002
- if (bypassCheckBit || (checkBit & changeMask)) {
24003
- // The value has been updated since last checked
24004
- var value = '';
24005
- for (var j = i + 1; j <= (i + skipCodes); j++) {
24006
- var opCode = updateOpCodes[j];
24007
- if (typeof opCode == 'string') {
24008
- value += opCode;
24009
- }
24010
- else if (typeof opCode == 'number') {
24011
- if (opCode < 0) {
24012
- // It's a binding index whose value is negative
24013
- value += renderStringify(lView[bindingsStartIndex - opCode]);
24014
- }
24015
- else {
24016
- var nodeIndex = opCode >>> 2 /* SHIFT_REF */;
24017
- var tIcuIndex = void 0;
24018
- var tIcu = void 0;
24019
- var icuTNode = void 0;
24020
- switch (opCode & 3 /* MASK_OPCODE */) {
24021
- case 1 /* Attr */:
24022
- var propName = updateOpCodes[++j];
24023
- var sanitizeFn = updateOpCodes[++j];
24024
- elementPropertyInternal(tView, getTNode(tView, nodeIndex), lView, propName, value, lView[RENDERER], sanitizeFn, false);
24025
- break;
24026
- case 0 /* Text */:
24027
- textBindingInternal(lView, nodeIndex, value);
24028
- break;
24029
- case 2 /* IcuSwitch */:
24030
- tIcuIndex = updateOpCodes[++j];
24031
- tIcu = icus[tIcuIndex];
24032
- icuTNode = getTNode(tView, nodeIndex);
24033
- // If there is an active case, delete the old nodes
24034
- if (icuTNode.activeCaseIndex !== null) {
24035
- var removeCodes = tIcu.remove[icuTNode.activeCaseIndex];
24036
- for (var k = 0; k < removeCodes.length; k++) {
24037
- var removeOpCode = removeCodes[k];
24038
- switch (removeOpCode & 7 /* MASK_OPCODE */) {
24039
- case 3 /* Remove */:
24040
- var nodeIndex_1 = removeOpCode >>> 3 /* SHIFT_REF */;
24041
- // Remove DOM element, but do *not* mark TNode as detached, since we are
24042
- // just switching ICU cases (while keeping the same TNode), so a DOM element
24043
- // representing a new ICU case will be re-created.
24044
- removeNode(tView, lView, nodeIndex_1, /* markAsDetached */ false);
24045
- break;
24046
- case 6 /* RemoveNestedIcu */:
24047
- var nestedIcuNodeIndex = removeCodes[k + 1] >>> 3 /* SHIFT_REF */;
24048
- var nestedIcuTNode = getTNode(tView, nestedIcuNodeIndex);
24049
- var activeIndex = nestedIcuTNode.activeCaseIndex;
24050
- if (activeIndex !== null) {
24051
- var nestedIcuTIndex = removeOpCode >>> 3 /* SHIFT_REF */;
24052
- var nestedTIcu = icus[nestedIcuTIndex];
24053
- addAllToArray(nestedTIcu.remove[activeIndex], removeCodes);
24054
- }
24055
- break;
24056
- }
24057
- }
24058
- }
24059
- // Update the active caseIndex
24060
- var caseIndex = getCaseIndex(tIcu, value);
24061
- icuTNode.activeCaseIndex = caseIndex !== -1 ? caseIndex : null;
24062
- if (caseIndex > -1) {
24063
- // Add the nodes for the new case
24064
- readCreateOpCodes(-1, tIcu.create[caseIndex], tView, lView);
24065
- caseCreated = true;
24066
- }
24067
- break;
24068
- case 3 /* IcuUpdate */:
24069
- tIcuIndex = updateOpCodes[++j];
24070
- tIcu = icus[tIcuIndex];
24071
- icuTNode = getTNode(tView, nodeIndex);
24072
- if (icuTNode.activeCaseIndex !== null) {
24073
- readUpdateOpCodes(tIcu.update[icuTNode.activeCaseIndex], icus, bindingsStartIndex, changeMask, tView, lView, caseCreated);
24074
- }
24075
- break;
24076
- }
24077
- }
24543
+ }
24544
+ var currentTemplateId = templateIdsStack_1[templateIdsStack_1.length - 1];
24545
+ var idx = 0;
24546
+ // find placeholder index that matches current template id
24547
+ for (var i = 0; i < placeholders.length; i++) {
24548
+ if (placeholders[i][0] === currentTemplateId) {
24549
+ idx = i;
24550
+ break;
24078
24551
  }
24079
24552
  }
24080
- }
24081
- i += skipCodes;
24553
+ // update template id stack based on the current tag extracted
24554
+ var _a = __read(placeholders[idx], 3), templateId = _a[0], isCloseTemplateTag = _a[1], placeholder = _a[2];
24555
+ if (isCloseTemplateTag) {
24556
+ templateIdsStack_1.pop();
24557
+ }
24558
+ else if (currentTemplateId !== templateId) {
24559
+ templateIdsStack_1.push(templateId);
24560
+ }
24561
+ // remove processed tag from the list
24562
+ placeholders.splice(idx, 1);
24563
+ return placeholder;
24564
+ });
24082
24565
  }
24083
- }
24084
- function removeNode(tView, lView, index, markAsDetached) {
24085
- var removedPhTNode = getTNode(tView, index);
24086
- var removedPhRNode = getNativeByIndex(index, lView);
24087
- if (removedPhRNode) {
24088
- nativeRemoveNode(lView[RENDERER], removedPhRNode);
24566
+ // return current result if no replacements specified
24567
+ if (!Object.keys(replacements).length) {
24568
+ return result;
24089
24569
  }
24090
- var slotValue = load(lView, index);
24091
- if (isLContainer(slotValue)) {
24092
- var lContainer = slotValue;
24093
- if (removedPhTNode.type !== 0 /* Container */) {
24094
- nativeRemoveNode(lView[RENDERER], lContainer[NATIVE]);
24570
+ /**
24571
+ * Step 2: replace all ICU vars (like "VAR_PLURAL")
24572
+ */
24573
+ result = result.replace(PP_ICU_VARS_REGEXP, function (match, start, key, _type, _idx, end) {
24574
+ return replacements.hasOwnProperty(key) ? "" + start + replacements[key] + end : match;
24575
+ });
24576
+ /**
24577
+ * Step 3: replace all placeholders used inside ICUs in a form of {PLACEHOLDER}
24578
+ */
24579
+ result = result.replace(PP_ICU_PLACEHOLDERS_REGEXP, function (match, key) {
24580
+ return replacements.hasOwnProperty(key) ? replacements[key] : match;
24581
+ });
24582
+ /**
24583
+ * Step 4: replace all ICU references with corresponding values (like �ICU_EXP_ICU_1�) in case
24584
+ * multiple ICUs have the same placeholder name
24585
+ */
24586
+ result = result.replace(PP_ICUS_REGEXP, function (match, key) {
24587
+ if (replacements.hasOwnProperty(key)) {
24588
+ var list = replacements[key];
24589
+ if (!list.length) {
24590
+ throw new Error("i18n postprocess: unmatched ICU - " + match + " with key: " + key);
24591
+ }
24592
+ return list.shift();
24095
24593
  }
24096
- }
24097
- if (markAsDetached) {
24098
- // Define this node as detached to avoid projecting it later
24099
- removedPhTNode.flags |= 64 /* isDetached */;
24100
- }
24101
- ngDevMode && ngDevMode.rendererRemoveNode++;
24594
+ return match;
24595
+ });
24596
+ return result;
24102
24597
  }
24598
+
24103
24599
  /**
24600
+ * @license
24601
+ * Copyright Google LLC All Rights Reserved.
24104
24602
  *
24105
- * Use this instruction to create a translation block that doesn't contain any placeholder.
24106
- * It calls both {@link i18nStart} and {@link i18nEnd} in one instruction.
24603
+ * Use of this source code is governed by an MIT-style license that can be
24604
+ * found in the LICENSE file at https://angular.io/license
24605
+ */
24606
+ /**
24607
+ * Marks a block of text as translatable.
24107
24608
  *
24609
+ * The instructions `i18nStart` and `i18nEnd` mark the translation block in the template.
24108
24610
  * The translation `message` is the value which is locale specific. The translation string may
24109
24611
  * contain placeholders which associate inner elements and sub-templates within the translation.
24110
24612
  *
@@ -24116,6 +24618,10 @@
24116
24618
  * and end of DOM element that were embedded in the original translation block. The placeholder
24117
24619
  * `index` points to the element index in the template instructions set. An optional `block` that
24118
24620
  * matches the sub-template in which it was declared.
24621
+ * - `�!{index}(:{block})�`/`�/!{index}(:{block})�`: *Projection Placeholder*: Marks the
24622
+ * beginning and end of <ng-content> that was embedded in the original translation block.
24623
+ * The placeholder `index` points to the element index in the template instructions set.
24624
+ * An optional `block` that matches the sub-template in which it was declared.
24119
24625
  * - `�*{index}:{block}�`/`�/*{index}:{block}�`: *Sub-template Placeholder*: Sub-templates must be
24120
24626
  * split up and translated separately in each angular template function. The `index` points to the
24121
24627
  * `template` instruction index. A `block` that matches the sub-template in which it was declared.
@@ -24126,364 +24632,123 @@
24126
24632
  *
24127
24633
  * @codeGenApi
24128
24634
  */
24129
- function ɵɵi18n(index, message, subTemplateIndex) {
24130
- ɵɵi18nStart(index, message, subTemplateIndex);
24131
- ɵɵi18nEnd();
24132
- }
24133
- /**
24134
- * Marks a list of attributes as translatable.
24135
- *
24136
- * @param index A unique index in the static block
24137
- * @param values
24138
- *
24139
- * @codeGenApi
24140
- */
24141
- function ɵɵi18nAttributes(index, values) {
24142
- var lView = getLView();
24143
- var tView = getTView();
24144
- ngDevMode && assertDefined(tView, "tView should be defined");
24145
- i18nAttributesFirstPass(lView, tView, index, values);
24146
- }
24147
- /**
24148
- * See `i18nAttributes` above.
24149
- */
24150
- function i18nAttributesFirstPass(lView, tView, index, values) {
24151
- var previousElement = getPreviousOrParentTNode();
24152
- var previousElementIndex = previousElement.index - HEADER_OFFSET;
24153
- var updateOpCodes = [];
24154
- for (var i = 0; i < values.length; i += 2) {
24155
- var attrName = values[i];
24156
- var message = values[i + 1];
24157
- var parts = message.split(ICU_REGEXP);
24158
- for (var j = 0; j < parts.length; j++) {
24159
- var value = parts[j];
24160
- if (j & 1) {
24161
- // Odd indexes are ICU expressions
24162
- // TODO(ocombe): support ICU expressions in attributes
24163
- throw new Error('ICU expressions are not yet supported in attributes');
24164
- }
24165
- else if (value !== '') {
24166
- // Even indexes are text (including bindings)
24167
- var hasBinding = !!value.match(BINDING_REGEXP);
24168
- if (hasBinding) {
24169
- if (tView.firstCreatePass && tView.data[index + HEADER_OFFSET] === null) {
24170
- addAllToArray(generateBindingUpdateOpCodes(value, previousElementIndex, attrName), updateOpCodes);
24171
- }
24172
- }
24173
- else {
24174
- var tNode = getTNode(tView, previousElementIndex);
24175
- // Set attributes for Elements only, for other types (like ElementContainer),
24176
- // only set inputs below
24177
- if (tNode.type === 3 /* Element */) {
24178
- elementAttributeInternal(tNode, lView, attrName, value, null, null);
24179
- }
24180
- // Check if that attribute is a directive input
24181
- var dataValue = tNode.inputs !== null && tNode.inputs[attrName];
24182
- if (dataValue) {
24183
- setInputsForProperty(tView, lView, dataValue, attrName, value);
24184
- if (ngDevMode) {
24185
- var element = getNativeByIndex(previousElementIndex, lView);
24186
- setNgReflectProperties(lView, element, tNode.type, dataValue, value);
24187
- }
24188
- }
24189
- }
24190
- }
24191
- }
24192
- }
24193
- if (tView.firstCreatePass && tView.data[index + HEADER_OFFSET] === null) {
24194
- tView.data[index + HEADER_OFFSET] = updateOpCodes;
24195
- }
24196
- }
24197
- var changeMask = 0;
24198
- var shiftsCounter = 0;
24199
- /**
24200
- * Stores the values of the bindings during each update cycle in order to determine if we need to
24201
- * update the translated nodes.
24202
- *
24203
- * @param value The binding's value
24204
- * @returns This function returns itself so that it may be chained
24205
- * (e.g. `i18nExp(ctx.name)(ctx.title)`)
24206
- *
24207
- * @codeGenApi
24208
- */
24209
- function ɵɵi18nExp(value) {
24210
- var lView = getLView();
24211
- if (bindingUpdated(lView, nextBindingIndex(), value)) {
24212
- changeMask = changeMask | (1 << shiftsCounter);
24213
- }
24214
- shiftsCounter++;
24215
- return ɵɵi18nExp;
24216
- }
24217
- /**
24218
- * Updates a translation block or an i18n attribute when the bindings have changed.
24219
- *
24220
- * @param index Index of either {@link i18nStart} (translation block) or {@link i18nAttributes}
24221
- * (i18n attribute) on which it should update the content.
24222
- *
24223
- * @codeGenApi
24224
- */
24225
- function ɵɵi18nApply(index) {
24226
- if (shiftsCounter) {
24227
- var tView = getTView();
24228
- ngDevMode && assertDefined(tView, "tView should be defined");
24229
- var tI18n = tView.data[index + HEADER_OFFSET];
24230
- var updateOpCodes = void 0;
24231
- var icus = null;
24232
- if (Array.isArray(tI18n)) {
24233
- updateOpCodes = tI18n;
24234
- }
24235
- else {
24236
- updateOpCodes = tI18n.update;
24237
- icus = tI18n.icus;
24238
- }
24239
- var bindingsStartIndex = getBindingIndex() - shiftsCounter - 1;
24240
- var lView = getLView();
24241
- readUpdateOpCodes(updateOpCodes, icus, bindingsStartIndex, changeMask, tView, lView);
24242
- // Reset changeMask & maskBit to default for the next update cycle
24243
- changeMask = 0;
24244
- shiftsCounter = 0;
24245
- }
24246
- }
24247
- /**
24248
- * Returns the index of the current case of an ICU expression depending on the main binding value
24249
- *
24250
- * @param icuExpression
24251
- * @param bindingValue The value of the main binding used by this ICU expression
24252
- */
24253
- function getCaseIndex(icuExpression, bindingValue) {
24254
- var index = icuExpression.cases.indexOf(bindingValue);
24255
- if (index === -1) {
24256
- switch (icuExpression.type) {
24257
- case 1 /* plural */: {
24258
- var resolvedCase = getPluralCase(bindingValue, getLocaleId());
24259
- index = icuExpression.cases.indexOf(resolvedCase);
24260
- if (index === -1 && resolvedCase !== 'other') {
24261
- index = icuExpression.cases.indexOf('other');
24262
- }
24263
- break;
24264
- }
24265
- case 0 /* select */: {
24266
- index = icuExpression.cases.indexOf('other');
24267
- break;
24268
- }
24269
- }
24270
- }
24271
- return index;
24272
- }
24273
- /**
24274
- * Generate the OpCodes for ICU expressions.
24275
- *
24276
- * @param tIcus
24277
- * @param icuExpression
24278
- * @param startIndex
24279
- * @param expandoStartIndex
24280
- */
24281
- function icuStart(tIcus, icuExpression, startIndex, expandoStartIndex) {
24282
- var createCodes = [];
24283
- var removeCodes = [];
24284
- var updateCodes = [];
24285
- var vars = [];
24286
- var childIcus = [];
24287
- for (var i = 0; i < icuExpression.values.length; i++) {
24288
- // Each value is an array of strings & other ICU expressions
24289
- var valueArr = icuExpression.values[i];
24290
- var nestedIcus = [];
24291
- for (var j = 0; j < valueArr.length; j++) {
24292
- var value = valueArr[j];
24293
- if (typeof value !== 'string') {
24294
- // It is an nested ICU expression
24295
- var icuIndex = nestedIcus.push(value) - 1;
24296
- // Replace nested ICU expression by a comment node
24297
- valueArr[j] = "<!--\uFFFD" + icuIndex + "\uFFFD-->";
24298
- }
24299
- }
24300
- var icuCase = parseIcuCase(valueArr.join(''), startIndex, nestedIcus, tIcus, expandoStartIndex);
24301
- createCodes.push(icuCase.create);
24302
- removeCodes.push(icuCase.remove);
24303
- updateCodes.push(icuCase.update);
24304
- vars.push(icuCase.vars);
24305
- childIcus.push(icuCase.childIcus);
24635
+ function ɵɵi18nStart(index, message, subTemplateIndex) {
24636
+ var tView = getTView();
24637
+ ngDevMode && assertDefined(tView, "tView should be defined");
24638
+ pushI18nIndex(index);
24639
+ // We need to delay projections until `i18nEnd`
24640
+ setDelayProjection(true);
24641
+ if (tView.firstCreatePass && tView.data[index + HEADER_OFFSET] === null) {
24642
+ i18nStartFirstPass(getLView(), tView, index, message, subTemplateIndex);
24306
24643
  }
24307
- var tIcu = {
24308
- type: icuExpression.type,
24309
- vars: vars,
24310
- childIcus: childIcus,
24311
- cases: icuExpression.cases,
24312
- create: createCodes,
24313
- remove: removeCodes,
24314
- update: updateCodes
24315
- };
24316
- tIcus.push(tIcu);
24317
- // Adding the maximum possible of vars needed (based on the cases with the most vars)
24318
- i18nVarsCount += Math.max.apply(Math, __spread(vars));
24319
24644
  }
24320
24645
  /**
24321
- * Transforms a string template into an HTML template and a list of instructions used to update
24322
- * attributes or nodes that contain bindings.
24646
+ * Translates a translation block marked by `i18nStart` and `i18nEnd`. It inserts the text/ICU nodes
24647
+ * into the render tree, moves the placeholder nodes and removes the deleted nodes.
24323
24648
  *
24324
- * @param unsafeHtml The string to parse
24325
- * @param parentIndex
24326
- * @param nestedIcus
24327
- * @param tIcus
24328
- * @param expandoStartIndex
24649
+ * @codeGenApi
24329
24650
  */
24330
- function parseIcuCase(unsafeHtml, parentIndex, nestedIcus, tIcus, expandoStartIndex) {
24331
- var inertBodyHelper = getInertBodyHelper(getDocument());
24332
- var inertBodyElement = inertBodyHelper.getInertBodyElement(unsafeHtml);
24333
- if (!inertBodyElement) {
24334
- throw new Error('Unable to generate inert body element');
24335
- }
24336
- var wrapper = getTemplateContent(inertBodyElement) || inertBodyElement;
24337
- var opCodes = { vars: 0, childIcus: [], create: [], remove: [], update: [] };
24338
- parseNodes(wrapper.firstChild, opCodes, parentIndex, nestedIcus, tIcus, expandoStartIndex);
24339
- return opCodes;
24651
+ function ɵɵi18nEnd() {
24652
+ var lView = getLView();
24653
+ var tView = getTView();
24654
+ ngDevMode && assertDefined(tView, "tView should be defined");
24655
+ i18nEndFirstPass(tView, lView);
24656
+ // Stop delaying projections
24657
+ setDelayProjection(false);
24340
24658
  }
24341
- var NESTED_ICU = /�(\d+)�/;
24342
24659
  /**
24343
- * Parses a node, its children and its siblings, and generates the mutate & update OpCodes.
24344
24660
  *
24345
- * @param currentNode The first node to parse
24346
- * @param icuCase The data for the ICU expression case that contains those nodes
24347
- * @param parentIndex Index of the current node's parent
24348
- * @param nestedIcus Data for the nested ICU expressions that this case contains
24349
- * @param tIcus Data for all ICU expressions of the current message
24350
- * @param expandoStartIndex Expando start index for the current ICU expression
24661
+ * Use this instruction to create a translation block that doesn't contain any placeholder.
24662
+ * It calls both {@link i18nStart} and {@link i18nEnd} in one instruction.
24663
+ *
24664
+ * The translation `message` is the value which is locale specific. The translation string may
24665
+ * contain placeholders which associate inner elements and sub-templates within the translation.
24666
+ *
24667
+ * The translation `message` placeholders are:
24668
+ * - `�{index}(:{block})�`: *Binding Placeholder*: Marks a location where an expression will be
24669
+ * interpolated into. The placeholder `index` points to the expression binding index. An optional
24670
+ * `block` that matches the sub-template in which it was declared.
24671
+ * - `�#{index}(:{block})�`/`�/#{index}(:{block})�`: *Element Placeholder*: Marks the beginning
24672
+ * and end of DOM element that were embedded in the original translation block. The placeholder
24673
+ * `index` points to the element index in the template instructions set. An optional `block` that
24674
+ * matches the sub-template in which it was declared.
24675
+ * - `�*{index}:{block}�`/`�/*{index}:{block}�`: *Sub-template Placeholder*: Sub-templates must be
24676
+ * split up and translated separately in each angular template function. The `index` points to the
24677
+ * `template` instruction index. A `block` that matches the sub-template in which it was declared.
24678
+ *
24679
+ * @param index A unique index of the translation in the static block.
24680
+ * @param message The translation message.
24681
+ * @param subTemplateIndex Optional sub-template index in the `message`.
24682
+ *
24683
+ * @codeGenApi
24351
24684
  */
24352
- function parseNodes(currentNode, icuCase, parentIndex, nestedIcus, tIcus, expandoStartIndex) {
24353
- if (currentNode) {
24354
- var nestedIcusToCreate = [];
24355
- while (currentNode) {
24356
- var nextNode = currentNode.nextSibling;
24357
- var newIndex = expandoStartIndex + ++icuCase.vars;
24358
- switch (currentNode.nodeType) {
24359
- case Node.ELEMENT_NODE:
24360
- var element = currentNode;
24361
- var tagName = element.tagName.toLowerCase();
24362
- if (!VALID_ELEMENTS.hasOwnProperty(tagName)) {
24363
- // This isn't a valid element, we won't create an element for it
24364
- icuCase.vars--;
24365
- }
24366
- else {
24367
- icuCase.create.push(ELEMENT_MARKER, tagName, newIndex, parentIndex << 17 /* SHIFT_PARENT */ | 1 /* AppendChild */);
24368
- var elAttrs = element.attributes;
24369
- for (var i = 0; i < elAttrs.length; i++) {
24370
- var attr = elAttrs.item(i);
24371
- var lowerAttrName = attr.name.toLowerCase();
24372
- var hasBinding_1 = !!attr.value.match(BINDING_REGEXP);
24373
- // we assume the input string is safe, unless it's using a binding
24374
- if (hasBinding_1) {
24375
- if (VALID_ATTRS.hasOwnProperty(lowerAttrName)) {
24376
- if (URI_ATTRS[lowerAttrName]) {
24377
- addAllToArray(generateBindingUpdateOpCodes(attr.value, newIndex, attr.name, _sanitizeUrl), icuCase.update);
24378
- }
24379
- else if (SRCSET_ATTRS[lowerAttrName]) {
24380
- addAllToArray(generateBindingUpdateOpCodes(attr.value, newIndex, attr.name, sanitizeSrcset), icuCase.update);
24381
- }
24382
- else {
24383
- addAllToArray(generateBindingUpdateOpCodes(attr.value, newIndex, attr.name), icuCase.update);
24384
- }
24385
- }
24386
- else {
24387
- ngDevMode &&
24388
- console.warn("WARNING: ignoring unsafe attribute value " + lowerAttrName + " on element " + tagName + " (see http://g.co/ng/security#xss)");
24389
- }
24390
- }
24391
- else {
24392
- icuCase.create.push(newIndex << 3 /* SHIFT_REF */ | 4 /* Attr */, attr.name, attr.value);
24393
- }
24394
- }
24395
- // Parse the children of this node (if any)
24396
- parseNodes(currentNode.firstChild, icuCase, newIndex, nestedIcus, tIcus, expandoStartIndex);
24397
- // Remove the parent node after the children
24398
- icuCase.remove.push(newIndex << 3 /* SHIFT_REF */ | 3 /* Remove */);
24399
- }
24400
- break;
24401
- case Node.TEXT_NODE:
24402
- var value = currentNode.textContent || '';
24403
- var hasBinding = value.match(BINDING_REGEXP);
24404
- icuCase.create.push(hasBinding ? '' : value, newIndex, parentIndex << 17 /* SHIFT_PARENT */ | 1 /* AppendChild */);
24405
- icuCase.remove.push(newIndex << 3 /* SHIFT_REF */ | 3 /* Remove */);
24406
- if (hasBinding) {
24407
- addAllToArray(generateBindingUpdateOpCodes(value, newIndex), icuCase.update);
24408
- }
24409
- break;
24410
- case Node.COMMENT_NODE:
24411
- // Check if the comment node is a placeholder for a nested ICU
24412
- var match = NESTED_ICU.exec(currentNode.textContent || '');
24413
- if (match) {
24414
- var nestedIcuIndex = parseInt(match[1], 10);
24415
- var newLocal = ngDevMode ? "nested ICU " + nestedIcuIndex : '';
24416
- // Create the comment node that will anchor the ICU expression
24417
- icuCase.create.push(COMMENT_MARKER, newLocal, newIndex, parentIndex << 17 /* SHIFT_PARENT */ | 1 /* AppendChild */);
24418
- var nestedIcu = nestedIcus[nestedIcuIndex];
24419
- nestedIcusToCreate.push([nestedIcu, newIndex]);
24420
- }
24421
- else {
24422
- // We do not handle any other type of comment
24423
- icuCase.vars--;
24424
- }
24425
- break;
24426
- default:
24427
- // We do not handle any other type of element
24428
- icuCase.vars--;
24429
- }
24430
- currentNode = nextNode;
24431
- }
24432
- for (var i = 0; i < nestedIcusToCreate.length; i++) {
24433
- var nestedIcu = nestedIcusToCreate[i][0];
24434
- var nestedIcuNodeIndex = nestedIcusToCreate[i][1];
24435
- icuStart(tIcus, nestedIcu, nestedIcuNodeIndex, expandoStartIndex + icuCase.vars);
24436
- // Since this is recursive, the last TIcu that was pushed is the one we want
24437
- var nestTIcuIndex = tIcus.length - 1;
24438
- icuCase.vars += Math.max.apply(Math, __spread(tIcus[nestTIcuIndex].vars));
24439
- icuCase.childIcus.push(nestTIcuIndex);
24440
- var mask = getBindingMask(nestedIcu);
24441
- icuCase.update.push(toMaskBit(nestedIcu.mainBinding), // mask of the main binding
24442
- 3, // skip 3 opCodes if not changed
24443
- -1 - nestedIcu.mainBinding, nestedIcuNodeIndex << 2 /* SHIFT_REF */ | 2 /* IcuSwitch */, nestTIcuIndex, mask, // mask of all the bindings of this ICU expression
24444
- 2, // skip 2 opCodes if not changed
24445
- nestedIcuNodeIndex << 2 /* SHIFT_REF */ | 3 /* IcuUpdate */, nestTIcuIndex);
24446
- icuCase.remove.push(nestTIcuIndex << 3 /* SHIFT_REF */ | 6 /* RemoveNestedIcu */, nestedIcuNodeIndex << 3 /* SHIFT_REF */ | 3 /* Remove */);
24447
- }
24448
- }
24685
+ function ɵɵi18n(index, message, subTemplateIndex) {
24686
+ ɵɵi18nStart(index, message, subTemplateIndex);
24687
+ ɵɵi18nEnd();
24449
24688
  }
24450
24689
  /**
24451
- * Angular Dart introduced &ngsp; as a placeholder for non-removable space, see:
24452
- * https://github.com/dart-lang/angular/blob/0bb611387d29d65b5af7f9d2515ab571fd3fbee4/_tests/test/compiler/preserve_whitespace_test.dart#L25-L32
24453
- * In Angular Dart &ngsp; is converted to the 0xE500 PUA (Private Use Areas) unicode character
24454
- * and later on replaced by a space. We are re-implementing the same idea here, since translations
24455
- * might contain this special character.
24690
+ * Marks a list of attributes as translatable.
24691
+ *
24692
+ * @param index A unique index in the static block
24693
+ * @param values
24694
+ *
24695
+ * @codeGenApi
24456
24696
  */
24457
- var NGSP_UNICODE_REGEXP = /\uE500/g;
24458
- function replaceNgsp(value) {
24459
- return value.replace(NGSP_UNICODE_REGEXP, ' ');
24697
+ function ɵɵi18nAttributes(index, values) {
24698
+ var lView = getLView();
24699
+ var tView = getTView();
24700
+ ngDevMode && assertDefined(tView, "tView should be defined");
24701
+ i18nAttributesFirstPass(lView, tView, index, values);
24460
24702
  }
24461
24703
  /**
24462
- * The locale id that the application is currently using (for translations and ICU expressions).
24463
- * This is the ivy version of `LOCALE_ID` that was defined as an injection token for the view engine
24464
- * but is now defined as a global value.
24704
+ * Stores the values of the bindings during each update cycle in order to determine if we need to
24705
+ * update the translated nodes.
24706
+ *
24707
+ * @param value The binding's value
24708
+ * @returns This function returns itself so that it may be chained
24709
+ * (e.g. `i18nExp(ctx.name)(ctx.title)`)
24710
+ *
24711
+ * @codeGenApi
24465
24712
  */
24466
- var LOCALE_ID = DEFAULT_LOCALE_ID;
24713
+ function ɵɵi18nExp(value) {
24714
+ var lView = getLView();
24715
+ setMaskBit(bindingUpdated(lView, nextBindingIndex(), value));
24716
+ return ɵɵi18nExp;
24717
+ }
24467
24718
  /**
24468
- * Sets the locale id that will be used for translations and ICU expressions.
24469
- * This is the ivy version of `LOCALE_ID` that was defined as an injection token for the view engine
24470
- * but is now defined as a global value.
24719
+ * Updates a translation block or an i18n attribute when the bindings have changed.
24471
24720
  *
24472
- * @param localeId
24721
+ * @param index Index of either {@link i18nStart} (translation block) or {@link i18nAttributes}
24722
+ * (i18n attribute) on which it should update the content.
24723
+ *
24724
+ * @codeGenApi
24473
24725
  */
24474
- function setLocaleId(localeId) {
24475
- assertDefined(localeId, "Expected localeId to be defined");
24476
- if (typeof localeId === 'string') {
24477
- LOCALE_ID = localeId.toLowerCase().replace(/_/g, '-');
24478
- }
24726
+ function ɵɵi18nApply(index) {
24727
+ applyI18n(getTView(), getLView(), index);
24479
24728
  }
24480
24729
  /**
24481
- * Gets the locale id that will be used for translations and ICU expressions.
24482
- * This is the ivy version of `LOCALE_ID` that was defined as an injection token for the view engine
24483
- * but is now defined as a global value.
24730
+ * Handles message string post-processing for internationalization.
24731
+ *
24732
+ * Handles message string post-processing by transforming it from intermediate
24733
+ * format (that might contain some markers that we need to replace) to the final
24734
+ * form, consumable by i18nStart instruction. Post processing steps include:
24735
+ *
24736
+ * 1. Resolve all multi-value cases (like [�*1:1��#2:1�|�#4:1�|�5�])
24737
+ * 2. Replace all ICU vars (like "VAR_PLURAL")
24738
+ * 3. Replace all placeholders used inside ICUs in a form of {PLACEHOLDER}
24739
+ * 4. Replace all ICU references with corresponding values (like �ICU_EXP_ICU_1�)
24740
+ * in case multiple ICUs have the same placeholder name
24741
+ *
24742
+ * @param message Raw translation string for post processing
24743
+ * @param replacements Set of replacements that should be applied
24744
+ *
24745
+ * @returns Transformed string that can be consumed by i18nStart instruction
24746
+ *
24747
+ * @codeGenApi
24484
24748
  */
24485
- function getLocaleId() {
24486
- return LOCALE_ID;
24749
+ function ɵɵi18nPostprocess(message, replacements) {
24750
+ if (replacements === void 0) { replacements = {}; }
24751
+ return i18nPostprocess(message, replacements);
24487
24752
  }
24488
24753
 
24489
24754
  /**
@@ -24923,7 +25188,7 @@
24923
25188
  * it to `undefined`.
24924
25189
  */
24925
25190
  function getPureFunctionReturnValue(lView, returnValueIndex) {
24926
- ngDevMode && assertDataInRange(lView, returnValueIndex);
25191
+ ngDevMode && assertIndexInRange(lView, returnValueIndex);
24927
25192
  var lastReturnValue = lView[returnValueIndex];
24928
25193
  return lastReturnValue === NO_CHANGE ? undefined : lastReturnValue;
24929
25194
  }
@@ -25548,7 +25813,7 @@
25548
25813
  }
25549
25814
  };
25550
25815
  TQueries_.prototype.getByIndex = function (index) {
25551
- ngDevMode && assertDataInRange(this.queries, index);
25816
+ ngDevMode && assertIndexInRange(this.queries, index);
25552
25817
  return this.queries[index];
25553
25818
  };
25554
25819
  Object.defineProperty(TQueries_.prototype, "length", {
@@ -25624,21 +25889,23 @@
25624
25889
  return this._appliesToNextNode;
25625
25890
  };
25626
25891
  TQuery_.prototype.matchTNode = function (tView, tNode) {
25627
- if (Array.isArray(this.metadata.predicate)) {
25628
- var localNames = this.metadata.predicate;
25629
- for (var i = 0; i < localNames.length; i++) {
25630
- this.matchTNodeWithReadOption(tView, tNode, getIdxOfMatchingSelector(tNode, localNames[i]));
25892
+ var predicate = this.metadata.predicate;
25893
+ if (Array.isArray(predicate)) {
25894
+ for (var i = 0; i < predicate.length; i++) {
25895
+ var name = predicate[i];
25896
+ this.matchTNodeWithReadOption(tView, tNode, getIdxOfMatchingSelector(tNode, name));
25897
+ // Also try matching the name to a provider since strings can be used as DI tokens too.
25898
+ this.matchTNodeWithReadOption(tView, tNode, locateDirectiveOrProvider(tNode, tView, name, false, false));
25631
25899
  }
25632
25900
  }
25633
25901
  else {
25634
- var typePredicate = this.metadata.predicate;
25635
- if (typePredicate === TemplateRef) {
25902
+ if (predicate === TemplateRef) {
25636
25903
  if (tNode.type === 0 /* Container */) {
25637
25904
  this.matchTNodeWithReadOption(tView, tNode, -1);
25638
25905
  }
25639
25906
  }
25640
25907
  else {
25641
- this.matchTNodeWithReadOption(tView, tNode, locateDirectiveOrProvider(tNode, tView, typePredicate, false, false));
25908
+ this.matchTNodeWithReadOption(tView, tNode, locateDirectiveOrProvider(tNode, tView, predicate, false, false));
25642
25909
  }
25643
25910
  }
25644
25911
  };
@@ -25751,7 +26018,7 @@
25751
26018
  result.push(null);
25752
26019
  }
25753
26020
  else {
25754
- ngDevMode && assertDataInRange(tViewData, matchedNodeIdx);
26021
+ ngDevMode && assertIndexInRange(tViewData, matchedNodeIdx);
25755
26022
  var tNode = tViewData[matchedNodeIdx];
25756
26023
  result.push(createResultForNode(lView, tNode, tQueryMatches[i + 1], tQuery.metadata.read));
25757
26024
  }
@@ -25913,7 +26180,7 @@
25913
26180
  function loadQueryInternal(lView, queryIndex) {
25914
26181
  ngDevMode &&
25915
26182
  assertDefined(lView[QUERIES], 'LQueries should be defined when trying to load a query');
25916
- ngDevMode && assertDataInRange(lView[QUERIES].queries, queryIndex);
26183
+ ngDevMode && assertIndexInRange(lView[QUERIES].queries, queryIndex);
25917
26184
  return lView[QUERIES].queries[queryIndex].queryList;
25918
26185
  }
25919
26186
  function createLQuery(tView, lView) {
@@ -26610,6 +26877,20 @@
26610
26877
  * Use of this source code is governed by an MIT-style license that can be
26611
26878
  * found in the LICENSE file at https://angular.io/license
26612
26879
  */
26880
+ /**
26881
+ * Keep track of the compilation depth to avoid reentrancy issues during JIT compilation. This
26882
+ * matters in the following scenario:
26883
+ *
26884
+ * Consider a component 'A' that extends component 'B', both declared in module 'M'. During
26885
+ * the compilation of 'A' the definition of 'B' is requested to capture the inheritance chain,
26886
+ * potentially triggering compilation of 'B'. If this nested compilation were to trigger
26887
+ * `flushModuleScopingQueueAsMuchAsPossible` it may happen that module 'M' is still pending in the
26888
+ * queue, resulting in 'A' and 'B' to be patched with the NgModule scope. As the compilation of
26889
+ * 'A' is still in progress, this would introduce a circular dependency on its compilation. To avoid
26890
+ * this issue, the module scope queue is only flushed for compilations at the depth 0, to ensure
26891
+ * all compilations have finished.
26892
+ */
26893
+ var compilationDepth = 0;
26613
26894
  /**
26614
26895
  * Compile an Angular component according to its decorator metadata, and patch the resulting
26615
26896
  * component def (ɵcmp) onto the component type.
@@ -26670,16 +26951,25 @@
26670
26951
  }
26671
26952
  var templateUrl = metadata.templateUrl || "ng:///" + type.name + "/template.html";
26672
26953
  var meta = Object.assign(Object.assign({}, directiveMetadata(type, metadata)), { typeSourceSpan: compiler.createParseSourceSpan('Component', type.name, templateUrl), template: metadata.template || '', preserveWhitespaces: preserveWhitespaces, styles: metadata.styles || EMPTY_ARRAY, animations: metadata.animations, directives: [], changeDetection: metadata.changeDetection, pipes: new Map(), encapsulation: encapsulation, interpolation: metadata.interpolation, viewProviders: metadata.viewProviders || null });
26673
- if (meta.usesInheritance) {
26674
- addDirectiveDefToUndecoratedParents(type);
26954
+ compilationDepth++;
26955
+ try {
26956
+ if (meta.usesInheritance) {
26957
+ addDirectiveDefToUndecoratedParents(type);
26958
+ }
26959
+ ngComponentDef = compiler.compileComponent(angularCoreEnv, templateUrl, meta);
26960
+ }
26961
+ finally {
26962
+ // Ensure that the compilation depth is decremented even when the compilation failed.
26963
+ compilationDepth--;
26964
+ }
26965
+ if (compilationDepth === 0) {
26966
+ // When NgModule decorator executed, we enqueued the module definition such that
26967
+ // it would only dequeue and add itself as module scope to all of its declarations,
26968
+ // but only if if all of its declarations had resolved. This call runs the check
26969
+ // to see if any modules that are in the queue can be dequeued and add scope to
26970
+ // their declarations.
26971
+ flushModuleScopingQueueAsMuchAsPossible();
26675
26972
  }
26676
- ngComponentDef = compiler.compileComponent(angularCoreEnv, templateUrl, meta);
26677
- // When NgModule decorator executed, we enqueued the module definition such that
26678
- // it would only dequeue and add itself as module scope to all of its declarations,
26679
- // but only if if all of its declarations had resolved. This call runs the check
26680
- // to see if any modules that are in the queue can be dequeued and add scope to
26681
- // their declarations.
26682
- flushModuleScopingQueueAsMuchAsPossible();
26683
26973
  // If component compilation is async, then the @NgModule annotation which declares the
26684
26974
  // component may execute and set an ngSelectorScope property on the component type. This
26685
26975
  // allows the component to patch itself with directiveDefs from the module after it
@@ -32488,8 +32778,8 @@
32488
32778
  exports.ɵangular_packages_core_core_bm = makeParamDecorator;
32489
32779
  exports.ɵangular_packages_core_core_bn = makePropDecorator;
32490
32780
  exports.ɵangular_packages_core_core_bo = getClosureSafeProperty;
32491
- exports.ɵangular_packages_core_core_bq = noSideEffects;
32492
- exports.ɵangular_packages_core_core_br = getRootContext;
32781
+ exports.ɵangular_packages_core_core_bq = getRootContext;
32782
+ exports.ɵangular_packages_core_core_br = i18nPostprocess;
32493
32783
  exports.ɵangular_packages_core_core_c = NullInjector;
32494
32784
  exports.ɵangular_packages_core_core_d = ReflectiveInjector_;
32495
32785
  exports.ɵangular_packages_core_core_e = ReflectiveDependency;
@@ -32565,6 +32855,7 @@
32565
32855
  exports.ɵmod = moduleDef;
32566
32856
  exports.ɵmpd = moduleProvideDef;
32567
32857
  exports.ɵncd = ngContentDef;
32858
+ exports.ɵnoSideEffects = noSideEffects;
32568
32859
  exports.ɵnov = nodeValue;
32569
32860
  exports.ɵoverrideComponentView = overrideComponentView;
32570
32861
  exports.ɵoverrideProvider = overrideProvider;