@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
package/fesm2015/core.js CHANGED
@@ -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
  */
@@ -1085,7 +1085,7 @@ function assertDomNode(node) {
1085
1085
  (typeof node === 'object' && node != null &&
1086
1086
  node.constructor.name === 'WebWorkerRenderNode'), true, `The provided value must be an instance of a DOM Node but got ${stringify(node)}`);
1087
1087
  }
1088
- function assertDataInRange(arr, index) {
1088
+ function assertIndexInRange(arr, index) {
1089
1089
  const maxLen = arr ? arr.length : 0;
1090
1090
  assertLessThan(index, maxLen, `Index expected to be less than ${maxLen} but got ${index}`);
1091
1091
  }
@@ -2331,7 +2331,7 @@ function getNativeByIndex(index, lView) {
2331
2331
  */
2332
2332
  function getNativeByTNode(tNode, lView) {
2333
2333
  ngDevMode && assertTNodeForLView(tNode, lView);
2334
- ngDevMode && assertDataInRange(lView, tNode.index);
2334
+ ngDevMode && assertIndexInRange(lView, tNode.index);
2335
2335
  const node = unwrapRNode(lView[tNode.index]);
2336
2336
  ngDevMode && !isProceduralRenderer(lView[RENDERER]) && assertDomNode(node);
2337
2337
  return node;
@@ -2361,12 +2361,12 @@ function getTNode(tView, index) {
2361
2361
  }
2362
2362
  /** Retrieves a value from any `LView` or `TData`. */
2363
2363
  function load(view, index) {
2364
- ngDevMode && assertDataInRange(view, index + HEADER_OFFSET);
2364
+ ngDevMode && assertIndexInRange(view, index + HEADER_OFFSET);
2365
2365
  return view[index + HEADER_OFFSET];
2366
2366
  }
2367
2367
  function getComponentLViewByIndex(nodeIndex, hostView) {
2368
2368
  // Could be an LView or an LContainer. If LContainer, unwrap to find LView.
2369
- ngDevMode && assertDataInRange(hostView, nodeIndex);
2369
+ ngDevMode && assertIndexInRange(hostView, nodeIndex);
2370
2370
  const slotValue = hostView[nodeIndex];
2371
2371
  const lView = isLView(slotValue) ? slotValue : slotValue[HOST];
2372
2372
  return lView;
@@ -5517,6 +5517,18 @@ function getExpressionChangedErrorDetails(lView, bindingIndex, oldValue, newValu
5517
5517
  return { propName: undefined, oldValue, newValue };
5518
5518
  }
5519
5519
 
5520
+ /**
5521
+ * Converts `TNodeType` into human readable text.
5522
+ * Make sure this matches with `TNodeType`
5523
+ */
5524
+ const TNodeTypeAsString = [
5525
+ 'Container',
5526
+ 'Projection',
5527
+ 'View',
5528
+ 'Element',
5529
+ 'ElementContainer',
5530
+ 'IcuContainer' // 5
5531
+ ];
5520
5532
  // Note: This hack is necessary so we don't erroneously get a circular dependency
5521
5533
  // failure based on types.
5522
5534
  const unusedValueExportToPlacateAjd$4 = 1;
@@ -6150,7 +6162,7 @@ function ɵɵselect(index) {
6150
6162
  }
6151
6163
  function selectIndexInternal(tView, lView, index, checkNoChangesMode) {
6152
6164
  ngDevMode && assertGreaterThan(index, -1, 'Invalid index');
6153
- ngDevMode && assertDataInRange(lView, index + HEADER_OFFSET);
6165
+ ngDevMode && assertIndexInRange(lView, index + HEADER_OFFSET);
6154
6166
  // Flush the initial hooks for elements in the view that have been added up to this point.
6155
6167
  // PERF WARNING: do NOT extract this to a separate function without running benchmarks
6156
6168
  if (!checkNoChangesMode) {
@@ -6175,33 +6187,6 @@ function selectIndexInternal(tView, lView, index, checkNoChangesMode) {
6175
6187
  setSelectedIndex(index);
6176
6188
  }
6177
6189
 
6178
- /**
6179
- * @license
6180
- * Copyright Google LLC All Rights Reserved.
6181
- *
6182
- * Use of this source code is governed by an MIT-style license that can be
6183
- * found in the LICENSE file at https://angular.io/license
6184
- */
6185
- /**
6186
- * Marks that the next string is for element.
6187
- *
6188
- * See `I18nMutateOpCodes` documentation.
6189
- */
6190
- const ELEMENT_MARKER = {
6191
- marker: 'element'
6192
- };
6193
- /**
6194
- * Marks that the next string is for comment.
6195
- *
6196
- * See `I18nMutateOpCodes` documentation.
6197
- */
6198
- const COMMENT_MARKER = {
6199
- marker: 'comment'
6200
- };
6201
- // Note: This hack is necessary so we don't erroneously get a circular dependency
6202
- // failure based on types.
6203
- const unusedValueExportToPlacateAjd$6 = 1;
6204
-
6205
6190
  /**
6206
6191
  * @license
6207
6192
  * Copyright Google LLC All Rights Reserved.
@@ -6265,8 +6250,37 @@ function getTStylingRangeTail(tStylingRange) {
6265
6250
  * Use of this source code is governed by an MIT-style license that can be
6266
6251
  * found in the LICENSE file at https://angular.io/license
6267
6252
  */
6253
+ /**
6254
+ * Patch a `debug` property on top of the existing object.
6255
+ *
6256
+ * NOTE: always call this method with `ngDevMode && attachDebugObject(...)`
6257
+ *
6258
+ * @param obj Object to patch
6259
+ * @param debug Value to patch
6260
+ */
6268
6261
  function attachDebugObject(obj, debug) {
6269
- Object.defineProperty(obj, 'debug', { value: debug, enumerable: false });
6262
+ if (ngDevMode) {
6263
+ Object.defineProperty(obj, 'debug', { value: debug, enumerable: false });
6264
+ }
6265
+ else {
6266
+ throw new Error('This method should be guarded with `ngDevMode` so that it can be tree shaken in production!');
6267
+ }
6268
+ }
6269
+ /**
6270
+ * Patch a `debug` property getter on top of the existing object.
6271
+ *
6272
+ * NOTE: always call this method with `ngDevMode && attachDebugObject(...)`
6273
+ *
6274
+ * @param obj Object to patch
6275
+ * @param debugGetter Getter returning a value to patch
6276
+ */
6277
+ function attachDebugGetter(obj, debugGetter) {
6278
+ if (ngDevMode) {
6279
+ Object.defineProperty(obj, 'debug', { get: debugGetter, enumerable: false });
6280
+ }
6281
+ else {
6282
+ throw new Error('This method should be guarded with `ngDevMode` so that it can be tree shaken in production!');
6283
+ }
6270
6284
  }
6271
6285
 
6272
6286
  /**
@@ -6387,8 +6401,9 @@ const TViewConstructor = class TView {
6387
6401
  firstChild, //
6388
6402
  schemas, //
6389
6403
  consts, //
6390
- incompleteFirstPass //
6391
- ) {
6404
+ incompleteFirstPass, //
6405
+ _decls, //
6406
+ _vars) {
6392
6407
  this.type = type;
6393
6408
  this.id = id;
6394
6409
  this.blueprint = blueprint;
@@ -6420,6 +6435,8 @@ const TViewConstructor = class TView {
6420
6435
  this.schemas = schemas;
6421
6436
  this.consts = consts;
6422
6437
  this.incompleteFirstPass = incompleteFirstPass;
6438
+ this._decls = _decls;
6439
+ this._vars = _vars;
6423
6440
  }
6424
6441
  get template_() {
6425
6442
  const buf = [];
@@ -6639,19 +6656,23 @@ function toDebug(obj) {
6639
6656
  function toHtml(value, includeChildren = false) {
6640
6657
  const node = unwrapRNode(value);
6641
6658
  if (node) {
6642
- const isTextNode = node.nodeType === Node.TEXT_NODE;
6643
- const outerHTML = (isTextNode ? node.textContent : node.outerHTML) || '';
6644
- if (includeChildren || isTextNode) {
6645
- return outerHTML;
6646
- }
6647
- else {
6648
- const innerHTML = '>' + node.innerHTML + '<';
6649
- return (outerHTML.split(innerHTML)[0]) + '>';
6659
+ switch (node.nodeType) {
6660
+ case Node.TEXT_NODE:
6661
+ return node.textContent;
6662
+ case Node.COMMENT_NODE:
6663
+ return `<!--${node.textContent}-->`;
6664
+ case Node.ELEMENT_NODE:
6665
+ const outerHTML = node.outerHTML;
6666
+ if (includeChildren) {
6667
+ return outerHTML;
6668
+ }
6669
+ else {
6670
+ const innerHTML = '>' + node.innerHTML + '<';
6671
+ return (outerHTML.split(innerHTML)[0]) + '>';
6672
+ }
6650
6673
  }
6651
6674
  }
6652
- else {
6653
- return null;
6654
- }
6675
+ return null;
6655
6676
  }
6656
6677
  class LViewDebug {
6657
6678
  constructor(_raw_lView) {
@@ -6678,7 +6699,7 @@ class LViewDebug {
6678
6699
  get parent() {
6679
6700
  return toDebug(this._raw_lView[PARENT]);
6680
6701
  }
6681
- get host() {
6702
+ get hostHTML() {
6682
6703
  return toHtml(this._raw_lView[HOST], true);
6683
6704
  }
6684
6705
  get html() {
@@ -6689,8 +6710,7 @@ class LViewDebug {
6689
6710
  }
6690
6711
  /**
6691
6712
  * The tree of nodes associated with the current `LView`. The nodes have been normalized into
6692
- * a
6693
- * tree structure with relevant details pulled out for readability.
6713
+ * a tree structure with relevant details pulled out for readability.
6694
6714
  */
6695
6715
  get nodes() {
6696
6716
  const lView = this._raw_lView;
@@ -6733,6 +6753,25 @@ class LViewDebug {
6733
6753
  get tHost() {
6734
6754
  return this._raw_lView[T_HOST];
6735
6755
  }
6756
+ get decls() {
6757
+ const tView = this.tView;
6758
+ const start = HEADER_OFFSET;
6759
+ return toLViewRange(this.tView, this._raw_lView, start, start + tView._decls);
6760
+ }
6761
+ get vars() {
6762
+ const tView = this.tView;
6763
+ const start = HEADER_OFFSET + tView._decls;
6764
+ return toLViewRange(this.tView, this._raw_lView, start, start + tView._vars);
6765
+ }
6766
+ get i18n() {
6767
+ const tView = this.tView;
6768
+ const start = HEADER_OFFSET + tView._decls + tView._vars;
6769
+ return toLViewRange(this.tView, this._raw_lView, start, this.tView.expandoStartIndex);
6770
+ }
6771
+ get expando() {
6772
+ const tView = this.tView;
6773
+ return toLViewRange(this.tView, this._raw_lView, this.tView.expandoStartIndex, this._raw_lView.length);
6774
+ }
6736
6775
  /**
6737
6776
  * Normalized view of child views (and containers) attached at this location.
6738
6777
  */
@@ -6746,6 +6785,13 @@ class LViewDebug {
6746
6785
  return childViews;
6747
6786
  }
6748
6787
  }
6788
+ function toLViewRange(tView, lView, start, end) {
6789
+ let content = [];
6790
+ for (let index = start; index < end; index++) {
6791
+ content.push({ index: index, t: tView.data[index], l: lView[index] });
6792
+ }
6793
+ return { start: start, end: end, length: end - start, content: content };
6794
+ }
6749
6795
  /**
6750
6796
  * Turns a flat list of nodes into a tree by walking the associated `TNode` tree.
6751
6797
  *
@@ -6763,18 +6809,17 @@ function toDebugNodes(tNode, lView) {
6763
6809
  return debugNodes;
6764
6810
  }
6765
6811
  else {
6766
- return null;
6812
+ return [];
6767
6813
  }
6768
6814
  }
6769
6815
  function buildDebugNode(tNode, lView, nodeIndex) {
6770
6816
  const rawValue = lView[nodeIndex];
6771
6817
  const native = unwrapRNode(rawValue);
6772
- const componentLViewDebug = toDebug(readLViewValue(rawValue));
6773
6818
  return {
6774
6819
  html: toHtml(native),
6820
+ type: TNodeTypeAsString[tNode.type],
6775
6821
  native: native,
6776
- nodes: toDebugNodes(tNode.child, lView),
6777
- component: componentLViewDebug,
6822
+ children: toDebugNodes(tNode.child, lView),
6778
6823
  };
6779
6824
  }
6780
6825
  class LContainerDebug {
@@ -6819,196 +6864,6 @@ function readLViewValue(value) {
6819
6864
  }
6820
6865
  return null;
6821
6866
  }
6822
- class I18NDebugItem {
6823
- constructor(__raw_opCode, _lView, nodeIndex, type) {
6824
- this.__raw_opCode = __raw_opCode;
6825
- this._lView = _lView;
6826
- this.nodeIndex = nodeIndex;
6827
- this.type = type;
6828
- }
6829
- get tNode() {
6830
- return getTNode(this._lView[TVIEW], this.nodeIndex);
6831
- }
6832
- }
6833
- /**
6834
- * Turns a list of "Create" & "Update" OpCodes into a human-readable list of operations for
6835
- * debugging purposes.
6836
- * @param mutateOpCodes mutation opCodes to read
6837
- * @param updateOpCodes update opCodes to read
6838
- * @param icus list of ICU expressions
6839
- * @param lView The view the opCodes are acting on
6840
- */
6841
- function attachI18nOpCodesDebug(mutateOpCodes, updateOpCodes, icus, lView) {
6842
- attachDebugObject(mutateOpCodes, new I18nMutateOpCodesDebug(mutateOpCodes, lView));
6843
- attachDebugObject(updateOpCodes, new I18nUpdateOpCodesDebug(updateOpCodes, icus, lView));
6844
- if (icus) {
6845
- icus.forEach(icu => {
6846
- icu.create.forEach(icuCase => {
6847
- attachDebugObject(icuCase, new I18nMutateOpCodesDebug(icuCase, lView));
6848
- });
6849
- icu.update.forEach(icuCase => {
6850
- attachDebugObject(icuCase, new I18nUpdateOpCodesDebug(icuCase, icus, lView));
6851
- });
6852
- });
6853
- }
6854
- }
6855
- class I18nMutateOpCodesDebug {
6856
- constructor(__raw_opCodes, __lView) {
6857
- this.__raw_opCodes = __raw_opCodes;
6858
- this.__lView = __lView;
6859
- }
6860
- /**
6861
- * A list of operation information about how the OpCodes will act on the view.
6862
- */
6863
- get operations() {
6864
- const { __lView, __raw_opCodes } = this;
6865
- const results = [];
6866
- for (let i = 0; i < __raw_opCodes.length; i++) {
6867
- const opCode = __raw_opCodes[i];
6868
- let result;
6869
- if (typeof opCode === 'string') {
6870
- result = {
6871
- __raw_opCode: opCode,
6872
- type: 'Create Text Node',
6873
- nodeIndex: __raw_opCodes[++i],
6874
- text: opCode,
6875
- };
6876
- }
6877
- if (typeof opCode === 'number') {
6878
- switch (opCode & 7 /* MASK_OPCODE */) {
6879
- case 1 /* AppendChild */:
6880
- const destinationNodeIndex = opCode >>> 17 /* SHIFT_PARENT */;
6881
- result = new I18NDebugItem(opCode, __lView, destinationNodeIndex, 'AppendChild');
6882
- break;
6883
- case 0 /* Select */:
6884
- const nodeIndex = opCode >>> 3 /* SHIFT_REF */;
6885
- result = new I18NDebugItem(opCode, __lView, nodeIndex, 'Select');
6886
- break;
6887
- case 5 /* ElementEnd */:
6888
- let elementIndex = opCode >>> 3 /* SHIFT_REF */;
6889
- result = new I18NDebugItem(opCode, __lView, elementIndex, 'ElementEnd');
6890
- break;
6891
- case 4 /* Attr */:
6892
- elementIndex = opCode >>> 3 /* SHIFT_REF */;
6893
- result = new I18NDebugItem(opCode, __lView, elementIndex, 'Attr');
6894
- result['attrName'] = __raw_opCodes[++i];
6895
- result['attrValue'] = __raw_opCodes[++i];
6896
- break;
6897
- }
6898
- }
6899
- if (!result) {
6900
- switch (opCode) {
6901
- case COMMENT_MARKER:
6902
- result = {
6903
- __raw_opCode: opCode,
6904
- type: 'COMMENT_MARKER',
6905
- commentValue: __raw_opCodes[++i],
6906
- nodeIndex: __raw_opCodes[++i],
6907
- };
6908
- break;
6909
- case ELEMENT_MARKER:
6910
- result = {
6911
- __raw_opCode: opCode,
6912
- type: 'ELEMENT_MARKER',
6913
- };
6914
- break;
6915
- }
6916
- }
6917
- if (!result) {
6918
- result = {
6919
- __raw_opCode: opCode,
6920
- type: 'Unknown Op Code',
6921
- code: opCode,
6922
- };
6923
- }
6924
- results.push(result);
6925
- }
6926
- return results;
6927
- }
6928
- }
6929
- class I18nUpdateOpCodesDebug {
6930
- constructor(__raw_opCodes, icus, __lView) {
6931
- this.__raw_opCodes = __raw_opCodes;
6932
- this.icus = icus;
6933
- this.__lView = __lView;
6934
- }
6935
- /**
6936
- * A list of operation information about how the OpCodes will act on the view.
6937
- */
6938
- get operations() {
6939
- const { __lView, __raw_opCodes, icus } = this;
6940
- const results = [];
6941
- for (let i = 0; i < __raw_opCodes.length; i++) {
6942
- // bit code to check if we should apply the next update
6943
- const checkBit = __raw_opCodes[i];
6944
- // Number of opCodes to skip until next set of update codes
6945
- const skipCodes = __raw_opCodes[++i];
6946
- let value = '';
6947
- for (let j = i + 1; j <= (i + skipCodes); j++) {
6948
- const opCode = __raw_opCodes[j];
6949
- if (typeof opCode === 'string') {
6950
- value += opCode;
6951
- }
6952
- else if (typeof opCode == 'number') {
6953
- if (opCode < 0) {
6954
- // It's a binding index whose value is negative
6955
- // We cannot know the value of the binding so we only show the index
6956
- value += `�${-opCode - 1}�`;
6957
- }
6958
- else {
6959
- const nodeIndex = opCode >>> 2 /* SHIFT_REF */;
6960
- let tIcuIndex;
6961
- let tIcu;
6962
- switch (opCode & 3 /* MASK_OPCODE */) {
6963
- case 1 /* Attr */:
6964
- const attrName = __raw_opCodes[++j];
6965
- const sanitizeFn = __raw_opCodes[++j];
6966
- results.push({
6967
- __raw_opCode: opCode,
6968
- checkBit,
6969
- type: 'Attr',
6970
- attrValue: value,
6971
- attrName,
6972
- sanitizeFn,
6973
- });
6974
- break;
6975
- case 0 /* Text */:
6976
- results.push({
6977
- __raw_opCode: opCode,
6978
- checkBit,
6979
- type: 'Text',
6980
- nodeIndex,
6981
- text: value,
6982
- });
6983
- break;
6984
- case 2 /* IcuSwitch */:
6985
- tIcuIndex = __raw_opCodes[++j];
6986
- tIcu = icus[tIcuIndex];
6987
- let result = new I18NDebugItem(opCode, __lView, nodeIndex, 'IcuSwitch');
6988
- result['tIcuIndex'] = tIcuIndex;
6989
- result['checkBit'] = checkBit;
6990
- result['mainBinding'] = value;
6991
- result['tIcu'] = tIcu;
6992
- results.push(result);
6993
- break;
6994
- case 3 /* IcuUpdate */:
6995
- tIcuIndex = __raw_opCodes[++j];
6996
- tIcu = icus[tIcuIndex];
6997
- result = new I18NDebugItem(opCode, __lView, nodeIndex, 'IcuUpdate');
6998
- result['tIcuIndex'] = tIcuIndex;
6999
- result['checkBit'] = checkBit;
7000
- result['tIcu'] = tIcu;
7001
- results.push(result);
7002
- break;
7003
- }
7004
- }
7005
- }
7006
- }
7007
- i += skipCodes;
7008
- }
7009
- return results;
7010
- }
7011
- }
7012
6867
 
7013
6868
  const ɵ0$4 = () => Promise.resolve(null);
7014
6869
  /**
@@ -7529,7 +7384,7 @@ function createTView(type, viewIndex, templateFn, decls, vars, directives, pipes
7529
7384
  // that has a host binding, we will update the blueprint with that def's hostVars count.
7530
7385
  const initialViewLength = bindingStartIndex + vars;
7531
7386
  const blueprint = createViewBlueprint(bindingStartIndex, initialViewLength);
7532
- return blueprint[TVIEW] = ngDevMode ?
7387
+ const tView = blueprint[TVIEW] = ngDevMode ?
7533
7388
  new TViewConstructor(type, viewIndex, // id: number,
7534
7389
  blueprint, // blueprint: LView,
7535
7390
  templateFn, // template: ComponentTemplate<{}>|null,
@@ -7561,8 +7416,9 @@ function createTView(type, viewIndex, templateFn, decls, vars, directives, pipes
7561
7416
  null, // firstChild: TNode|null,
7562
7417
  schemas, // schemas: SchemaMetadata[]|null,
7563
7418
  consts, // consts: TConstants|null
7564
- false // incompleteFirstPass: boolean
7565
- ) :
7419
+ false, // incompleteFirstPass: boolean
7420
+ decls, // ngDevMode only: decls
7421
+ vars) :
7566
7422
  {
7567
7423
  type: type,
7568
7424
  id: viewIndex,
@@ -7596,6 +7452,13 @@ function createTView(type, viewIndex, templateFn, decls, vars, directives, pipes
7596
7452
  consts: consts,
7597
7453
  incompleteFirstPass: false
7598
7454
  };
7455
+ if (ngDevMode) {
7456
+ // For performance reasons it is important that the tView retains the same shape during runtime.
7457
+ // (To make sure that all of the code is monomorphic.) For this reason we seal the object to
7458
+ // prevent class transitions.
7459
+ Object.seal(tView);
7460
+ }
7461
+ return tView;
7599
7462
  }
7600
7463
  function createViewBlueprint(bindingStartIndex, initialViewLength) {
7601
7464
  const blueprint = ngDevMode ? new LViewBlueprint() : [];
@@ -7669,37 +7532,38 @@ function storeCleanupWithContext(tView, lView, context, cleanupFn) {
7669
7532
  function createTNode(tView, tParent, type, adjustedIndex, tagName, attrs) {
7670
7533
  ngDevMode && ngDevMode.tNode++;
7671
7534
  let injectorIndex = tParent ? tParent.injectorIndex : -1;
7672
- return ngDevMode ? new TNodeDebug(tView, // tView_: TView
7673
- type, // type: TNodeType
7674
- adjustedIndex, // index: number
7675
- injectorIndex, // injectorIndex: number
7676
- -1, // directiveStart: number
7677
- -1, // directiveEnd: number
7678
- -1, // directiveStylingLast: number
7679
- null, // propertyBindings: number[]|null
7680
- 0, // flags: TNodeFlags
7681
- 0, // providerIndexes: TNodeProviderIndexes
7682
- tagName, // tagName: string|null
7683
- attrs, // attrs: (string|AttributeMarker|(string|SelectorFlags)[])[]|null
7684
- null, // mergedAttrs
7685
- null, // localNames: (string|number)[]|null
7686
- undefined, // initialInputs: (string[]|null)[]|null|undefined
7687
- null, // inputs: PropertyAliases|null
7688
- null, // outputs: PropertyAliases|null
7689
- null, // tViews: ITView|ITView[]|null
7690
- null, // next: ITNode|null
7691
- null, // projectionNext: ITNode|null
7692
- null, // child: ITNode|null
7693
- tParent, // parent: TElementNode|TContainerNode|null
7694
- null, // projection: number|(ITNode|RNode[])[]|null
7695
- null, // styles: string|null
7696
- null, // stylesWithoutHost: string|null
7697
- undefined, // residualStyles: string|null
7698
- null, // classes: string|null
7699
- null, // classesWithoutHost: string|null
7700
- undefined, // residualClasses: string|null
7701
- 0, // classBindings: TStylingRange;
7702
- 0) :
7535
+ const tNode = ngDevMode ?
7536
+ new TNodeDebug(tView, // tView_: TView
7537
+ type, // type: TNodeType
7538
+ adjustedIndex, // index: number
7539
+ injectorIndex, // injectorIndex: number
7540
+ -1, // directiveStart: number
7541
+ -1, // directiveEnd: number
7542
+ -1, // directiveStylingLast: number
7543
+ null, // propertyBindings: number[]|null
7544
+ 0, // flags: TNodeFlags
7545
+ 0, // providerIndexes: TNodeProviderIndexes
7546
+ tagName, // tagName: string|null
7547
+ attrs, // attrs: (string|AttributeMarker|(string|SelectorFlags)[])[]|null
7548
+ null, // mergedAttrs
7549
+ null, // localNames: (string|number)[]|null
7550
+ undefined, // initialInputs: (string[]|null)[]|null|undefined
7551
+ null, // inputs: PropertyAliases|null
7552
+ null, // outputs: PropertyAliases|null
7553
+ null, // tViews: ITView|ITView[]|null
7554
+ null, // next: ITNode|null
7555
+ null, // projectionNext: ITNode|null
7556
+ null, // child: ITNode|null
7557
+ tParent, // parent: TElementNode|TContainerNode|null
7558
+ null, // projection: number|(ITNode|RNode[])[]|null
7559
+ null, // styles: string|null
7560
+ null, // stylesWithoutHost: string|null
7561
+ undefined, // residualStyles: string|null
7562
+ null, // classes: string|null
7563
+ null, // classesWithoutHost: string|null
7564
+ undefined, // residualClasses: string|null
7565
+ 0, // classBindings: TStylingRange;
7566
+ 0) :
7703
7567
  {
7704
7568
  type: type,
7705
7569
  index: adjustedIndex,
@@ -7732,6 +7596,13 @@ function createTNode(tView, tParent, type, adjustedIndex, tagName, attrs) {
7732
7596
  classBindings: 0,
7733
7597
  styleBindings: 0,
7734
7598
  };
7599
+ if (ngDevMode) {
7600
+ // For performance reasons it is important that the tNode retains the same shape during runtime.
7601
+ // (To make sure that all of the code is monomorphic.) For this reason we seal the object to
7602
+ // prevent class transitions.
7603
+ Object.seal(tNode);
7604
+ }
7605
+ return tNode;
7735
7606
  }
7736
7607
  function generatePropertyAliases(inputAliasMap, directiveDefIdx, propStore) {
7737
7608
  for (let publicName in inputAliasMap) {
@@ -8767,7 +8638,7 @@ function setInputsForProperty(tView, lView, inputs, publicName, value) {
8767
8638
  const index = inputs[i++];
8768
8639
  const privateName = inputs[i++];
8769
8640
  const instance = lView[index];
8770
- ngDevMode && assertDataInRange(lView, index);
8641
+ ngDevMode && assertIndexInRange(lView, index);
8771
8642
  const def = tView.data[index];
8772
8643
  if (def.setInput !== null) {
8773
8644
  def.setInput(instance, value, publicName, privateName);
@@ -8782,7 +8653,7 @@ function setInputsForProperty(tView, lView, inputs, publicName, value) {
8782
8653
  */
8783
8654
  function textBindingInternal(lView, index, value) {
8784
8655
  ngDevMode && assertNotSame(value, NO_CHANGE, 'value should not be NO_CHANGE');
8785
- ngDevMode && assertDataInRange(lView, index + HEADER_OFFSET);
8656
+ ngDevMode && assertIndexInRange(lView, index + HEADER_OFFSET);
8786
8657
  const element = getNativeByIndex(index, lView);
8787
8658
  ngDevMode && assertDefined(element, 'native element should exist');
8788
8659
  ngDevMode && ngDevMode.rendererSetText++;
@@ -9063,16 +8934,6 @@ function detachView(lContainer, removeIndex) {
9063
8934
  }
9064
8935
  return viewToDetach;
9065
8936
  }
9066
- /**
9067
- * Removes a view from a container, i.e. detaches it and then destroys the underlying LView.
9068
- *
9069
- * @param lContainer The container from which to remove a view
9070
- * @param removeIndex The index of the view to remove
9071
- */
9072
- function removeView(lContainer, removeIndex) {
9073
- const detachedView = detachView(lContainer, removeIndex);
9074
- detachedView && destroyLView(detachedView[TVIEW], detachedView);
9075
- }
9076
8937
  /**
9077
8938
  * A standalone function which destroys an LView,
9078
8939
  * conducting clean up (e.g. removing listeners, calling onDestroys).
@@ -10295,8 +10156,17 @@ function createContainerRef(ViewContainerRefToken, ElementRefToken, hostTNode, h
10295
10156
  remove(index) {
10296
10157
  this.allocateContainerIfNeeded();
10297
10158
  const adjustedIdx = this._adjustIndex(index, -1);
10298
- removeView(this._lContainer, adjustedIdx);
10299
- removeFromArray(this._lContainer[VIEW_REFS], adjustedIdx);
10159
+ const detachedView = detachView(this._lContainer, adjustedIdx);
10160
+ if (detachedView) {
10161
+ // Before destroying the view, remove it from the container's array of `ViewRef`s.
10162
+ // This ensures the view container length is updated before calling
10163
+ // `destroyLView`, which could recursively call view container methods that
10164
+ // rely on an accurate container length.
10165
+ // (e.g. a method on this view container being called by a child directive's OnDestroy
10166
+ // lifecycle hook)
10167
+ removeFromArray(this._lContainer[VIEW_REFS], adjustedIdx);
10168
+ destroyLView(detachedView[TVIEW], detachedView);
10169
+ }
10300
10170
  }
10301
10171
  detach(index) {
10302
10172
  this.allocateContainerIfNeeded();
@@ -10508,13 +10378,42 @@ function isType(v) {
10508
10378
  * Use of this source code is governed by an MIT-style license that can be
10509
10379
  * found in the LICENSE file at https://angular.io/license
10510
10380
  */
10381
+ /*
10382
+ * #########################
10383
+ * Attention: These Regular expressions have to hold even if the code is minified!
10384
+ * ##########################
10385
+ */
10386
+ /**
10387
+ * Regular expression that detects pass-through constructors for ES5 output. This Regex
10388
+ * intends to capture the common delegation pattern emitted by TypeScript and Babel. Also
10389
+ * it intends to capture the pattern where existing constructors have been downleveled from
10390
+ * ES2015 to ES5 using TypeScript w/ downlevel iteration. e.g.
10391
+ *
10392
+ * ```
10393
+ * function MyClass() {
10394
+ * var _this = _super.apply(this, arguments) || this;
10395
+ * ```
10396
+ *
10397
+ * ```
10398
+ * function MyClass() {
10399
+ * var _this = _super.apply(this, __spread(arguments)) || this;
10400
+ * ```
10401
+ *
10402
+ * More details can be found in: https://github.com/angular/angular/issues/38453.
10403
+ */
10404
+ const ES5_DELEGATE_CTOR = /^function\s+\S+\(\)\s*{[\s\S]+\.apply\(this,\s*(arguments|[^()]+\(arguments\))\)/;
10405
+ /** Regular expression that detects ES2015 classes which extend from other classes. */
10406
+ const ES2015_INHERITED_CLASS = /^class\s+[A-Za-z\d$_]*\s*extends\s+[^{]+{/;
10407
+ /**
10408
+ * Regular expression that detects ES2015 classes which extend from other classes and
10409
+ * have an explicit constructor defined.
10410
+ */
10411
+ const ES2015_INHERITED_CLASS_WITH_CTOR = /^class\s+[A-Za-z\d$_]*\s*extends\s+[^{]+{[\s\S]*constructor\s*\(/;
10511
10412
  /**
10512
- * Attention: These regex has to hold even if the code is minified!
10413
+ * Regular expression that detects ES2015 classes which extend from other classes
10414
+ * and inherit a constructor.
10513
10415
  */
10514
- const DELEGATE_CTOR = /^function\s+\S+\(\)\s*{[\s\S]+\.apply\(this,\s*arguments\)/;
10515
- const INHERITED_CLASS = /^class\s+[A-Za-z\d$_]*\s*extends\s+[^{]+{/;
10516
- const INHERITED_CLASS_WITH_CTOR = /^class\s+[A-Za-z\d$_]*\s*extends\s+[^{]+{[\s\S]*constructor\s*\(/;
10517
- const INHERITED_CLASS_WITH_DELEGATE_CTOR = /^class\s+[A-Za-z\d$_]*\s*extends\s+[^{]+{[\s\S]*constructor\s*\(\)\s*{\s*super\(\.\.\.arguments\)/;
10416
+ const ES2015_INHERITED_CLASS_WITH_DELEGATE_CTOR = /^class\s+[A-Za-z\d$_]*\s*extends\s+[^{]+{[\s\S]*constructor\s*\(\)\s*{\s*super\(\.\.\.arguments\)/;
10518
10417
  /**
10519
10418
  * Determine whether a stringified type is a class which delegates its constructor
10520
10419
  * to its parent.
@@ -10524,8 +10423,9 @@ const INHERITED_CLASS_WITH_DELEGATE_CTOR = /^class\s+[A-Za-z\d$_]*\s*extends\s+[
10524
10423
  * an initialized instance property.
10525
10424
  */
10526
10425
  function isDelegateCtor(typeStr) {
10527
- return DELEGATE_CTOR.test(typeStr) || INHERITED_CLASS_WITH_DELEGATE_CTOR.test(typeStr) ||
10528
- (INHERITED_CLASS.test(typeStr) && !INHERITED_CLASS_WITH_CTOR.test(typeStr));
10426
+ return ES5_DELEGATE_CTOR.test(typeStr) ||
10427
+ ES2015_INHERITED_CLASS_WITH_DELEGATE_CTOR.test(typeStr) ||
10428
+ (ES2015_INHERITED_CLASS.test(typeStr) && !ES2015_INHERITED_CLASS_WITH_CTOR.test(typeStr));
10529
10429
  }
10530
10430
  class ReflectionCapabilities {
10531
10431
  constructor(reflect) {
@@ -13076,7 +12976,7 @@ function updateBinding(lView, bindingIndex, value) {
13076
12976
  }
13077
12977
  /** Gets the current binding value. */
13078
12978
  function getBinding(lView, bindingIndex) {
13079
- ngDevMode && assertDataInRange(lView, bindingIndex);
12979
+ ngDevMode && assertIndexInRange(lView, bindingIndex);
13080
12980
  ngDevMode &&
13081
12981
  assertNotSame(lView[bindingIndex], NO_CHANGE, 'Stored value should never be NO_CHANGE.');
13082
12982
  return lView[bindingIndex];
@@ -13970,7 +13870,7 @@ function ɵɵelementStart(index, name, attrsIndex, localRefsIndex) {
13970
13870
  ngDevMode &&
13971
13871
  assertEqual(getBindingIndex(), tView.bindingStartIndex, 'elements should be created before any bindings');
13972
13872
  ngDevMode && ngDevMode.rendererCreateElement++;
13973
- ngDevMode && assertDataInRange(lView, adjustedIndex);
13873
+ ngDevMode && assertIndexInRange(lView, adjustedIndex);
13974
13874
  const renderer = lView[RENDERER];
13975
13875
  const native = lView[adjustedIndex] = elementCreate(name, renderer, getNamespace());
13976
13876
  const tNode = tView.firstCreatePass ?
@@ -14130,7 +14030,7 @@ function ɵɵelementContainerStart(index, attrsIndex, localRefsIndex) {
14130
14030
  const lView = getLView();
14131
14031
  const tView = getTView();
14132
14032
  const adjustedIndex = index + HEADER_OFFSET;
14133
- ngDevMode && assertDataInRange(lView, adjustedIndex);
14033
+ ngDevMode && assertIndexInRange(lView, adjustedIndex);
14134
14034
  ngDevMode &&
14135
14035
  assertEqual(getBindingIndex(), tView.bindingStartIndex, 'element containers should be created before any bindings');
14136
14036
  const tNode = tView.firstCreatePass ?
@@ -14394,7 +14294,7 @@ function listenerInternal(tView, lView, renderer, tNode, eventName, listenerFn,
14394
14294
  if (propsLength) {
14395
14295
  for (let i = 0; i < propsLength; i += 2) {
14396
14296
  const index = props[i];
14397
- ngDevMode && assertDataInRange(lView, index);
14297
+ ngDevMode && assertIndexInRange(lView, index);
14398
14298
  const minifiedName = props[i + 1];
14399
14299
  const directiveInstance = lView[index];
14400
14300
  const output = directiveInstance[minifiedName];
@@ -15452,7 +15352,7 @@ function markDuplicates(tData, tStylingKey, index, isPrevDir, isClassBinding) {
15452
15352
  // - we are a map in which case we have to continue searching even after we find what we were
15453
15353
  // looking for since we are a wild card and everything needs to be flipped to duplicate.
15454
15354
  while (cursor !== 0 && (foundDuplicate === false || isMap)) {
15455
- ngDevMode && assertDataInRange(tData, cursor);
15355
+ ngDevMode && assertIndexInRange(tData, cursor);
15456
15356
  const tStylingValueAtCursor = tData[cursor];
15457
15357
  const tStyleRangeAtCursor = tData[cursor + 1];
15458
15358
  if (isStylingMatch(tStylingValueAtCursor, tStylingKey)) {
@@ -15675,7 +15575,8 @@ function consumeStyleKey(text, startIndex, endIndex) {
15675
15575
  let ch;
15676
15576
  while (startIndex < endIndex &&
15677
15577
  ((ch = text.charCodeAt(startIndex)) === 45 /* DASH */ || ch === 95 /* UNDERSCORE */ ||
15678
- ((ch & -33 /* UPPER_CASE */) >= 65 /* A */ && (ch & -33 /* UPPER_CASE */) <= 90 /* Z */))) {
15578
+ ((ch & -33 /* UPPER_CASE */) >= 65 /* A */ && (ch & -33 /* UPPER_CASE */) <= 90 /* Z */) ||
15579
+ (ch >= 48 /* ZERO */ && ch <= 57 /* NINE */))) {
15679
15580
  startIndex++;
15680
15581
  }
15681
15582
  return startIndex;
@@ -16568,7 +16469,7 @@ function ɵɵtext(index, value = '') {
16568
16469
  const adjustedIndex = index + HEADER_OFFSET;
16569
16470
  ngDevMode &&
16570
16471
  assertEqual(getBindingIndex(), tView.bindingStartIndex, 'text nodes should be created before any bindings');
16571
- ngDevMode && assertDataInRange(lView, adjustedIndex);
16472
+ ngDevMode && assertIndexInRange(lView, adjustedIndex);
16572
16473
  const tNode = tView.firstCreatePass ?
16573
16474
  getOrCreateTNode(tView, lView[T_HOST], index, 3 /* Element */, null, null) :
16574
16475
  tView.data[adjustedIndex];
@@ -18436,7 +18337,7 @@ function renderComponent$1(componentType /* Type as workaround for: Microsoft/Ty
18436
18337
  */
18437
18338
  function createRootComponentView(rNode, def, rootView, rendererFactory, hostRenderer, sanitizer) {
18438
18339
  const tView = rootView[TVIEW];
18439
- ngDevMode && assertDataInRange(rootView, 0 + HEADER_OFFSET);
18340
+ ngDevMode && assertIndexInRange(rootView, 0 + HEADER_OFFSET);
18440
18341
  rootView[0 + HEADER_OFFSET] = rNode;
18441
18342
  const tNode = getOrCreateTNode(tView, null, 0, 3 /* Element */, null, null);
18442
18343
  const mergedAttrs = tNode.mergedAttrs = def.hostAttrs;
@@ -19308,7 +19209,7 @@ class Version {
19308
19209
  /**
19309
19210
  * @publicApi
19310
19211
  */
19311
- const VERSION = new Version('10.0.6');
19212
+ const VERSION = new Version('10.0.10');
19312
19213
 
19313
19214
  /**
19314
19215
  * @license
@@ -22347,30 +22248,6 @@ class ComponentRef$1 extends ComponentRef {
22347
22248
  }
22348
22249
  }
22349
22250
 
22350
- /**
22351
- * @license
22352
- * Copyright Google LLC All Rights Reserved.
22353
- *
22354
- * Use of this source code is governed by an MIT-style license that can be
22355
- * found in the LICENSE file at https://angular.io/license
22356
- */
22357
- /**
22358
- * NOTE: changes to the `ngI18nClosureMode` name must be synced with `compiler-cli/src/tooling.ts`.
22359
- */
22360
- if (typeof ngI18nClosureMode === 'undefined') {
22361
- // These property accesses can be ignored because ngI18nClosureMode will be set to false
22362
- // when optimizing code and the whole if statement will be dropped.
22363
- // Make sure to refer to ngI18nClosureMode as ['ngI18nClosureMode'] for closure.
22364
- // NOTE: we need to have it in IIFE so that the tree-shaker is happy.
22365
- (function () {
22366
- // tslint:disable-next-line:no-toplevel-property-access
22367
- _global['ngI18nClosureMode'] =
22368
- // TODO(FW-1250): validate that this actually, you know, works.
22369
- // tslint:disable-next-line:no-toplevel-property-access
22370
- typeof goog !== 'undefined' && typeof goog.getMsg === 'function';
22371
- })();
22372
- }
22373
-
22374
22251
  /**
22375
22252
  * @license
22376
22253
  * Copyright Google LLC All Rights Reserved.
@@ -22584,397 +22461,388 @@ const USD_CURRENCY_CODE = 'USD';
22584
22461
  * Use of this source code is governed by an MIT-style license that can be
22585
22462
  * found in the LICENSE file at https://angular.io/license
22586
22463
  */
22587
- const MARKER = `�`;
22588
- const ICU_BLOCK_REGEXP = /^\s*(�\d+:?\d*�)\s*,\s*(select|plural)\s*,/;
22589
- const SUBTEMPLATE_REGEXP = /�\/?\*(\d+:\d+)�/gi;
22590
- const PH_REGEXP = /�(\/?[#*!]\d+):?\d*�/gi;
22591
- const BINDING_REGEXP = /�(\d+):?\d*�/gi;
22592
- const ICU_REGEXP = /({\s*�\d+:?\d*�\s*,\s*\S{6}\s*,[\s\S]*})/gi;
22593
- // i18nPostprocess consts
22594
- const ROOT_TEMPLATE_ID = 0;
22595
- const PP_MULTI_VALUE_PLACEHOLDERS_REGEXP = /\[(�.+?�?)\]/;
22596
- const PP_PLACEHOLDERS_REGEXP = /\[(�.+?�?)\]|(�\/?\*\d+:\d+�)/g;
22597
- const PP_ICU_VARS_REGEXP = /({\s*)(VAR_(PLURAL|SELECT)(_\d+)?)(\s*,)/g;
22598
- const PP_ICU_PLACEHOLDERS_REGEXP = /{([A-Z0-9_]+)}/g;
22599
- const PP_ICUS_REGEXP = /�I18N_EXP_(ICU(_\d+)?)�/g;
22600
- const PP_CLOSE_TEMPLATE_REGEXP = /\/\*/;
22601
- const PP_TEMPLATE_ID_REGEXP = /\d+\:(\d+)/;
22602
22464
  /**
22603
- * Breaks pattern into strings and top level {...} blocks.
22604
- * Can be used to break a message into text and ICU expressions, or to break an ICU expression into
22605
- * keys and cases.
22606
- * Original code from closure library, modified for Angular.
22607
- *
22608
- * @param pattern (sub)Pattern to be broken.
22465
+ * The locale id that the application is currently using (for translations and ICU expressions).
22466
+ * This is the ivy version of `LOCALE_ID` that was defined as an injection token for the view engine
22467
+ * but is now defined as a global value.
22468
+ */
22469
+ let LOCALE_ID = DEFAULT_LOCALE_ID;
22470
+ /**
22471
+ * Sets the locale id that will be used for translations and ICU expressions.
22472
+ * This is the ivy version of `LOCALE_ID` that was defined as an injection token for the view engine
22473
+ * but is now defined as a global value.
22609
22474
  *
22475
+ * @param localeId
22610
22476
  */
22611
- function extractParts(pattern) {
22612
- if (!pattern) {
22613
- return [];
22614
- }
22615
- let prevPos = 0;
22616
- const braceStack = [];
22617
- const results = [];
22618
- const braces = /[{}]/g;
22619
- // lastIndex doesn't get set to 0 so we have to.
22620
- braces.lastIndex = 0;
22621
- let match;
22622
- while (match = braces.exec(pattern)) {
22623
- const pos = match.index;
22624
- if (match[0] == '}') {
22625
- braceStack.pop();
22626
- if (braceStack.length == 0) {
22627
- // End of the block.
22628
- const block = pattern.substring(prevPos, pos);
22629
- if (ICU_BLOCK_REGEXP.test(block)) {
22630
- results.push(parseICUBlock(block));
22631
- }
22632
- else {
22633
- results.push(block);
22634
- }
22635
- prevPos = pos + 1;
22636
- }
22637
- }
22638
- else {
22639
- if (braceStack.length == 0) {
22640
- const substring = pattern.substring(prevPos, pos);
22641
- results.push(substring);
22642
- prevPos = pos + 1;
22643
- }
22644
- braceStack.push('{');
22645
- }
22477
+ function setLocaleId(localeId) {
22478
+ assertDefined(localeId, `Expected localeId to be defined`);
22479
+ if (typeof localeId === 'string') {
22480
+ LOCALE_ID = localeId.toLowerCase().replace(/_/g, '-');
22646
22481
  }
22647
- const substring = pattern.substring(prevPos);
22648
- results.push(substring);
22649
- return results;
22650
22482
  }
22651
22483
  /**
22652
- * Parses text containing an ICU expression and produces a JSON object for it.
22653
- * Original code from closure library, modified for Angular.
22654
- *
22655
- * @param pattern Text containing an ICU expression that needs to be parsed.
22656
- *
22484
+ * Gets the locale id that will be used for translations and ICU expressions.
22485
+ * This is the ivy version of `LOCALE_ID` that was defined as an injection token for the view engine
22486
+ * but is now defined as a global value.
22657
22487
  */
22658
- function parseICUBlock(pattern) {
22659
- const cases = [];
22660
- const values = [];
22661
- let icuType = 1 /* plural */;
22662
- let mainBinding = 0;
22663
- pattern = pattern.replace(ICU_BLOCK_REGEXP, function (str, binding, type) {
22664
- if (type === 'select') {
22665
- icuType = 0 /* select */;
22666
- }
22667
- else {
22668
- icuType = 1 /* plural */;
22669
- }
22670
- mainBinding = parseInt(binding.substr(1), 10);
22671
- return '';
22672
- });
22673
- const parts = extractParts(pattern);
22674
- // Looking for (key block)+ sequence. One of the keys has to be "other".
22675
- for (let pos = 0; pos < parts.length;) {
22676
- let key = parts[pos++].trim();
22677
- if (icuType === 1 /* plural */) {
22678
- // Key can be "=x", we just want "x"
22679
- key = key.replace(/\s*(?:=)?(\w+)\s*/, '$1');
22680
- }
22681
- if (key.length) {
22682
- cases.push(key);
22683
- }
22684
- const blocks = extractParts(parts[pos++]);
22685
- if (cases.length > values.length) {
22686
- values.push(blocks);
22687
- }
22688
- }
22689
- // TODO(ocombe): support ICU expressions in attributes, see #21615
22690
- return { type: icuType, mainBinding: mainBinding, cases, values };
22488
+ function getLocaleId() {
22489
+ return LOCALE_ID;
22691
22490
  }
22491
+
22692
22492
  /**
22693
- * Removes everything inside the sub-templates of a message.
22493
+ * @license
22494
+ * Copyright Google LLC All Rights Reserved.
22495
+ *
22496
+ * Use of this source code is governed by an MIT-style license that can be
22497
+ * found in the LICENSE file at https://angular.io/license
22694
22498
  */
22695
- function removeInnerTemplateTranslation(message) {
22696
- let match;
22697
- let res = '';
22698
- let index = 0;
22699
- let inTemplate = false;
22700
- let tagMatched;
22701
- while ((match = SUBTEMPLATE_REGEXP.exec(message)) !== null) {
22702
- if (!inTemplate) {
22703
- res += message.substring(index, match.index + match[0].length);
22704
- tagMatched = match[1];
22705
- inTemplate = true;
22706
- }
22707
- else {
22708
- if (match[0] === `${MARKER}/*${tagMatched}${MARKER}`) {
22709
- index = match.index;
22710
- inTemplate = false;
22711
- }
22712
- }
22713
- }
22714
- ngDevMode &&
22715
- assertEqual(inTemplate, false, `Tag mismatch: unable to find the end of the sub-template in the translation "${message}"`);
22716
- res += message.substr(index);
22717
- return res;
22718
- }
22719
22499
  /**
22720
- * Extracts a part of a message and removes the rest.
22721
- *
22722
- * This method is used for extracting a part of the message associated with a template. A translated
22723
- * message can span multiple templates.
22724
- *
22725
- * Example:
22726
- * ```
22727
- * <div i18n>Translate <span *ngIf>me</span>!</div>
22728
- * ```
22729
- *
22730
- * @param message The message to crop
22731
- * @param subTemplateIndex Index of the sub-template to extract. If undefined it returns the
22732
- * external template and removes all sub-templates.
22500
+ * NOTE: changes to the `ngI18nClosureMode` name must be synced with `compiler-cli/src/tooling.ts`.
22733
22501
  */
22734
- function getTranslationForTemplate(message, subTemplateIndex) {
22735
- if (isRootTemplateMessage(subTemplateIndex)) {
22736
- // We want the root template message, ignore all sub-templates
22737
- return removeInnerTemplateTranslation(message);
22738
- }
22739
- else {
22740
- // We want a specific sub-template
22741
- const start = message.indexOf(`:${subTemplateIndex}${MARKER}`) + 2 + subTemplateIndex.toString().length;
22742
- const end = message.search(new RegExp(`${MARKER}\\/\\*\\d+:${subTemplateIndex}${MARKER}`));
22743
- return removeInnerTemplateTranslation(message.substring(start, end));
22744
- }
22502
+ if (typeof ngI18nClosureMode === 'undefined') {
22503
+ // These property accesses can be ignored because ngI18nClosureMode will be set to false
22504
+ // when optimizing code and the whole if statement will be dropped.
22505
+ // Make sure to refer to ngI18nClosureMode as ['ngI18nClosureMode'] for closure.
22506
+ // NOTE: we need to have it in IIFE so that the tree-shaker is happy.
22507
+ (function () {
22508
+ // tslint:disable-next-line:no-toplevel-property-access
22509
+ _global['ngI18nClosureMode'] =
22510
+ // TODO(FW-1250): validate that this actually, you know, works.
22511
+ // tslint:disable-next-line:no-toplevel-property-access
22512
+ typeof goog !== 'undefined' && typeof goog.getMsg === 'function';
22513
+ })();
22745
22514
  }
22515
+
22746
22516
  /**
22747
- * Generate the OpCodes to update the bindings of a string.
22517
+ * @license
22518
+ * Copyright Google LLC All Rights Reserved.
22748
22519
  *
22749
- * @param str The string containing the bindings.
22750
- * @param destinationNode Index of the destination node which will receive the binding.
22751
- * @param attrName Name of the attribute, if the string belongs to an attribute.
22752
- * @param sanitizeFn Sanitization function used to sanitize the string after update, if necessary.
22520
+ * Use of this source code is governed by an MIT-style license that can be
22521
+ * found in the LICENSE file at https://angular.io/license
22753
22522
  */
22754
- function generateBindingUpdateOpCodes(str, destinationNode, attrName, sanitizeFn = null) {
22755
- const updateOpCodes = [null, null]; // Alloc space for mask and size
22756
- const textParts = str.split(BINDING_REGEXP);
22757
- let mask = 0;
22758
- for (let j = 0; j < textParts.length; j++) {
22759
- const textValue = textParts[j];
22760
- if (j & 1) {
22761
- // Odd indexes are bindings
22762
- const bindingIndex = parseInt(textValue, 10);
22763
- updateOpCodes.push(-1 - bindingIndex);
22764
- mask = mask | toMaskBit(bindingIndex);
22765
- }
22766
- else if (textValue !== '') {
22767
- // Even indexes are text
22768
- updateOpCodes.push(textValue);
22769
- }
22770
- }
22771
- updateOpCodes.push(destinationNode << 2 /* SHIFT_REF */ |
22772
- (attrName ? 1 /* Attr */ : 0 /* Text */));
22773
- if (attrName) {
22774
- updateOpCodes.push(attrName, sanitizeFn);
22775
- }
22776
- updateOpCodes[0] = mask;
22777
- updateOpCodes[1] = updateOpCodes.length - 2;
22778
- return updateOpCodes;
22523
+ function getParentFromI18nMutateOpCode(mergedCode) {
22524
+ return mergedCode >>> 17 /* SHIFT_PARENT */;
22779
22525
  }
22780
- function getBindingMask(icuExpression, mask = 0) {
22781
- mask = mask | toMaskBit(icuExpression.mainBinding);
22782
- let match;
22783
- for (let i = 0; i < icuExpression.values.length; i++) {
22784
- const valueArr = icuExpression.values[i];
22785
- for (let j = 0; j < valueArr.length; j++) {
22786
- const value = valueArr[j];
22787
- if (typeof value === 'string') {
22788
- while (match = BINDING_REGEXP.exec(value)) {
22789
- mask = mask | toMaskBit(parseInt(match[1], 10));
22790
- }
22791
- }
22792
- else {
22793
- mask = getBindingMask(value, mask);
22794
- }
22795
- }
22796
- }
22797
- return mask;
22526
+ function getRefFromI18nMutateOpCode(mergedCode) {
22527
+ return (mergedCode & 131064 /* MASK_REF */) >>> 3 /* SHIFT_REF */;
22528
+ }
22529
+ function getInstructionFromI18nMutateOpCode(mergedCode) {
22530
+ return mergedCode & 7 /* MASK_INSTRUCTION */;
22798
22531
  }
22799
- const i18nIndexStack = [];
22800
- let i18nIndexStackPointer = -1;
22801
22532
  /**
22802
- * Convert binding index to mask bit.
22533
+ * Marks that the next string is an element name.
22803
22534
  *
22804
- * Each index represents a single bit on the bit-mask. Because bit-mask only has 32 bits, we make
22805
- * the 32nd bit share all masks for all bindings higher than 32. Since it is extremely rare to have
22806
- * more than 32 bindings this will be hit very rarely. The downside of hitting this corner case is
22807
- * that we will execute binding code more often than necessary. (penalty of performance)
22535
+ * See `I18nMutateOpCodes` documentation.
22808
22536
  */
22809
- function toMaskBit(bindingIndex) {
22810
- return 1 << Math.min(bindingIndex, 31);
22811
- }
22812
- const parentIndexStack = [];
22537
+ const ELEMENT_MARKER = {
22538
+ marker: 'element'
22539
+ };
22813
22540
  /**
22814
- * Marks a block of text as translatable.
22815
- *
22816
- * The instructions `i18nStart` and `i18nEnd` mark the translation block in the template.
22817
- * The translation `message` is the value which is locale specific. The translation string may
22818
- * contain placeholders which associate inner elements and sub-templates within the translation.
22819
- *
22820
- * The translation `message` placeholders are:
22821
- * - `�{index}(:{block})�`: *Binding Placeholder*: Marks a location where an expression will be
22822
- * interpolated into. The placeholder `index` points to the expression binding index. An optional
22823
- * `block` that matches the sub-template in which it was declared.
22824
- * - `�#{index}(:{block})�`/`�/#{index}(:{block})�`: *Element Placeholder*: Marks the beginning
22825
- * and end of DOM element that were embedded in the original translation block. The placeholder
22826
- * `index` points to the element index in the template instructions set. An optional `block` that
22827
- * matches the sub-template in which it was declared.
22828
- * - `�!{index}(:{block})�`/`�/!{index}(:{block})�`: *Projection Placeholder*: Marks the
22829
- * beginning and end of <ng-content> that was embedded in the original translation block.
22830
- * The placeholder `index` points to the element index in the template instructions set.
22831
- * An optional `block` that matches the sub-template in which it was declared.
22832
- * - `�*{index}:{block}�`/`�/*{index}:{block}�`: *Sub-template Placeholder*: Sub-templates must be
22833
- * split up and translated separately in each angular template function. The `index` points to the
22834
- * `template` instruction index. A `block` that matches the sub-template in which it was declared.
22541
+ * Marks that the next string is comment text.
22835
22542
  *
22836
- * @param index A unique index of the translation in the static block.
22837
- * @param message The translation message.
22838
- * @param subTemplateIndex Optional sub-template index in the `message`.
22543
+ * See `I18nMutateOpCodes` documentation.
22544
+ */
22545
+ const COMMENT_MARKER = {
22546
+ marker: 'comment'
22547
+ };
22548
+ // Note: This hack is necessary so we don't erroneously get a circular dependency
22549
+ // failure based on types.
22550
+ const unusedValueExportToPlacateAjd$6 = 1;
22551
+
22552
+ /**
22553
+ * @license
22554
+ * Copyright Google LLC All Rights Reserved.
22839
22555
  *
22840
- * @codeGenApi
22556
+ * Use of this source code is governed by an MIT-style license that can be
22557
+ * found in the LICENSE file at https://angular.io/license
22841
22558
  */
22842
- function ɵɵi18nStart(index, message, subTemplateIndex) {
22843
- const tView = getTView();
22844
- ngDevMode && assertDefined(tView, `tView should be defined`);
22559
+ const i18nIndexStack = [];
22560
+ let i18nIndexStackPointer = -1;
22561
+ function popI18nIndex() {
22562
+ return i18nIndexStack[i18nIndexStackPointer--];
22563
+ }
22564
+ function pushI18nIndex(index) {
22845
22565
  i18nIndexStack[++i18nIndexStackPointer] = index;
22846
- // We need to delay projections until `i18nEnd`
22847
- setDelayProjection(true);
22848
- if (tView.firstCreatePass && tView.data[index + HEADER_OFFSET] === null) {
22849
- i18nStartFirstPass(getLView(), tView, index, message, subTemplateIndex);
22566
+ }
22567
+ let changeMask = 0b0;
22568
+ let shiftsCounter = 0;
22569
+ function setMaskBit(bit) {
22570
+ if (bit) {
22571
+ changeMask = changeMask | (1 << shiftsCounter);
22850
22572
  }
22573
+ shiftsCounter++;
22851
22574
  }
22852
- // Count for the number of vars that will be allocated for each i18n block.
22853
- // It is global because this is used in multiple functions that include loops and recursive calls.
22854
- // This is reset to 0 when `i18nStartFirstPass` is called.
22855
- let i18nVarsCount;
22856
- function allocNodeIndex(startIndex) {
22857
- return startIndex + i18nVarsCount++;
22575
+ function applyI18n(tView, lView, index) {
22576
+ if (shiftsCounter > 0) {
22577
+ ngDevMode && assertDefined(tView, `tView should be defined`);
22578
+ const tI18n = tView.data[index + HEADER_OFFSET];
22579
+ let updateOpCodes;
22580
+ let tIcus = null;
22581
+ if (Array.isArray(tI18n)) {
22582
+ updateOpCodes = tI18n;
22583
+ }
22584
+ else {
22585
+ updateOpCodes = tI18n.update;
22586
+ tIcus = tI18n.icus;
22587
+ }
22588
+ const bindingsStartIndex = getBindingIndex() - shiftsCounter - 1;
22589
+ applyUpdateOpCodes(tView, tIcus, lView, updateOpCodes, bindingsStartIndex, changeMask);
22590
+ // Reset changeMask & maskBit to default for the next update cycle
22591
+ changeMask = 0b0;
22592
+ shiftsCounter = 0;
22593
+ }
22858
22594
  }
22859
22595
  /**
22860
- * See `i18nStart` above.
22596
+ * Apply `I18nMutateOpCodes` OpCodes.
22597
+ *
22598
+ * @param tView Current `TView`
22599
+ * @param rootIndex Pointer to the root (parent) tNode for the i18n.
22600
+ * @param createOpCodes OpCodes to process
22601
+ * @param lView Current `LView`
22861
22602
  */
22862
- function i18nStartFirstPass(lView, tView, index, message, subTemplateIndex) {
22863
- const startIndex = tView.blueprint.length - HEADER_OFFSET;
22864
- i18nVarsCount = 0;
22865
- const previousOrParentTNode = getPreviousOrParentTNode();
22866
- const parentTNode = getIsParent() ? previousOrParentTNode : previousOrParentTNode && previousOrParentTNode.parent;
22867
- let parentIndex = parentTNode && parentTNode !== lView[T_HOST] ? parentTNode.index - HEADER_OFFSET : index;
22868
- let parentIndexPointer = 0;
22869
- parentIndexStack[parentIndexPointer] = parentIndex;
22870
- const createOpCodes = [];
22871
- // If the previous node wasn't the direct parent then we have a translation without top level
22872
- // element and we need to keep a reference of the previous element if there is one. We should also
22873
- // keep track whether an element was a parent node or not, so that the logic that consumes
22874
- // the generated `I18nMutateOpCode`s can leverage this information to properly set TNode state
22875
- // (whether it's a parent or sibling).
22876
- if (index > 0 && previousOrParentTNode !== parentTNode) {
22877
- let previousTNodeIndex = previousOrParentTNode.index - HEADER_OFFSET;
22878
- // If current TNode is a sibling node, encode it using a negative index. This information is
22879
- // required when the `Select` action is processed (see the `readCreateOpCodes` function).
22880
- if (!getIsParent()) {
22881
- previousTNodeIndex = ~previousTNodeIndex;
22603
+ function applyCreateOpCodes(tView, rootindex, createOpCodes, lView) {
22604
+ const renderer = lView[RENDERER];
22605
+ let currentTNode = null;
22606
+ let previousTNode = null;
22607
+ const visitedNodes = [];
22608
+ for (let i = 0; i < createOpCodes.length; i++) {
22609
+ const opCode = createOpCodes[i];
22610
+ if (typeof opCode == 'string') {
22611
+ const textRNode = createTextNode(opCode, renderer);
22612
+ const textNodeIndex = createOpCodes[++i];
22613
+ ngDevMode && ngDevMode.rendererCreateTextNode++;
22614
+ previousTNode = currentTNode;
22615
+ currentTNode =
22616
+ createDynamicNodeAtIndex(tView, lView, textNodeIndex, 3 /* Element */, textRNode, null);
22617
+ visitedNodes.push(textNodeIndex);
22618
+ setIsNotParent();
22882
22619
  }
22883
- // Create an OpCode to select the previous TNode
22884
- createOpCodes.push(previousTNodeIndex << 3 /* SHIFT_REF */ | 0 /* Select */);
22885
- }
22886
- const updateOpCodes = [];
22887
- const icuExpressions = [];
22888
- if (message === '' && isRootTemplateMessage(subTemplateIndex)) {
22889
- // If top level translation is an empty string, do not invoke additional processing
22890
- // and just create op codes for empty text node instead.
22891
- createOpCodes.push(message, allocNodeIndex(startIndex), parentIndex << 17 /* SHIFT_PARENT */ | 1 /* AppendChild */);
22892
- }
22893
- else {
22894
- const templateTranslation = getTranslationForTemplate(message, subTemplateIndex);
22895
- const msgParts = replaceNgsp(templateTranslation).split(PH_REGEXP);
22896
- for (let i = 0; i < msgParts.length; i++) {
22897
- let value = msgParts[i];
22898
- if (i & 1) {
22899
- // Odd indexes are placeholders (elements and sub-templates)
22900
- if (value.charAt(0) === '/') {
22901
- // It is a closing tag
22902
- if (value.charAt(1) === "#" /* ELEMENT */) {
22903
- const phIndex = parseInt(value.substr(2), 10);
22904
- parentIndex = parentIndexStack[--parentIndexPointer];
22905
- createOpCodes.push(phIndex << 3 /* SHIFT_REF */ | 5 /* ElementEnd */);
22620
+ else if (typeof opCode == 'number') {
22621
+ switch (opCode & 7 /* MASK_INSTRUCTION */) {
22622
+ case 1 /* AppendChild */:
22623
+ const destinationNodeIndex = opCode >>> 17 /* SHIFT_PARENT */;
22624
+ let destinationTNode;
22625
+ if (destinationNodeIndex === rootindex) {
22626
+ // If the destination node is `i18nStart`, we don't have a
22627
+ // top-level node and we should use the host node instead
22628
+ destinationTNode = lView[T_HOST];
22906
22629
  }
22907
- }
22908
- else {
22909
- const phIndex = parseInt(value.substr(1), 10);
22910
- const isElement = value.charAt(0) === "#" /* ELEMENT */;
22911
- // The value represents a placeholder that we move to the designated index.
22912
- // Note: positive indicies indicate that a TNode with a given index should also be marked
22913
- // as parent while executing `Select` instruction.
22914
- createOpCodes.push((isElement ? phIndex : ~phIndex) << 3 /* SHIFT_REF */ |
22915
- 0 /* Select */, parentIndex << 17 /* SHIFT_PARENT */ | 1 /* AppendChild */);
22916
- if (isElement) {
22917
- parentIndexStack[++parentIndexPointer] = parentIndex = phIndex;
22630
+ else {
22631
+ destinationTNode = getTNode(tView, destinationNodeIndex);
22918
22632
  }
22919
- }
22633
+ ngDevMode &&
22634
+ assertDefined(currentTNode, `You need to create or select a node before you can insert it into the DOM`);
22635
+ previousTNode =
22636
+ appendI18nNode(tView, currentTNode, destinationTNode, previousTNode, lView);
22637
+ break;
22638
+ case 0 /* Select */:
22639
+ // Negative indices indicate that a given TNode is a sibling node, not a parent node
22640
+ // (see `i18nStartFirstPass` for additional information).
22641
+ const isParent = opCode >= 0;
22642
+ // FIXME(misko): This SHIFT_REF looks suspect as it does not have mask.
22643
+ const nodeIndex = (isParent ? opCode : ~opCode) >>> 3 /* SHIFT_REF */;
22644
+ visitedNodes.push(nodeIndex);
22645
+ previousTNode = currentTNode;
22646
+ currentTNode = getTNode(tView, nodeIndex);
22647
+ if (currentTNode) {
22648
+ setPreviousOrParentTNode(currentTNode, isParent);
22649
+ }
22650
+ break;
22651
+ case 5 /* ElementEnd */:
22652
+ const elementIndex = opCode >>> 3 /* SHIFT_REF */;
22653
+ previousTNode = currentTNode = getTNode(tView, elementIndex);
22654
+ setPreviousOrParentTNode(currentTNode, false);
22655
+ break;
22656
+ case 4 /* Attr */:
22657
+ const elementNodeIndex = opCode >>> 3 /* SHIFT_REF */;
22658
+ const attrName = createOpCodes[++i];
22659
+ const attrValue = createOpCodes[++i];
22660
+ // This code is used for ICU expressions only, since we don't support
22661
+ // directives/components in ICUs, we don't need to worry about inputs here
22662
+ elementAttributeInternal(getTNode(tView, elementNodeIndex), lView, attrName, attrValue, null, null);
22663
+ break;
22664
+ default:
22665
+ throw new Error(`Unable to determine the type of mutate operation for "${opCode}"`);
22920
22666
  }
22921
- else {
22922
- // Even indexes are text (including bindings & ICU expressions)
22923
- const parts = extractParts(value);
22924
- for (let j = 0; j < parts.length; j++) {
22925
- if (j & 1) {
22926
- // Odd indexes are ICU expressions
22927
- const icuExpression = parts[j];
22928
- // Verify that ICU expression has the right shape. Translations might contain invalid
22929
- // constructions (while original messages were correct), so ICU parsing at runtime may
22930
- // not succeed (thus `icuExpression` remains a string).
22931
- if (typeof icuExpression !== 'object') {
22932
- throw new Error(`Unable to parse ICU expression in "${templateTranslation}" message.`);
22933
- }
22934
- // Create the comment node that will anchor the ICU expression
22935
- const icuNodeIndex = allocNodeIndex(startIndex);
22936
- createOpCodes.push(COMMENT_MARKER, ngDevMode ? `ICU ${icuNodeIndex}` : '', icuNodeIndex, parentIndex << 17 /* SHIFT_PARENT */ | 1 /* AppendChild */);
22937
- // Update codes for the ICU expression
22938
- const mask = getBindingMask(icuExpression);
22939
- icuStart(icuExpressions, icuExpression, icuNodeIndex, icuNodeIndex);
22940
- // Since this is recursive, the last TIcu that was pushed is the one we want
22941
- const tIcuIndex = icuExpressions.length - 1;
22942
- updateOpCodes.push(toMaskBit(icuExpression.mainBinding), // mask of the main binding
22943
- 3, // skip 3 opCodes if not changed
22944
- -1 - icuExpression.mainBinding, icuNodeIndex << 2 /* SHIFT_REF */ | 2 /* IcuSwitch */, tIcuIndex, mask, // mask of all the bindings of this ICU expression
22945
- 2, // skip 2 opCodes if not changed
22946
- icuNodeIndex << 2 /* SHIFT_REF */ | 3 /* IcuUpdate */, tIcuIndex);
22667
+ }
22668
+ else {
22669
+ switch (opCode) {
22670
+ case COMMENT_MARKER:
22671
+ const commentValue = createOpCodes[++i];
22672
+ const commentNodeIndex = createOpCodes[++i];
22673
+ ngDevMode &&
22674
+ assertEqual(typeof commentValue, 'string', `Expected "${commentValue}" to be a comment node value`);
22675
+ const commentRNode = renderer.createComment(commentValue);
22676
+ ngDevMode && ngDevMode.rendererCreateComment++;
22677
+ previousTNode = currentTNode;
22678
+ currentTNode = createDynamicNodeAtIndex(tView, lView, commentNodeIndex, 5 /* IcuContainer */, commentRNode, null);
22679
+ visitedNodes.push(commentNodeIndex);
22680
+ attachPatchData(commentRNode, lView);
22681
+ // We will add the case nodes later, during the update phase
22682
+ setIsNotParent();
22683
+ break;
22684
+ case ELEMENT_MARKER:
22685
+ const tagNameValue = createOpCodes[++i];
22686
+ const elementNodeIndex = createOpCodes[++i];
22687
+ ngDevMode &&
22688
+ assertEqual(typeof tagNameValue, 'string', `Expected "${tagNameValue}" to be an element node tag name`);
22689
+ const elementRNode = renderer.createElement(tagNameValue);
22690
+ ngDevMode && ngDevMode.rendererCreateElement++;
22691
+ previousTNode = currentTNode;
22692
+ currentTNode = createDynamicNodeAtIndex(tView, lView, elementNodeIndex, 3 /* Element */, elementRNode, tagNameValue);
22693
+ visitedNodes.push(elementNodeIndex);
22694
+ break;
22695
+ default:
22696
+ throw new Error(`Unable to determine the type of mutate operation for "${opCode}"`);
22697
+ }
22698
+ }
22699
+ }
22700
+ setIsNotParent();
22701
+ return visitedNodes;
22702
+ }
22703
+ /**
22704
+ * Apply `I18nUpdateOpCodes` OpCodes
22705
+ *
22706
+ * @param tView Current `TView`
22707
+ * @param tIcus If ICUs present than this contains them.
22708
+ * @param lView Current `LView`
22709
+ * @param updateOpCodes OpCodes to process
22710
+ * @param bindingsStartIndex Location of the first `ɵɵi18nApply`
22711
+ * @param changeMask Each bit corresponds to a `ɵɵi18nExp` (Counting backwards from
22712
+ * `bindingsStartIndex`)
22713
+ */
22714
+ function applyUpdateOpCodes(tView, tIcus, lView, updateOpCodes, bindingsStartIndex, changeMask) {
22715
+ let caseCreated = false;
22716
+ for (let i = 0; i < updateOpCodes.length; i++) {
22717
+ // bit code to check if we should apply the next update
22718
+ const checkBit = updateOpCodes[i];
22719
+ // Number of opCodes to skip until next set of update codes
22720
+ const skipCodes = updateOpCodes[++i];
22721
+ if (checkBit & changeMask) {
22722
+ // The value has been updated since last checked
22723
+ let value = '';
22724
+ for (let j = i + 1; j <= (i + skipCodes); j++) {
22725
+ const opCode = updateOpCodes[j];
22726
+ if (typeof opCode == 'string') {
22727
+ value += opCode;
22728
+ }
22729
+ else if (typeof opCode == 'number') {
22730
+ if (opCode < 0) {
22731
+ // Negative opCode represent `i18nExp` values offset.
22732
+ value += renderStringify(lView[bindingsStartIndex - opCode]);
22947
22733
  }
22948
- else if (parts[j] !== '') {
22949
- const text = parts[j];
22950
- // Even indexes are text (including bindings)
22951
- const hasBinding = text.match(BINDING_REGEXP);
22952
- // Create text nodes
22953
- const textNodeIndex = allocNodeIndex(startIndex);
22954
- createOpCodes.push(
22955
- // If there is a binding, the value will be set during update
22956
- hasBinding ? '' : text, textNodeIndex, parentIndex << 17 /* SHIFT_PARENT */ | 1 /* AppendChild */);
22957
- if (hasBinding) {
22958
- addAllToArray(generateBindingUpdateOpCodes(text, textNodeIndex), updateOpCodes);
22734
+ else {
22735
+ const nodeIndex = opCode >>> 2 /* SHIFT_REF */;
22736
+ switch (opCode & 3 /* MASK_OPCODE */) {
22737
+ case 1 /* Attr */:
22738
+ const propName = updateOpCodes[++j];
22739
+ const sanitizeFn = updateOpCodes[++j];
22740
+ elementPropertyInternal(tView, getTNode(tView, nodeIndex), lView, propName, value, lView[RENDERER], sanitizeFn, false);
22741
+ break;
22742
+ case 0 /* Text */:
22743
+ textBindingInternal(lView, nodeIndex, value);
22744
+ break;
22745
+ case 2 /* IcuSwitch */:
22746
+ caseCreated =
22747
+ applyIcuSwitchCase(tView, tIcus, updateOpCodes[++j], lView, value);
22748
+ break;
22749
+ case 3 /* IcuUpdate */:
22750
+ applyIcuUpdateCase(tView, tIcus, updateOpCodes[++j], bindingsStartIndex, lView, caseCreated);
22751
+ break;
22959
22752
  }
22960
22753
  }
22961
22754
  }
22962
22755
  }
22963
22756
  }
22757
+ i += skipCodes;
22964
22758
  }
22965
- if (i18nVarsCount > 0) {
22966
- allocExpando(tView, lView, i18nVarsCount);
22759
+ }
22760
+ /**
22761
+ * Apply OpCodes associated with updating an existing ICU.
22762
+ *
22763
+ * @param tView Current `TView`
22764
+ * @param tIcus ICUs active at this location.
22765
+ * @param tIcuIndex Index into `tIcus` to process.
22766
+ * @param bindingsStartIndex Location of the first `ɵɵi18nApply`
22767
+ * @param lView Current `LView`
22768
+ * @param changeMask Each bit corresponds to a `ɵɵi18nExp` (Counting backwards from
22769
+ * `bindingsStartIndex`)
22770
+ */
22771
+ function applyIcuUpdateCase(tView, tIcus, tIcuIndex, bindingsStartIndex, lView, caseCreated) {
22772
+ ngDevMode && assertIndexInRange(tIcus, tIcuIndex);
22773
+ const tIcu = tIcus[tIcuIndex];
22774
+ ngDevMode && assertIndexInRange(lView, tIcu.currentCaseLViewIndex);
22775
+ const activeCaseIndex = lView[tIcu.currentCaseLViewIndex];
22776
+ if (activeCaseIndex !== null) {
22777
+ const mask = caseCreated ?
22778
+ -1 : // -1 is same as all bits on, which simulates creation since it marks all bits dirty
22779
+ changeMask;
22780
+ applyUpdateOpCodes(tView, tIcus, lView, tIcu.update[activeCaseIndex], bindingsStartIndex, mask);
22781
+ }
22782
+ }
22783
+ /**
22784
+ * Apply OpCodes associated with switching a case on ICU.
22785
+ *
22786
+ * This involves tearing down existing case and than building up a new case.
22787
+ *
22788
+ * @param tView Current `TView`
22789
+ * @param tIcus ICUs active at this location.
22790
+ * @param tICuIndex Index into `tIcus` to process.
22791
+ * @param lView Current `LView`
22792
+ * @param value Value of the case to update to.
22793
+ * @returns true if a new case was created (needed so that the update executes regardless of the
22794
+ * bitmask)
22795
+ */
22796
+ function applyIcuSwitchCase(tView, tIcus, tICuIndex, lView, value) {
22797
+ applyIcuSwitchCaseRemove(tView, tIcus, tICuIndex, lView);
22798
+ // Rebuild a new case for this ICU
22799
+ let caseCreated = false;
22800
+ const tIcu = tIcus[tICuIndex];
22801
+ const caseIndex = getCaseIndex(tIcu, value);
22802
+ lView[tIcu.currentCaseLViewIndex] = caseIndex !== -1 ? caseIndex : null;
22803
+ if (caseIndex > -1) {
22804
+ // Add the nodes for the new case
22805
+ applyCreateOpCodes(tView, -1, // -1 means we don't have parent node
22806
+ tIcu.create[caseIndex], lView);
22807
+ caseCreated = true;
22808
+ }
22809
+ return caseCreated;
22810
+ }
22811
+ /**
22812
+ * Apply OpCodes associated with tearing down of DOM.
22813
+ *
22814
+ * This involves tearing down existing case and than building up a new case.
22815
+ *
22816
+ * @param tView Current `TView`
22817
+ * @param tIcus ICUs active at this location.
22818
+ * @param tIcuIndex Index into `tIcus` to process.
22819
+ * @param lView Current `LView`
22820
+ * @returns true if a new case was created (needed so that the update executes regardless of the
22821
+ * bitmask)
22822
+ */
22823
+ function applyIcuSwitchCaseRemove(tView, tIcus, tIcuIndex, lView) {
22824
+ ngDevMode && assertIndexInRange(tIcus, tIcuIndex);
22825
+ const tIcu = tIcus[tIcuIndex];
22826
+ const activeCaseIndex = lView[tIcu.currentCaseLViewIndex];
22827
+ if (activeCaseIndex !== null) {
22828
+ const removeCodes = tIcu.remove[activeCaseIndex];
22829
+ for (let k = 0; k < removeCodes.length; k++) {
22830
+ const removeOpCode = removeCodes[k];
22831
+ const nodeOrIcuIndex = removeOpCode >>> 3 /* SHIFT_REF */;
22832
+ switch (removeOpCode & 7 /* MASK_INSTRUCTION */) {
22833
+ case 3 /* Remove */:
22834
+ // FIXME(misko): this comment is wrong!
22835
+ // Remove DOM element, but do *not* mark TNode as detached, since we are
22836
+ // just switching ICU cases (while keeping the same TNode), so a DOM element
22837
+ // representing a new ICU case will be re-created.
22838
+ removeNode(tView, lView, nodeOrIcuIndex, /* markAsDetached */ false);
22839
+ break;
22840
+ case 6 /* RemoveNestedIcu */:
22841
+ applyIcuSwitchCaseRemove(tView, tIcus, nodeOrIcuIndex, lView);
22842
+ break;
22843
+ }
22844
+ }
22967
22845
  }
22968
- ngDevMode &&
22969
- attachI18nOpCodesDebug(createOpCodes, updateOpCodes, icuExpressions.length ? icuExpressions : null, lView);
22970
- // NOTE: local var needed to properly assert the type of `TI18n`.
22971
- const tI18n = {
22972
- vars: i18nVarsCount,
22973
- create: createOpCodes,
22974
- update: updateOpCodes,
22975
- icus: icuExpressions.length ? icuExpressions : null,
22976
- };
22977
- tView.data[index + HEADER_OFFSET] = tI18n;
22978
22846
  }
22979
22847
  function appendI18nNode(tView, tNode, parentTNode, previousTNode, lView) {
22980
22848
  ngDevMode && ngDevMode.rendererMoveNode++;
@@ -23018,9 +22886,905 @@ function appendI18nNode(tView, tNode, parentTNode, previousTNode, lView) {
23018
22886
  }
23019
22887
  return tNode;
23020
22888
  }
23021
- function isRootTemplateMessage(subTemplateIndex) {
23022
- return subTemplateIndex === undefined;
23023
- }
22889
+ /**
22890
+ * See `i18nEnd` above.
22891
+ */
22892
+ function i18nEndFirstPass(tView, lView) {
22893
+ ngDevMode &&
22894
+ assertEqual(getBindingIndex(), tView.bindingStartIndex, 'i18nEnd should be called before any binding');
22895
+ const rootIndex = popI18nIndex();
22896
+ const tI18n = tView.data[rootIndex + HEADER_OFFSET];
22897
+ ngDevMode && assertDefined(tI18n, `You should call i18nStart before i18nEnd`);
22898
+ // Find the last node that was added before `i18nEnd`
22899
+ const lastCreatedNode = getPreviousOrParentTNode();
22900
+ // Read the instructions to insert/move/remove DOM elements
22901
+ const visitedNodes = applyCreateOpCodes(tView, rootIndex, tI18n.create, lView);
22902
+ // Remove deleted nodes
22903
+ let index = rootIndex + 1;
22904
+ while (index <= lastCreatedNode.index - HEADER_OFFSET) {
22905
+ if (visitedNodes.indexOf(index) === -1) {
22906
+ removeNode(tView, lView, index, /* markAsDetached */ true);
22907
+ }
22908
+ // Check if an element has any local refs and skip them
22909
+ const tNode = getTNode(tView, index);
22910
+ if (tNode &&
22911
+ (tNode.type === 0 /* Container */ || tNode.type === 3 /* Element */ ||
22912
+ tNode.type === 4 /* ElementContainer */) &&
22913
+ tNode.localNames !== null) {
22914
+ // Divide by 2 to get the number of local refs,
22915
+ // since they are stored as an array that also includes directive indexes,
22916
+ // i.e. ["localRef", directiveIndex, ...]
22917
+ index += tNode.localNames.length >> 1;
22918
+ }
22919
+ index++;
22920
+ }
22921
+ }
22922
+ function removeNode(tView, lView, index, markAsDetached) {
22923
+ const removedPhTNode = getTNode(tView, index);
22924
+ const removedPhRNode = getNativeByIndex(index, lView);
22925
+ if (removedPhRNode) {
22926
+ nativeRemoveNode(lView[RENDERER], removedPhRNode);
22927
+ }
22928
+ const slotValue = load(lView, index);
22929
+ if (isLContainer(slotValue)) {
22930
+ const lContainer = slotValue;
22931
+ if (removedPhTNode.type !== 0 /* Container */) {
22932
+ nativeRemoveNode(lView[RENDERER], lContainer[NATIVE]);
22933
+ }
22934
+ }
22935
+ if (markAsDetached) {
22936
+ // Define this node as detached to avoid projecting it later
22937
+ removedPhTNode.flags |= 64 /* isDetached */;
22938
+ }
22939
+ ngDevMode && ngDevMode.rendererRemoveNode++;
22940
+ }
22941
+ /**
22942
+ * Creates and stores the dynamic TNode, and unhooks it from the tree for now.
22943
+ */
22944
+ function createDynamicNodeAtIndex(tView, lView, index, type, native, name) {
22945
+ const previousOrParentTNode = getPreviousOrParentTNode();
22946
+ ngDevMode && assertIndexInRange(lView, index + HEADER_OFFSET);
22947
+ lView[index + HEADER_OFFSET] = native;
22948
+ // FIXME(misko): Why does this create A TNode??? I would not expect this to be here.
22949
+ const tNode = getOrCreateTNode(tView, lView[T_HOST], index, type, name, null);
22950
+ // We are creating a dynamic node, the previous tNode might not be pointing at this node.
22951
+ // We will link ourselves into the tree later with `appendI18nNode`.
22952
+ if (previousOrParentTNode && previousOrParentTNode.next === tNode) {
22953
+ previousOrParentTNode.next = null;
22954
+ }
22955
+ return tNode;
22956
+ }
22957
+ /**
22958
+ * Returns the index of the current case of an ICU expression depending on the main binding value
22959
+ *
22960
+ * @param icuExpression
22961
+ * @param bindingValue The value of the main binding used by this ICU expression
22962
+ */
22963
+ function getCaseIndex(icuExpression, bindingValue) {
22964
+ let index = icuExpression.cases.indexOf(bindingValue);
22965
+ if (index === -1) {
22966
+ switch (icuExpression.type) {
22967
+ case 1 /* plural */: {
22968
+ const resolvedCase = getPluralCase(bindingValue, getLocaleId());
22969
+ index = icuExpression.cases.indexOf(resolvedCase);
22970
+ if (index === -1 && resolvedCase !== 'other') {
22971
+ index = icuExpression.cases.indexOf('other');
22972
+ }
22973
+ break;
22974
+ }
22975
+ case 0 /* select */: {
22976
+ index = icuExpression.cases.indexOf('other');
22977
+ break;
22978
+ }
22979
+ }
22980
+ }
22981
+ return index;
22982
+ }
22983
+
22984
+ /**
22985
+ * @license
22986
+ * Copyright Google LLC All Rights Reserved.
22987
+ *
22988
+ * Use of this source code is governed by an MIT-style license that can be
22989
+ * found in the LICENSE file at https://angular.io/license
22990
+ */
22991
+ /**
22992
+ * Converts `I18nUpdateOpCodes` array into a human readable format.
22993
+ *
22994
+ * This function is attached to the `I18nUpdateOpCodes.debug` property if `ngDevMode` is enabled.
22995
+ * This function provides a human readable view of the opcodes. This is useful when debugging the
22996
+ * application as well as writing more readable tests.
22997
+ *
22998
+ * @param this `I18nUpdateOpCodes` if attached as a method.
22999
+ * @param opcodes `I18nUpdateOpCodes` if invoked as a function.
23000
+ */
23001
+ function i18nUpdateOpCodesToString(opcodes) {
23002
+ const parser = new OpCodeParser(opcodes || (Array.isArray(this) ? this : []));
23003
+ let lines = [];
23004
+ function consumeOpCode(value) {
23005
+ const ref = value >>> 2 /* SHIFT_REF */;
23006
+ const opCode = value & 3 /* MASK_OPCODE */;
23007
+ switch (opCode) {
23008
+ case 0 /* Text */:
23009
+ return `(lView[${ref}] as Text).textContent = $$$`;
23010
+ case 1 /* Attr */:
23011
+ const attrName = parser.consumeString();
23012
+ const sanitizationFn = parser.consumeFunction();
23013
+ const value = sanitizationFn ? `(${sanitizationFn})($$$)` : '$$$';
23014
+ return `(lView[${ref}] as Element).setAttribute('${attrName}', ${value})`;
23015
+ case 2 /* IcuSwitch */:
23016
+ return `icuSwitchCase(lView[${ref}] as Comment, ${parser.consumeNumber()}, $$$)`;
23017
+ case 3 /* IcuUpdate */:
23018
+ return `icuUpdateCase(lView[${ref}] as Comment, ${parser.consumeNumber()})`;
23019
+ }
23020
+ throw new Error('unexpected OpCode');
23021
+ }
23022
+ while (parser.hasMore()) {
23023
+ let mask = parser.consumeNumber();
23024
+ let size = parser.consumeNumber();
23025
+ const end = parser.i + size;
23026
+ const statements = [];
23027
+ let statement = '';
23028
+ while (parser.i < end) {
23029
+ let value = parser.consumeNumberOrString();
23030
+ if (typeof value === 'string') {
23031
+ statement += value;
23032
+ }
23033
+ else if (value < 0) {
23034
+ // Negative numbers are ref indexes
23035
+ statement += '${lView[' + (0 - value) + ']}';
23036
+ }
23037
+ else {
23038
+ // Positive numbers are operations.
23039
+ const opCodeText = consumeOpCode(value);
23040
+ statements.push(opCodeText.replace('$$$', '`' + statement + '`') + ';');
23041
+ statement = '';
23042
+ }
23043
+ }
23044
+ lines.push(`if (mask & 0b${mask.toString(2)}) { ${statements.join(' ')} }`);
23045
+ }
23046
+ return lines;
23047
+ }
23048
+ /**
23049
+ * Converts `I18nMutableOpCodes` array into a human readable format.
23050
+ *
23051
+ * This function is attached to the `I18nMutableOpCodes.debug` if `ngDevMode` is enabled. This
23052
+ * function provides a human readable view of the opcodes. This is useful when debugging the
23053
+ * application as well as writing more readable tests.
23054
+ *
23055
+ * @param this `I18nMutableOpCodes` if attached as a method.
23056
+ * @param opcodes `I18nMutableOpCodes` if invoked as a function.
23057
+ */
23058
+ function i18nMutateOpCodesToString(opcodes) {
23059
+ const parser = new OpCodeParser(opcodes || (Array.isArray(this) ? this : []));
23060
+ let lines = [];
23061
+ function consumeOpCode(opCode) {
23062
+ const parent = getParentFromI18nMutateOpCode(opCode);
23063
+ const ref = getRefFromI18nMutateOpCode(opCode);
23064
+ switch (getInstructionFromI18nMutateOpCode(opCode)) {
23065
+ case 0 /* Select */:
23066
+ lastRef = ref;
23067
+ return '';
23068
+ case 1 /* AppendChild */:
23069
+ return `(lView[${parent}] as Element).appendChild(lView[${lastRef}])`;
23070
+ case 3 /* Remove */:
23071
+ return `(lView[${parent}] as Element).remove(lView[${ref}])`;
23072
+ case 4 /* Attr */:
23073
+ return `(lView[${ref}] as Element).setAttribute("${parser.consumeString()}", "${parser.consumeString()}")`;
23074
+ case 5 /* ElementEnd */:
23075
+ return `setPreviousOrParentTNode(tView.data[${ref}] as TNode)`;
23076
+ case 6 /* RemoveNestedIcu */:
23077
+ return `removeNestedICU(${ref})`;
23078
+ }
23079
+ throw new Error('Unexpected OpCode');
23080
+ }
23081
+ let lastRef = -1;
23082
+ while (parser.hasMore()) {
23083
+ let value = parser.consumeNumberStringOrMarker();
23084
+ if (value === COMMENT_MARKER) {
23085
+ const text = parser.consumeString();
23086
+ lastRef = parser.consumeNumber();
23087
+ lines.push(`lView[${lastRef}] = document.createComment("${text}")`);
23088
+ }
23089
+ else if (value === ELEMENT_MARKER) {
23090
+ const text = parser.consumeString();
23091
+ lastRef = parser.consumeNumber();
23092
+ lines.push(`lView[${lastRef}] = document.createElement("${text}")`);
23093
+ }
23094
+ else if (typeof value === 'string') {
23095
+ lastRef = parser.consumeNumber();
23096
+ lines.push(`lView[${lastRef}] = document.createTextNode("${value}")`);
23097
+ }
23098
+ else if (typeof value === 'number') {
23099
+ const line = consumeOpCode(value);
23100
+ line && lines.push(line);
23101
+ }
23102
+ else {
23103
+ throw new Error('Unexpected value');
23104
+ }
23105
+ }
23106
+ return lines;
23107
+ }
23108
+ class OpCodeParser {
23109
+ constructor(codes) {
23110
+ this.i = 0;
23111
+ this.codes = codes;
23112
+ }
23113
+ hasMore() {
23114
+ return this.i < this.codes.length;
23115
+ }
23116
+ consumeNumber() {
23117
+ let value = this.codes[this.i++];
23118
+ assertNumber(value, 'expecting number in OpCode');
23119
+ return value;
23120
+ }
23121
+ consumeString() {
23122
+ let value = this.codes[this.i++];
23123
+ assertString(value, 'expecting string in OpCode');
23124
+ return value;
23125
+ }
23126
+ consumeFunction() {
23127
+ let value = this.codes[this.i++];
23128
+ if (value === null || typeof value === 'function') {
23129
+ return value;
23130
+ }
23131
+ throw new Error('expecting function in OpCode');
23132
+ }
23133
+ consumeNumberOrString() {
23134
+ let value = this.codes[this.i++];
23135
+ if (typeof value === 'string') {
23136
+ return value;
23137
+ }
23138
+ assertNumber(value, 'expecting number or string in OpCode');
23139
+ return value;
23140
+ }
23141
+ consumeNumberStringOrMarker() {
23142
+ let value = this.codes[this.i++];
23143
+ if (typeof value === 'string' || typeof value === 'number' || value == COMMENT_MARKER ||
23144
+ value == ELEMENT_MARKER) {
23145
+ return value;
23146
+ }
23147
+ assertNumber(value, 'expecting number, string, COMMENT_MARKER or ELEMENT_MARKER in OpCode');
23148
+ return value;
23149
+ }
23150
+ }
23151
+
23152
+ /**
23153
+ * @license
23154
+ * Copyright Google LLC All Rights Reserved.
23155
+ *
23156
+ * Use of this source code is governed by an MIT-style license that can be
23157
+ * found in the LICENSE file at https://angular.io/license
23158
+ */
23159
+ const BINDING_REGEXP = /�(\d+):?\d*�/gi;
23160
+ const ICU_REGEXP = /({\s*�\d+:?\d*�\s*,\s*\S{6}\s*,[\s\S]*})/gi;
23161
+ const NESTED_ICU = /�(\d+)�/;
23162
+ const ICU_BLOCK_REGEXP = /^\s*(�\d+:?\d*�)\s*,\s*(select|plural)\s*,/;
23163
+ // Count for the number of vars that will be allocated for each i18n block.
23164
+ // It is global because this is used in multiple functions that include loops and recursive calls.
23165
+ // This is reset to 0 when `i18nStartFirstPass` is called.
23166
+ let i18nVarsCount;
23167
+ const parentIndexStack = [];
23168
+ const MARKER = `�`;
23169
+ const SUBTEMPLATE_REGEXP = /�\/?\*(\d+:\d+)�/gi;
23170
+ const PH_REGEXP = /�(\/?[#*!]\d+):?\d*�/gi;
23171
+ /**
23172
+ * Angular Dart introduced &ngsp; as a placeholder for non-removable space, see:
23173
+ * https://github.com/dart-lang/angular/blob/0bb611387d29d65b5af7f9d2515ab571fd3fbee4/_tests/test/compiler/preserve_whitespace_test.dart#L25-L32
23174
+ * In Angular Dart &ngsp; is converted to the 0xE500 PUA (Private Use Areas) unicode character
23175
+ * and later on replaced by a space. We are re-implementing the same idea here, since translations
23176
+ * might contain this special character.
23177
+ */
23178
+ const NGSP_UNICODE_REGEXP = /\uE500/g;
23179
+ function replaceNgsp(value) {
23180
+ return value.replace(NGSP_UNICODE_REGEXP, ' ');
23181
+ }
23182
+ /**
23183
+ * See `i18nStart` above.
23184
+ */
23185
+ function i18nStartFirstPass(lView, tView, index, message, subTemplateIndex) {
23186
+ const startIndex = tView.blueprint.length - HEADER_OFFSET;
23187
+ i18nVarsCount = 0;
23188
+ const previousOrParentTNode = getPreviousOrParentTNode();
23189
+ const parentTNode = getIsParent() ? previousOrParentTNode : previousOrParentTNode && previousOrParentTNode.parent;
23190
+ let parentIndex = parentTNode && parentTNode !== lView[T_HOST] ? parentTNode.index - HEADER_OFFSET : index;
23191
+ let parentIndexPointer = 0;
23192
+ parentIndexStack[parentIndexPointer] = parentIndex;
23193
+ const createOpCodes = [];
23194
+ if (ngDevMode) {
23195
+ attachDebugGetter(createOpCodes, i18nMutateOpCodesToString);
23196
+ }
23197
+ // If the previous node wasn't the direct parent then we have a translation without top level
23198
+ // element and we need to keep a reference of the previous element if there is one. We should also
23199
+ // keep track whether an element was a parent node or not, so that the logic that consumes
23200
+ // the generated `I18nMutateOpCode`s can leverage this information to properly set TNode state
23201
+ // (whether it's a parent or sibling).
23202
+ if (index > 0 && previousOrParentTNode !== parentTNode) {
23203
+ let previousTNodeIndex = previousOrParentTNode.index - HEADER_OFFSET;
23204
+ // If current TNode is a sibling node, encode it using a negative index. This information is
23205
+ // required when the `Select` action is processed (see the `readCreateOpCodes` function).
23206
+ if (!getIsParent()) {
23207
+ previousTNodeIndex = ~previousTNodeIndex;
23208
+ }
23209
+ // Create an OpCode to select the previous TNode
23210
+ createOpCodes.push(previousTNodeIndex << 3 /* SHIFT_REF */ | 0 /* Select */);
23211
+ }
23212
+ const updateOpCodes = [];
23213
+ if (ngDevMode) {
23214
+ attachDebugGetter(updateOpCodes, i18nUpdateOpCodesToString);
23215
+ }
23216
+ const icuExpressions = [];
23217
+ if (message === '' && isRootTemplateMessage(subTemplateIndex)) {
23218
+ // If top level translation is an empty string, do not invoke additional processing
23219
+ // and just create op codes for empty text node instead.
23220
+ createOpCodes.push(message, allocNodeIndex(startIndex), parentIndex << 17 /* SHIFT_PARENT */ | 1 /* AppendChild */);
23221
+ }
23222
+ else {
23223
+ const templateTranslation = getTranslationForTemplate(message, subTemplateIndex);
23224
+ const msgParts = replaceNgsp(templateTranslation).split(PH_REGEXP);
23225
+ for (let i = 0; i < msgParts.length; i++) {
23226
+ let value = msgParts[i];
23227
+ if (i & 1) {
23228
+ // Odd indexes are placeholders (elements and sub-templates)
23229
+ if (value.charAt(0) === '/') {
23230
+ // It is a closing tag
23231
+ if (value.charAt(1) === "#" /* ELEMENT */) {
23232
+ const phIndex = parseInt(value.substr(2), 10);
23233
+ parentIndex = parentIndexStack[--parentIndexPointer];
23234
+ createOpCodes.push(phIndex << 3 /* SHIFT_REF */ | 5 /* ElementEnd */);
23235
+ }
23236
+ }
23237
+ else {
23238
+ const phIndex = parseInt(value.substr(1), 10);
23239
+ const isElement = value.charAt(0) === "#" /* ELEMENT */;
23240
+ // The value represents a placeholder that we move to the designated index.
23241
+ // Note: positive indicies indicate that a TNode with a given index should also be marked
23242
+ // as parent while executing `Select` instruction.
23243
+ createOpCodes.push((isElement ? phIndex : ~phIndex) << 3 /* SHIFT_REF */ |
23244
+ 0 /* Select */, parentIndex << 17 /* SHIFT_PARENT */ | 1 /* AppendChild */);
23245
+ if (isElement) {
23246
+ parentIndexStack[++parentIndexPointer] = parentIndex = phIndex;
23247
+ }
23248
+ }
23249
+ }
23250
+ else {
23251
+ // Even indexes are text (including bindings & ICU expressions)
23252
+ const parts = extractParts(value);
23253
+ for (let j = 0; j < parts.length; j++) {
23254
+ if (j & 1) {
23255
+ // Odd indexes are ICU expressions
23256
+ const icuExpression = parts[j];
23257
+ // Verify that ICU expression has the right shape. Translations might contain invalid
23258
+ // constructions (while original messages were correct), so ICU parsing at runtime may
23259
+ // not succeed (thus `icuExpression` remains a string).
23260
+ if (typeof icuExpression !== 'object') {
23261
+ throw new Error(`Unable to parse ICU expression in "${templateTranslation}" message.`);
23262
+ }
23263
+ // Create the comment node that will anchor the ICU expression
23264
+ const icuNodeIndex = allocNodeIndex(startIndex);
23265
+ createOpCodes.push(COMMENT_MARKER, ngDevMode ? `ICU ${icuNodeIndex}` : '', icuNodeIndex, parentIndex << 17 /* SHIFT_PARENT */ | 1 /* AppendChild */);
23266
+ // Update codes for the ICU expression
23267
+ const mask = getBindingMask(icuExpression);
23268
+ icuStart(icuExpressions, icuExpression, icuNodeIndex, icuNodeIndex);
23269
+ // Since this is recursive, the last TIcu that was pushed is the one we want
23270
+ const tIcuIndex = icuExpressions.length - 1;
23271
+ updateOpCodes.push(toMaskBit(icuExpression.mainBinding), // mask of the main binding
23272
+ 3, // skip 3 opCodes if not changed
23273
+ -1 - icuExpression.mainBinding, icuNodeIndex << 2 /* SHIFT_REF */ | 2 /* IcuSwitch */, tIcuIndex, mask, // mask of all the bindings of this ICU expression
23274
+ 2, // skip 2 opCodes if not changed
23275
+ icuNodeIndex << 2 /* SHIFT_REF */ | 3 /* IcuUpdate */, tIcuIndex);
23276
+ }
23277
+ else if (parts[j] !== '') {
23278
+ const text = parts[j];
23279
+ // Even indexes are text (including bindings)
23280
+ const hasBinding = text.match(BINDING_REGEXP);
23281
+ // Create text nodes
23282
+ const textNodeIndex = allocNodeIndex(startIndex);
23283
+ createOpCodes.push(
23284
+ // If there is a binding, the value will be set during update
23285
+ hasBinding ? '' : text, textNodeIndex, parentIndex << 17 /* SHIFT_PARENT */ | 1 /* AppendChild */);
23286
+ if (hasBinding) {
23287
+ addAllToArray(generateBindingUpdateOpCodes(text, textNodeIndex), updateOpCodes);
23288
+ }
23289
+ }
23290
+ }
23291
+ }
23292
+ }
23293
+ }
23294
+ if (i18nVarsCount > 0) {
23295
+ allocExpando(tView, lView, i18nVarsCount);
23296
+ }
23297
+ // NOTE: local var needed to properly assert the type of `TI18n`.
23298
+ const tI18n = {
23299
+ vars: i18nVarsCount,
23300
+ create: createOpCodes,
23301
+ update: updateOpCodes,
23302
+ icus: icuExpressions.length ? icuExpressions : null,
23303
+ };
23304
+ tView.data[index + HEADER_OFFSET] = tI18n;
23305
+ }
23306
+ /**
23307
+ * See `i18nAttributes` above.
23308
+ */
23309
+ function i18nAttributesFirstPass(lView, tView, index, values) {
23310
+ const previousElement = getPreviousOrParentTNode();
23311
+ const previousElementIndex = previousElement.index - HEADER_OFFSET;
23312
+ const updateOpCodes = [];
23313
+ if (ngDevMode) {
23314
+ attachDebugGetter(updateOpCodes, i18nUpdateOpCodesToString);
23315
+ }
23316
+ for (let i = 0; i < values.length; i += 2) {
23317
+ const attrName = values[i];
23318
+ const message = values[i + 1];
23319
+ const parts = message.split(ICU_REGEXP);
23320
+ for (let j = 0; j < parts.length; j++) {
23321
+ const value = parts[j];
23322
+ if (j & 1) {
23323
+ // Odd indexes are ICU expressions
23324
+ // TODO(ocombe): support ICU expressions in attributes
23325
+ throw new Error('ICU expressions are not yet supported in attributes');
23326
+ }
23327
+ else if (value !== '') {
23328
+ // Even indexes are text (including bindings)
23329
+ const hasBinding = !!value.match(BINDING_REGEXP);
23330
+ if (hasBinding) {
23331
+ if (tView.firstCreatePass && tView.data[index + HEADER_OFFSET] === null) {
23332
+ addAllToArray(generateBindingUpdateOpCodes(value, previousElementIndex, attrName), updateOpCodes);
23333
+ }
23334
+ }
23335
+ else {
23336
+ const tNode = getTNode(tView, previousElementIndex);
23337
+ // Set attributes for Elements only, for other types (like ElementContainer),
23338
+ // only set inputs below
23339
+ if (tNode.type === 3 /* Element */) {
23340
+ elementAttributeInternal(tNode, lView, attrName, value, null, null);
23341
+ }
23342
+ // Check if that attribute is a directive input
23343
+ const dataValue = tNode.inputs !== null && tNode.inputs[attrName];
23344
+ if (dataValue) {
23345
+ setInputsForProperty(tView, lView, dataValue, attrName, value);
23346
+ if (ngDevMode) {
23347
+ const element = getNativeByIndex(previousElementIndex, lView);
23348
+ setNgReflectProperties(lView, element, tNode.type, dataValue, value);
23349
+ }
23350
+ }
23351
+ }
23352
+ }
23353
+ }
23354
+ }
23355
+ if (tView.firstCreatePass && tView.data[index + HEADER_OFFSET] === null) {
23356
+ tView.data[index + HEADER_OFFSET] = updateOpCodes;
23357
+ }
23358
+ }
23359
+ /**
23360
+ * Generate the OpCodes to update the bindings of a string.
23361
+ *
23362
+ * @param str The string containing the bindings.
23363
+ * @param destinationNode Index of the destination node which will receive the binding.
23364
+ * @param attrName Name of the attribute, if the string belongs to an attribute.
23365
+ * @param sanitizeFn Sanitization function used to sanitize the string after update, if necessary.
23366
+ */
23367
+ function generateBindingUpdateOpCodes(str, destinationNode, attrName, sanitizeFn = null) {
23368
+ const updateOpCodes = [null, null]; // Alloc space for mask and size
23369
+ if (ngDevMode) {
23370
+ attachDebugGetter(updateOpCodes, i18nUpdateOpCodesToString);
23371
+ }
23372
+ const textParts = str.split(BINDING_REGEXP);
23373
+ let mask = 0;
23374
+ for (let j = 0; j < textParts.length; j++) {
23375
+ const textValue = textParts[j];
23376
+ if (j & 1) {
23377
+ // Odd indexes are bindings
23378
+ const bindingIndex = parseInt(textValue, 10);
23379
+ updateOpCodes.push(-1 - bindingIndex);
23380
+ mask = mask | toMaskBit(bindingIndex);
23381
+ }
23382
+ else if (textValue !== '') {
23383
+ // Even indexes are text
23384
+ updateOpCodes.push(textValue);
23385
+ }
23386
+ }
23387
+ updateOpCodes.push(destinationNode << 2 /* SHIFT_REF */ |
23388
+ (attrName ? 1 /* Attr */ : 0 /* Text */));
23389
+ if (attrName) {
23390
+ updateOpCodes.push(attrName, sanitizeFn);
23391
+ }
23392
+ updateOpCodes[0] = mask;
23393
+ updateOpCodes[1] = updateOpCodes.length - 2;
23394
+ return updateOpCodes;
23395
+ }
23396
+ function getBindingMask(icuExpression, mask = 0) {
23397
+ mask = mask | toMaskBit(icuExpression.mainBinding);
23398
+ let match;
23399
+ for (let i = 0; i < icuExpression.values.length; i++) {
23400
+ const valueArr = icuExpression.values[i];
23401
+ for (let j = 0; j < valueArr.length; j++) {
23402
+ const value = valueArr[j];
23403
+ if (typeof value === 'string') {
23404
+ while (match = BINDING_REGEXP.exec(value)) {
23405
+ mask = mask | toMaskBit(parseInt(match[1], 10));
23406
+ }
23407
+ }
23408
+ else {
23409
+ mask = getBindingMask(value, mask);
23410
+ }
23411
+ }
23412
+ }
23413
+ return mask;
23414
+ }
23415
+ function allocNodeIndex(startIndex) {
23416
+ return startIndex + i18nVarsCount++;
23417
+ }
23418
+ /**
23419
+ * Convert binding index to mask bit.
23420
+ *
23421
+ * Each index represents a single bit on the bit-mask. Because bit-mask only has 32 bits, we make
23422
+ * the 32nd bit share all masks for all bindings higher than 32. Since it is extremely rare to have
23423
+ * more than 32 bindings this will be hit very rarely. The downside of hitting this corner case is
23424
+ * that we will execute binding code more often than necessary. (penalty of performance)
23425
+ */
23426
+ function toMaskBit(bindingIndex) {
23427
+ return 1 << Math.min(bindingIndex, 31);
23428
+ }
23429
+ function isRootTemplateMessage(subTemplateIndex) {
23430
+ return subTemplateIndex === undefined;
23431
+ }
23432
+ /**
23433
+ * Removes everything inside the sub-templates of a message.
23434
+ */
23435
+ function removeInnerTemplateTranslation(message) {
23436
+ let match;
23437
+ let res = '';
23438
+ let index = 0;
23439
+ let inTemplate = false;
23440
+ let tagMatched;
23441
+ while ((match = SUBTEMPLATE_REGEXP.exec(message)) !== null) {
23442
+ if (!inTemplate) {
23443
+ res += message.substring(index, match.index + match[0].length);
23444
+ tagMatched = match[1];
23445
+ inTemplate = true;
23446
+ }
23447
+ else {
23448
+ if (match[0] === `${MARKER}/*${tagMatched}${MARKER}`) {
23449
+ index = match.index;
23450
+ inTemplate = false;
23451
+ }
23452
+ }
23453
+ }
23454
+ ngDevMode &&
23455
+ assertEqual(inTemplate, false, `Tag mismatch: unable to find the end of the sub-template in the translation "${message}"`);
23456
+ res += message.substr(index);
23457
+ return res;
23458
+ }
23459
+ /**
23460
+ * Extracts a part of a message and removes the rest.
23461
+ *
23462
+ * This method is used for extracting a part of the message associated with a template. A translated
23463
+ * message can span multiple templates.
23464
+ *
23465
+ * Example:
23466
+ * ```
23467
+ * <div i18n>Translate <span *ngIf>me</span>!</div>
23468
+ * ```
23469
+ *
23470
+ * @param message The message to crop
23471
+ * @param subTemplateIndex Index of the sub-template to extract. If undefined it returns the
23472
+ * external template and removes all sub-templates.
23473
+ */
23474
+ function getTranslationForTemplate(message, subTemplateIndex) {
23475
+ if (isRootTemplateMessage(subTemplateIndex)) {
23476
+ // We want the root template message, ignore all sub-templates
23477
+ return removeInnerTemplateTranslation(message);
23478
+ }
23479
+ else {
23480
+ // We want a specific sub-template
23481
+ const start = message.indexOf(`:${subTemplateIndex}${MARKER}`) + 2 + subTemplateIndex.toString().length;
23482
+ const end = message.search(new RegExp(`${MARKER}\\/\\*\\d+:${subTemplateIndex}${MARKER}`));
23483
+ return removeInnerTemplateTranslation(message.substring(start, end));
23484
+ }
23485
+ }
23486
+ /**
23487
+ * Generate the OpCodes for ICU expressions.
23488
+ *
23489
+ * @param tIcus
23490
+ * @param icuExpression
23491
+ * @param startIndex
23492
+ * @param expandoStartIndex
23493
+ */
23494
+ function icuStart(tIcus, icuExpression, startIndex, expandoStartIndex) {
23495
+ const createCodes = [];
23496
+ const removeCodes = [];
23497
+ const updateCodes = [];
23498
+ const vars = [];
23499
+ const childIcus = [];
23500
+ const values = icuExpression.values;
23501
+ for (let i = 0; i < values.length; i++) {
23502
+ // Each value is an array of strings & other ICU expressions
23503
+ const valueArr = values[i];
23504
+ const nestedIcus = [];
23505
+ for (let j = 0; j < valueArr.length; j++) {
23506
+ const value = valueArr[j];
23507
+ if (typeof value !== 'string') {
23508
+ // It is an nested ICU expression
23509
+ const icuIndex = nestedIcus.push(value) - 1;
23510
+ // Replace nested ICU expression by a comment node
23511
+ valueArr[j] = `<!--�${icuIndex}�-->`;
23512
+ }
23513
+ }
23514
+ const icuCase = parseIcuCase(valueArr.join(''), startIndex, nestedIcus, tIcus, expandoStartIndex);
23515
+ createCodes.push(icuCase.create);
23516
+ removeCodes.push(icuCase.remove);
23517
+ updateCodes.push(icuCase.update);
23518
+ vars.push(icuCase.vars);
23519
+ childIcus.push(icuCase.childIcus);
23520
+ }
23521
+ const tIcu = {
23522
+ type: icuExpression.type,
23523
+ vars,
23524
+ currentCaseLViewIndex: HEADER_OFFSET +
23525
+ expandoStartIndex // expandoStartIndex does not include the header so add it.
23526
+ + 1,
23527
+ childIcus,
23528
+ cases: icuExpression.cases,
23529
+ create: createCodes,
23530
+ remove: removeCodes,
23531
+ update: updateCodes
23532
+ };
23533
+ tIcus.push(tIcu);
23534
+ // Adding the maximum possible of vars needed (based on the cases with the most vars)
23535
+ i18nVarsCount += Math.max(...vars);
23536
+ }
23537
+ /**
23538
+ * Parses text containing an ICU expression and produces a JSON object for it.
23539
+ * Original code from closure library, modified for Angular.
23540
+ *
23541
+ * @param pattern Text containing an ICU expression that needs to be parsed.
23542
+ *
23543
+ */
23544
+ function parseICUBlock(pattern) {
23545
+ const cases = [];
23546
+ const values = [];
23547
+ let icuType = 1 /* plural */;
23548
+ let mainBinding = 0;
23549
+ pattern = pattern.replace(ICU_BLOCK_REGEXP, function (str, binding, type) {
23550
+ if (type === 'select') {
23551
+ icuType = 0 /* select */;
23552
+ }
23553
+ else {
23554
+ icuType = 1 /* plural */;
23555
+ }
23556
+ mainBinding = parseInt(binding.substr(1), 10);
23557
+ return '';
23558
+ });
23559
+ const parts = extractParts(pattern);
23560
+ // Looking for (key block)+ sequence. One of the keys has to be "other".
23561
+ for (let pos = 0; pos < parts.length;) {
23562
+ let key = parts[pos++].trim();
23563
+ if (icuType === 1 /* plural */) {
23564
+ // Key can be "=x", we just want "x"
23565
+ key = key.replace(/\s*(?:=)?(\w+)\s*/, '$1');
23566
+ }
23567
+ if (key.length) {
23568
+ cases.push(key);
23569
+ }
23570
+ const blocks = extractParts(parts[pos++]);
23571
+ if (cases.length > values.length) {
23572
+ values.push(blocks);
23573
+ }
23574
+ }
23575
+ // TODO(ocombe): support ICU expressions in attributes, see #21615
23576
+ return { type: icuType, mainBinding: mainBinding, cases, values };
23577
+ }
23578
+ /**
23579
+ * Transforms a string template into an HTML template and a list of instructions used to update
23580
+ * attributes or nodes that contain bindings.
23581
+ *
23582
+ * @param unsafeHtml The string to parse
23583
+ * @param parentIndex
23584
+ * @param nestedIcus
23585
+ * @param tIcus
23586
+ * @param expandoStartIndex
23587
+ */
23588
+ function parseIcuCase(unsafeHtml, parentIndex, nestedIcus, tIcus, expandoStartIndex) {
23589
+ const inertBodyHelper = getInertBodyHelper(getDocument());
23590
+ const inertBodyElement = inertBodyHelper.getInertBodyElement(unsafeHtml);
23591
+ if (!inertBodyElement) {
23592
+ throw new Error('Unable to generate inert body element');
23593
+ }
23594
+ const wrapper = getTemplateContent(inertBodyElement) || inertBodyElement;
23595
+ const opCodes = {
23596
+ vars: 1,
23597
+ childIcus: [],
23598
+ create: [],
23599
+ remove: [],
23600
+ update: []
23601
+ };
23602
+ if (ngDevMode) {
23603
+ attachDebugGetter(opCodes.create, i18nMutateOpCodesToString);
23604
+ attachDebugGetter(opCodes.remove, i18nMutateOpCodesToString);
23605
+ attachDebugGetter(opCodes.update, i18nUpdateOpCodesToString);
23606
+ }
23607
+ parseNodes(wrapper.firstChild, opCodes, parentIndex, nestedIcus, tIcus, expandoStartIndex);
23608
+ return opCodes;
23609
+ }
23610
+ /**
23611
+ * Breaks pattern into strings and top level {...} blocks.
23612
+ * Can be used to break a message into text and ICU expressions, or to break an ICU expression into
23613
+ * keys and cases.
23614
+ * Original code from closure library, modified for Angular.
23615
+ *
23616
+ * @param pattern (sub)Pattern to be broken.
23617
+ *
23618
+ */
23619
+ function extractParts(pattern) {
23620
+ if (!pattern) {
23621
+ return [];
23622
+ }
23623
+ let prevPos = 0;
23624
+ const braceStack = [];
23625
+ const results = [];
23626
+ const braces = /[{}]/g;
23627
+ // lastIndex doesn't get set to 0 so we have to.
23628
+ braces.lastIndex = 0;
23629
+ let match;
23630
+ while (match = braces.exec(pattern)) {
23631
+ const pos = match.index;
23632
+ if (match[0] == '}') {
23633
+ braceStack.pop();
23634
+ if (braceStack.length == 0) {
23635
+ // End of the block.
23636
+ const block = pattern.substring(prevPos, pos);
23637
+ if (ICU_BLOCK_REGEXP.test(block)) {
23638
+ results.push(parseICUBlock(block));
23639
+ }
23640
+ else {
23641
+ results.push(block);
23642
+ }
23643
+ prevPos = pos + 1;
23644
+ }
23645
+ }
23646
+ else {
23647
+ if (braceStack.length == 0) {
23648
+ const substring = pattern.substring(prevPos, pos);
23649
+ results.push(substring);
23650
+ prevPos = pos + 1;
23651
+ }
23652
+ braceStack.push('{');
23653
+ }
23654
+ }
23655
+ const substring = pattern.substring(prevPos);
23656
+ results.push(substring);
23657
+ return results;
23658
+ }
23659
+ /**
23660
+ * Parses a node, its children and its siblings, and generates the mutate & update OpCodes.
23661
+ *
23662
+ * @param currentNode The first node to parse
23663
+ * @param icuCase The data for the ICU expression case that contains those nodes
23664
+ * @param parentIndex Index of the current node's parent
23665
+ * @param nestedIcus Data for the nested ICU expressions that this case contains
23666
+ * @param tIcus Data for all ICU expressions of the current message
23667
+ * @param expandoStartIndex Expando start index for the current ICU expression
23668
+ */
23669
+ function parseNodes(currentNode, icuCase, parentIndex, nestedIcus, tIcus, expandoStartIndex) {
23670
+ if (currentNode) {
23671
+ const nestedIcusToCreate = [];
23672
+ while (currentNode) {
23673
+ const nextNode = currentNode.nextSibling;
23674
+ const newIndex = expandoStartIndex + ++icuCase.vars;
23675
+ switch (currentNode.nodeType) {
23676
+ case Node.ELEMENT_NODE:
23677
+ const element = currentNode;
23678
+ const tagName = element.tagName.toLowerCase();
23679
+ if (!VALID_ELEMENTS.hasOwnProperty(tagName)) {
23680
+ // This isn't a valid element, we won't create an element for it
23681
+ icuCase.vars--;
23682
+ }
23683
+ else {
23684
+ icuCase.create.push(ELEMENT_MARKER, tagName, newIndex, parentIndex << 17 /* SHIFT_PARENT */ | 1 /* AppendChild */);
23685
+ const elAttrs = element.attributes;
23686
+ for (let i = 0; i < elAttrs.length; i++) {
23687
+ const attr = elAttrs.item(i);
23688
+ const lowerAttrName = attr.name.toLowerCase();
23689
+ const hasBinding = !!attr.value.match(BINDING_REGEXP);
23690
+ // we assume the input string is safe, unless it's using a binding
23691
+ if (hasBinding) {
23692
+ if (VALID_ATTRS.hasOwnProperty(lowerAttrName)) {
23693
+ if (URI_ATTRS[lowerAttrName]) {
23694
+ addAllToArray(generateBindingUpdateOpCodes(attr.value, newIndex, attr.name, _sanitizeUrl), icuCase.update);
23695
+ }
23696
+ else if (SRCSET_ATTRS[lowerAttrName]) {
23697
+ addAllToArray(generateBindingUpdateOpCodes(attr.value, newIndex, attr.name, sanitizeSrcset), icuCase.update);
23698
+ }
23699
+ else {
23700
+ addAllToArray(generateBindingUpdateOpCodes(attr.value, newIndex, attr.name), icuCase.update);
23701
+ }
23702
+ }
23703
+ else {
23704
+ ngDevMode &&
23705
+ console.warn(`WARNING: ignoring unsafe attribute value ${lowerAttrName} on element ${tagName} (see http://g.co/ng/security#xss)`);
23706
+ }
23707
+ }
23708
+ else {
23709
+ icuCase.create.push(newIndex << 3 /* SHIFT_REF */ | 4 /* Attr */, attr.name, attr.value);
23710
+ }
23711
+ }
23712
+ // Parse the children of this node (if any)
23713
+ parseNodes(currentNode.firstChild, icuCase, newIndex, nestedIcus, tIcus, expandoStartIndex);
23714
+ // Remove the parent node after the children
23715
+ icuCase.remove.push(newIndex << 3 /* SHIFT_REF */ | 3 /* Remove */);
23716
+ }
23717
+ break;
23718
+ case Node.TEXT_NODE:
23719
+ const value = currentNode.textContent || '';
23720
+ const hasBinding = value.match(BINDING_REGEXP);
23721
+ icuCase.create.push(hasBinding ? '' : value, newIndex, parentIndex << 17 /* SHIFT_PARENT */ | 1 /* AppendChild */);
23722
+ icuCase.remove.push(newIndex << 3 /* SHIFT_REF */ | 3 /* Remove */);
23723
+ if (hasBinding) {
23724
+ addAllToArray(generateBindingUpdateOpCodes(value, newIndex), icuCase.update);
23725
+ }
23726
+ break;
23727
+ case Node.COMMENT_NODE:
23728
+ // Check if the comment node is a placeholder for a nested ICU
23729
+ const match = NESTED_ICU.exec(currentNode.textContent || '');
23730
+ if (match) {
23731
+ const nestedIcuIndex = parseInt(match[1], 10);
23732
+ const newLocal = ngDevMode ? `nested ICU ${nestedIcuIndex}` : '';
23733
+ // Create the comment node that will anchor the ICU expression
23734
+ icuCase.create.push(COMMENT_MARKER, newLocal, newIndex, parentIndex << 17 /* SHIFT_PARENT */ | 1 /* AppendChild */);
23735
+ const nestedIcu = nestedIcus[nestedIcuIndex];
23736
+ nestedIcusToCreate.push([nestedIcu, newIndex]);
23737
+ }
23738
+ else {
23739
+ // We do not handle any other type of comment
23740
+ icuCase.vars--;
23741
+ }
23742
+ break;
23743
+ default:
23744
+ // We do not handle any other type of element
23745
+ icuCase.vars--;
23746
+ }
23747
+ currentNode = nextNode;
23748
+ }
23749
+ for (let i = 0; i < nestedIcusToCreate.length; i++) {
23750
+ const nestedIcu = nestedIcusToCreate[i][0];
23751
+ const nestedIcuNodeIndex = nestedIcusToCreate[i][1];
23752
+ icuStart(tIcus, nestedIcu, nestedIcuNodeIndex, expandoStartIndex + icuCase.vars);
23753
+ // Since this is recursive, the last TIcu that was pushed is the one we want
23754
+ const nestTIcuIndex = tIcus.length - 1;
23755
+ icuCase.vars += Math.max(...tIcus[nestTIcuIndex].vars);
23756
+ icuCase.childIcus.push(nestTIcuIndex);
23757
+ const mask = getBindingMask(nestedIcu);
23758
+ icuCase.update.push(toMaskBit(nestedIcu.mainBinding), // mask of the main binding
23759
+ 3, // skip 3 opCodes if not changed
23760
+ -1 - nestedIcu.mainBinding, nestedIcuNodeIndex << 2 /* SHIFT_REF */ | 2 /* IcuSwitch */,
23761
+ // FIXME(misko): Index should be part of the opcode
23762
+ nestTIcuIndex, mask, // mask of all the bindings of this ICU expression
23763
+ 2, // skip 2 opCodes if not changed
23764
+ nestedIcuNodeIndex << 2 /* SHIFT_REF */ | 3 /* IcuUpdate */, nestTIcuIndex);
23765
+ icuCase.remove.push(nestTIcuIndex << 3 /* SHIFT_REF */ | 6 /* RemoveNestedIcu */,
23766
+ // FIXME(misko): Index should be part of the opcode
23767
+ nestedIcuNodeIndex << 3 /* SHIFT_REF */ | 3 /* Remove */);
23768
+ }
23769
+ }
23770
+ }
23771
+
23772
+ /**
23773
+ * @license
23774
+ * Copyright Google LLC All Rights Reserved.
23775
+ *
23776
+ * Use of this source code is governed by an MIT-style license that can be
23777
+ * found in the LICENSE file at https://angular.io/license
23778
+ */
23779
+ // i18nPostprocess consts
23780
+ const ROOT_TEMPLATE_ID = 0;
23781
+ const PP_MULTI_VALUE_PLACEHOLDERS_REGEXP = /\[(�.+?�?)\]/;
23782
+ const PP_PLACEHOLDERS_REGEXP = /\[(�.+?�?)\]|(�\/?\*\d+:\d+�)/g;
23783
+ const PP_ICU_VARS_REGEXP = /({\s*)(VAR_(PLURAL|SELECT)(_\d+)?)(\s*,)/g;
23784
+ const PP_ICU_PLACEHOLDERS_REGEXP = /{([A-Z0-9_]+)}/g;
23785
+ const PP_ICUS_REGEXP = /�I18N_EXP_(ICU(_\d+)?)�/g;
23786
+ const PP_CLOSE_TEMPLATE_REGEXP = /\/\*/;
23787
+ const PP_TEMPLATE_ID_REGEXP = /\d+\:(\d+)/;
23024
23788
  /**
23025
23789
  * Handles message string post-processing for internationalization.
23026
23790
  *
@@ -23041,7 +23805,7 @@ function isRootTemplateMessage(subTemplateIndex) {
23041
23805
  *
23042
23806
  * @codeGenApi
23043
23807
  */
23044
- function ɵɵi18nPostprocess(message, replacements = {}) {
23808
+ function i18nPostprocess(message, replacements = {}) {
23045
23809
  /**
23046
23810
  * Step 1: resolve all multi-value placeholders like [�#5�|�*1:1��#2:1�|�#4:1�]
23047
23811
  *
@@ -23069,337 +23833,74 @@ function ɵɵi18nPostprocess(message, replacements = {}) {
23069
23833
  matches[content] = placeholders;
23070
23834
  }
23071
23835
  if (!placeholders.length) {
23072
- throw new Error(`i18n postprocess: unmatched placeholder - ${content}`);
23073
- }
23074
- const currentTemplateId = templateIdsStack[templateIdsStack.length - 1];
23075
- let idx = 0;
23076
- // find placeholder index that matches current template id
23077
- for (let i = 0; i < placeholders.length; i++) {
23078
- if (placeholders[i][0] === currentTemplateId) {
23079
- idx = i;
23080
- break;
23081
- }
23082
- }
23083
- // update template id stack based on the current tag extracted
23084
- const [templateId, isCloseTemplateTag, placeholder] = placeholders[idx];
23085
- if (isCloseTemplateTag) {
23086
- templateIdsStack.pop();
23087
- }
23088
- else if (currentTemplateId !== templateId) {
23089
- templateIdsStack.push(templateId);
23090
- }
23091
- // remove processed tag from the list
23092
- placeholders.splice(idx, 1);
23093
- return placeholder;
23094
- });
23095
- }
23096
- // return current result if no replacements specified
23097
- if (!Object.keys(replacements).length) {
23098
- return result;
23099
- }
23100
- /**
23101
- * Step 2: replace all ICU vars (like "VAR_PLURAL")
23102
- */
23103
- result = result.replace(PP_ICU_VARS_REGEXP, (match, start, key, _type, _idx, end) => {
23104
- return replacements.hasOwnProperty(key) ? `${start}${replacements[key]}${end}` : match;
23105
- });
23106
- /**
23107
- * Step 3: replace all placeholders used inside ICUs in a form of {PLACEHOLDER}
23108
- */
23109
- result = result.replace(PP_ICU_PLACEHOLDERS_REGEXP, (match, key) => {
23110
- return replacements.hasOwnProperty(key) ? replacements[key] : match;
23111
- });
23112
- /**
23113
- * Step 4: replace all ICU references with corresponding values (like �ICU_EXP_ICU_1�) in case
23114
- * multiple ICUs have the same placeholder name
23115
- */
23116
- result = result.replace(PP_ICUS_REGEXP, (match, key) => {
23117
- if (replacements.hasOwnProperty(key)) {
23118
- const list = replacements[key];
23119
- if (!list.length) {
23120
- throw new Error(`i18n postprocess: unmatched ICU - ${match} with key: ${key}`);
23121
- }
23122
- return list.shift();
23123
- }
23124
- return match;
23125
- });
23126
- return result;
23127
- }
23128
- /**
23129
- * Translates a translation block marked by `i18nStart` and `i18nEnd`. It inserts the text/ICU nodes
23130
- * into the render tree, moves the placeholder nodes and removes the deleted nodes.
23131
- *
23132
- * @codeGenApi
23133
- */
23134
- function ɵɵi18nEnd() {
23135
- const lView = getLView();
23136
- const tView = getTView();
23137
- ngDevMode && assertDefined(tView, `tView should be defined`);
23138
- i18nEndFirstPass(tView, lView);
23139
- // Stop delaying projections
23140
- setDelayProjection(false);
23141
- }
23142
- /**
23143
- * See `i18nEnd` above.
23144
- */
23145
- function i18nEndFirstPass(tView, lView) {
23146
- ngDevMode &&
23147
- assertEqual(getBindingIndex(), tView.bindingStartIndex, 'i18nEnd should be called before any binding');
23148
- const rootIndex = i18nIndexStack[i18nIndexStackPointer--];
23149
- const tI18n = tView.data[rootIndex + HEADER_OFFSET];
23150
- ngDevMode && assertDefined(tI18n, `You should call i18nStart before i18nEnd`);
23151
- // Find the last node that was added before `i18nEnd`
23152
- const lastCreatedNode = getPreviousOrParentTNode();
23153
- // Read the instructions to insert/move/remove DOM elements
23154
- const visitedNodes = readCreateOpCodes(rootIndex, tI18n.create, tView, lView);
23155
- // Remove deleted nodes
23156
- let index = rootIndex + 1;
23157
- while (index <= lastCreatedNode.index - HEADER_OFFSET) {
23158
- if (visitedNodes.indexOf(index) === -1) {
23159
- removeNode(tView, lView, index, /* markAsDetached */ true);
23160
- }
23161
- // Check if an element has any local refs and skip them
23162
- const tNode = getTNode(tView, index);
23163
- if (tNode &&
23164
- (tNode.type === 0 /* Container */ || tNode.type === 3 /* Element */ ||
23165
- tNode.type === 4 /* ElementContainer */) &&
23166
- tNode.localNames !== null) {
23167
- // Divide by 2 to get the number of local refs,
23168
- // since they are stored as an array that also includes directive indexes,
23169
- // i.e. ["localRef", directiveIndex, ...]
23170
- index += tNode.localNames.length >> 1;
23171
- }
23172
- index++;
23173
- }
23174
- }
23175
- /**
23176
- * Creates and stores the dynamic TNode, and unhooks it from the tree for now.
23177
- */
23178
- function createDynamicNodeAtIndex(tView, lView, index, type, native, name) {
23179
- const previousOrParentTNode = getPreviousOrParentTNode();
23180
- ngDevMode && assertDataInRange(lView, index + HEADER_OFFSET);
23181
- lView[index + HEADER_OFFSET] = native;
23182
- const tNode = getOrCreateTNode(tView, lView[T_HOST], index, type, name, null);
23183
- // We are creating a dynamic node, the previous tNode might not be pointing at this node.
23184
- // We will link ourselves into the tree later with `appendI18nNode`.
23185
- if (previousOrParentTNode && previousOrParentTNode.next === tNode) {
23186
- previousOrParentTNode.next = null;
23187
- }
23188
- return tNode;
23189
- }
23190
- function readCreateOpCodes(index, createOpCodes, tView, lView) {
23191
- const renderer = lView[RENDERER];
23192
- let currentTNode = null;
23193
- let previousTNode = null;
23194
- const visitedNodes = [];
23195
- for (let i = 0; i < createOpCodes.length; i++) {
23196
- const opCode = createOpCodes[i];
23197
- if (typeof opCode == 'string') {
23198
- const textRNode = createTextNode(opCode, renderer);
23199
- const textNodeIndex = createOpCodes[++i];
23200
- ngDevMode && ngDevMode.rendererCreateTextNode++;
23201
- previousTNode = currentTNode;
23202
- currentTNode =
23203
- createDynamicNodeAtIndex(tView, lView, textNodeIndex, 3 /* Element */, textRNode, null);
23204
- visitedNodes.push(textNodeIndex);
23205
- setIsNotParent();
23206
- }
23207
- else if (typeof opCode == 'number') {
23208
- switch (opCode & 7 /* MASK_OPCODE */) {
23209
- case 1 /* AppendChild */:
23210
- const destinationNodeIndex = opCode >>> 17 /* SHIFT_PARENT */;
23211
- let destinationTNode;
23212
- if (destinationNodeIndex === index) {
23213
- // If the destination node is `i18nStart`, we don't have a
23214
- // top-level node and we should use the host node instead
23215
- destinationTNode = lView[T_HOST];
23216
- }
23217
- else {
23218
- destinationTNode = getTNode(tView, destinationNodeIndex);
23219
- }
23220
- ngDevMode &&
23221
- assertDefined(currentTNode, `You need to create or select a node before you can insert it into the DOM`);
23222
- previousTNode =
23223
- appendI18nNode(tView, currentTNode, destinationTNode, previousTNode, lView);
23224
- break;
23225
- case 0 /* Select */:
23226
- // Negative indicies indicate that a given TNode is a sibling node, not a parent node
23227
- // (see `i18nStartFirstPass` for additional information).
23228
- const isParent = opCode >= 0;
23229
- const nodeIndex = (isParent ? opCode : ~opCode) >>> 3 /* SHIFT_REF */;
23230
- visitedNodes.push(nodeIndex);
23231
- previousTNode = currentTNode;
23232
- currentTNode = getTNode(tView, nodeIndex);
23233
- if (currentTNode) {
23234
- setPreviousOrParentTNode(currentTNode, isParent);
23235
- }
23236
- break;
23237
- case 5 /* ElementEnd */:
23238
- const elementIndex = opCode >>> 3 /* SHIFT_REF */;
23239
- previousTNode = currentTNode = getTNode(tView, elementIndex);
23240
- setPreviousOrParentTNode(currentTNode, false);
23241
- break;
23242
- case 4 /* Attr */:
23243
- const elementNodeIndex = opCode >>> 3 /* SHIFT_REF */;
23244
- const attrName = createOpCodes[++i];
23245
- const attrValue = createOpCodes[++i];
23246
- // This code is used for ICU expressions only, since we don't support
23247
- // directives/components in ICUs, we don't need to worry about inputs here
23248
- elementAttributeInternal(getTNode(tView, elementNodeIndex), lView, attrName, attrValue, null, null);
23249
- break;
23250
- default:
23251
- throw new Error(`Unable to determine the type of mutate operation for "${opCode}"`);
23252
- }
23253
- }
23254
- else {
23255
- switch (opCode) {
23256
- case COMMENT_MARKER:
23257
- const commentValue = createOpCodes[++i];
23258
- const commentNodeIndex = createOpCodes[++i];
23259
- ngDevMode &&
23260
- assertEqual(typeof commentValue, 'string', `Expected "${commentValue}" to be a comment node value`);
23261
- const commentRNode = renderer.createComment(commentValue);
23262
- ngDevMode && ngDevMode.rendererCreateComment++;
23263
- previousTNode = currentTNode;
23264
- currentTNode = createDynamicNodeAtIndex(tView, lView, commentNodeIndex, 5 /* IcuContainer */, commentRNode, null);
23265
- visitedNodes.push(commentNodeIndex);
23266
- attachPatchData(commentRNode, lView);
23267
- currentTNode.activeCaseIndex = null;
23268
- // We will add the case nodes later, during the update phase
23269
- setIsNotParent();
23270
- break;
23271
- case ELEMENT_MARKER:
23272
- const tagNameValue = createOpCodes[++i];
23273
- const elementNodeIndex = createOpCodes[++i];
23274
- ngDevMode &&
23275
- assertEqual(typeof tagNameValue, 'string', `Expected "${tagNameValue}" to be an element node tag name`);
23276
- const elementRNode = renderer.createElement(tagNameValue);
23277
- ngDevMode && ngDevMode.rendererCreateElement++;
23278
- previousTNode = currentTNode;
23279
- currentTNode = createDynamicNodeAtIndex(tView, lView, elementNodeIndex, 3 /* Element */, elementRNode, tagNameValue);
23280
- visitedNodes.push(elementNodeIndex);
23281
- break;
23282
- default:
23283
- throw new Error(`Unable to determine the type of mutate operation for "${opCode}"`);
23284
- }
23285
- }
23286
- }
23287
- setIsNotParent();
23288
- return visitedNodes;
23289
- }
23290
- function readUpdateOpCodes(updateOpCodes, icus, bindingsStartIndex, changeMask, tView, lView, bypassCheckBit = false) {
23291
- let caseCreated = false;
23292
- for (let i = 0; i < updateOpCodes.length; i++) {
23293
- // bit code to check if we should apply the next update
23294
- const checkBit = updateOpCodes[i];
23295
- // Number of opCodes to skip until next set of update codes
23296
- const skipCodes = updateOpCodes[++i];
23297
- if (bypassCheckBit || (checkBit & changeMask)) {
23298
- // The value has been updated since last checked
23299
- let value = '';
23300
- for (let j = i + 1; j <= (i + skipCodes); j++) {
23301
- const opCode = updateOpCodes[j];
23302
- if (typeof opCode == 'string') {
23303
- value += opCode;
23304
- }
23305
- else if (typeof opCode == 'number') {
23306
- if (opCode < 0) {
23307
- // It's a binding index whose value is negative
23308
- value += renderStringify(lView[bindingsStartIndex - opCode]);
23309
- }
23310
- else {
23311
- const nodeIndex = opCode >>> 2 /* SHIFT_REF */;
23312
- let tIcuIndex;
23313
- let tIcu;
23314
- let icuTNode;
23315
- switch (opCode & 3 /* MASK_OPCODE */) {
23316
- case 1 /* Attr */:
23317
- const propName = updateOpCodes[++j];
23318
- const sanitizeFn = updateOpCodes[++j];
23319
- elementPropertyInternal(tView, getTNode(tView, nodeIndex), lView, propName, value, lView[RENDERER], sanitizeFn, false);
23320
- break;
23321
- case 0 /* Text */:
23322
- textBindingInternal(lView, nodeIndex, value);
23323
- break;
23324
- case 2 /* IcuSwitch */:
23325
- tIcuIndex = updateOpCodes[++j];
23326
- tIcu = icus[tIcuIndex];
23327
- icuTNode = getTNode(tView, nodeIndex);
23328
- // If there is an active case, delete the old nodes
23329
- if (icuTNode.activeCaseIndex !== null) {
23330
- const removeCodes = tIcu.remove[icuTNode.activeCaseIndex];
23331
- for (let k = 0; k < removeCodes.length; k++) {
23332
- const removeOpCode = removeCodes[k];
23333
- switch (removeOpCode & 7 /* MASK_OPCODE */) {
23334
- case 3 /* Remove */:
23335
- const nodeIndex = removeOpCode >>> 3 /* SHIFT_REF */;
23336
- // Remove DOM element, but do *not* mark TNode as detached, since we are
23337
- // just switching ICU cases (while keeping the same TNode), so a DOM element
23338
- // representing a new ICU case will be re-created.
23339
- removeNode(tView, lView, nodeIndex, /* markAsDetached */ false);
23340
- break;
23341
- case 6 /* RemoveNestedIcu */:
23342
- const nestedIcuNodeIndex = removeCodes[k + 1] >>> 3 /* SHIFT_REF */;
23343
- const nestedIcuTNode = getTNode(tView, nestedIcuNodeIndex);
23344
- const activeIndex = nestedIcuTNode.activeCaseIndex;
23345
- if (activeIndex !== null) {
23346
- const nestedIcuTIndex = removeOpCode >>> 3 /* SHIFT_REF */;
23347
- const nestedTIcu = icus[nestedIcuTIndex];
23348
- addAllToArray(nestedTIcu.remove[activeIndex], removeCodes);
23349
- }
23350
- break;
23351
- }
23352
- }
23353
- }
23354
- // Update the active caseIndex
23355
- const caseIndex = getCaseIndex(tIcu, value);
23356
- icuTNode.activeCaseIndex = caseIndex !== -1 ? caseIndex : null;
23357
- if (caseIndex > -1) {
23358
- // Add the nodes for the new case
23359
- readCreateOpCodes(-1, tIcu.create[caseIndex], tView, lView);
23360
- caseCreated = true;
23361
- }
23362
- break;
23363
- case 3 /* IcuUpdate */:
23364
- tIcuIndex = updateOpCodes[++j];
23365
- tIcu = icus[tIcuIndex];
23366
- icuTNode = getTNode(tView, nodeIndex);
23367
- if (icuTNode.activeCaseIndex !== null) {
23368
- readUpdateOpCodes(tIcu.update[icuTNode.activeCaseIndex], icus, bindingsStartIndex, changeMask, tView, lView, caseCreated);
23369
- }
23370
- break;
23371
- }
23372
- }
23836
+ throw new Error(`i18n postprocess: unmatched placeholder - ${content}`);
23837
+ }
23838
+ const currentTemplateId = templateIdsStack[templateIdsStack.length - 1];
23839
+ let idx = 0;
23840
+ // find placeholder index that matches current template id
23841
+ for (let i = 0; i < placeholders.length; i++) {
23842
+ if (placeholders[i][0] === currentTemplateId) {
23843
+ idx = i;
23844
+ break;
23373
23845
  }
23374
23846
  }
23375
- }
23376
- i += skipCodes;
23847
+ // update template id stack based on the current tag extracted
23848
+ const [templateId, isCloseTemplateTag, placeholder] = placeholders[idx];
23849
+ if (isCloseTemplateTag) {
23850
+ templateIdsStack.pop();
23851
+ }
23852
+ else if (currentTemplateId !== templateId) {
23853
+ templateIdsStack.push(templateId);
23854
+ }
23855
+ // remove processed tag from the list
23856
+ placeholders.splice(idx, 1);
23857
+ return placeholder;
23858
+ });
23377
23859
  }
23378
- }
23379
- function removeNode(tView, lView, index, markAsDetached) {
23380
- const removedPhTNode = getTNode(tView, index);
23381
- const removedPhRNode = getNativeByIndex(index, lView);
23382
- if (removedPhRNode) {
23383
- nativeRemoveNode(lView[RENDERER], removedPhRNode);
23860
+ // return current result if no replacements specified
23861
+ if (!Object.keys(replacements).length) {
23862
+ return result;
23384
23863
  }
23385
- const slotValue = load(lView, index);
23386
- if (isLContainer(slotValue)) {
23387
- const lContainer = slotValue;
23388
- if (removedPhTNode.type !== 0 /* Container */) {
23389
- nativeRemoveNode(lView[RENDERER], lContainer[NATIVE]);
23864
+ /**
23865
+ * Step 2: replace all ICU vars (like "VAR_PLURAL")
23866
+ */
23867
+ result = result.replace(PP_ICU_VARS_REGEXP, (match, start, key, _type, _idx, end) => {
23868
+ return replacements.hasOwnProperty(key) ? `${start}${replacements[key]}${end}` : match;
23869
+ });
23870
+ /**
23871
+ * Step 3: replace all placeholders used inside ICUs in a form of {PLACEHOLDER}
23872
+ */
23873
+ result = result.replace(PP_ICU_PLACEHOLDERS_REGEXP, (match, key) => {
23874
+ return replacements.hasOwnProperty(key) ? replacements[key] : match;
23875
+ });
23876
+ /**
23877
+ * Step 4: replace all ICU references with corresponding values (like �ICU_EXP_ICU_1�) in case
23878
+ * multiple ICUs have the same placeholder name
23879
+ */
23880
+ result = result.replace(PP_ICUS_REGEXP, (match, key) => {
23881
+ if (replacements.hasOwnProperty(key)) {
23882
+ const list = replacements[key];
23883
+ if (!list.length) {
23884
+ throw new Error(`i18n postprocess: unmatched ICU - ${match} with key: ${key}`);
23885
+ }
23886
+ return list.shift();
23390
23887
  }
23391
- }
23392
- if (markAsDetached) {
23393
- // Define this node as detached to avoid projecting it later
23394
- removedPhTNode.flags |= 64 /* isDetached */;
23395
- }
23396
- ngDevMode && ngDevMode.rendererRemoveNode++;
23888
+ return match;
23889
+ });
23890
+ return result;
23397
23891
  }
23892
+
23398
23893
  /**
23894
+ * @license
23895
+ * Copyright Google LLC All Rights Reserved.
23399
23896
  *
23400
- * Use this instruction to create a translation block that doesn't contain any placeholder.
23401
- * It calls both {@link i18nStart} and {@link i18nEnd} in one instruction.
23897
+ * Use of this source code is governed by an MIT-style license that can be
23898
+ * found in the LICENSE file at https://angular.io/license
23899
+ */
23900
+ /**
23901
+ * Marks a block of text as translatable.
23402
23902
  *
23903
+ * The instructions `i18nStart` and `i18nEnd` mark the translation block in the template.
23403
23904
  * The translation `message` is the value which is locale specific. The translation string may
23404
23905
  * contain placeholders which associate inner elements and sub-templates within the translation.
23405
23906
  *
@@ -23411,6 +23912,10 @@ function removeNode(tView, lView, index, markAsDetached) {
23411
23912
  * and end of DOM element that were embedded in the original translation block. The placeholder
23412
23913
  * `index` points to the element index in the template instructions set. An optional `block` that
23413
23914
  * matches the sub-template in which it was declared.
23915
+ * - `�!{index}(:{block})�`/`�/!{index}(:{block})�`: *Projection Placeholder*: Marks the
23916
+ * beginning and end of <ng-content> that was embedded in the original translation block.
23917
+ * The placeholder `index` points to the element index in the template instructions set.
23918
+ * An optional `block` that matches the sub-template in which it was declared.
23414
23919
  * - `�*{index}:{block}�`/`�/*{index}:{block}�`: *Sub-template Placeholder*: Sub-templates must be
23415
23920
  * split up and translated separately in each angular template function. The `index` points to the
23416
23921
  * `template` instruction index. A `block` that matches the sub-template in which it was declared.
@@ -23421,364 +23926,122 @@ function removeNode(tView, lView, index, markAsDetached) {
23421
23926
  *
23422
23927
  * @codeGenApi
23423
23928
  */
23424
- function ɵɵi18n(index, message, subTemplateIndex) {
23425
- ɵɵi18nStart(index, message, subTemplateIndex);
23426
- ɵɵi18nEnd();
23427
- }
23428
- /**
23429
- * Marks a list of attributes as translatable.
23430
- *
23431
- * @param index A unique index in the static block
23432
- * @param values
23433
- *
23434
- * @codeGenApi
23435
- */
23436
- function ɵɵi18nAttributes(index, values) {
23437
- const lView = getLView();
23438
- const tView = getTView();
23439
- ngDevMode && assertDefined(tView, `tView should be defined`);
23440
- i18nAttributesFirstPass(lView, tView, index, values);
23441
- }
23442
- /**
23443
- * See `i18nAttributes` above.
23444
- */
23445
- function i18nAttributesFirstPass(lView, tView, index, values) {
23446
- const previousElement = getPreviousOrParentTNode();
23447
- const previousElementIndex = previousElement.index - HEADER_OFFSET;
23448
- const updateOpCodes = [];
23449
- for (let i = 0; i < values.length; i += 2) {
23450
- const attrName = values[i];
23451
- const message = values[i + 1];
23452
- const parts = message.split(ICU_REGEXP);
23453
- for (let j = 0; j < parts.length; j++) {
23454
- const value = parts[j];
23455
- if (j & 1) {
23456
- // Odd indexes are ICU expressions
23457
- // TODO(ocombe): support ICU expressions in attributes
23458
- throw new Error('ICU expressions are not yet supported in attributes');
23459
- }
23460
- else if (value !== '') {
23461
- // Even indexes are text (including bindings)
23462
- const hasBinding = !!value.match(BINDING_REGEXP);
23463
- if (hasBinding) {
23464
- if (tView.firstCreatePass && tView.data[index + HEADER_OFFSET] === null) {
23465
- addAllToArray(generateBindingUpdateOpCodes(value, previousElementIndex, attrName), updateOpCodes);
23466
- }
23467
- }
23468
- else {
23469
- const tNode = getTNode(tView, previousElementIndex);
23470
- // Set attributes for Elements only, for other types (like ElementContainer),
23471
- // only set inputs below
23472
- if (tNode.type === 3 /* Element */) {
23473
- elementAttributeInternal(tNode, lView, attrName, value, null, null);
23474
- }
23475
- // Check if that attribute is a directive input
23476
- const dataValue = tNode.inputs !== null && tNode.inputs[attrName];
23477
- if (dataValue) {
23478
- setInputsForProperty(tView, lView, dataValue, attrName, value);
23479
- if (ngDevMode) {
23480
- const element = getNativeByIndex(previousElementIndex, lView);
23481
- setNgReflectProperties(lView, element, tNode.type, dataValue, value);
23482
- }
23483
- }
23484
- }
23485
- }
23486
- }
23487
- }
23488
- if (tView.firstCreatePass && tView.data[index + HEADER_OFFSET] === null) {
23489
- tView.data[index + HEADER_OFFSET] = updateOpCodes;
23490
- }
23491
- }
23492
- let changeMask = 0b0;
23493
- let shiftsCounter = 0;
23494
- /**
23495
- * Stores the values of the bindings during each update cycle in order to determine if we need to
23496
- * update the translated nodes.
23497
- *
23498
- * @param value The binding's value
23499
- * @returns This function returns itself so that it may be chained
23500
- * (e.g. `i18nExp(ctx.name)(ctx.title)`)
23501
- *
23502
- * @codeGenApi
23503
- */
23504
- function ɵɵi18nExp(value) {
23505
- const lView = getLView();
23506
- if (bindingUpdated(lView, nextBindingIndex(), value)) {
23507
- changeMask = changeMask | (1 << shiftsCounter);
23508
- }
23509
- shiftsCounter++;
23510
- return ɵɵi18nExp;
23511
- }
23512
- /**
23513
- * Updates a translation block or an i18n attribute when the bindings have changed.
23514
- *
23515
- * @param index Index of either {@link i18nStart} (translation block) or {@link i18nAttributes}
23516
- * (i18n attribute) on which it should update the content.
23517
- *
23518
- * @codeGenApi
23519
- */
23520
- function ɵɵi18nApply(index) {
23521
- if (shiftsCounter) {
23522
- const tView = getTView();
23523
- ngDevMode && assertDefined(tView, `tView should be defined`);
23524
- const tI18n = tView.data[index + HEADER_OFFSET];
23525
- let updateOpCodes;
23526
- let icus = null;
23527
- if (Array.isArray(tI18n)) {
23528
- updateOpCodes = tI18n;
23529
- }
23530
- else {
23531
- updateOpCodes = tI18n.update;
23532
- icus = tI18n.icus;
23533
- }
23534
- const bindingsStartIndex = getBindingIndex() - shiftsCounter - 1;
23535
- const lView = getLView();
23536
- readUpdateOpCodes(updateOpCodes, icus, bindingsStartIndex, changeMask, tView, lView);
23537
- // Reset changeMask & maskBit to default for the next update cycle
23538
- changeMask = 0b0;
23539
- shiftsCounter = 0;
23540
- }
23541
- }
23542
- /**
23543
- * Returns the index of the current case of an ICU expression depending on the main binding value
23544
- *
23545
- * @param icuExpression
23546
- * @param bindingValue The value of the main binding used by this ICU expression
23547
- */
23548
- function getCaseIndex(icuExpression, bindingValue) {
23549
- let index = icuExpression.cases.indexOf(bindingValue);
23550
- if (index === -1) {
23551
- switch (icuExpression.type) {
23552
- case 1 /* plural */: {
23553
- const resolvedCase = getPluralCase(bindingValue, getLocaleId());
23554
- index = icuExpression.cases.indexOf(resolvedCase);
23555
- if (index === -1 && resolvedCase !== 'other') {
23556
- index = icuExpression.cases.indexOf('other');
23557
- }
23558
- break;
23559
- }
23560
- case 0 /* select */: {
23561
- index = icuExpression.cases.indexOf('other');
23562
- break;
23563
- }
23564
- }
23565
- }
23566
- return index;
23567
- }
23568
- /**
23569
- * Generate the OpCodes for ICU expressions.
23570
- *
23571
- * @param tIcus
23572
- * @param icuExpression
23573
- * @param startIndex
23574
- * @param expandoStartIndex
23575
- */
23576
- function icuStart(tIcus, icuExpression, startIndex, expandoStartIndex) {
23577
- const createCodes = [];
23578
- const removeCodes = [];
23579
- const updateCodes = [];
23580
- const vars = [];
23581
- const childIcus = [];
23582
- for (let i = 0; i < icuExpression.values.length; i++) {
23583
- // Each value is an array of strings & other ICU expressions
23584
- const valueArr = icuExpression.values[i];
23585
- const nestedIcus = [];
23586
- for (let j = 0; j < valueArr.length; j++) {
23587
- const value = valueArr[j];
23588
- if (typeof value !== 'string') {
23589
- // It is an nested ICU expression
23590
- const icuIndex = nestedIcus.push(value) - 1;
23591
- // Replace nested ICU expression by a comment node
23592
- valueArr[j] = `<!--�${icuIndex}�-->`;
23593
- }
23594
- }
23595
- const icuCase = parseIcuCase(valueArr.join(''), startIndex, nestedIcus, tIcus, expandoStartIndex);
23596
- createCodes.push(icuCase.create);
23597
- removeCodes.push(icuCase.remove);
23598
- updateCodes.push(icuCase.update);
23599
- vars.push(icuCase.vars);
23600
- childIcus.push(icuCase.childIcus);
23929
+ function ɵɵi18nStart(index, message, subTemplateIndex) {
23930
+ const tView = getTView();
23931
+ ngDevMode && assertDefined(tView, `tView should be defined`);
23932
+ pushI18nIndex(index);
23933
+ // We need to delay projections until `i18nEnd`
23934
+ setDelayProjection(true);
23935
+ if (tView.firstCreatePass && tView.data[index + HEADER_OFFSET] === null) {
23936
+ i18nStartFirstPass(getLView(), tView, index, message, subTemplateIndex);
23601
23937
  }
23602
- const tIcu = {
23603
- type: icuExpression.type,
23604
- vars,
23605
- childIcus,
23606
- cases: icuExpression.cases,
23607
- create: createCodes,
23608
- remove: removeCodes,
23609
- update: updateCodes
23610
- };
23611
- tIcus.push(tIcu);
23612
- // Adding the maximum possible of vars needed (based on the cases with the most vars)
23613
- i18nVarsCount += Math.max(...vars);
23614
23938
  }
23615
23939
  /**
23616
- * Transforms a string template into an HTML template and a list of instructions used to update
23617
- * attributes or nodes that contain bindings.
23940
+ * Translates a translation block marked by `i18nStart` and `i18nEnd`. It inserts the text/ICU nodes
23941
+ * into the render tree, moves the placeholder nodes and removes the deleted nodes.
23618
23942
  *
23619
- * @param unsafeHtml The string to parse
23620
- * @param parentIndex
23621
- * @param nestedIcus
23622
- * @param tIcus
23623
- * @param expandoStartIndex
23943
+ * @codeGenApi
23624
23944
  */
23625
- function parseIcuCase(unsafeHtml, parentIndex, nestedIcus, tIcus, expandoStartIndex) {
23626
- const inertBodyHelper = getInertBodyHelper(getDocument());
23627
- const inertBodyElement = inertBodyHelper.getInertBodyElement(unsafeHtml);
23628
- if (!inertBodyElement) {
23629
- throw new Error('Unable to generate inert body element');
23630
- }
23631
- const wrapper = getTemplateContent(inertBodyElement) || inertBodyElement;
23632
- const opCodes = { vars: 0, childIcus: [], create: [], remove: [], update: [] };
23633
- parseNodes(wrapper.firstChild, opCodes, parentIndex, nestedIcus, tIcus, expandoStartIndex);
23634
- return opCodes;
23945
+ function ɵɵi18nEnd() {
23946
+ const lView = getLView();
23947
+ const tView = getTView();
23948
+ ngDevMode && assertDefined(tView, `tView should be defined`);
23949
+ i18nEndFirstPass(tView, lView);
23950
+ // Stop delaying projections
23951
+ setDelayProjection(false);
23635
23952
  }
23636
- const NESTED_ICU = /�(\d+)�/;
23637
23953
  /**
23638
- * Parses a node, its children and its siblings, and generates the mutate & update OpCodes.
23639
23954
  *
23640
- * @param currentNode The first node to parse
23641
- * @param icuCase The data for the ICU expression case that contains those nodes
23642
- * @param parentIndex Index of the current node's parent
23643
- * @param nestedIcus Data for the nested ICU expressions that this case contains
23644
- * @param tIcus Data for all ICU expressions of the current message
23645
- * @param expandoStartIndex Expando start index for the current ICU expression
23955
+ * Use this instruction to create a translation block that doesn't contain any placeholder.
23956
+ * It calls both {@link i18nStart} and {@link i18nEnd} in one instruction.
23957
+ *
23958
+ * The translation `message` is the value which is locale specific. The translation string may
23959
+ * contain placeholders which associate inner elements and sub-templates within the translation.
23960
+ *
23961
+ * The translation `message` placeholders are:
23962
+ * - `�{index}(:{block})�`: *Binding Placeholder*: Marks a location where an expression will be
23963
+ * interpolated into. The placeholder `index` points to the expression binding index. An optional
23964
+ * `block` that matches the sub-template in which it was declared.
23965
+ * - `�#{index}(:{block})�`/`�/#{index}(:{block})�`: *Element Placeholder*: Marks the beginning
23966
+ * and end of DOM element that were embedded in the original translation block. The placeholder
23967
+ * `index` points to the element index in the template instructions set. An optional `block` that
23968
+ * matches the sub-template in which it was declared.
23969
+ * - `�*{index}:{block}�`/`�/*{index}:{block}�`: *Sub-template Placeholder*: Sub-templates must be
23970
+ * split up and translated separately in each angular template function. The `index` points to the
23971
+ * `template` instruction index. A `block` that matches the sub-template in which it was declared.
23972
+ *
23973
+ * @param index A unique index of the translation in the static block.
23974
+ * @param message The translation message.
23975
+ * @param subTemplateIndex Optional sub-template index in the `message`.
23976
+ *
23977
+ * @codeGenApi
23646
23978
  */
23647
- function parseNodes(currentNode, icuCase, parentIndex, nestedIcus, tIcus, expandoStartIndex) {
23648
- if (currentNode) {
23649
- const nestedIcusToCreate = [];
23650
- while (currentNode) {
23651
- const nextNode = currentNode.nextSibling;
23652
- const newIndex = expandoStartIndex + ++icuCase.vars;
23653
- switch (currentNode.nodeType) {
23654
- case Node.ELEMENT_NODE:
23655
- const element = currentNode;
23656
- const tagName = element.tagName.toLowerCase();
23657
- if (!VALID_ELEMENTS.hasOwnProperty(tagName)) {
23658
- // This isn't a valid element, we won't create an element for it
23659
- icuCase.vars--;
23660
- }
23661
- else {
23662
- icuCase.create.push(ELEMENT_MARKER, tagName, newIndex, parentIndex << 17 /* SHIFT_PARENT */ | 1 /* AppendChild */);
23663
- const elAttrs = element.attributes;
23664
- for (let i = 0; i < elAttrs.length; i++) {
23665
- const attr = elAttrs.item(i);
23666
- const lowerAttrName = attr.name.toLowerCase();
23667
- const hasBinding = !!attr.value.match(BINDING_REGEXP);
23668
- // we assume the input string is safe, unless it's using a binding
23669
- if (hasBinding) {
23670
- if (VALID_ATTRS.hasOwnProperty(lowerAttrName)) {
23671
- if (URI_ATTRS[lowerAttrName]) {
23672
- addAllToArray(generateBindingUpdateOpCodes(attr.value, newIndex, attr.name, _sanitizeUrl), icuCase.update);
23673
- }
23674
- else if (SRCSET_ATTRS[lowerAttrName]) {
23675
- addAllToArray(generateBindingUpdateOpCodes(attr.value, newIndex, attr.name, sanitizeSrcset), icuCase.update);
23676
- }
23677
- else {
23678
- addAllToArray(generateBindingUpdateOpCodes(attr.value, newIndex, attr.name), icuCase.update);
23679
- }
23680
- }
23681
- else {
23682
- ngDevMode &&
23683
- console.warn(`WARNING: ignoring unsafe attribute value ${lowerAttrName} on element ${tagName} (see http://g.co/ng/security#xss)`);
23684
- }
23685
- }
23686
- else {
23687
- icuCase.create.push(newIndex << 3 /* SHIFT_REF */ | 4 /* Attr */, attr.name, attr.value);
23688
- }
23689
- }
23690
- // Parse the children of this node (if any)
23691
- parseNodes(currentNode.firstChild, icuCase, newIndex, nestedIcus, tIcus, expandoStartIndex);
23692
- // Remove the parent node after the children
23693
- icuCase.remove.push(newIndex << 3 /* SHIFT_REF */ | 3 /* Remove */);
23694
- }
23695
- break;
23696
- case Node.TEXT_NODE:
23697
- const value = currentNode.textContent || '';
23698
- const hasBinding = value.match(BINDING_REGEXP);
23699
- icuCase.create.push(hasBinding ? '' : value, newIndex, parentIndex << 17 /* SHIFT_PARENT */ | 1 /* AppendChild */);
23700
- icuCase.remove.push(newIndex << 3 /* SHIFT_REF */ | 3 /* Remove */);
23701
- if (hasBinding) {
23702
- addAllToArray(generateBindingUpdateOpCodes(value, newIndex), icuCase.update);
23703
- }
23704
- break;
23705
- case Node.COMMENT_NODE:
23706
- // Check if the comment node is a placeholder for a nested ICU
23707
- const match = NESTED_ICU.exec(currentNode.textContent || '');
23708
- if (match) {
23709
- const nestedIcuIndex = parseInt(match[1], 10);
23710
- const newLocal = ngDevMode ? `nested ICU ${nestedIcuIndex}` : '';
23711
- // Create the comment node that will anchor the ICU expression
23712
- icuCase.create.push(COMMENT_MARKER, newLocal, newIndex, parentIndex << 17 /* SHIFT_PARENT */ | 1 /* AppendChild */);
23713
- const nestedIcu = nestedIcus[nestedIcuIndex];
23714
- nestedIcusToCreate.push([nestedIcu, newIndex]);
23715
- }
23716
- else {
23717
- // We do not handle any other type of comment
23718
- icuCase.vars--;
23719
- }
23720
- break;
23721
- default:
23722
- // We do not handle any other type of element
23723
- icuCase.vars--;
23724
- }
23725
- currentNode = nextNode;
23726
- }
23727
- for (let i = 0; i < nestedIcusToCreate.length; i++) {
23728
- const nestedIcu = nestedIcusToCreate[i][0];
23729
- const nestedIcuNodeIndex = nestedIcusToCreate[i][1];
23730
- icuStart(tIcus, nestedIcu, nestedIcuNodeIndex, expandoStartIndex + icuCase.vars);
23731
- // Since this is recursive, the last TIcu that was pushed is the one we want
23732
- const nestTIcuIndex = tIcus.length - 1;
23733
- icuCase.vars += Math.max(...tIcus[nestTIcuIndex].vars);
23734
- icuCase.childIcus.push(nestTIcuIndex);
23735
- const mask = getBindingMask(nestedIcu);
23736
- icuCase.update.push(toMaskBit(nestedIcu.mainBinding), // mask of the main binding
23737
- 3, // skip 3 opCodes if not changed
23738
- -1 - nestedIcu.mainBinding, nestedIcuNodeIndex << 2 /* SHIFT_REF */ | 2 /* IcuSwitch */, nestTIcuIndex, mask, // mask of all the bindings of this ICU expression
23739
- 2, // skip 2 opCodes if not changed
23740
- nestedIcuNodeIndex << 2 /* SHIFT_REF */ | 3 /* IcuUpdate */, nestTIcuIndex);
23741
- icuCase.remove.push(nestTIcuIndex << 3 /* SHIFT_REF */ | 6 /* RemoveNestedIcu */, nestedIcuNodeIndex << 3 /* SHIFT_REF */ | 3 /* Remove */);
23742
- }
23743
- }
23979
+ function ɵɵi18n(index, message, subTemplateIndex) {
23980
+ ɵɵi18nStart(index, message, subTemplateIndex);
23981
+ ɵɵi18nEnd();
23744
23982
  }
23745
23983
  /**
23746
- * Angular Dart introduced &ngsp; as a placeholder for non-removable space, see:
23747
- * https://github.com/dart-lang/angular/blob/0bb611387d29d65b5af7f9d2515ab571fd3fbee4/_tests/test/compiler/preserve_whitespace_test.dart#L25-L32
23748
- * In Angular Dart &ngsp; is converted to the 0xE500 PUA (Private Use Areas) unicode character
23749
- * and later on replaced by a space. We are re-implementing the same idea here, since translations
23750
- * might contain this special character.
23984
+ * Marks a list of attributes as translatable.
23985
+ *
23986
+ * @param index A unique index in the static block
23987
+ * @param values
23988
+ *
23989
+ * @codeGenApi
23751
23990
  */
23752
- const NGSP_UNICODE_REGEXP = /\uE500/g;
23753
- function replaceNgsp(value) {
23754
- return value.replace(NGSP_UNICODE_REGEXP, ' ');
23991
+ function ɵɵi18nAttributes(index, values) {
23992
+ const lView = getLView();
23993
+ const tView = getTView();
23994
+ ngDevMode && assertDefined(tView, `tView should be defined`);
23995
+ i18nAttributesFirstPass(lView, tView, index, values);
23755
23996
  }
23756
23997
  /**
23757
- * The locale id that the application is currently using (for translations and ICU expressions).
23758
- * This is the ivy version of `LOCALE_ID` that was defined as an injection token for the view engine
23759
- * but is now defined as a global value.
23998
+ * Stores the values of the bindings during each update cycle in order to determine if we need to
23999
+ * update the translated nodes.
24000
+ *
24001
+ * @param value The binding's value
24002
+ * @returns This function returns itself so that it may be chained
24003
+ * (e.g. `i18nExp(ctx.name)(ctx.title)`)
24004
+ *
24005
+ * @codeGenApi
23760
24006
  */
23761
- let LOCALE_ID = DEFAULT_LOCALE_ID;
24007
+ function ɵɵi18nExp(value) {
24008
+ const lView = getLView();
24009
+ setMaskBit(bindingUpdated(lView, nextBindingIndex(), value));
24010
+ return ɵɵi18nExp;
24011
+ }
23762
24012
  /**
23763
- * Sets the locale id that will be used for translations and ICU expressions.
23764
- * This is the ivy version of `LOCALE_ID` that was defined as an injection token for the view engine
23765
- * but is now defined as a global value.
24013
+ * Updates a translation block or an i18n attribute when the bindings have changed.
23766
24014
  *
23767
- * @param localeId
24015
+ * @param index Index of either {@link i18nStart} (translation block) or {@link i18nAttributes}
24016
+ * (i18n attribute) on which it should update the content.
24017
+ *
24018
+ * @codeGenApi
23768
24019
  */
23769
- function setLocaleId(localeId) {
23770
- assertDefined(localeId, `Expected localeId to be defined`);
23771
- if (typeof localeId === 'string') {
23772
- LOCALE_ID = localeId.toLowerCase().replace(/_/g, '-');
23773
- }
24020
+ function ɵɵi18nApply(index) {
24021
+ applyI18n(getTView(), getLView(), index);
23774
24022
  }
23775
24023
  /**
23776
- * Gets the locale id that will be used for translations and ICU expressions.
23777
- * This is the ivy version of `LOCALE_ID` that was defined as an injection token for the view engine
23778
- * but is now defined as a global value.
24024
+ * Handles message string post-processing for internationalization.
24025
+ *
24026
+ * Handles message string post-processing by transforming it from intermediate
24027
+ * format (that might contain some markers that we need to replace) to the final
24028
+ * form, consumable by i18nStart instruction. Post processing steps include:
24029
+ *
24030
+ * 1. Resolve all multi-value cases (like [�*1:1��#2:1�|�#4:1�|�5�])
24031
+ * 2. Replace all ICU vars (like "VAR_PLURAL")
24032
+ * 3. Replace all placeholders used inside ICUs in a form of {PLACEHOLDER}
24033
+ * 4. Replace all ICU references with corresponding values (like �ICU_EXP_ICU_1�)
24034
+ * in case multiple ICUs have the same placeholder name
24035
+ *
24036
+ * @param message Raw translation string for post processing
24037
+ * @param replacements Set of replacements that should be applied
24038
+ *
24039
+ * @returns Transformed string that can be consumed by i18nStart instruction
24040
+ *
24041
+ * @codeGenApi
23779
24042
  */
23780
- function getLocaleId() {
23781
- return LOCALE_ID;
24043
+ function ɵɵi18nPostprocess(message, replacements = {}) {
24044
+ return i18nPostprocess(message, replacements);
23782
24045
  }
23783
24046
 
23784
24047
  /**
@@ -24223,7 +24486,7 @@ function ɵɵpureFunctionV(slotOffset, pureFn, exps, thisArg) {
24223
24486
  * it to `undefined`.
24224
24487
  */
24225
24488
  function getPureFunctionReturnValue(lView, returnValueIndex) {
24226
- ngDevMode && assertDataInRange(lView, returnValueIndex);
24489
+ ngDevMode && assertIndexInRange(lView, returnValueIndex);
24227
24490
  const lastReturnValue = lView[returnValueIndex];
24228
24491
  return lastReturnValue === NO_CHANGE ? undefined : lastReturnValue;
24229
24492
  }
@@ -24844,7 +25107,7 @@ class TQueries_ {
24844
25107
  }
24845
25108
  }
24846
25109
  getByIndex(index) {
24847
- ngDevMode && assertDataInRange(this.queries, index);
25110
+ ngDevMode && assertIndexInRange(this.queries, index);
24848
25111
  return this.queries[index];
24849
25112
  }
24850
25113
  get length() {
@@ -24914,21 +25177,23 @@ class TQuery_ {
24914
25177
  return this._appliesToNextNode;
24915
25178
  }
24916
25179
  matchTNode(tView, tNode) {
24917
- if (Array.isArray(this.metadata.predicate)) {
24918
- const localNames = this.metadata.predicate;
24919
- for (let i = 0; i < localNames.length; i++) {
24920
- this.matchTNodeWithReadOption(tView, tNode, getIdxOfMatchingSelector(tNode, localNames[i]));
25180
+ const predicate = this.metadata.predicate;
25181
+ if (Array.isArray(predicate)) {
25182
+ for (let i = 0; i < predicate.length; i++) {
25183
+ const name = predicate[i];
25184
+ this.matchTNodeWithReadOption(tView, tNode, getIdxOfMatchingSelector(tNode, name));
25185
+ // Also try matching the name to a provider since strings can be used as DI tokens too.
25186
+ this.matchTNodeWithReadOption(tView, tNode, locateDirectiveOrProvider(tNode, tView, name, false, false));
24921
25187
  }
24922
25188
  }
24923
25189
  else {
24924
- const typePredicate = this.metadata.predicate;
24925
- if (typePredicate === TemplateRef) {
25190
+ if (predicate === TemplateRef) {
24926
25191
  if (tNode.type === 0 /* Container */) {
24927
25192
  this.matchTNodeWithReadOption(tView, tNode, -1);
24928
25193
  }
24929
25194
  }
24930
25195
  else {
24931
- this.matchTNodeWithReadOption(tView, tNode, locateDirectiveOrProvider(tNode, tView, typePredicate, false, false));
25196
+ this.matchTNodeWithReadOption(tView, tNode, locateDirectiveOrProvider(tNode, tView, predicate, false, false));
24932
25197
  }
24933
25198
  }
24934
25199
  }
@@ -25040,7 +25305,7 @@ function materializeViewResults(tView, lView, tQuery, queryIndex) {
25040
25305
  result.push(null);
25041
25306
  }
25042
25307
  else {
25043
- ngDevMode && assertDataInRange(tViewData, matchedNodeIdx);
25308
+ ngDevMode && assertIndexInRange(tViewData, matchedNodeIdx);
25044
25309
  const tNode = tViewData[matchedNodeIdx];
25045
25310
  result.push(createResultForNode(lView, tNode, tQueryMatches[i + 1], tQuery.metadata.read));
25046
25311
  }
@@ -25202,7 +25467,7 @@ function ɵɵloadQuery() {
25202
25467
  function loadQueryInternal(lView, queryIndex) {
25203
25468
  ngDevMode &&
25204
25469
  assertDefined(lView[QUERIES], 'LQueries should be defined when trying to load a query');
25205
- ngDevMode && assertDataInRange(lView[QUERIES].queries, queryIndex);
25470
+ ngDevMode && assertIndexInRange(lView[QUERIES].queries, queryIndex);
25206
25471
  return lView[QUERIES].queries[queryIndex].queryList;
25207
25472
  }
25208
25473
  function createLQuery(tView, lView) {
@@ -25906,6 +26171,20 @@ function isNgModule(value) {
25906
26171
  * Use of this source code is governed by an MIT-style license that can be
25907
26172
  * found in the LICENSE file at https://angular.io/license
25908
26173
  */
26174
+ /**
26175
+ * Keep track of the compilation depth to avoid reentrancy issues during JIT compilation. This
26176
+ * matters in the following scenario:
26177
+ *
26178
+ * Consider a component 'A' that extends component 'B', both declared in module 'M'. During
26179
+ * the compilation of 'A' the definition of 'B' is requested to capture the inheritance chain,
26180
+ * potentially triggering compilation of 'B'. If this nested compilation were to trigger
26181
+ * `flushModuleScopingQueueAsMuchAsPossible` it may happen that module 'M' is still pending in the
26182
+ * queue, resulting in 'A' and 'B' to be patched with the NgModule scope. As the compilation of
26183
+ * 'A' is still in progress, this would introduce a circular dependency on its compilation. To avoid
26184
+ * this issue, the module scope queue is only flushed for compilations at the depth 0, to ensure
26185
+ * all compilations have finished.
26186
+ */
26187
+ let compilationDepth = 0;
25909
26188
  /**
25910
26189
  * Compile an Angular component according to its decorator metadata, and patch the resulting
25911
26190
  * component def (ɵcmp) onto the component type.
@@ -25966,16 +26245,25 @@ function compileComponent(type, metadata) {
25966
26245
  }
25967
26246
  const templateUrl = metadata.templateUrl || `ng:///${type.name}/template.html`;
25968
26247
  const meta = Object.assign(Object.assign({}, directiveMetadata(type, metadata)), { typeSourceSpan: compiler.createParseSourceSpan('Component', type.name, templateUrl), template: metadata.template || '', preserveWhitespaces, styles: metadata.styles || EMPTY_ARRAY, animations: metadata.animations, directives: [], changeDetection: metadata.changeDetection, pipes: new Map(), encapsulation, interpolation: metadata.interpolation, viewProviders: metadata.viewProviders || null });
25969
- if (meta.usesInheritance) {
25970
- addDirectiveDefToUndecoratedParents(type);
26248
+ compilationDepth++;
26249
+ try {
26250
+ if (meta.usesInheritance) {
26251
+ addDirectiveDefToUndecoratedParents(type);
26252
+ }
26253
+ ngComponentDef = compiler.compileComponent(angularCoreEnv, templateUrl, meta);
26254
+ }
26255
+ finally {
26256
+ // Ensure that the compilation depth is decremented even when the compilation failed.
26257
+ compilationDepth--;
26258
+ }
26259
+ if (compilationDepth === 0) {
26260
+ // When NgModule decorator executed, we enqueued the module definition such that
26261
+ // it would only dequeue and add itself as module scope to all of its declarations,
26262
+ // but only if if all of its declarations had resolved. This call runs the check
26263
+ // to see if any modules that are in the queue can be dequeued and add scope to
26264
+ // their declarations.
26265
+ flushModuleScopingQueueAsMuchAsPossible();
25971
26266
  }
25972
- ngComponentDef = compiler.compileComponent(angularCoreEnv, templateUrl, meta);
25973
- // When NgModule decorator executed, we enqueued the module definition such that
25974
- // it would only dequeue and add itself as module scope to all of its declarations,
25975
- // but only if if all of its declarations had resolved. This call runs the check
25976
- // to see if any modules that are in the queue can be dequeued and add scope to
25977
- // their declarations.
25978
- flushModuleScopingQueueAsMuchAsPossible();
25979
26267
  // If component compilation is async, then the @NgModule annotation which declares the
25980
26268
  // component may execute and set an ngSelectorScope property on the component type. This
25981
26269
  // allows the component to patch itself with directiveDefs from the module after it
@@ -31451,5 +31739,5 @@ if (ngDevMode) {
31451
31739
  * Generated bundle index. Do not edit.
31452
31740
  */
31453
31741
 
31454
- export { ANALYZE_FOR_ENTRY_COMPONENTS, APP_BOOTSTRAP_LISTENER, APP_ID, APP_INITIALIZER, ApplicationInitStatus, ApplicationModule, ApplicationRef, Attribute, COMPILER_OPTIONS, CUSTOM_ELEMENTS_SCHEMA, ChangeDetectionStrategy, ChangeDetectorRef, Compiler, CompilerFactory, Component, ComponentFactory, ComponentFactoryResolver, ComponentRef, ContentChild, ContentChildren, DEFAULT_CURRENCY_CODE, DebugElement, DebugEventListener, DebugNode, DefaultIterableDiffer, Directive, ElementRef, EmbeddedViewRef, ErrorHandler, EventEmitter, Host, HostBinding, HostListener, INJECTOR, Inject, InjectFlags, Injectable, InjectionToken, Injector, Input, IterableDiffers, KeyValueDiffers, LOCALE_ID$1 as LOCALE_ID, MissingTranslationStrategy, ModuleWithComponentFactories, NO_ERRORS_SCHEMA, NgModule, NgModuleFactory, NgModuleFactoryLoader, NgModuleRef, NgProbeToken, NgZone, Optional, Output, PACKAGE_ROOT_URL, PLATFORM_ID, PLATFORM_INITIALIZER, Pipe, PlatformRef, Query, QueryList, ReflectiveInjector, ReflectiveKey, Renderer2, RendererFactory2, RendererStyleFlags2, ResolvedReflectiveFactory, Sanitizer, SecurityContext, Self, SimpleChange, SkipSelf, SystemJsNgModuleLoader, SystemJsNgModuleLoaderConfig, TRANSLATIONS, TRANSLATIONS_FORMAT, TemplateRef, Testability, TestabilityRegistry, Type, VERSION, Version, ViewChild, ViewChildren, ViewContainerRef, ViewEncapsulation$1 as ViewEncapsulation, ViewRef$1 as ViewRef, WrappedValue, asNativeElements, assertPlatform, createPlatform, createPlatformFactory, defineInjectable, destroyPlatform, enableProdMode, forwardRef, getDebugNode$1 as getDebugNode, getModuleFactory, getPlatform, inject, isDevMode, platformCore, resolveForwardRef, setTestabilityGetter, ɵ0, ɵ1, ALLOW_MULTIPLE_PLATFORMS as ɵALLOW_MULTIPLE_PLATFORMS, APP_ID_RANDOM_PROVIDER as ɵAPP_ID_RANDOM_PROVIDER, ChangeDetectorStatus as ɵChangeDetectorStatus, CodegenComponentFactoryResolver as ɵCodegenComponentFactoryResolver, Compiler_compileModuleAndAllComponentsAsync__POST_R3__ as ɵCompiler_compileModuleAndAllComponentsAsync__POST_R3__, Compiler_compileModuleAndAllComponentsSync__POST_R3__ as ɵCompiler_compileModuleAndAllComponentsSync__POST_R3__, Compiler_compileModuleAsync__POST_R3__ as ɵCompiler_compileModuleAsync__POST_R3__, Compiler_compileModuleSync__POST_R3__ as ɵCompiler_compileModuleSync__POST_R3__, ComponentFactory as ɵComponentFactory, Console as ɵConsole, DEFAULT_LOCALE_ID as ɵDEFAULT_LOCALE_ID, EMPTY_ARRAY$4 as ɵEMPTY_ARRAY, EMPTY_MAP as ɵEMPTY_MAP, INJECTOR_IMPL__POST_R3__ as ɵINJECTOR_IMPL__POST_R3__, INJECTOR_SCOPE as ɵINJECTOR_SCOPE, LifecycleHooksFeature as ɵLifecycleHooksFeature, LocaleDataIndex as ɵLocaleDataIndex, NG_COMP_DEF as ɵNG_COMP_DEF, NG_DIR_DEF as ɵNG_DIR_DEF, NG_ELEMENT_ID as ɵNG_ELEMENT_ID, NG_INJ_DEF as ɵNG_INJ_DEF, NG_MOD_DEF as ɵNG_MOD_DEF, NG_PIPE_DEF as ɵNG_PIPE_DEF, NG_PROV_DEF as ɵNG_PROV_DEF, NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR as ɵNOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR, NO_CHANGE as ɵNO_CHANGE, NgModuleFactory$1 as ɵNgModuleFactory, NoopNgZone as ɵNoopNgZone, ReflectionCapabilities as ɵReflectionCapabilities, ComponentFactory$1 as ɵRender3ComponentFactory, ComponentRef$1 as ɵRender3ComponentRef, NgModuleRef$1 as ɵRender3NgModuleRef, SWITCH_CHANGE_DETECTOR_REF_FACTORY__POST_R3__ as ɵSWITCH_CHANGE_DETECTOR_REF_FACTORY__POST_R3__, SWITCH_COMPILE_COMPONENT__POST_R3__ as ɵSWITCH_COMPILE_COMPONENT__POST_R3__, SWITCH_COMPILE_DIRECTIVE__POST_R3__ as ɵSWITCH_COMPILE_DIRECTIVE__POST_R3__, SWITCH_COMPILE_INJECTABLE__POST_R3__ as ɵSWITCH_COMPILE_INJECTABLE__POST_R3__, SWITCH_COMPILE_NGMODULE__POST_R3__ as ɵSWITCH_COMPILE_NGMODULE__POST_R3__, SWITCH_COMPILE_PIPE__POST_R3__ as ɵSWITCH_COMPILE_PIPE__POST_R3__, SWITCH_ELEMENT_REF_FACTORY__POST_R3__ as ɵSWITCH_ELEMENT_REF_FACTORY__POST_R3__, SWITCH_IVY_ENABLED__POST_R3__ as ɵSWITCH_IVY_ENABLED__POST_R3__, SWITCH_RENDERER2_FACTORY__POST_R3__ as ɵSWITCH_RENDERER2_FACTORY__POST_R3__, SWITCH_TEMPLATE_REF_FACTORY__POST_R3__ as ɵSWITCH_TEMPLATE_REF_FACTORY__POST_R3__, SWITCH_VIEW_CONTAINER_REF_FACTORY__POST_R3__ as ɵSWITCH_VIEW_CONTAINER_REF_FACTORY__POST_R3__, _sanitizeHtml as ɵ_sanitizeHtml, _sanitizeUrl as ɵ_sanitizeUrl, allowSanitizationBypassAndThrow as ɵallowSanitizationBypassAndThrow, anchorDef as ɵand, isForwardRef as ɵangular_packages_core_core_a, injectInjectorOnly as ɵangular_packages_core_core_b, instructionState as ɵangular_packages_core_core_ba, getLView as ɵangular_packages_core_core_bb, getPreviousOrParentTNode as ɵangular_packages_core_core_bc, getBindingRoot as ɵangular_packages_core_core_bd, nextContextImpl as ɵangular_packages_core_core_be, pureFunction1Internal as ɵangular_packages_core_core_bg, pureFunction2Internal as ɵangular_packages_core_core_bh, pureFunction3Internal as ɵangular_packages_core_core_bi, pureFunction4Internal as ɵangular_packages_core_core_bj, pureFunctionVInternal as ɵangular_packages_core_core_bk, getUrlSanitizer as ɵangular_packages_core_core_bl, makeParamDecorator as ɵangular_packages_core_core_bm, makePropDecorator as ɵangular_packages_core_core_bn, getClosureSafeProperty as ɵangular_packages_core_core_bo, noSideEffects as ɵangular_packages_core_core_bq, getRootContext as ɵangular_packages_core_core_br, NullInjector as ɵangular_packages_core_core_c, ReflectiveInjector_ as ɵangular_packages_core_core_d, ReflectiveDependency as ɵangular_packages_core_core_e, resolveReflectiveProviders as ɵangular_packages_core_core_f, _appIdRandomProviderFactory as ɵangular_packages_core_core_g, createElementRef as ɵangular_packages_core_core_h, createTemplateRef as ɵangular_packages_core_core_i, getModuleFactory__PRE_R3__ as ɵangular_packages_core_core_j, DebugNode__PRE_R3__ as ɵangular_packages_core_core_k, DebugElement__PRE_R3__ as ɵangular_packages_core_core_l, getDebugNodeR2__PRE_R3__ as ɵangular_packages_core_core_m, DefaultIterableDifferFactory as ɵangular_packages_core_core_n, DefaultKeyValueDifferFactory as ɵangular_packages_core_core_o, _iterableDiffersFactory as ɵangular_packages_core_core_p, _keyValueDiffersFactory as ɵangular_packages_core_core_q, _localeFactory as ɵangular_packages_core_core_r, APPLICATION_MODULE_PROVIDERS as ɵangular_packages_core_core_s, zoneSchedulerFactory as ɵangular_packages_core_core_t, USD_CURRENCY_CODE as ɵangular_packages_core_core_u, _def as ɵangular_packages_core_core_v, DebugContext as ɵangular_packages_core_core_w, NgOnChangesFeatureImpl as ɵangular_packages_core_core_x, SCHEDULER as ɵangular_packages_core_core_y, injectAttributeImpl as ɵangular_packages_core_core_z, bypassSanitizationTrustHtml as ɵbypassSanitizationTrustHtml, bypassSanitizationTrustResourceUrl as ɵbypassSanitizationTrustResourceUrl, bypassSanitizationTrustScript as ɵbypassSanitizationTrustScript, bypassSanitizationTrustStyle as ɵbypassSanitizationTrustStyle, bypassSanitizationTrustUrl as ɵbypassSanitizationTrustUrl, createComponentFactory as ɵccf, clearOverrides as ɵclearOverrides, clearResolutionOfComponentResourcesQueue as ɵclearResolutionOfComponentResourcesQueue, createNgModuleFactory as ɵcmf, compileComponent as ɵcompileComponent, compileDirective as ɵcompileDirective, compileNgModule as ɵcompileNgModule, compileNgModuleDefs as ɵcompileNgModuleDefs, compileNgModuleFactory__POST_R3__ as ɵcompileNgModuleFactory__POST_R3__, compilePipe as ɵcompilePipe, createInjector as ɵcreateInjector, createRendererType2 as ɵcrt, defaultIterableDiffers as ɵdefaultIterableDiffers, defaultKeyValueDiffers as ɵdefaultKeyValueDiffers, detectChanges as ɵdetectChanges, devModeEqual as ɵdevModeEqual, directiveDef as ɵdid, elementDef as ɵeld, findLocaleData as ɵfindLocaleData, flushModuleScopingQueueAsMuchAsPossible as ɵflushModuleScopingQueueAsMuchAsPossible, getComponentViewDefinitionFactory as ɵgetComponentViewDefinitionFactory, getDebugNodeR2 as ɵgetDebugNodeR2, getDebugNode__POST_R3__ as ɵgetDebugNode__POST_R3__, getDirectives as ɵgetDirectives, getHostElement as ɵgetHostElement, getInjectableDef as ɵgetInjectableDef, getLContext as ɵgetLContext, getLocaleCurrencyCode as ɵgetLocaleCurrencyCode, getLocalePluralCase as ɵgetLocalePluralCase, getModuleFactory__POST_R3__ as ɵgetModuleFactory__POST_R3__, getSanitizationBypassType as ɵgetSanitizationBypassType, _global as ɵglobal, initServicesIfNeeded as ɵinitServicesIfNeeded, inlineInterpolate as ɵinlineInterpolate, interpolate as ɵinterpolate, isBoundToModule__POST_R3__ as ɵisBoundToModule__POST_R3__, isDefaultChangeDetectionStrategy as ɵisDefaultChangeDetectionStrategy, isListLikeIterable as ɵisListLikeIterable, isObservable as ɵisObservable, isPromise as ɵisPromise, ivyEnabled as ɵivyEnabled, makeDecorator as ɵmakeDecorator, markDirty as ɵmarkDirty, moduleDef as ɵmod, moduleProvideDef as ɵmpd, ngContentDef as ɵncd, nodeValue as ɵnov, overrideComponentView as ɵoverrideComponentView, overrideProvider as ɵoverrideProvider, pureArrayDef as ɵpad, patchComponentDefWithScope as ɵpatchComponentDefWithScope, pipeDef as ɵpid, pureObjectDef as ɵpod, purePipeDef as ɵppd, providerDef as ɵprd, publishDefaultGlobalUtils as ɵpublishDefaultGlobalUtils, publishGlobalUtil as ɵpublishGlobalUtil, queryDef as ɵqud, registerLocaleData as ɵregisterLocaleData, registerModuleFactory as ɵregisterModuleFactory, registerNgModuleType as ɵregisterNgModuleType, renderComponent$1 as ɵrenderComponent, resetCompiledComponents as ɵresetCompiledComponents, resetJitOptions as ɵresetJitOptions, resolveComponentResources as ɵresolveComponentResources, setClassMetadata as ɵsetClassMetadata, setCurrentInjector as ɵsetCurrentInjector, setDocument as ɵsetDocument, setLocaleId as ɵsetLocaleId, store as ɵstore, stringify as ɵstringify, textDef as ɵted, transitiveScopesFor as ɵtransitiveScopesFor, unregisterAllLocaleData as ɵunregisterLocaleData, unwrapValue as ɵunv, unwrapSafeValue as ɵunwrapSafeValue, viewDef as ɵvid, whenRendered as ɵwhenRendered, ɵɵCopyDefinitionFeature, ɵɵInheritDefinitionFeature, ɵɵNgOnChangesFeature, ɵɵProvidersFeature, ɵɵadvance, ɵɵattribute, ɵɵattributeInterpolate1, ɵɵattributeInterpolate2, ɵɵattributeInterpolate3, ɵɵattributeInterpolate4, ɵɵattributeInterpolate5, ɵɵattributeInterpolate6, ɵɵattributeInterpolate7, ɵɵattributeInterpolate8, ɵɵattributeInterpolateV, ɵɵclassMap, ɵɵclassMapInterpolate1, ɵɵclassMapInterpolate2, ɵɵclassMapInterpolate3, ɵɵclassMapInterpolate4, ɵɵclassMapInterpolate5, ɵɵclassMapInterpolate6, ɵɵclassMapInterpolate7, ɵɵclassMapInterpolate8, ɵɵclassMapInterpolateV, ɵɵclassProp, ɵɵcontentQuery, ɵɵdefineComponent, ɵɵdefineDirective, ɵɵdefineInjectable, ɵɵdefineInjector, ɵɵdefineNgModule, ɵɵdefinePipe, ɵɵdirectiveInject, ɵɵdisableBindings, ɵɵelement, ɵɵelementContainer, ɵɵelementContainerEnd, ɵɵelementContainerStart, ɵɵelementEnd, ɵɵelementStart, ɵɵenableBindings, ɵɵgetCurrentView, ɵɵgetFactoryOf, ɵɵgetInheritedFactory, ɵɵhostProperty, ɵɵi18n, ɵɵi18nApply, ɵɵi18nAttributes, ɵɵi18nEnd, ɵɵi18nExp, ɵɵi18nPostprocess, ɵɵi18nStart, ɵɵinject, ɵɵinjectAttribute, ɵɵinjectPipeChangeDetectorRef, ɵɵinvalidFactory, ɵɵinvalidFactoryDep, ɵɵlistener, ɵɵloadQuery, ɵɵnamespaceHTML, ɵɵnamespaceMathML, ɵɵnamespaceSVG, ɵɵnextContext, ɵɵpipe, ɵɵpipeBind1, ɵɵpipeBind2, ɵɵpipeBind3, ɵɵpipeBind4, ɵɵpipeBindV, ɵɵprojection, ɵɵprojectionDef, ɵɵproperty, ɵɵpropertyInterpolate, ɵɵpropertyInterpolate1, ɵɵpropertyInterpolate2, ɵɵpropertyInterpolate3, ɵɵpropertyInterpolate4, ɵɵpropertyInterpolate5, ɵɵpropertyInterpolate6, ɵɵpropertyInterpolate7, ɵɵpropertyInterpolate8, ɵɵpropertyInterpolateV, ɵɵpureFunction0, ɵɵpureFunction1, ɵɵpureFunction2, ɵɵpureFunction3, ɵɵpureFunction4, ɵɵpureFunction5, ɵɵpureFunction6, ɵɵpureFunction7, ɵɵpureFunction8, ɵɵpureFunctionV, ɵɵqueryRefresh, ɵɵreference, ɵɵresolveBody, ɵɵresolveDocument, ɵɵresolveWindow, ɵɵrestoreView, ɵɵsanitizeHtml, ɵɵsanitizeResourceUrl, ɵɵsanitizeScript, ɵɵsanitizeStyle, ɵɵsanitizeUrl, ɵɵsanitizeUrlOrResourceUrl, ɵɵselect, ɵɵsetComponentScope, ɵɵsetNgModuleScope, ɵɵstaticContentQuery, ɵɵstaticViewQuery, ɵɵstyleMap, ɵɵstyleMapInterpolate1, ɵɵstyleMapInterpolate2, ɵɵstyleMapInterpolate3, ɵɵstyleMapInterpolate4, ɵɵstyleMapInterpolate5, ɵɵstyleMapInterpolate6, ɵɵstyleMapInterpolate7, ɵɵstyleMapInterpolate8, ɵɵstyleMapInterpolateV, ɵɵstyleProp, ɵɵstylePropInterpolate1, ɵɵstylePropInterpolate2, ɵɵstylePropInterpolate3, ɵɵstylePropInterpolate4, ɵɵstylePropInterpolate5, ɵɵstylePropInterpolate6, ɵɵstylePropInterpolate7, ɵɵstylePropInterpolate8, ɵɵstylePropInterpolateV, ɵɵsyntheticHostListener, ɵɵsyntheticHostProperty, ɵɵtemplate, ɵɵtemplateRefExtractor, ɵɵtext, ɵɵtextInterpolate, ɵɵtextInterpolate1, ɵɵtextInterpolate2, ɵɵtextInterpolate3, ɵɵtextInterpolate4, ɵɵtextInterpolate5, ɵɵtextInterpolate6, ɵɵtextInterpolate7, ɵɵtextInterpolate8, ɵɵtextInterpolateV, ɵɵviewQuery };
31742
+ export { ANALYZE_FOR_ENTRY_COMPONENTS, APP_BOOTSTRAP_LISTENER, APP_ID, APP_INITIALIZER, ApplicationInitStatus, ApplicationModule, ApplicationRef, Attribute, COMPILER_OPTIONS, CUSTOM_ELEMENTS_SCHEMA, ChangeDetectionStrategy, ChangeDetectorRef, Compiler, CompilerFactory, Component, ComponentFactory, ComponentFactoryResolver, ComponentRef, ContentChild, ContentChildren, DEFAULT_CURRENCY_CODE, DebugElement, DebugEventListener, DebugNode, DefaultIterableDiffer, Directive, ElementRef, EmbeddedViewRef, ErrorHandler, EventEmitter, Host, HostBinding, HostListener, INJECTOR, Inject, InjectFlags, Injectable, InjectionToken, Injector, Input, IterableDiffers, KeyValueDiffers, LOCALE_ID$1 as LOCALE_ID, MissingTranslationStrategy, ModuleWithComponentFactories, NO_ERRORS_SCHEMA, NgModule, NgModuleFactory, NgModuleFactoryLoader, NgModuleRef, NgProbeToken, NgZone, Optional, Output, PACKAGE_ROOT_URL, PLATFORM_ID, PLATFORM_INITIALIZER, Pipe, PlatformRef, Query, QueryList, ReflectiveInjector, ReflectiveKey, Renderer2, RendererFactory2, RendererStyleFlags2, ResolvedReflectiveFactory, Sanitizer, SecurityContext, Self, SimpleChange, SkipSelf, SystemJsNgModuleLoader, SystemJsNgModuleLoaderConfig, TRANSLATIONS, TRANSLATIONS_FORMAT, TemplateRef, Testability, TestabilityRegistry, Type, VERSION, Version, ViewChild, ViewChildren, ViewContainerRef, ViewEncapsulation$1 as ViewEncapsulation, ViewRef$1 as ViewRef, WrappedValue, asNativeElements, assertPlatform, createPlatform, createPlatformFactory, defineInjectable, destroyPlatform, enableProdMode, forwardRef, getDebugNode$1 as getDebugNode, getModuleFactory, getPlatform, inject, isDevMode, platformCore, resolveForwardRef, setTestabilityGetter, ɵ0, ɵ1, ALLOW_MULTIPLE_PLATFORMS as ɵALLOW_MULTIPLE_PLATFORMS, APP_ID_RANDOM_PROVIDER as ɵAPP_ID_RANDOM_PROVIDER, ChangeDetectorStatus as ɵChangeDetectorStatus, CodegenComponentFactoryResolver as ɵCodegenComponentFactoryResolver, Compiler_compileModuleAndAllComponentsAsync__POST_R3__ as ɵCompiler_compileModuleAndAllComponentsAsync__POST_R3__, Compiler_compileModuleAndAllComponentsSync__POST_R3__ as ɵCompiler_compileModuleAndAllComponentsSync__POST_R3__, Compiler_compileModuleAsync__POST_R3__ as ɵCompiler_compileModuleAsync__POST_R3__, Compiler_compileModuleSync__POST_R3__ as ɵCompiler_compileModuleSync__POST_R3__, ComponentFactory as ɵComponentFactory, Console as ɵConsole, DEFAULT_LOCALE_ID as ɵDEFAULT_LOCALE_ID, EMPTY_ARRAY$4 as ɵEMPTY_ARRAY, EMPTY_MAP as ɵEMPTY_MAP, INJECTOR_IMPL__POST_R3__ as ɵINJECTOR_IMPL__POST_R3__, INJECTOR_SCOPE as ɵINJECTOR_SCOPE, LifecycleHooksFeature as ɵLifecycleHooksFeature, LocaleDataIndex as ɵLocaleDataIndex, NG_COMP_DEF as ɵNG_COMP_DEF, NG_DIR_DEF as ɵNG_DIR_DEF, NG_ELEMENT_ID as ɵNG_ELEMENT_ID, NG_INJ_DEF as ɵNG_INJ_DEF, NG_MOD_DEF as ɵNG_MOD_DEF, NG_PIPE_DEF as ɵNG_PIPE_DEF, NG_PROV_DEF as ɵNG_PROV_DEF, NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR as ɵNOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR, NO_CHANGE as ɵNO_CHANGE, NgModuleFactory$1 as ɵNgModuleFactory, NoopNgZone as ɵNoopNgZone, ReflectionCapabilities as ɵReflectionCapabilities, ComponentFactory$1 as ɵRender3ComponentFactory, ComponentRef$1 as ɵRender3ComponentRef, NgModuleRef$1 as ɵRender3NgModuleRef, SWITCH_CHANGE_DETECTOR_REF_FACTORY__POST_R3__ as ɵSWITCH_CHANGE_DETECTOR_REF_FACTORY__POST_R3__, SWITCH_COMPILE_COMPONENT__POST_R3__ as ɵSWITCH_COMPILE_COMPONENT__POST_R3__, SWITCH_COMPILE_DIRECTIVE__POST_R3__ as ɵSWITCH_COMPILE_DIRECTIVE__POST_R3__, SWITCH_COMPILE_INJECTABLE__POST_R3__ as ɵSWITCH_COMPILE_INJECTABLE__POST_R3__, SWITCH_COMPILE_NGMODULE__POST_R3__ as ɵSWITCH_COMPILE_NGMODULE__POST_R3__, SWITCH_COMPILE_PIPE__POST_R3__ as ɵSWITCH_COMPILE_PIPE__POST_R3__, SWITCH_ELEMENT_REF_FACTORY__POST_R3__ as ɵSWITCH_ELEMENT_REF_FACTORY__POST_R3__, SWITCH_IVY_ENABLED__POST_R3__ as ɵSWITCH_IVY_ENABLED__POST_R3__, SWITCH_RENDERER2_FACTORY__POST_R3__ as ɵSWITCH_RENDERER2_FACTORY__POST_R3__, SWITCH_TEMPLATE_REF_FACTORY__POST_R3__ as ɵSWITCH_TEMPLATE_REF_FACTORY__POST_R3__, SWITCH_VIEW_CONTAINER_REF_FACTORY__POST_R3__ as ɵSWITCH_VIEW_CONTAINER_REF_FACTORY__POST_R3__, _sanitizeHtml as ɵ_sanitizeHtml, _sanitizeUrl as ɵ_sanitizeUrl, allowSanitizationBypassAndThrow as ɵallowSanitizationBypassAndThrow, anchorDef as ɵand, isForwardRef as ɵangular_packages_core_core_a, injectInjectorOnly as ɵangular_packages_core_core_b, instructionState as ɵangular_packages_core_core_ba, getLView as ɵangular_packages_core_core_bb, getPreviousOrParentTNode as ɵangular_packages_core_core_bc, getBindingRoot as ɵangular_packages_core_core_bd, nextContextImpl as ɵangular_packages_core_core_be, pureFunction1Internal as ɵangular_packages_core_core_bg, pureFunction2Internal as ɵangular_packages_core_core_bh, pureFunction3Internal as ɵangular_packages_core_core_bi, pureFunction4Internal as ɵangular_packages_core_core_bj, pureFunctionVInternal as ɵangular_packages_core_core_bk, getUrlSanitizer as ɵangular_packages_core_core_bl, makeParamDecorator as ɵangular_packages_core_core_bm, makePropDecorator as ɵangular_packages_core_core_bn, getClosureSafeProperty as ɵangular_packages_core_core_bo, getRootContext as ɵangular_packages_core_core_bq, i18nPostprocess as ɵangular_packages_core_core_br, NullInjector as ɵangular_packages_core_core_c, ReflectiveInjector_ as ɵangular_packages_core_core_d, ReflectiveDependency as ɵangular_packages_core_core_e, resolveReflectiveProviders as ɵangular_packages_core_core_f, _appIdRandomProviderFactory as ɵangular_packages_core_core_g, createElementRef as ɵangular_packages_core_core_h, createTemplateRef as ɵangular_packages_core_core_i, getModuleFactory__PRE_R3__ as ɵangular_packages_core_core_j, DebugNode__PRE_R3__ as ɵangular_packages_core_core_k, DebugElement__PRE_R3__ as ɵangular_packages_core_core_l, getDebugNodeR2__PRE_R3__ as ɵangular_packages_core_core_m, DefaultIterableDifferFactory as ɵangular_packages_core_core_n, DefaultKeyValueDifferFactory as ɵangular_packages_core_core_o, _iterableDiffersFactory as ɵangular_packages_core_core_p, _keyValueDiffersFactory as ɵangular_packages_core_core_q, _localeFactory as ɵangular_packages_core_core_r, APPLICATION_MODULE_PROVIDERS as ɵangular_packages_core_core_s, zoneSchedulerFactory as ɵangular_packages_core_core_t, USD_CURRENCY_CODE as ɵangular_packages_core_core_u, _def as ɵangular_packages_core_core_v, DebugContext as ɵangular_packages_core_core_w, NgOnChangesFeatureImpl as ɵangular_packages_core_core_x, SCHEDULER as ɵangular_packages_core_core_y, injectAttributeImpl as ɵangular_packages_core_core_z, bypassSanitizationTrustHtml as ɵbypassSanitizationTrustHtml, bypassSanitizationTrustResourceUrl as ɵbypassSanitizationTrustResourceUrl, bypassSanitizationTrustScript as ɵbypassSanitizationTrustScript, bypassSanitizationTrustStyle as ɵbypassSanitizationTrustStyle, bypassSanitizationTrustUrl as ɵbypassSanitizationTrustUrl, createComponentFactory as ɵccf, clearOverrides as ɵclearOverrides, clearResolutionOfComponentResourcesQueue as ɵclearResolutionOfComponentResourcesQueue, createNgModuleFactory as ɵcmf, compileComponent as ɵcompileComponent, compileDirective as ɵcompileDirective, compileNgModule as ɵcompileNgModule, compileNgModuleDefs as ɵcompileNgModuleDefs, compileNgModuleFactory__POST_R3__ as ɵcompileNgModuleFactory__POST_R3__, compilePipe as ɵcompilePipe, createInjector as ɵcreateInjector, createRendererType2 as ɵcrt, defaultIterableDiffers as ɵdefaultIterableDiffers, defaultKeyValueDiffers as ɵdefaultKeyValueDiffers, detectChanges as ɵdetectChanges, devModeEqual as ɵdevModeEqual, directiveDef as ɵdid, elementDef as ɵeld, findLocaleData as ɵfindLocaleData, flushModuleScopingQueueAsMuchAsPossible as ɵflushModuleScopingQueueAsMuchAsPossible, getComponentViewDefinitionFactory as ɵgetComponentViewDefinitionFactory, getDebugNodeR2 as ɵgetDebugNodeR2, getDebugNode__POST_R3__ as ɵgetDebugNode__POST_R3__, getDirectives as ɵgetDirectives, getHostElement as ɵgetHostElement, getInjectableDef as ɵgetInjectableDef, getLContext as ɵgetLContext, getLocaleCurrencyCode as ɵgetLocaleCurrencyCode, getLocalePluralCase as ɵgetLocalePluralCase, getModuleFactory__POST_R3__ as ɵgetModuleFactory__POST_R3__, getSanitizationBypassType as ɵgetSanitizationBypassType, _global as ɵglobal, initServicesIfNeeded as ɵinitServicesIfNeeded, inlineInterpolate as ɵinlineInterpolate, interpolate as ɵinterpolate, isBoundToModule__POST_R3__ as ɵisBoundToModule__POST_R3__, isDefaultChangeDetectionStrategy as ɵisDefaultChangeDetectionStrategy, isListLikeIterable as ɵisListLikeIterable, isObservable as ɵisObservable, isPromise as ɵisPromise, ivyEnabled as ɵivyEnabled, makeDecorator as ɵmakeDecorator, markDirty as ɵmarkDirty, moduleDef as ɵmod, moduleProvideDef as ɵmpd, ngContentDef as ɵncd, noSideEffects as ɵnoSideEffects, nodeValue as ɵnov, overrideComponentView as ɵoverrideComponentView, overrideProvider as ɵoverrideProvider, pureArrayDef as ɵpad, patchComponentDefWithScope as ɵpatchComponentDefWithScope, pipeDef as ɵpid, pureObjectDef as ɵpod, purePipeDef as ɵppd, providerDef as ɵprd, publishDefaultGlobalUtils as ɵpublishDefaultGlobalUtils, publishGlobalUtil as ɵpublishGlobalUtil, queryDef as ɵqud, registerLocaleData as ɵregisterLocaleData, registerModuleFactory as ɵregisterModuleFactory, registerNgModuleType as ɵregisterNgModuleType, renderComponent$1 as ɵrenderComponent, resetCompiledComponents as ɵresetCompiledComponents, resetJitOptions as ɵresetJitOptions, resolveComponentResources as ɵresolveComponentResources, setClassMetadata as ɵsetClassMetadata, setCurrentInjector as ɵsetCurrentInjector, setDocument as ɵsetDocument, setLocaleId as ɵsetLocaleId, store as ɵstore, stringify as ɵstringify, textDef as ɵted, transitiveScopesFor as ɵtransitiveScopesFor, unregisterAllLocaleData as ɵunregisterLocaleData, unwrapValue as ɵunv, unwrapSafeValue as ɵunwrapSafeValue, viewDef as ɵvid, whenRendered as ɵwhenRendered, ɵɵCopyDefinitionFeature, ɵɵInheritDefinitionFeature, ɵɵNgOnChangesFeature, ɵɵProvidersFeature, ɵɵadvance, ɵɵattribute, ɵɵattributeInterpolate1, ɵɵattributeInterpolate2, ɵɵattributeInterpolate3, ɵɵattributeInterpolate4, ɵɵattributeInterpolate5, ɵɵattributeInterpolate6, ɵɵattributeInterpolate7, ɵɵattributeInterpolate8, ɵɵattributeInterpolateV, ɵɵclassMap, ɵɵclassMapInterpolate1, ɵɵclassMapInterpolate2, ɵɵclassMapInterpolate3, ɵɵclassMapInterpolate4, ɵɵclassMapInterpolate5, ɵɵclassMapInterpolate6, ɵɵclassMapInterpolate7, ɵɵclassMapInterpolate8, ɵɵclassMapInterpolateV, ɵɵclassProp, ɵɵcontentQuery, ɵɵdefineComponent, ɵɵdefineDirective, ɵɵdefineInjectable, ɵɵdefineInjector, ɵɵdefineNgModule, ɵɵdefinePipe, ɵɵdirectiveInject, ɵɵdisableBindings, ɵɵelement, ɵɵelementContainer, ɵɵelementContainerEnd, ɵɵelementContainerStart, ɵɵelementEnd, ɵɵelementStart, ɵɵenableBindings, ɵɵgetCurrentView, ɵɵgetFactoryOf, ɵɵgetInheritedFactory, ɵɵhostProperty, ɵɵi18n, ɵɵi18nApply, ɵɵi18nAttributes, ɵɵi18nEnd, ɵɵi18nExp, ɵɵi18nPostprocess, ɵɵi18nStart, ɵɵinject, ɵɵinjectAttribute, ɵɵinjectPipeChangeDetectorRef, ɵɵinvalidFactory, ɵɵinvalidFactoryDep, ɵɵlistener, ɵɵloadQuery, ɵɵnamespaceHTML, ɵɵnamespaceMathML, ɵɵnamespaceSVG, ɵɵnextContext, ɵɵpipe, ɵɵpipeBind1, ɵɵpipeBind2, ɵɵpipeBind3, ɵɵpipeBind4, ɵɵpipeBindV, ɵɵprojection, ɵɵprojectionDef, ɵɵproperty, ɵɵpropertyInterpolate, ɵɵpropertyInterpolate1, ɵɵpropertyInterpolate2, ɵɵpropertyInterpolate3, ɵɵpropertyInterpolate4, ɵɵpropertyInterpolate5, ɵɵpropertyInterpolate6, ɵɵpropertyInterpolate7, ɵɵpropertyInterpolate8, ɵɵpropertyInterpolateV, ɵɵpureFunction0, ɵɵpureFunction1, ɵɵpureFunction2, ɵɵpureFunction3, ɵɵpureFunction4, ɵɵpureFunction5, ɵɵpureFunction6, ɵɵpureFunction7, ɵɵpureFunction8, ɵɵpureFunctionV, ɵɵqueryRefresh, ɵɵreference, ɵɵresolveBody, ɵɵresolveDocument, ɵɵresolveWindow, ɵɵrestoreView, ɵɵsanitizeHtml, ɵɵsanitizeResourceUrl, ɵɵsanitizeScript, ɵɵsanitizeStyle, ɵɵsanitizeUrl, ɵɵsanitizeUrlOrResourceUrl, ɵɵselect, ɵɵsetComponentScope, ɵɵsetNgModuleScope, ɵɵstaticContentQuery, ɵɵstaticViewQuery, ɵɵstyleMap, ɵɵstyleMapInterpolate1, ɵɵstyleMapInterpolate2, ɵɵstyleMapInterpolate3, ɵɵstyleMapInterpolate4, ɵɵstyleMapInterpolate5, ɵɵstyleMapInterpolate6, ɵɵstyleMapInterpolate7, ɵɵstyleMapInterpolate8, ɵɵstyleMapInterpolateV, ɵɵstyleProp, ɵɵstylePropInterpolate1, ɵɵstylePropInterpolate2, ɵɵstylePropInterpolate3, ɵɵstylePropInterpolate4, ɵɵstylePropInterpolate5, ɵɵstylePropInterpolate6, ɵɵstylePropInterpolate7, ɵɵstylePropInterpolate8, ɵɵstylePropInterpolateV, ɵɵsyntheticHostListener, ɵɵsyntheticHostProperty, ɵɵtemplate, ɵɵtemplateRefExtractor, ɵɵtext, ɵɵtextInterpolate, ɵɵtextInterpolate1, ɵɵtextInterpolate2, ɵɵtextInterpolate3, ɵɵtextInterpolate4, ɵɵtextInterpolate5, ɵɵtextInterpolate6, ɵɵtextInterpolate7, ɵɵtextInterpolate8, ɵɵtextInterpolateV, ɵɵviewQuery };
31455
31743
  //# sourceMappingURL=core.js.map