@wavemaker-ai/angular-codegen 1.0.0-rc.330 → 1.0.0-rc.334

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.
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  /**
4
- * @license Angular v20.3.19
4
+ * @license Angular v20.3.28
5
5
  * (c) 2010-2025 Google LLC. https://angular.dev/
6
6
  * License: MIT
7
7
  */
@@ -408,6 +408,151 @@ class SelectorlessMatcher {
408
408
  return this.registry.has(name) ? this.registry.get(name) : [];
409
409
  }
410
410
  }
411
+
412
+ /**
413
+ * A SecurityContext marks a location that has dangerous security implications, e.g. a DOM property
414
+ * like `innerHTML` that could cause Cross Site Scripting (XSS) security bugs when improperly
415
+ * handled.
416
+ *
417
+ * See DomSanitizer for more details on security in Angular applications.
418
+ *
419
+ * @publicApi
420
+ */
421
+ var SecurityContext$1;
422
+ (function (SecurityContext) {
423
+ SecurityContext[SecurityContext["NONE"] = 0] = "NONE";
424
+ SecurityContext[SecurityContext["HTML"] = 1] = "HTML";
425
+ SecurityContext[SecurityContext["STYLE"] = 2] = "STYLE";
426
+ SecurityContext[SecurityContext["SCRIPT"] = 3] = "SCRIPT";
427
+ SecurityContext[SecurityContext["URL"] = 4] = "URL";
428
+ SecurityContext[SecurityContext["RESOURCE_URL"] = 5] = "RESOURCE_URL";
429
+ SecurityContext[SecurityContext["ATTRIBUTE_NO_BINDING"] = 6] = "ATTRIBUTE_NO_BINDING";
430
+ })(SecurityContext$1 || (SecurityContext$1 = {}));
431
+ // =================================================================================================
432
+ // =================================================================================================
433
+ // =========== S T O P - S T O P - S T O P - S T O P - S T O P - S T O P ===========
434
+ // =================================================================================================
435
+ // =================================================================================================
436
+ //
437
+ // DO NOT EDIT THIS LIST OF SECURITY SENSITIVE PROPERTIES WITHOUT A SECURITY REVIEW!
438
+ //
439
+ // =================================================================================================
440
+ /**
441
+ * Map from tagName|propertyName to SecurityContext. Properties applying to all tags use '*'.
442
+ */
443
+ let _SECURITY_SCHEMA$1;
444
+ const SVG_NAMESPACE$1$1 = 'svg';
445
+ const MATH_ML_NAMESPACE$1$1 = 'math';
446
+ /**
447
+ * @remarks Keep is a copy of DOM Security Schema.
448
+ * @see [SECURITY_SCHEMA](../../../compiler/src/schema/dom_security_schema.ts)
449
+ */
450
+ function SECURITY_SCHEMA$1() {
451
+ if (!_SECURITY_SCHEMA$1) {
452
+ _SECURITY_SCHEMA$1 = {};
453
+ // Case is insignificant below, all element and attribute names are lower-cased for lookup.
454
+ registerContext$1(SecurityContext$1.HTML, /** Namespace */ undefined, [
455
+ ['iframe', ['srcdoc']],
456
+ ['*', ['innerHTML', 'outerHTML']],
457
+ ]);
458
+ registerContext$1(SecurityContext$1.STYLE, /** Namespace */ undefined, [['*', ['style']]]);
459
+ // NB: no SCRIPT contexts here, they are never allowed due to the parser stripping them.
460
+ registerContext$1(SecurityContext$1.URL, /** Namespace */ undefined, [
461
+ ['*', ['formAction']],
462
+ ['area', ['href']],
463
+ ['a', ['href', 'xlink:href']],
464
+ ['form', ['action']],
465
+ // The below two items are safe and should be removed but they require a G3 clean-up as a small number of tests fail.
466
+ ['img', ['src']],
467
+ ['video', ['src']],
468
+ ]);
469
+ registerContext$1(SecurityContext$1.URL, MATH_ML_NAMESPACE$1$1, [
470
+ // MathML namespace
471
+ // https://crsrc.org/c/third_party/blink/renderer/core/sanitizer/sanitizer.cc;l=753-768;drc=b3eb16372dcd3317d65e9e0265015e322494edcd;bpv=1;bpt=1
472
+ ['*', ['href', 'xlink:href']],
473
+ ['annotation', ['href', 'xlink:href']],
474
+ ['annotation-xml', ['href', 'xlink:href']],
475
+ ['maction', ['href', 'xlink:href']],
476
+ ['malignmark', ['href', 'xlink:href']],
477
+ ['math', ['href', 'xlink:href']],
478
+ ['mroot', ['href', 'xlink:href']],
479
+ ['msqrt', ['href', 'xlink:href']],
480
+ ['merror', ['href', 'xlink:href']],
481
+ ['mfrac', ['href', 'xlink:href']],
482
+ ['mglyph', ['href', 'xlink:href']],
483
+ ['msub', ['href', 'xlink:href']],
484
+ ['msup', ['href', 'xlink:href']],
485
+ ['msubsup', ['href', 'xlink:href']],
486
+ ['mmultiscripts', ['href', 'xlink:href']],
487
+ ['mprescripts', ['href', 'xlink:href']],
488
+ ['mi', ['href', 'xlink:href']],
489
+ ['mn', ['href', 'xlink:href']],
490
+ ['mo', ['href', 'xlink:href']],
491
+ ['mpadded', ['href', 'xlink:href']],
492
+ ['mphantom', ['href', 'xlink:href']],
493
+ ['mrow', ['href', 'xlink:href']],
494
+ ['ms', ['href', 'xlink:href']],
495
+ ['mspace', ['href', 'xlink:href']],
496
+ ['mstyle', ['href', 'xlink:href']],
497
+ ['mtable', ['href', 'xlink:href']],
498
+ ['mtd', ['href', 'xlink:href']],
499
+ ['mtr', ['href', 'xlink:href']],
500
+ ['mtext', ['href', 'xlink:href']],
501
+ ['mover', ['href', 'xlink:href']],
502
+ ['munder', ['href', 'xlink:href']],
503
+ ['munderover', ['href', 'xlink:href']],
504
+ ['semantics', ['href', 'xlink:href']],
505
+ ['none', ['href', 'xlink:href']],
506
+ ]);
507
+ registerContext$1(SecurityContext$1.RESOURCE_URL, /** Namespace */ undefined, [
508
+ ['base', ['href']],
509
+ ['embed', ['src']],
510
+ ['frame', ['src']],
511
+ ['iframe', ['src']],
512
+ ['link', ['href']],
513
+ ['object', ['codebase', 'data']],
514
+ ]);
515
+ registerContext$1(SecurityContext$1.URL, SVG_NAMESPACE$1$1, [['a', ['href', 'xlink:href']]]);
516
+ // Keep this in sync with SECURITY_SENSITIVE_ELEMENTS in packages/core/src/sanitization/sanitization.ts
517
+ // Unknown is the internal tag name for unknown elements example used for host-bindings.
518
+ // These are unsafe as `attributeName` can be `href` or `xlink:href`
519
+ // See: http://b/463880509#comment7
520
+ registerContext$1(SecurityContext$1.ATTRIBUTE_NO_BINDING, SVG_NAMESPACE$1$1, [
521
+ ['animate', ['attributeName', 'values', 'to', 'from']],
522
+ ['set', ['to', 'attributeName']],
523
+ ['animateMotion', ['attributeName']],
524
+ ['animateTransform', ['attributeName']],
525
+ ]);
526
+ registerContext$1(SecurityContext$1.ATTRIBUTE_NO_BINDING, /** Namespace */ undefined, [
527
+ [
528
+ 'unknown',
529
+ [
530
+ 'attributeName',
531
+ 'values',
532
+ 'to',
533
+ 'from',
534
+ 'sandbox',
535
+ 'allow',
536
+ 'allowFullscreen',
537
+ 'referrerPolicy',
538
+ 'csp',
539
+ 'fetchPriority',
540
+ ],
541
+ ],
542
+ ['iframe', ['sandbox', 'allow', 'allowFullscreen', 'referrerPolicy', 'csp', 'fetchPriority']],
543
+ ]);
544
+ }
545
+ return _SECURITY_SCHEMA$1;
546
+ }
547
+ function registerContext$1(ctx, namespace, specs) {
548
+ for (const [element, attributeNames] of specs) {
549
+ let tagName = namespace && element !== 'unknown' ? `:${namespace}:${element}` : element;
550
+ tagName = tagName.toLowerCase();
551
+ for (const attr of attributeNames) {
552
+ _SECURITY_SCHEMA$1[`${tagName}|${attr.toLowerCase()}`] = ctx;
553
+ }
554
+ }
555
+ }
411
556
  var ViewEncapsulation$1$1;
412
557
  (function (ViewEncapsulation) {
413
558
  ViewEncapsulation[ViewEncapsulation["Emulated"] = 0] = "Emulated";
@@ -433,16 +578,6 @@ const CUSTOM_ELEMENTS_SCHEMA$1 = {
433
578
  const NO_ERRORS_SCHEMA$1 = {
434
579
  name: 'no-errors-schema',
435
580
  };
436
- var SecurityContext$1;
437
- (function (SecurityContext) {
438
- SecurityContext[SecurityContext["NONE"] = 0] = "NONE";
439
- SecurityContext[SecurityContext["HTML"] = 1] = "HTML";
440
- SecurityContext[SecurityContext["STYLE"] = 2] = "STYLE";
441
- SecurityContext[SecurityContext["SCRIPT"] = 3] = "SCRIPT";
442
- SecurityContext[SecurityContext["URL"] = 4] = "URL";
443
- SecurityContext[SecurityContext["RESOURCE_URL"] = 5] = "RESOURCE_URL";
444
- SecurityContext[SecurityContext["ATTRIBUTE_NO_BINDING"] = 6] = "ATTRIBUTE_NO_BINDING";
445
- })(SecurityContext$1 || (SecurityContext$1 = {}));
446
581
  var MissingTranslationStrategy$1;
447
582
  (function (MissingTranslationStrategy) {
448
583
  MissingTranslationStrategy[MissingTranslationStrategy["Error"] = 0] = "Error";
@@ -4277,7 +4412,7 @@ var TagContentType;
4277
4412
  TagContentType[TagContentType["ESCAPABLE_RAW_TEXT"] = 1] = "ESCAPABLE_RAW_TEXT";
4278
4413
  TagContentType[TagContentType["PARSABLE_DATA"] = 2] = "PARSABLE_DATA";
4279
4414
  })(TagContentType || (TagContentType = {}));
4280
- function splitNsName(elementName, fatal = true) {
4415
+ function splitNsName$1(elementName, fatal = true) {
4281
4416
  if (elementName[0] != ':') {
4282
4417
  return [null, elementName];
4283
4418
  }
@@ -4294,18 +4429,18 @@ function splitNsName(elementName, fatal = true) {
4294
4429
  }
4295
4430
  // `<ng-container>` tags work the same regardless the namespace
4296
4431
  function isNgContainer(tagName) {
4297
- return splitNsName(tagName)[1] === 'ng-container';
4432
+ return splitNsName$1(tagName)[1] === 'ng-container';
4298
4433
  }
4299
4434
  // `<ng-content>` tags work the same regardless the namespace
4300
4435
  function isNgContent(tagName) {
4301
- return splitNsName(tagName)[1] === 'ng-content';
4436
+ return splitNsName$1(tagName)[1] === 'ng-content';
4302
4437
  }
4303
4438
  // `<ng-template>` tags work the same regardless the namespace
4304
4439
  function isNgTemplate(tagName) {
4305
- return splitNsName(tagName)[1] === 'ng-template';
4440
+ return splitNsName$1(tagName)[1] === 'ng-template';
4306
4441
  }
4307
4442
  function getNsPrefix(fullName) {
4308
- return fullName === null ? null : splitNsName(fullName)[0];
4443
+ return fullName === null ? null : splitNsName$1(fullName)[0];
4309
4444
  }
4310
4445
  function mergeNsAndName(prefix, localName) {
4311
4446
  return prefix ? `:${prefix}:${localName}` : localName;
@@ -5363,10 +5498,10 @@ function createCssSelectorFromNode(node) {
5363
5498
  const elementName = node instanceof Element$1 ? node.name : 'ng-template';
5364
5499
  const attributes = getAttrsForDirectiveMatching(node);
5365
5500
  const cssSelector = new CssSelector();
5366
- const elementNameNoNs = splitNsName(elementName)[1];
5501
+ const elementNameNoNs = splitNsName$1(elementName)[1];
5367
5502
  cssSelector.setElement(elementNameNoNs);
5368
5503
  Object.getOwnPropertyNames(attributes).forEach((name) => {
5369
- const nameNoNs = splitNsName(name)[1];
5504
+ const nameNoNs = splitNsName$1(name)[1];
5370
5505
  const value = attributes[name];
5371
5506
  cssSelector.addAttribute(nameNoNs, value);
5372
5507
  if (name.toLowerCase() === 'class') {
@@ -11013,7 +11148,7 @@ function specializeBindings(job) {
11013
11148
  OpList.replace(op, createAnimationBindingOp(op.name, op.target, op.name === 'animate.enter' ? "enter" /* ir.AnimationKind.ENTER */ : "leave" /* ir.AnimationKind.LEAVE */, op.expression, op.securityContext, op.sourceSpan, 0 /* ir.AnimationBindingKind.STRING */));
11014
11149
  }
11015
11150
  else {
11016
- const [namespace, name] = splitNsName(op.name);
11151
+ const [namespace, name] = splitNsName$1(op.name);
11017
11152
  OpList.replace(op, createAttributeOp(op.target, namespace, name, op.expression, op.securityContext, op.isTextAttribute, op.isStructuralTemplateAttribute, op.templateKind, op.i18nMessage, op.sourceSpan));
11018
11153
  }
11019
11154
  break;
@@ -11451,10 +11586,7 @@ class ElementAttributes {
11451
11586
  if (value === null) {
11452
11587
  throw Error('Attribute, i18n attribute, & style element attributes must have a value');
11453
11588
  }
11454
- if (trustedValueFn !== null) {
11455
- if (!isStringLiteral(value)) {
11456
- throw Error('AssertionError: extracted attribute value should be string literal');
11457
- }
11589
+ if (trustedValueFn !== null && isStringLiteral(value)) {
11458
11590
  array.push(taggedTemplate(trustedValueFn, new TemplateLiteralExpr([new TemplateLiteralElementExpr(value.value)], []), undefined, value.sourceSpan));
11459
11591
  }
11460
11592
  else {
@@ -17116,7 +17248,7 @@ class _TreeBuilder {
17116
17248
  if (!prefix && parent) {
17117
17249
  const parentName = parent instanceof Element$2 ? parent.name : parent.tagName;
17118
17250
  if (parentName !== null) {
17119
- const parentTagName = splitNsName(parentName)[1];
17251
+ const parentTagName = splitNsName$1(parentName)[1];
17120
17252
  const parentTagDefinition = this._getTagDefinition(parentTagName);
17121
17253
  if (parentTagDefinition !== null && !parentTagDefinition.preventNamespaceInheritance) {
17122
17254
  prefix = getNsPrefix(parentName);
@@ -19409,162 +19541,8 @@ function interleave(left, right) {
19409
19541
  return result;
19410
19542
  }
19411
19543
 
19412
- // =================================================================================================
19413
- // =================================================================================================
19414
- // =========== S T O P - S T O P - S T O P - S T O P - S T O P - S T O P ===========
19415
- // =================================================================================================
19416
- // =================================================================================================
19417
- //
19418
- // DO NOT EDIT THIS LIST OF SECURITY SENSITIVE PROPERTIES WITHOUT A SECURITY REVIEW!
19419
- //
19420
- // =================================================================================================
19421
- /** Map from tagName|propertyName to SecurityContext. Properties applying to all tags use '*'. */
19422
- let _SECURITY_SCHEMA;
19423
- function SECURITY_SCHEMA() {
19424
- if (!_SECURITY_SCHEMA) {
19425
- _SECURITY_SCHEMA = {};
19426
- // Case is insignificant below, all element and attribute names are lower-cased for lookup.
19427
- registerContext(SecurityContext$1.HTML, ['iframe|srcdoc', '*|innerHTML', '*|outerHTML']);
19428
- registerContext(SecurityContext$1.STYLE, ['*|style']);
19429
- // NB: no SCRIPT contexts here, they are never allowed due to the parser stripping them.
19430
- registerContext(SecurityContext$1.URL, [
19431
- '*|formAction',
19432
- 'area|href',
19433
- 'area|ping',
19434
- 'audio|src',
19435
- 'a|href',
19436
- 'a|xlink:href',
19437
- 'a|ping',
19438
- 'blockquote|cite',
19439
- 'body|background',
19440
- 'del|cite',
19441
- 'form|action',
19442
- 'img|src',
19443
- 'input|src',
19444
- 'ins|cite',
19445
- 'q|cite',
19446
- 'source|src',
19447
- 'track|src',
19448
- 'video|poster',
19449
- 'video|src',
19450
- // MathML namespace
19451
- // https://crsrc.org/c/third_party/blink/renderer/core/sanitizer/sanitizer.cc;l=753-768;drc=b3eb16372dcd3317d65e9e0265015e322494edcd;bpv=1;bpt=1
19452
- 'annotation|href',
19453
- 'annotation|xlink:href',
19454
- 'annotation-xml|href',
19455
- 'annotation-xml|xlink:href',
19456
- 'maction|href',
19457
- 'maction|xlink:href',
19458
- 'malignmark|href',
19459
- 'malignmark|xlink:href',
19460
- 'math|href',
19461
- 'math|xlink:href',
19462
- 'mroot|href',
19463
- 'mroot|xlink:href',
19464
- 'msqrt|href',
19465
- 'msqrt|xlink:href',
19466
- 'merror|href',
19467
- 'merror|xlink:href',
19468
- 'mfrac|href',
19469
- 'mfrac|xlink:href',
19470
- 'mglyph|href',
19471
- 'mglyph|xlink:href',
19472
- 'msub|href',
19473
- 'msub|xlink:href',
19474
- 'msup|href',
19475
- 'msup|xlink:href',
19476
- 'msubsup|href',
19477
- 'msubsup|xlink:href',
19478
- 'mmultiscripts|href',
19479
- 'mmultiscripts|xlink:href',
19480
- 'mprescripts|href',
19481
- 'mprescripts|xlink:href',
19482
- 'mi|href',
19483
- 'mi|xlink:href',
19484
- 'mn|href',
19485
- 'mn|xlink:href',
19486
- 'mo|href',
19487
- 'mo|xlink:href',
19488
- 'mpadded|href',
19489
- 'mpadded|xlink:href',
19490
- 'mphantom|href',
19491
- 'mphantom|xlink:href',
19492
- 'mrow|href',
19493
- 'mrow|xlink:href',
19494
- 'ms|href',
19495
- 'ms|xlink:href',
19496
- 'mspace|href',
19497
- 'mspace|xlink:href',
19498
- 'mstyle|href',
19499
- 'mstyle|xlink:href',
19500
- 'mtable|href',
19501
- 'mtable|xlink:href',
19502
- 'mtd|href',
19503
- 'mtd|xlink:href',
19504
- 'mtr|href',
19505
- 'mtr|xlink:href',
19506
- 'mtext|href',
19507
- 'mtext|xlink:href',
19508
- 'mover|href',
19509
- 'mover|xlink:href',
19510
- 'munder|href',
19511
- 'munder|xlink:href',
19512
- 'munderover|href',
19513
- 'munderover|xlink:href',
19514
- 'semantics|href',
19515
- 'semantics|xlink:href',
19516
- 'none|href',
19517
- 'none|xlink:href',
19518
- ]);
19519
- registerContext(SecurityContext$1.RESOURCE_URL, [
19520
- 'applet|code',
19521
- 'applet|codebase',
19522
- 'base|href',
19523
- 'embed|src',
19524
- 'frame|src',
19525
- 'head|profile',
19526
- 'html|manifest',
19527
- 'iframe|src',
19528
- 'link|href',
19529
- 'media|src',
19530
- 'object|codebase',
19531
- 'object|data',
19532
- 'script|src',
19533
- // The below two are for Script SVG
19534
- // See: https://developer.mozilla.org/en-US/docs/Web/API/SVGScriptElement/href
19535
- 'script|href',
19536
- 'script|xlink:href',
19537
- ]);
19538
- // Keep this in sync with SECURITY_SENSITIVE_ELEMENTS in packages/core/src/sanitization/sanitization.ts
19539
- // Unknown is the internal tag name for unknown elements example used for host-bindings.
19540
- // These are unsafe as `attributeName` can be `href` or `xlink:href`
19541
- // See: http://b/463880509#comment7
19542
- registerContext(SecurityContext$1.ATTRIBUTE_NO_BINDING, [
19543
- 'animate|attributeName',
19544
- 'set|attributeName',
19545
- 'animateMotion|attributeName',
19546
- 'animateTransform|attributeName',
19547
- 'unknown|attributeName',
19548
- 'iframe|sandbox',
19549
- 'iframe|allow',
19550
- 'iframe|allowFullscreen',
19551
- 'iframe|referrerPolicy',
19552
- 'iframe|csp',
19553
- 'iframe|fetchPriority',
19554
- 'unknown|sandbox',
19555
- 'unknown|allow',
19556
- 'unknown|allowFullscreen',
19557
- 'unknown|referrerPolicy',
19558
- 'unknown|csp',
19559
- 'unknown|fetchPriority',
19560
- ]);
19561
- }
19562
- return _SECURITY_SCHEMA;
19563
- }
19564
- function registerContext(ctx, specs) {
19565
- for (const spec of specs)
19566
- _SECURITY_SCHEMA[spec.toLowerCase()] = ctx;
19567
- }
19544
+ const SVG_NAMESPACE$2 = 'svg';
19545
+ const MATH_ML_NAMESPACE$2 = 'math';
19568
19546
 
19569
19547
  class ElementSchemaRegistry {
19570
19548
  }
@@ -19573,6 +19551,11 @@ const BOOLEAN = 'boolean';
19573
19551
  const NUMBER = 'number';
19574
19552
  const STRING = 'string';
19575
19553
  const OBJECT = 'object';
19554
+ function normalizeTagName$1(tagName) {
19555
+ const tagNameLower = tagName.toLowerCase();
19556
+ const [ns, name] = splitNsName$1(tagNameLower, false);
19557
+ return ns === SVG_NAMESPACE$2 || ns === MATH_ML_NAMESPACE$2 ? `:${ns}:${name}` : name;
19558
+ }
19576
19559
  /**
19577
19560
  * This array represents the DOM schema. It encodes inheritance, properties, and events.
19578
19561
  *
@@ -19918,8 +19901,9 @@ class DomElementSchemaRegistry extends ElementSchemaRegistry {
19918
19901
  if (schemaMetas.some((schema) => schema.name === NO_ERRORS_SCHEMA$1.name)) {
19919
19902
  return true;
19920
19903
  }
19921
- if (tagName.indexOf('-') > -1) {
19922
- if (isNgContainer(tagName) || isNgContent(tagName)) {
19904
+ const normalizedTag = normalizeTagName$1(tagName);
19905
+ if (normalizedTag.includes('-')) {
19906
+ if (isNgContainer(normalizedTag) || isNgContent(normalizedTag)) {
19923
19907
  return false;
19924
19908
  }
19925
19909
  if (schemaMetas.some((schema) => schema.name === CUSTOM_ELEMENTS_SCHEMA$1.name)) {
@@ -19928,15 +19912,16 @@ class DomElementSchemaRegistry extends ElementSchemaRegistry {
19928
19912
  return true;
19929
19913
  }
19930
19914
  }
19931
- const elementProperties = this._schema.get(tagName.toLowerCase()) || this._schema.get('unknown');
19915
+ const elementProperties = this._schema.get(normalizedTag) || this._schema.get('unknown');
19932
19916
  return elementProperties.has(propName);
19933
19917
  }
19934
19918
  hasElement(tagName, schemaMetas) {
19935
19919
  if (schemaMetas.some((schema) => schema.name === NO_ERRORS_SCHEMA$1.name)) {
19936
19920
  return true;
19937
19921
  }
19938
- if (tagName.indexOf('-') > -1) {
19939
- if (isNgContainer(tagName) || isNgContent(tagName)) {
19922
+ const normalizedTag = normalizeTagName$1(tagName);
19923
+ if (normalizedTag.includes('-')) {
19924
+ if (isNgContainer(normalizedTag) || isNgContent(normalizedTag)) {
19940
19925
  return true;
19941
19926
  }
19942
19927
  if (schemaMetas.some((schema) => schema.name === CUSTOM_ELEMENTS_SCHEMA$1.name)) {
@@ -19944,7 +19929,7 @@ class DomElementSchemaRegistry extends ElementSchemaRegistry {
19944
19929
  return true;
19945
19930
  }
19946
19931
  }
19947
- return this._schema.has(tagName.toLowerCase());
19932
+ return this._schema.has(normalizedTag);
19948
19933
  }
19949
19934
  /**
19950
19935
  * securityContext returns the security context for the given property on the given DOM tag.
@@ -19961,16 +19946,15 @@ class DomElementSchemaRegistry extends ElementSchemaRegistry {
19961
19946
  // NB: For security purposes, use the mapped property name, not the attribute name.
19962
19947
  propName = this.getMappedPropName(propName);
19963
19948
  }
19964
- // Make sure comparisons are case insensitive, so that case differences between attribute and
19965
- // property names do not have a security impact.
19966
- tagName = tagName.toLowerCase();
19949
+ const normalizedTag = normalizeTagName$1(tagName);
19967
19950
  propName = propName.toLowerCase();
19968
- let ctx = SECURITY_SCHEMA()[tagName + '|' + propName];
19969
- if (ctx) {
19970
- return ctx;
19971
- }
19972
- ctx = SECURITY_SCHEMA()['*|' + propName];
19973
- return ctx ? ctx : SecurityContext$1.NONE;
19951
+ const [namespace] = splitNsName$1(normalizedTag, false);
19952
+ const securitySchema = SECURITY_SCHEMA$1();
19953
+ const ctx = securitySchema[normalizedTag + '|' + propName] ??
19954
+ (namespace ? securitySchema[`:${namespace}:*|${propName}`] : undefined) ??
19955
+ securitySchema['*|' + propName] ??
19956
+ SecurityContext$1.NONE;
19957
+ return ctx;
19974
19958
  }
19975
19959
  getMappedPropName(propName) {
19976
19960
  return _ATTR_TO_PROP.get(propName) ?? propName;
@@ -20004,12 +19988,14 @@ class DomElementSchemaRegistry extends ElementSchemaRegistry {
20004
19988
  return Array.from(this._schema.keys());
20005
19989
  }
20006
19990
  allKnownAttributesOfElement(tagName) {
20007
- const elementProperties = this._schema.get(tagName.toLowerCase()) || this._schema.get('unknown');
19991
+ const normalizedTag = normalizeTagName$1(tagName);
19992
+ const elementProperties = this._schema.get(normalizedTag) || this._schema.get('unknown');
20008
19993
  // Convert properties to attributes.
20009
19994
  return Array.from(elementProperties.keys()).map((prop) => _PROP_TO_ATTR.get(prop) ?? prop);
20010
19995
  }
20011
19996
  allKnownEventsOfElement(tagName) {
20012
- return Array.from(this._eventSchema.get(tagName.toLowerCase()) ?? []);
19997
+ const normalizedTag = normalizeTagName$1(tagName);
19998
+ return Array.from(this._eventSchema.get(normalizedTag) ?? []);
20013
19999
  }
20014
20000
  normalizeAnimationStyleProperty(propName) {
20015
20001
  return dashCaseToCamelCase(propName);
@@ -20858,7 +20844,7 @@ class I18nMetaVisitor {
20858
20844
  else {
20859
20845
  isTrustedType = isTrustedTypesSink(node.name, name);
20860
20846
  }
20861
- if (isTrustedType) {
20847
+ if (isTrustedType || isPossibleEventHandler(name)) {
20862
20848
  this._reportError(attr, `Translating attribute '${name}' is disallowed for security reasons.`);
20863
20849
  }
20864
20850
  else {
@@ -20989,6 +20975,16 @@ function i18nMetaToJSDoc(meta) {
20989
20975
  }
20990
20976
  return jsDocComment(tags);
20991
20977
  }
20978
+ /**
20979
+ * Check if the propertyName is a potential event handler.
20980
+ * We consider a property to be a potential event handler if its name is longer than 2 characters and starts with 'on' (e.g. 'onclick', 'onload', etc.).
20981
+ * @param propertyName The name of the property to check.
20982
+ * @returns True if the property is a potential event handler, false otherwise.
20983
+ */
20984
+ function isPossibleEventHandler(propertyName) {
20985
+ const name = propertyName.toLowerCase();
20986
+ return name.length > 2 && name !== 'only' && name.startsWith('on');
20987
+ }
20992
20988
 
20993
20989
  /** Closure uses `goog.getMsg(message)` to lookup translations */
20994
20990
  const GOOG_GET_MSG = 'goog.getMsg';
@@ -24214,6 +24210,61 @@ function updatePlaceholder(op, value, i18nContexts, icuPlaceholders) {
24214
24210
  }
24215
24211
  }
24216
24212
 
24213
+ /**
24214
+ * Wraps static i18n extracted attributes in their corresponding sanitizers/validators.
24215
+ */
24216
+ function resolveI18nAttrSanitizers(job) {
24217
+ const tagNamesByElement = new Map();
24218
+ for (const unit of job.units) {
24219
+ for (const op of unit.ops()) {
24220
+ if (op.kind === OpKind.ElementStart || op.kind === OpKind.Template) {
24221
+ let tag = op.tag ?? '';
24222
+ switch (op.namespace) {
24223
+ case Namespace.SVG:
24224
+ tag = `:${SVG_NAMESPACE$2}:${tag}`;
24225
+ break;
24226
+ case Namespace.Math:
24227
+ tag = `:${MATH_ML_NAMESPACE$2}:${tag}`;
24228
+ break;
24229
+ }
24230
+ tagNamesByElement.set(op.xref, tag);
24231
+ }
24232
+ }
24233
+ }
24234
+ for (const unit of job.units) {
24235
+ for (const op of unit.create) {
24236
+ if (op.kind === OpKind.ExtractedAttribute &&
24237
+ op.i18nContext !== null &&
24238
+ op.expression !== null) {
24239
+ const tagName = tagNamesByElement.get(op.target) ?? '';
24240
+ let expr = op.expression;
24241
+ switch (op.securityContext) {
24242
+ case SecurityContext$1.HTML:
24243
+ expr = importExpr(Identifiers.sanitizeHtml).callFn([expr]);
24244
+ break;
24245
+ case SecurityContext$1.STYLE:
24246
+ expr = importExpr(Identifiers.sanitizeStyle).callFn([expr]);
24247
+ break;
24248
+ case SecurityContext$1.SCRIPT:
24249
+ expr = importExpr(Identifiers.sanitizeScript).callFn([expr]);
24250
+ break;
24251
+ case SecurityContext$1.URL:
24252
+ expr = importExpr(Identifiers.sanitizeUrl).callFn([expr]);
24253
+ break;
24254
+ case SecurityContext$1.RESOURCE_URL:
24255
+ expr = importExpr(Identifiers.sanitizeResourceUrl).callFn([expr]);
24256
+ break;
24257
+ case SecurityContext$1.ATTRIBUTE_NO_BINDING:
24258
+ expr = importExpr(Identifiers.validateAttribute)
24259
+ .callFn([expr, literal(tagName), literal(op.name)]);
24260
+ break;
24261
+ }
24262
+ op.expression = expr;
24263
+ }
24264
+ }
24265
+ }
24266
+ }
24267
+
24217
24268
  /**
24218
24269
  * Resolves lexical references in views (`ir.LexicalReadExpr`) to either a target variable or to
24219
24270
  * property reads on the top-level component context.
@@ -24379,15 +24430,14 @@ function resolveSanitizers(job) {
24379
24430
  case OpKind.Property:
24380
24431
  case OpKind.Attribute:
24381
24432
  case OpKind.DomProperty:
24433
+ case OpKind.TwoWayProperty:
24382
24434
  let sanitizerFn = null;
24383
24435
  if (Array.isArray(op.securityContext) &&
24384
- op.securityContext.length === 2 &&
24385
- op.securityContext.includes(SecurityContext$1.URL) &&
24386
- op.securityContext.includes(SecurityContext$1.RESOURCE_URL)) {
24387
- // When the host element isn't known, some URL attributes (such as "src" and "href") may
24388
- // be part of multiple different security contexts. In this case we use special
24389
- // sanitization function and select the actual sanitizer at runtime based on a tag name
24390
- // that is provided while invoking sanitization function.
24436
+ hasCompositeUrlSecurityContext(op.securityContext)) {
24437
+ // When the host element isn't known, attributes such as `href`, `src`, `data`,
24438
+ // `action`, and `codebase` may be part of multiple security contexts. In this case we
24439
+ // use a special sanitization function and select the actual behavior at runtime based
24440
+ // on the concrete host element.
24391
24441
  sanitizerFn = Identifiers.sanitizeUrlOrResourceUrl;
24392
24442
  }
24393
24443
  else {
@@ -24399,21 +24449,47 @@ function resolveSanitizers(job) {
24399
24449
  }
24400
24450
  }
24401
24451
  }
24452
+ function hasCompositeUrlSecurityContext(securityContext) {
24453
+ let hasUrlContext = false;
24454
+ let hasResourceUrlContext = false;
24455
+ let hasNoneContext = false;
24456
+ for (const context of securityContext) {
24457
+ switch (context) {
24458
+ case SecurityContext$1.URL:
24459
+ hasUrlContext = true;
24460
+ break;
24461
+ case SecurityContext$1.RESOURCE_URL:
24462
+ hasResourceUrlContext = true;
24463
+ break;
24464
+ case SecurityContext$1.NONE:
24465
+ hasNoneContext = true;
24466
+ break;
24467
+ default:
24468
+ return false;
24469
+ }
24470
+ }
24471
+ return (((hasUrlContext || hasResourceUrlContext) && hasNoneContext) ||
24472
+ (hasUrlContext && hasResourceUrlContext));
24473
+ }
24402
24474
  /**
24403
- * Asserts that there is only a single security context and returns it.
24475
+ * Asserts that there is only a single non-NONE security context and returns it.
24404
24476
  */
24405
24477
  function getOnlySecurityContext(securityContext) {
24406
- if (Array.isArray(securityContext)) {
24407
- if (securityContext.length > 1) {
24408
- // TODO: What should we do here? TDB just took the first one, but this feels like something we
24409
- // would want to know about and create a special case for like we did for Url/ResourceUrl. My
24410
- // guess is that, outside of the Url/ResourceUrl case, this never actually happens. If there
24411
- // do turn out to be other cases, throwing an error until we can address it feels safer.
24412
- throw Error(`AssertionError: Ambiguous security context`);
24413
- }
24414
- return securityContext[0] || SecurityContext$1.NONE;
24478
+ if (!Array.isArray(securityContext)) {
24479
+ return securityContext;
24480
+ }
24481
+ if (securityContext.length < 2) {
24482
+ return securityContext[0] ?? SecurityContext$1.NONE;
24415
24483
  }
24416
- return securityContext;
24484
+ const nonNoneSecurityContexts = securityContext.filter((context) => context !== SecurityContext$1.NONE);
24485
+ if (nonNoneSecurityContexts.length > 1) {
24486
+ // TODO: What should we do here? TDB just took the first one, but this feels like something we
24487
+ // would want to know about and create a special case for like we did for Url/ResourceUrl. My
24488
+ // guess is that, outside of the Url/ResourceUrl case, this never actually happens. If there
24489
+ // do turn out to be other cases, throwing an error until we can address it feels safer.
24490
+ throw Error(`AssertionError: Ambiguous security context`);
24491
+ }
24492
+ return nonNoneSecurityContexts[0] ?? SecurityContext$1.NONE;
24417
24493
  }
24418
24494
 
24419
24495
  /**
@@ -25613,6 +25689,7 @@ const phases = [
25613
25689
  { kind: CompilationJobKind.Tmpl, fn: resolveI18nExpressionPlaceholders },
25614
25690
  { kind: CompilationJobKind.Tmpl, fn: extractI18nMessages },
25615
25691
  { kind: CompilationJobKind.Tmpl, fn: collectI18nConsts },
25692
+ { kind: CompilationJobKind.Tmpl, fn: resolveI18nAttrSanitizers },
25616
25693
  { kind: CompilationJobKind.Tmpl, fn: collectConstExpressions },
25617
25694
  { kind: CompilationJobKind.Both, fn: collectElementConsts },
25618
25695
  { kind: CompilationJobKind.Tmpl, fn: removeI18nContexts },
@@ -25726,200 +25803,714 @@ function emitHostBindingFunction(job) {
25726
25803
  /* sourceSpan */ undefined, job.root.fnName);
25727
25804
  }
25728
25805
 
25729
- const compatibilityMode = CompatibilityMode.TemplateDefinitionBuilder;
25730
- // Schema containing DOM elements and their properties.
25731
- const domSchema = new DomElementSchemaRegistry();
25732
- // Tag name of the `ng-template` element.
25733
- const NG_TEMPLATE_TAG_NAME = 'ng-template';
25734
- // prefix for any animation binding
25735
- const ANIMATE_PREFIX$1 = 'animate.';
25736
- function isI18nRootNode(meta) {
25737
- return meta instanceof Message;
25738
- }
25739
- function isSingleI18nIcu(meta) {
25740
- return isI18nRootNode(meta) && meta.nodes.length === 1 && meta.nodes[0] instanceof Icu;
25741
- }
25742
- /**
25743
- * Process a template AST and convert it into a `ComponentCompilation` in the intermediate
25744
- * representation.
25745
- * TODO: Refactor more of the ingestion code into phases.
25746
- */
25747
- function ingestComponent(componentName, template, constantPool, compilationMode, relativeContextFilePath, i18nUseExternalIds, deferMeta, allDeferrableDepsFn, relativeTemplatePath, enableDebugLocations) {
25748
- const job = new ComponentCompilationJob(componentName, constantPool, compatibilityMode, compilationMode, relativeContextFilePath, i18nUseExternalIds, deferMeta, allDeferrableDepsFn, relativeTemplatePath, enableDebugLocations);
25749
- ingestNodes(job.root, template);
25750
- return job;
25751
- }
25806
+ const PROPERTY_PARTS_SEPARATOR = '.';
25807
+ const ATTRIBUTE_PREFIX = 'attr';
25808
+ const ANIMATE_PREFIX$1 = 'animate';
25809
+ const CLASS_PREFIX = 'class';
25810
+ const STYLE_PREFIX = 'style';
25811
+ const TEMPLATE_ATTR_PREFIX$1 = '*';
25812
+ const LEGACY_ANIMATE_PROP_PREFIX = 'animate-';
25752
25813
  /**
25753
- * Process a host binding AST and convert it into a `HostBindingCompilationJob` in the intermediate
25754
- * representation.
25814
+ * Parses bindings in templates and in the directive host area.
25755
25815
  */
25756
- function ingestHostBinding(input, bindingParser, constantPool) {
25757
- const job = new HostBindingCompilationJob(input.componentName, constantPool, compatibilityMode, TemplateCompilationMode.DomOnly);
25758
- for (const property of input.properties ?? []) {
25759
- let bindingKind = BindingKind.Property;
25760
- // TODO: this should really be handled in the parser.
25761
- if (property.name.startsWith('attr.')) {
25762
- property.name = property.name.substring('attr.'.length);
25763
- bindingKind = BindingKind.Attribute;
25764
- }
25765
- if (property.isLegacyAnimation) {
25766
- bindingKind = BindingKind.LegacyAnimation;
25767
- }
25768
- if (property.isAnimation) {
25769
- bindingKind = BindingKind.Animation;
25770
- }
25771
- const securityContexts = bindingParser
25772
- .calcPossibleSecurityContexts(input.componentSelector, property.name, bindingKind === BindingKind.Attribute)
25773
- .filter((context) => context !== SecurityContext$1.NONE);
25774
- ingestDomProperty(job, property, bindingKind, securityContexts);
25775
- }
25776
- for (const [name, expr] of Object.entries(input.attributes) ?? []) {
25777
- const securityContexts = bindingParser
25778
- .calcPossibleSecurityContexts(input.componentSelector, name, true)
25779
- .filter((context) => context !== SecurityContext$1.NONE);
25780
- ingestHostAttribute(job, name, expr, securityContexts);
25781
- }
25782
- for (const event of input.events ?? []) {
25783
- ingestHostEvent(job, event);
25816
+ class BindingParser {
25817
+ _exprParser;
25818
+ _interpolationConfig;
25819
+ _schemaRegistry;
25820
+ errors;
25821
+ constructor(_exprParser, _interpolationConfig, _schemaRegistry, errors) {
25822
+ this._exprParser = _exprParser;
25823
+ this._interpolationConfig = _interpolationConfig;
25824
+ this._schemaRegistry = _schemaRegistry;
25825
+ this.errors = errors;
25784
25826
  }
25785
- return job;
25786
- }
25787
- // TODO: We should refactor the parser to use the same types and structures for host bindings as
25788
- // with ordinary components. This would allow us to share a lot more ingestion code.
25789
- function ingestDomProperty(job, property, bindingKind, securityContexts) {
25790
- let expression;
25791
- const ast = property.expression.ast;
25792
- if (ast instanceof Interpolation$1) {
25793
- expression = new Interpolation(ast.strings, ast.expressions.map((expr) => convertAst(expr, job, property.sourceSpan)), []);
25827
+ get interpolationConfig() {
25828
+ return this._interpolationConfig;
25794
25829
  }
25795
- else {
25796
- expression = convertAst(ast, job, property.sourceSpan);
25830
+ createBoundHostProperties(properties, sourceSpan) {
25831
+ const boundProps = [];
25832
+ for (const propName of Object.keys(properties)) {
25833
+ const expression = properties[propName];
25834
+ if (typeof expression === 'string') {
25835
+ this.parsePropertyBinding(propName, expression, true, false, sourceSpan, sourceSpan.start.offset, undefined, [],
25836
+ // Use the `sourceSpan` for `keySpan`. This isn't really accurate, but neither is the
25837
+ // sourceSpan, as it represents the sourceSpan of the host itself rather than the
25838
+ // source of the host binding (which doesn't exist in the template). Regardless,
25839
+ // neither of these values are used in Ivy but are only here to satisfy the function
25840
+ // signature. This should likely be refactored in the future so that `sourceSpan`
25841
+ // isn't being used inaccurately.
25842
+ boundProps, sourceSpan);
25843
+ }
25844
+ else {
25845
+ this._reportError(`Value of the host property binding "${propName}" needs to be a string representing an expression but got "${expression}" (${typeof expression})`, sourceSpan);
25846
+ }
25847
+ }
25848
+ return boundProps;
25797
25849
  }
25798
- job.root.update.push(createBindingOp(job.root.xref, bindingKind, property.name, expression, null, securityContexts, false, false, null,
25799
- /* TODO: How do Host bindings handle i18n attrs? */ null, property.sourceSpan));
25800
- }
25801
- function ingestHostAttribute(job, name, value, securityContexts) {
25802
- const attrBinding = createBindingOp(job.root.xref, BindingKind.Attribute, name, value, null, securityContexts,
25803
- /* Host attributes should always be extracted to const hostAttrs, even if they are not
25804
- *strictly* text literals */
25805
- true, false, null,
25806
- /* TODO */ null,
25807
- /** TODO: May be null? */ value.sourceSpan);
25808
- job.root.update.push(attrBinding);
25809
- }
25810
- function ingestHostEvent(job, event) {
25811
- let eventBinding;
25812
- if (event.type === ParsedEventType.Animation) {
25813
- eventBinding = createAnimationListenerOp(job.root.xref, new SlotHandle(), event.name, null, makeListenerHandlerOps(job.root, event.handler, event.handlerSpan), event.name.endsWith('enter') ? "enter" /* ir.AnimationKind.ENTER */ : "leave" /* ir.AnimationKind.LEAVE */, event.targetOrPhase, true, event.sourceSpan);
25850
+ createDirectiveHostEventAsts(hostListeners, sourceSpan) {
25851
+ const targetEvents = [];
25852
+ for (const propName of Object.keys(hostListeners)) {
25853
+ const expression = hostListeners[propName];
25854
+ if (typeof expression === 'string') {
25855
+ // Use the `sourceSpan` for `keySpan` and `handlerSpan`. This isn't really accurate, but
25856
+ // neither is the `sourceSpan`, as it represents the `sourceSpan` of the host itself
25857
+ // rather than the source of the host binding (which doesn't exist in the template).
25858
+ // Regardless, neither of these values are used in Ivy but are only here to satisfy the
25859
+ // function signature. This should likely be refactored in the future so that `sourceSpan`
25860
+ // isn't being used inaccurately.
25861
+ this.parseEvent(propName, expression,
25862
+ /* isAssignmentEvent */ false, sourceSpan, sourceSpan, [], targetEvents, sourceSpan);
25863
+ }
25864
+ else {
25865
+ this._reportError(`Value of the host listener "${propName}" needs to be a string representing an expression but got "${expression}" (${typeof expression})`, sourceSpan);
25866
+ }
25867
+ }
25868
+ return targetEvents;
25814
25869
  }
25815
- else {
25816
- const [phase, target] = event.type !== ParsedEventType.LegacyAnimation
25817
- ? [null, event.targetOrPhase]
25818
- : [event.targetOrPhase, null];
25819
- eventBinding = createListenerOp(job.root.xref, new SlotHandle(), event.name, null, makeListenerHandlerOps(job.root, event.handler, event.handlerSpan), phase, target, true, event.sourceSpan);
25870
+ parseInterpolation(value, sourceSpan, interpolatedTokens) {
25871
+ const absoluteOffset = sourceSpan.fullStart.offset;
25872
+ try {
25873
+ const ast = this._exprParser.parseInterpolation(value, sourceSpan, absoluteOffset, interpolatedTokens, this._interpolationConfig);
25874
+ if (ast) {
25875
+ this.errors.push(...ast.errors);
25876
+ }
25877
+ return ast;
25878
+ }
25879
+ catch (e) {
25880
+ this._reportError(`${e}`, sourceSpan);
25881
+ return this._exprParser.wrapLiteralPrimitive('ERROR', sourceSpan, absoluteOffset);
25882
+ }
25820
25883
  }
25821
- job.root.create.push(eventBinding);
25822
- }
25823
- /**
25824
- * Ingest the nodes of a template AST into the given `ViewCompilation`.
25825
- */
25826
- function ingestNodes(unit, template) {
25827
- for (const node of template) {
25828
- if (node instanceof Element$1) {
25829
- ingestElement(unit, node);
25884
+ /**
25885
+ * Similar to `parseInterpolation`, but treats the provided string as a single expression
25886
+ * element that would normally appear within the interpolation prefix and suffix (`{{` and `}}`).
25887
+ * This is used for parsing the switch expression in ICUs.
25888
+ */
25889
+ parseInterpolationExpression(expression, sourceSpan) {
25890
+ const absoluteOffset = sourceSpan.start.offset;
25891
+ try {
25892
+ const ast = this._exprParser.parseInterpolationExpression(expression, sourceSpan, absoluteOffset);
25893
+ if (ast) {
25894
+ this.errors.push(...ast.errors);
25895
+ }
25896
+ return ast;
25830
25897
  }
25831
- else if (node instanceof Template) {
25832
- ingestTemplate(unit, node);
25898
+ catch (e) {
25899
+ this._reportError(`${e}`, sourceSpan);
25900
+ return this._exprParser.wrapLiteralPrimitive('ERROR', sourceSpan, absoluteOffset);
25833
25901
  }
25834
- else if (node instanceof Content) {
25835
- ingestContent(unit, node);
25902
+ }
25903
+ /**
25904
+ * Parses the bindings in a microsyntax expression, and converts them to
25905
+ * `ParsedProperty` or `ParsedVariable`.
25906
+ *
25907
+ * @param tplKey template binding name
25908
+ * @param tplValue template binding value
25909
+ * @param sourceSpan span of template binding relative to entire the template
25910
+ * @param absoluteValueOffset start of the tplValue relative to the entire template
25911
+ * @param targetMatchableAttrs potential attributes to match in the template
25912
+ * @param targetProps target property bindings in the template
25913
+ * @param targetVars target variables in the template
25914
+ */
25915
+ parseInlineTemplateBinding(tplKey, tplValue, sourceSpan, absoluteValueOffset, targetMatchableAttrs, targetProps, targetVars, isIvyAst) {
25916
+ const absoluteKeyOffset = sourceSpan.start.offset + TEMPLATE_ATTR_PREFIX$1.length;
25917
+ const bindings = this._parseTemplateBindings(tplKey, tplValue, sourceSpan, absoluteKeyOffset, absoluteValueOffset);
25918
+ for (const binding of bindings) {
25919
+ // sourceSpan is for the entire HTML attribute. bindingSpan is for a particular
25920
+ // binding within the microsyntax expression so it's more narrow than sourceSpan.
25921
+ const bindingSpan = moveParseSourceSpan(sourceSpan, binding.sourceSpan);
25922
+ const key = binding.key.source;
25923
+ const keySpan = moveParseSourceSpan(sourceSpan, binding.key.span);
25924
+ if (binding instanceof VariableBinding) {
25925
+ const value = binding.value ? binding.value.source : '$implicit';
25926
+ const valueSpan = binding.value
25927
+ ? moveParseSourceSpan(sourceSpan, binding.value.span)
25928
+ : undefined;
25929
+ targetVars.push(new ParsedVariable(key, value, bindingSpan, keySpan, valueSpan));
25930
+ }
25931
+ else if (binding.value) {
25932
+ const srcSpan = isIvyAst ? bindingSpan : sourceSpan;
25933
+ const valueSpan = moveParseSourceSpan(sourceSpan, binding.value.ast.sourceSpan);
25934
+ this._parsePropertyAst(key, binding.value, false, srcSpan, keySpan, valueSpan, targetMatchableAttrs, targetProps);
25935
+ }
25936
+ else {
25937
+ targetMatchableAttrs.push([key, '' /* value */]);
25938
+ // Since this is a literal attribute with no RHS, source span should be
25939
+ // just the key span.
25940
+ this.parseLiteralAttr(key, null /* value */, keySpan, absoluteValueOffset, undefined /* valueSpan */, targetMatchableAttrs, targetProps, keySpan);
25941
+ }
25836
25942
  }
25837
- else if (node instanceof Text$3) {
25838
- ingestText(unit, node, null);
25943
+ }
25944
+ /**
25945
+ * Parses the bindings in a microsyntax expression, e.g.
25946
+ * ```html
25947
+ * <tag *tplKey="let value1 = prop; let value2 = localVar">
25948
+ * ```
25949
+ *
25950
+ * @param tplKey template binding name
25951
+ * @param tplValue template binding value
25952
+ * @param sourceSpan span of template binding relative to entire the template
25953
+ * @param absoluteKeyOffset start of the `tplKey`
25954
+ * @param absoluteValueOffset start of the `tplValue`
25955
+ */
25956
+ _parseTemplateBindings(tplKey, tplValue, sourceSpan, absoluteKeyOffset, absoluteValueOffset) {
25957
+ try {
25958
+ const bindingsResult = this._exprParser.parseTemplateBindings(tplKey, tplValue, sourceSpan, absoluteKeyOffset, absoluteValueOffset);
25959
+ bindingsResult.errors.forEach((e) => this.errors.push(e));
25960
+ bindingsResult.warnings.forEach((warning) => {
25961
+ this._reportError(warning, sourceSpan, ParseErrorLevel.WARNING);
25962
+ });
25963
+ return bindingsResult.templateBindings;
25839
25964
  }
25840
- else if (node instanceof BoundText) {
25841
- ingestBoundText(unit, node, null);
25965
+ catch (e) {
25966
+ this._reportError(`${e}`, sourceSpan);
25967
+ return [];
25842
25968
  }
25843
- else if (node instanceof IfBlock) {
25844
- ingestIfBlock(unit, node);
25969
+ }
25970
+ parseLiteralAttr(name, value, sourceSpan, absoluteOffset, valueSpan, targetMatchableAttrs, targetProps, keySpan) {
25971
+ if (isLegacyAnimationLabel(name)) {
25972
+ name = name.substring(1);
25973
+ if (keySpan !== undefined) {
25974
+ keySpan = moveParseSourceSpan(keySpan, new AbsoluteSourceSpan(keySpan.start.offset + 1, keySpan.end.offset));
25975
+ }
25976
+ if (value) {
25977
+ this._reportError(`Assigning animation triggers via @prop="exp" attributes with an expression is invalid.` +
25978
+ ` Use property bindings (e.g. [@prop]="exp") or use an attribute without a value (e.g. @prop) instead.`, sourceSpan, ParseErrorLevel.ERROR);
25979
+ }
25980
+ this._parseLegacyAnimation(name, value, sourceSpan, absoluteOffset, keySpan, valueSpan, targetMatchableAttrs, targetProps);
25845
25981
  }
25846
- else if (node instanceof SwitchBlock) {
25847
- ingestSwitchBlock(unit, node);
25982
+ else {
25983
+ targetProps.push(new ParsedProperty(name, this._exprParser.wrapLiteralPrimitive(value, '', absoluteOffset), ParsedPropertyType.LITERAL_ATTR, sourceSpan, keySpan, valueSpan));
25848
25984
  }
25849
- else if (node instanceof DeferredBlock) {
25850
- ingestDeferBlock(unit, node);
25985
+ }
25986
+ parsePropertyBinding(name, expression, isHost, isPartOfAssignmentBinding, sourceSpan, absoluteOffset, valueSpan, targetMatchableAttrs, targetProps, keySpan) {
25987
+ if (name.length === 0) {
25988
+ this._reportError(`Property name is missing in binding`, sourceSpan);
25851
25989
  }
25852
- else if (node instanceof Icu$1) {
25853
- ingestIcu(unit, node);
25990
+ let isLegacyAnimationProp = false;
25991
+ if (name.startsWith(LEGACY_ANIMATE_PROP_PREFIX)) {
25992
+ isLegacyAnimationProp = true;
25993
+ name = name.substring(LEGACY_ANIMATE_PROP_PREFIX.length);
25994
+ if (keySpan !== undefined) {
25995
+ keySpan = moveParseSourceSpan(keySpan, new AbsoluteSourceSpan(keySpan.start.offset + LEGACY_ANIMATE_PROP_PREFIX.length, keySpan.end.offset));
25996
+ }
25854
25997
  }
25855
- else if (node instanceof ForLoopBlock) {
25856
- ingestForBlock(unit, node);
25998
+ else if (isLegacyAnimationLabel(name)) {
25999
+ isLegacyAnimationProp = true;
26000
+ name = name.substring(1);
26001
+ if (keySpan !== undefined) {
26002
+ keySpan = moveParseSourceSpan(keySpan, new AbsoluteSourceSpan(keySpan.start.offset + 1, keySpan.end.offset));
26003
+ }
25857
26004
  }
25858
- else if (node instanceof LetDeclaration$1) {
25859
- ingestLetDeclaration(unit, node);
26005
+ if (isLegacyAnimationProp) {
26006
+ this._parseLegacyAnimation(name, expression, sourceSpan, absoluteOffset, keySpan, valueSpan, targetMatchableAttrs, targetProps);
26007
+ }
26008
+ else if (name.startsWith(`${ANIMATE_PREFIX$1}${PROPERTY_PARTS_SEPARATOR}`)) {
26009
+ this._parseAnimation(name, this.parseBinding(expression, isHost, valueSpan || sourceSpan, absoluteOffset), sourceSpan, keySpan, valueSpan, targetMatchableAttrs, targetProps);
25860
26010
  }
25861
- else if (node instanceof Component$1) ;
25862
26011
  else {
25863
- throw new Error(`Unsupported template node: ${node.constructor.name}`);
26012
+ this._parsePropertyAst(name, this.parseBinding(expression, isHost, valueSpan || sourceSpan, absoluteOffset), isPartOfAssignmentBinding, sourceSpan, keySpan, valueSpan, targetMatchableAttrs, targetProps);
25864
26013
  }
25865
26014
  }
25866
- }
25867
- /**
25868
- * Ingest an element AST from the template into the given `ViewCompilation`.
25869
- */
25870
- function ingestElement(unit, element) {
25871
- if (element.i18n !== undefined &&
25872
- !(element.i18n instanceof Message || element.i18n instanceof TagPlaceholder)) {
25873
- throw Error(`Unhandled i18n metadata type for element: ${element.i18n.constructor.name}`);
25874
- }
25875
- const id = unit.job.allocateXrefId();
25876
- const [namespaceKey, elementName] = splitNsName(element.name);
25877
- const startOp = createElementStartOp(elementName, id, namespaceForKey(namespaceKey), element.i18n instanceof TagPlaceholder ? element.i18n : undefined, element.startSourceSpan, element.sourceSpan);
25878
- unit.create.push(startOp);
25879
- ingestElementBindings(unit, startOp, element);
25880
- ingestReferences(startOp, element);
25881
- // Start i18n, if needed, goes after the element create and bindings, but before the nodes
25882
- let i18nBlockId = null;
25883
- if (element.i18n instanceof Message) {
25884
- i18nBlockId = unit.job.allocateXrefId();
25885
- unit.create.push(createI18nStartOp(i18nBlockId, element.i18n, undefined, element.startSourceSpan));
26015
+ parsePropertyInterpolation(name, value, sourceSpan, valueSpan, targetMatchableAttrs, targetProps, keySpan, interpolatedTokens) {
26016
+ const expr = this.parseInterpolation(value, valueSpan || sourceSpan, interpolatedTokens);
26017
+ if (expr) {
26018
+ this._parsePropertyAst(name, expr, false, sourceSpan, keySpan, valueSpan, targetMatchableAttrs, targetProps);
26019
+ return true;
26020
+ }
26021
+ return false;
25886
26022
  }
25887
- ingestNodes(unit, element.children);
25888
- // The source span for the end op is typically the element closing tag. However, if no closing tag
25889
- // exists, such as in `<input>`, we use the start source span instead. Usually the start and end
25890
- // instructions will be collapsed into one `element` instruction, negating the purpose of this
25891
- // fallback, but in cases when it is not collapsed (such as an input with a binding), we still
25892
- // want to map the end instruction to the main element.
25893
- const endOp = createElementEndOp(id, element.endSourceSpan ?? element.startSourceSpan);
25894
- unit.create.push(endOp);
25895
- // If there is an i18n message associated with this element, insert i18n start and end ops.
25896
- if (i18nBlockId !== null) {
25897
- OpList.insertBefore(createI18nEndOp(i18nBlockId, element.endSourceSpan ?? element.startSourceSpan), endOp);
26023
+ _parsePropertyAst(name, ast, isPartOfAssignmentBinding, sourceSpan, keySpan, valueSpan, targetMatchableAttrs, targetProps) {
26024
+ targetMatchableAttrs.push([name, ast.source]);
26025
+ targetProps.push(new ParsedProperty(name, ast, isPartOfAssignmentBinding ? ParsedPropertyType.TWO_WAY : ParsedPropertyType.DEFAULT, sourceSpan, keySpan, valueSpan));
25898
26026
  }
25899
- }
25900
- /**
25901
- * Ingest an `ng-template` node from the AST into the given `ViewCompilation`.
25902
- */
25903
- function ingestTemplate(unit, tmpl) {
25904
- if (tmpl.i18n !== undefined &&
25905
- !(tmpl.i18n instanceof Message || tmpl.i18n instanceof TagPlaceholder)) {
25906
- throw Error(`Unhandled i18n metadata type for template: ${tmpl.i18n.constructor.name}`);
26027
+ _parseAnimation(name, ast, sourceSpan, keySpan, valueSpan, targetMatchableAttrs, targetProps) {
26028
+ targetMatchableAttrs.push([name, ast.source]);
26029
+ targetProps.push(new ParsedProperty(name, ast, ParsedPropertyType.ANIMATION, sourceSpan, keySpan, valueSpan));
25907
26030
  }
25908
- const childView = unit.job.allocateView(unit.xref);
25909
- let tagNameWithoutNamespace = tmpl.tagName;
25910
- let namespacePrefix = '';
25911
- if (tmpl.tagName) {
25912
- [namespacePrefix, tagNameWithoutNamespace] = splitNsName(tmpl.tagName);
26031
+ _parseLegacyAnimation(name, expression, sourceSpan, absoluteOffset, keySpan, valueSpan, targetMatchableAttrs, targetProps) {
26032
+ if (name.length === 0) {
26033
+ this._reportError('Animation trigger is missing', sourceSpan);
26034
+ }
26035
+ // This will occur when a @trigger is not paired with an expression.
26036
+ // For animations it is valid to not have an expression since */void
26037
+ // states will be applied by angular when the element is attached/detached
26038
+ const ast = this.parseBinding(expression || 'undefined', false, valueSpan || sourceSpan, absoluteOffset);
26039
+ targetMatchableAttrs.push([name, ast.source]);
26040
+ targetProps.push(new ParsedProperty(name, ast, ParsedPropertyType.LEGACY_ANIMATION, sourceSpan, keySpan, valueSpan));
25913
26041
  }
25914
- const i18nPlaceholder = tmpl.i18n instanceof TagPlaceholder ? tmpl.i18n : undefined;
25915
- const namespace = namespaceForKey(namespacePrefix);
25916
- const functionNameSuffix = tagNameWithoutNamespace === null ? '' : prefixWithNamespace(tagNameWithoutNamespace, namespace);
25917
- const templateKind = isPlainTemplate(tmpl)
25918
- ? TemplateKind.NgTemplate
25919
- : TemplateKind.Structural;
25920
- const templateOp = createTemplateOp(childView.xref, templateKind, tagNameWithoutNamespace, functionNameSuffix, namespace, i18nPlaceholder, tmpl.startSourceSpan, tmpl.sourceSpan);
25921
- unit.create.push(templateOp);
25922
- ingestTemplateBindings(unit, templateOp, tmpl, templateKind);
26042
+ parseBinding(value, isHostBinding, sourceSpan, absoluteOffset) {
26043
+ try {
26044
+ const ast = isHostBinding
26045
+ ? this._exprParser.parseSimpleBinding(value, sourceSpan, absoluteOffset, this._interpolationConfig)
26046
+ : this._exprParser.parseBinding(value, sourceSpan, absoluteOffset, this._interpolationConfig);
26047
+ if (ast) {
26048
+ this.errors.push(...ast.errors);
26049
+ }
26050
+ return ast;
26051
+ }
26052
+ catch (e) {
26053
+ this._reportError(`${e}`, sourceSpan);
26054
+ return this._exprParser.wrapLiteralPrimitive('ERROR', sourceSpan, absoluteOffset);
26055
+ }
26056
+ }
26057
+ createBoundElementProperty(elementSelector, boundProp, skipValidation = false, mapPropertyName = true) {
26058
+ if (boundProp.isLegacyAnimation) {
26059
+ return new BoundElementProperty(boundProp.name, BindingType.LegacyAnimation, SecurityContext$1.NONE, boundProp.expression, null, boundProp.sourceSpan, boundProp.keySpan, boundProp.valueSpan);
26060
+ }
26061
+ let unit = null;
26062
+ let bindingType = undefined;
26063
+ let boundPropertyName = null;
26064
+ const parts = boundProp.name.split(PROPERTY_PARTS_SEPARATOR);
26065
+ let securityContexts = undefined;
26066
+ // Check for special cases (prefix style, attr, class)
26067
+ if (parts.length > 1) {
26068
+ if (parts[0] == ATTRIBUTE_PREFIX) {
26069
+ boundPropertyName = parts.slice(1).join(PROPERTY_PARTS_SEPARATOR);
26070
+ if (!skipValidation) {
26071
+ this._validatePropertyOrAttributeName(boundPropertyName, boundProp.sourceSpan, true);
26072
+ }
26073
+ securityContexts = calcPossibleSecurityContexts(this._schemaRegistry, elementSelector, boundPropertyName, true);
26074
+ const nsSeparatorIdx = boundPropertyName.indexOf(':');
26075
+ if (nsSeparatorIdx > -1) {
26076
+ const ns = boundPropertyName.substring(0, nsSeparatorIdx);
26077
+ const name = boundPropertyName.substring(nsSeparatorIdx + 1);
26078
+ boundPropertyName = mergeNsAndName(ns, name);
26079
+ }
26080
+ bindingType = BindingType.Attribute;
26081
+ }
26082
+ else if (parts[0] == CLASS_PREFIX) {
26083
+ boundPropertyName = parts[1];
26084
+ bindingType = BindingType.Class;
26085
+ securityContexts = [SecurityContext$1.NONE];
26086
+ }
26087
+ else if (parts[0] == STYLE_PREFIX) {
26088
+ unit = parts.length > 2 ? parts[2] : null;
26089
+ boundPropertyName = parts[1];
26090
+ bindingType = BindingType.Style;
26091
+ securityContexts = [SecurityContext$1.STYLE];
26092
+ }
26093
+ else if (parts[0] == ANIMATE_PREFIX$1) {
26094
+ boundPropertyName = boundProp.name;
26095
+ bindingType = BindingType.Animation;
26096
+ securityContexts = [SecurityContext$1.NONE];
26097
+ }
26098
+ }
26099
+ // If not a special case, use the full property name
26100
+ if (boundPropertyName === null) {
26101
+ const mappedPropName = this._schemaRegistry.getMappedPropName(boundProp.name);
26102
+ boundPropertyName = mapPropertyName ? mappedPropName : boundProp.name;
26103
+ securityContexts = calcPossibleSecurityContexts(this._schemaRegistry, elementSelector, mappedPropName, false);
26104
+ bindingType =
26105
+ boundProp.type === ParsedPropertyType.TWO_WAY ? BindingType.TwoWay : BindingType.Property;
26106
+ if (!skipValidation) {
26107
+ this._validatePropertyOrAttributeName(mappedPropName, boundProp.sourceSpan, false);
26108
+ }
26109
+ }
26110
+ return new BoundElementProperty(boundPropertyName, bindingType, securityContexts[0], boundProp.expression, unit, boundProp.sourceSpan, boundProp.keySpan, boundProp.valueSpan);
26111
+ }
26112
+ parseEvent(name, expression, isAssignmentEvent, sourceSpan, handlerSpan, targetMatchableAttrs, targetEvents, keySpan) {
26113
+ if (name.length === 0) {
26114
+ this._reportError(`Event name is missing in binding`, sourceSpan);
26115
+ }
26116
+ if (isLegacyAnimationLabel(name)) {
26117
+ name = name.slice(1);
26118
+ if (keySpan !== undefined) {
26119
+ keySpan = moveParseSourceSpan(keySpan, new AbsoluteSourceSpan(keySpan.start.offset + 1, keySpan.end.offset));
26120
+ }
26121
+ this._parseLegacyAnimationEvent(name, expression, sourceSpan, handlerSpan, targetEvents, keySpan);
26122
+ }
26123
+ else {
26124
+ this._parseRegularEvent(name, expression, isAssignmentEvent, sourceSpan, handlerSpan, targetMatchableAttrs, targetEvents, keySpan);
26125
+ }
26126
+ }
26127
+ calcPossibleSecurityContexts(selector, propName, isAttribute) {
26128
+ const prop = this._schemaRegistry.getMappedPropName(propName);
26129
+ return calcPossibleSecurityContexts(this._schemaRegistry, selector, prop, isAttribute);
26130
+ }
26131
+ parseEventListenerName(rawName) {
26132
+ const [target, eventName] = splitAtColon(rawName, [null, rawName]);
26133
+ return { eventName: eventName, target };
26134
+ }
26135
+ parseLegacyAnimationEventName(rawName) {
26136
+ const matches = splitAtPeriod(rawName, [rawName, null]);
26137
+ return { eventName: matches[0], phase: matches[1] === null ? null : matches[1].toLowerCase() };
26138
+ }
26139
+ _parseLegacyAnimationEvent(name, expression, sourceSpan, handlerSpan, targetEvents, keySpan) {
26140
+ const { eventName, phase } = this.parseLegacyAnimationEventName(name);
26141
+ const ast = this._parseAction(expression, handlerSpan);
26142
+ targetEvents.push(new ParsedEvent(eventName, phase, ParsedEventType.LegacyAnimation, ast, sourceSpan, handlerSpan, keySpan));
26143
+ if (eventName.length === 0) {
26144
+ this._reportError(`Animation event name is missing in binding`, sourceSpan);
26145
+ }
26146
+ if (phase) {
26147
+ if (phase !== 'start' && phase !== 'done') {
26148
+ this._reportError(`The provided animation output phase value "${phase}" for "@${eventName}" is not supported (use start or done)`, sourceSpan);
26149
+ }
26150
+ }
26151
+ else {
26152
+ this._reportError(`The animation trigger output event (@${eventName}) is missing its phase value name (start or done are currently supported)`, sourceSpan);
26153
+ }
26154
+ }
26155
+ _parseRegularEvent(name, expression, isAssignmentEvent, sourceSpan, handlerSpan, targetMatchableAttrs, targetEvents, keySpan) {
26156
+ // long format: 'target: eventName'
26157
+ const { eventName, target } = this.parseEventListenerName(name);
26158
+ const prevErrorCount = this.errors.length;
26159
+ const ast = this._parseAction(expression, handlerSpan);
26160
+ const isValid = this.errors.length === prevErrorCount;
26161
+ targetMatchableAttrs.push([name, ast.source]);
26162
+ // Don't try to validate assignment events if there were other
26163
+ // parsing errors to avoid adding more noise to the error logs.
26164
+ if (isAssignmentEvent && isValid && !this._isAllowedAssignmentEvent(ast)) {
26165
+ this._reportError('Unsupported expression in a two-way binding', sourceSpan);
26166
+ }
26167
+ let eventType = ParsedEventType.Regular;
26168
+ if (isAssignmentEvent) {
26169
+ eventType = ParsedEventType.TwoWay;
26170
+ }
26171
+ if (name.startsWith(`${ANIMATE_PREFIX$1}${PROPERTY_PARTS_SEPARATOR}`)) {
26172
+ eventType = ParsedEventType.Animation;
26173
+ }
26174
+ targetEvents.push(new ParsedEvent(eventName, target, eventType, ast, sourceSpan, handlerSpan, keySpan));
26175
+ // Don't detect directives for event names for now,
26176
+ // so don't add the event name to the matchableAttrs
26177
+ }
26178
+ _parseAction(value, sourceSpan) {
26179
+ const absoluteOffset = sourceSpan && sourceSpan.start ? sourceSpan.start.offset : 0;
26180
+ try {
26181
+ const ast = this._exprParser.parseAction(value, sourceSpan, absoluteOffset, this._interpolationConfig);
26182
+ if (ast) {
26183
+ this.errors.push(...ast.errors);
26184
+ }
26185
+ if (!ast || ast.ast instanceof EmptyExpr$1) {
26186
+ this._reportError(`Empty expressions are not allowed`, sourceSpan);
26187
+ return this._exprParser.wrapLiteralPrimitive('ERROR', sourceSpan, absoluteOffset);
26188
+ }
26189
+ return ast;
26190
+ }
26191
+ catch (e) {
26192
+ this._reportError(`${e}`, sourceSpan);
26193
+ return this._exprParser.wrapLiteralPrimitive('ERROR', sourceSpan, absoluteOffset);
26194
+ }
26195
+ }
26196
+ _reportError(message, sourceSpan, level = ParseErrorLevel.ERROR) {
26197
+ this.errors.push(new ParseError(sourceSpan, message, level));
26198
+ }
26199
+ /**
26200
+ * @param propName the name of the property / attribute
26201
+ * @param sourceSpan
26202
+ * @param isAttr true when binding to an attribute
26203
+ */
26204
+ _validatePropertyOrAttributeName(propName, sourceSpan, isAttr) {
26205
+ const report = isAttr
26206
+ ? this._schemaRegistry.validateAttribute(propName)
26207
+ : this._schemaRegistry.validateProperty(propName);
26208
+ if (report.error) {
26209
+ this._reportError(report.msg, sourceSpan, ParseErrorLevel.ERROR);
26210
+ }
26211
+ }
26212
+ /**
26213
+ * Returns whether a parsed AST is allowed to be used within the event side of a two-way binding.
26214
+ * @param ast Parsed AST to be checked.
26215
+ */
26216
+ _isAllowedAssignmentEvent(ast) {
26217
+ if (ast instanceof ASTWithSource) {
26218
+ return this._isAllowedAssignmentEvent(ast.ast);
26219
+ }
26220
+ if (ast instanceof NonNullAssert) {
26221
+ return this._isAllowedAssignmentEvent(ast.expression);
26222
+ }
26223
+ if (ast instanceof Call &&
26224
+ ast.args.length === 1 &&
26225
+ ast.receiver instanceof PropertyRead &&
26226
+ ast.receiver.name === '$any' &&
26227
+ ast.receiver.receiver instanceof ImplicitReceiver &&
26228
+ !(ast.receiver.receiver instanceof ThisReceiver)) {
26229
+ return this._isAllowedAssignmentEvent(ast.args[0]);
26230
+ }
26231
+ if (ast instanceof PropertyRead || ast instanceof KeyedRead) {
26232
+ if (!hasRecursiveSafeReceiver(ast)) {
26233
+ return true;
26234
+ }
26235
+ }
26236
+ return false;
26237
+ }
26238
+ }
26239
+ function hasRecursiveSafeReceiver(ast) {
26240
+ if (ast instanceof SafePropertyRead || ast instanceof SafeKeyedRead) {
26241
+ return true;
26242
+ }
26243
+ if (ast instanceof ParenthesizedExpression) {
26244
+ return hasRecursiveSafeReceiver(ast.expression);
26245
+ }
26246
+ if (ast instanceof PropertyRead || ast instanceof KeyedRead || ast instanceof Call) {
26247
+ return hasRecursiveSafeReceiver(ast.receiver);
26248
+ }
26249
+ return false;
26250
+ }
26251
+ function isLegacyAnimationLabel(name) {
26252
+ return name[0] == '@';
26253
+ }
26254
+ function calcPossibleSecurityContexts(registry, selector, propName, isAttribute) {
26255
+ let ctxs;
26256
+ const [namespaceKey, baseSelector] = selector ? splitNsName$1(selector, false) : [null, selector];
26257
+ const nameToContext = (elName) => {
26258
+ const [nsStr, name] = splitNsName$1(elName, false);
26259
+ const ns = nsStr ?? namespaceKey;
26260
+ const fullName = ns ? `:${ns}:${name}` : name;
26261
+ return registry.securityContext(fullName, propName, isAttribute);
26262
+ };
26263
+ const allKnownElements = registry.allKnownElementNames();
26264
+ if (baseSelector === null) {
26265
+ ctxs = allKnownElements.map(nameToContext);
26266
+ }
26267
+ else {
26268
+ ctxs = [];
26269
+ CssSelector.parse(baseSelector).forEach((selector) => {
26270
+ let elementNames = selector.element ? [selector.element] : allKnownElements;
26271
+ if (selector.element && !registry.hasElement(selector.element, [])) {
26272
+ const svgElement = `:${SVG_NAMESPACE$2}:${selector.element}`;
26273
+ const mathElement = `:${MATH_ML_NAMESPACE$2}:${selector.element}`;
26274
+ if (registry.hasElement(svgElement, [])) {
26275
+ elementNames = [svgElement];
26276
+ }
26277
+ else if (registry.hasElement(mathElement, [])) {
26278
+ elementNames = [mathElement];
26279
+ }
26280
+ }
26281
+ const notElementNames = new Set(selector.notSelectors
26282
+ .filter((selector) => selector.isElementSelector())
26283
+ .map((selector) => selector.element?.toLowerCase()));
26284
+ const possibleElementNames = elementNames.filter((elName) => {
26285
+ const elNameLowerCase = elName.toLowerCase();
26286
+ return (!notElementNames.has(elNameLowerCase) &&
26287
+ !notElementNames.has(splitNsName$1(elNameLowerCase)[1]));
26288
+ });
26289
+ ctxs.push(...possibleElementNames.map(nameToContext));
26290
+ });
26291
+ }
26292
+ return ctxs.length === 0 ? [SecurityContext$1.NONE] : Array.from(new Set(ctxs)).sort();
26293
+ }
26294
+ /**
26295
+ * Compute a new ParseSourceSpan based off an original `sourceSpan` by using
26296
+ * absolute offsets from the specified `absoluteSpan`.
26297
+ *
26298
+ * @param sourceSpan original source span
26299
+ * @param absoluteSpan absolute source span to move to
26300
+ */
26301
+ function moveParseSourceSpan(sourceSpan, absoluteSpan) {
26302
+ // The difference of two absolute offsets provide the relative offset
26303
+ const startDiff = absoluteSpan.start - sourceSpan.start.offset;
26304
+ const endDiff = absoluteSpan.end - sourceSpan.end.offset;
26305
+ return new ParseSourceSpan(sourceSpan.start.moveBy(startDiff), sourceSpan.end.moveBy(endDiff), sourceSpan.fullStart.moveBy(startDiff), sourceSpan.details);
26306
+ }
26307
+
26308
+ const compatibilityMode = CompatibilityMode.TemplateDefinitionBuilder;
26309
+ // Schema containing DOM elements and their properties.
26310
+ const domSchema = new DomElementSchemaRegistry();
26311
+ // Tag name of the `ng-template` element.
26312
+ const NG_TEMPLATE_TAG_NAME = 'ng-template';
26313
+ // prefix for any animation binding
26314
+ const ANIMATE_PREFIX = 'animate.';
26315
+ function isI18nRootNode(meta) {
26316
+ return meta instanceof Message;
26317
+ }
26318
+ function isSingleI18nIcu(meta) {
26319
+ return isI18nRootNode(meta) && meta.nodes.length === 1 && meta.nodes[0] instanceof Icu;
26320
+ }
26321
+ /**
26322
+ * Process a template AST and convert it into a `ComponentCompilation` in the intermediate
26323
+ * representation.
26324
+ * TODO: Refactor more of the ingestion code into phases.
26325
+ */
26326
+ function ingestComponent(componentName, template, constantPool, compilationMode, relativeContextFilePath, i18nUseExternalIds, deferMeta, allDeferrableDepsFn, relativeTemplatePath, enableDebugLocations) {
26327
+ const job = new ComponentCompilationJob(componentName, constantPool, compatibilityMode, compilationMode, relativeContextFilePath, i18nUseExternalIds, deferMeta, allDeferrableDepsFn, relativeTemplatePath, enableDebugLocations);
26328
+ ingestNodes(job.root, template);
26329
+ return job;
26330
+ }
26331
+ /**
26332
+ * Process a host binding AST and convert it into a `HostBindingCompilationJob` in the intermediate
26333
+ * representation.
26334
+ */
26335
+ function ingestHostBinding(input, bindingParser, constantPool) {
26336
+ const job = new HostBindingCompilationJob(input.componentName, constantPool, compatibilityMode, TemplateCompilationMode.DomOnly);
26337
+ for (const property of input.properties ?? []) {
26338
+ let bindingKind = BindingKind.Property;
26339
+ // TODO: this should really be handled in the parser.
26340
+ if (property.name.startsWith('attr.')) {
26341
+ property.name = property.name.substring('attr.'.length);
26342
+ bindingKind = BindingKind.Attribute;
26343
+ }
26344
+ if (property.isLegacyAnimation) {
26345
+ bindingKind = BindingKind.LegacyAnimation;
26346
+ }
26347
+ if (property.isAnimation) {
26348
+ bindingKind = BindingKind.Animation;
26349
+ }
26350
+ const securityContexts = calcHostBindingSecurityContexts(bindingParser, input.componentSelector, property.name, bindingKind === BindingKind.Attribute);
26351
+ ingestDomProperty(job, property, bindingKind, securityContexts);
26352
+ }
26353
+ for (const [name, expr] of Object.entries(input.attributes) ?? []) {
26354
+ const securityContexts = calcHostBindingSecurityContexts(bindingParser, input.componentSelector, name, true);
26355
+ ingestHostAttribute(job, name, expr, securityContexts);
26356
+ }
26357
+ for (const event of input.events ?? []) {
26358
+ ingestHostEvent(job, event);
26359
+ }
26360
+ return job;
26361
+ }
26362
+ function calcHostBindingSecurityContexts(bindingParser, selector, name, isAttribute) {
26363
+ const declaringSelectorContexts = bindingParser.calcPossibleSecurityContexts(selector, name, isAttribute);
26364
+ const concreteHostContexts = calcPossibleSecurityContexts(domSchema, null, domSchema.getMappedPropName(name), isAttribute);
26365
+ const concreteHostNonNoneContexts = concreteHostContexts.filter((context) => context !== SecurityContext$1.NONE);
26366
+ const concreteHostNonNoneCount = concreteHostNonNoneContexts.length;
26367
+ const hasConcreteHostNoneContext = concreteHostNonNoneCount !== concreteHostContexts.length;
26368
+ // Host bindings can run against a concrete host whose element name differs from the declaring
26369
+ // selector, including dynamic root components whose TNode name is `#host`.
26370
+ if (hasConcreteHostNoneContext && concreteHostNonNoneCount > 0) {
26371
+ return concreteHostContexts;
26372
+ }
26373
+ if (concreteHostNonNoneContexts.some((context) => !declaringSelectorContexts.includes(context))) {
26374
+ return concreteHostContexts;
26375
+ }
26376
+ return declaringSelectorContexts.filter((context) => context !== SecurityContext$1.NONE);
26377
+ }
26378
+ // TODO: We should refactor the parser to use the same types and structures for host bindings as
26379
+ // with ordinary components. This would allow us to share a lot more ingestion code.
26380
+ function ingestDomProperty(job, property, bindingKind, securityContexts) {
26381
+ let expression;
26382
+ const ast = property.expression.ast;
26383
+ if (ast instanceof Interpolation$1) {
26384
+ expression = new Interpolation(ast.strings, ast.expressions.map((expr) => convertAst(expr, job, property.sourceSpan)), []);
26385
+ }
26386
+ else {
26387
+ expression = convertAst(ast, job, property.sourceSpan);
26388
+ }
26389
+ job.root.update.push(createBindingOp(job.root.xref, bindingKind, property.name, expression, null, securityContexts, false, false, null,
26390
+ /* TODO: How do Host bindings handle i18n attrs? */ null, property.sourceSpan));
26391
+ }
26392
+ function ingestHostAttribute(job, name, value, securityContexts) {
26393
+ const attrBinding = createBindingOp(job.root.xref, BindingKind.Attribute, name, value, null, securityContexts,
26394
+ /* Host attributes should always be extracted to const hostAttrs, even if they are not
26395
+ *strictly* text literals */
26396
+ true, false, null,
26397
+ /* TODO */ null,
26398
+ /** TODO: May be null? */ value.sourceSpan);
26399
+ job.root.update.push(attrBinding);
26400
+ }
26401
+ function ingestHostEvent(job, event) {
26402
+ let eventBinding;
26403
+ if (event.type === ParsedEventType.Animation) {
26404
+ eventBinding = createAnimationListenerOp(job.root.xref, new SlotHandle(), event.name, null, makeListenerHandlerOps(job.root, event.handler, event.handlerSpan), event.name.endsWith('enter') ? "enter" /* ir.AnimationKind.ENTER */ : "leave" /* ir.AnimationKind.LEAVE */, event.targetOrPhase, true, event.sourceSpan);
26405
+ }
26406
+ else {
26407
+ const [phase, target] = event.type !== ParsedEventType.LegacyAnimation
26408
+ ? [null, event.targetOrPhase]
26409
+ : [event.targetOrPhase, null];
26410
+ eventBinding = createListenerOp(job.root.xref, new SlotHandle(), event.name, null, makeListenerHandlerOps(job.root, event.handler, event.handlerSpan), phase, target, true, event.sourceSpan);
26411
+ }
26412
+ job.root.create.push(eventBinding);
26413
+ }
26414
+ /**
26415
+ * Ingest the nodes of a template AST into the given `ViewCompilation`.
26416
+ */
26417
+ function ingestNodes(unit, template) {
26418
+ for (const node of template) {
26419
+ if (node instanceof Element$1) {
26420
+ ingestElement(unit, node);
26421
+ }
26422
+ else if (node instanceof Template) {
26423
+ ingestTemplate(unit, node);
26424
+ }
26425
+ else if (node instanceof Content) {
26426
+ ingestContent(unit, node);
26427
+ }
26428
+ else if (node instanceof Text$3) {
26429
+ ingestText(unit, node, null);
26430
+ }
26431
+ else if (node instanceof BoundText) {
26432
+ ingestBoundText(unit, node, null);
26433
+ }
26434
+ else if (node instanceof IfBlock) {
26435
+ ingestIfBlock(unit, node);
26436
+ }
26437
+ else if (node instanceof SwitchBlock) {
26438
+ ingestSwitchBlock(unit, node);
26439
+ }
26440
+ else if (node instanceof DeferredBlock) {
26441
+ ingestDeferBlock(unit, node);
26442
+ }
26443
+ else if (node instanceof Icu$1) {
26444
+ ingestIcu(unit, node);
26445
+ }
26446
+ else if (node instanceof ForLoopBlock) {
26447
+ ingestForBlock(unit, node);
26448
+ }
26449
+ else if (node instanceof LetDeclaration$1) {
26450
+ ingestLetDeclaration(unit, node);
26451
+ }
26452
+ else if (node instanceof Component$1) ;
26453
+ else {
26454
+ throw new Error(`Unsupported template node: ${node.constructor.name}`);
26455
+ }
26456
+ }
26457
+ }
26458
+ /**
26459
+ * Ingest an element AST from the template into the given `ViewCompilation`.
26460
+ */
26461
+ function ingestElement(unit, element) {
26462
+ if (element.i18n !== undefined &&
26463
+ !(element.i18n instanceof Message || element.i18n instanceof TagPlaceholder)) {
26464
+ throw Error(`Unhandled i18n metadata type for element: ${element.i18n.constructor.name}`);
26465
+ }
26466
+ const id = unit.job.allocateXrefId();
26467
+ const [namespaceKey, elementName] = splitNsName$1(element.name);
26468
+ const startOp = createElementStartOp(elementName, id, namespaceForKey(namespaceKey), element.i18n instanceof TagPlaceholder ? element.i18n : undefined, element.startSourceSpan, element.sourceSpan);
26469
+ unit.create.push(startOp);
26470
+ ingestElementBindings(unit, startOp, element);
26471
+ ingestReferences(startOp, element);
26472
+ // Start i18n, if needed, goes after the element create and bindings, but before the nodes
26473
+ let i18nBlockId = null;
26474
+ if (element.i18n instanceof Message) {
26475
+ i18nBlockId = unit.job.allocateXrefId();
26476
+ unit.create.push(createI18nStartOp(i18nBlockId, element.i18n, undefined, element.startSourceSpan));
26477
+ }
26478
+ ingestNodes(unit, element.children);
26479
+ // The source span for the end op is typically the element closing tag. However, if no closing tag
26480
+ // exists, such as in `<input>`, we use the start source span instead. Usually the start and end
26481
+ // instructions will be collapsed into one `element` instruction, negating the purpose of this
26482
+ // fallback, but in cases when it is not collapsed (such as an input with a binding), we still
26483
+ // want to map the end instruction to the main element.
26484
+ const endOp = createElementEndOp(id, element.endSourceSpan ?? element.startSourceSpan);
26485
+ unit.create.push(endOp);
26486
+ // If there is an i18n message associated with this element, insert i18n start and end ops.
26487
+ if (i18nBlockId !== null) {
26488
+ OpList.insertBefore(createI18nEndOp(i18nBlockId, element.endSourceSpan ?? element.startSourceSpan), endOp);
26489
+ }
26490
+ }
26491
+ /**
26492
+ * Ingest an `ng-template` node from the AST into the given `ViewCompilation`.
26493
+ */
26494
+ function ingestTemplate(unit, tmpl) {
26495
+ if (tmpl.i18n !== undefined &&
26496
+ !(tmpl.i18n instanceof Message || tmpl.i18n instanceof TagPlaceholder)) {
26497
+ throw Error(`Unhandled i18n metadata type for template: ${tmpl.i18n.constructor.name}`);
26498
+ }
26499
+ const childView = unit.job.allocateView(unit.xref);
26500
+ let tagNameWithoutNamespace = tmpl.tagName;
26501
+ let namespacePrefix = '';
26502
+ if (tmpl.tagName) {
26503
+ [namespacePrefix, tagNameWithoutNamespace] = splitNsName$1(tmpl.tagName);
26504
+ }
26505
+ const i18nPlaceholder = tmpl.i18n instanceof TagPlaceholder ? tmpl.i18n : undefined;
26506
+ const namespace = namespaceForKey(namespacePrefix);
26507
+ const functionNameSuffix = tagNameWithoutNamespace === null ? '' : prefixWithNamespace(tagNameWithoutNamespace, namespace);
26508
+ const templateKind = isPlainTemplate(tmpl)
26509
+ ? TemplateKind.NgTemplate
26510
+ : TemplateKind.Structural;
26511
+ const templateOp = createTemplateOp(childView.xref, templateKind, tagNameWithoutNamespace, functionNameSuffix, namespace, i18nPlaceholder, tmpl.startSourceSpan, tmpl.sourceSpan);
26512
+ unit.create.push(templateOp);
26513
+ ingestTemplateBindings(unit, templateOp, tmpl, templateKind);
25923
26514
  ingestReferences(templateOp, tmpl);
25924
26515
  ingestNodes(childView, tmpl.children);
25925
26516
  for (const { name, value } of tmpl.variables) {
@@ -26460,7 +27051,7 @@ const BINDING_KINDS = new Map([
26460
27051
  * | `<ng-template *ngIf>` (structural) | null |
26461
27052
  */
26462
27053
  function isPlainTemplate(tmpl) {
26463
- return splitNsName(tmpl.tagName ?? '')[1] === NG_TEMPLATE_TAG_NAME;
27054
+ return splitNsName$1(tmpl.tagName ?? '')[1] === NG_TEMPLATE_TAG_NAME;
26464
27055
  }
26465
27056
  /**
26466
27057
  * Ensures that the i18nMeta, if provided, is an i18n.Message.
@@ -26483,7 +27074,19 @@ function ingestElementBindings(unit, op, element) {
26483
27074
  let i18nAttributeBindingNames = new Set();
26484
27075
  for (const attr of element.attributes) {
26485
27076
  // Attribute literal bindings, such as `attr.foo="bar"`.
26486
- const securityContext = domSchema.securityContext(element.name, attr.name, true);
27077
+ const [ns, elementName] = splitNsName$1(element.name);
27078
+ let namespace = ns;
27079
+ if (!ns) {
27080
+ switch (op.namespace) {
27081
+ case Namespace.SVG:
27082
+ namespace = SVG_NAMESPACE$2;
27083
+ break;
27084
+ case Namespace.Math:
27085
+ namespace = MATH_ML_NAMESPACE$2;
27086
+ break;
27087
+ }
27088
+ }
27089
+ const securityContext = domSchema.securityContext(namespace ? `:${namespace}:${elementName}` : elementName, attr.name, true);
26487
27090
  bindings.push(createBindingOp(op.xref, BindingKind.Attribute, attr.name, convertAstWithInterpolation(unit.job, attr.value, attr.i18n), null, securityContext, true, false, null, asMessage(attr.i18n), attr.sourceSpan));
26488
27091
  if (attr.i18n) {
26489
27092
  i18nAttributeBindingNames.add(attr.name);
@@ -26767,715 +27370,234 @@ function ingestControlFlowInsertionPoint(unit, xref, node) {
26767
27370
  if (child instanceof Element$1 || (child instanceof Template && child.tagName !== null)) {
26768
27371
  root = child;
26769
27372
  }
26770
- else {
26771
- return null;
26772
- }
26773
- }
26774
- // If we've found a single root node, its tag name and attributes can be
26775
- // copied to the surrounding template to be used for content projection.
26776
- if (root !== null) {
26777
- // Collect the static attributes for content projection purposes.
26778
- for (const attr of root.attributes) {
26779
- if (!attr.name.startsWith(ANIMATE_PREFIX$1)) {
26780
- const securityContext = domSchema.securityContext(NG_TEMPLATE_TAG_NAME, attr.name, true);
26781
- unit.update.push(createBindingOp(xref, BindingKind.Attribute, attr.name, literal(attr.value), null, securityContext, true, false, null, asMessage(attr.i18n), attr.sourceSpan));
26782
- }
26783
- }
26784
- // Also collect the inputs since they participate in content projection as well.
26785
- // Note that TDB used to collect the outputs as well, but it wasn't passing them into
26786
- // the template instruction. Here we just don't collect them.
26787
- for (const attr of root.inputs) {
26788
- if (attr.type !== BindingType.LegacyAnimation &&
26789
- attr.type !== BindingType.Animation &&
26790
- attr.type !== BindingType.Attribute) {
26791
- const securityContext = domSchema.securityContext(NG_TEMPLATE_TAG_NAME, attr.name, true);
26792
- unit.create.push(createExtractedAttributeOp(xref, BindingKind.Property, null, attr.name, null, null, null, securityContext));
26793
- }
26794
- }
26795
- const tagName = root instanceof Element$1 ? root.name : root.tagName;
26796
- // Don't pass along `ng-template` tag name since it enables directive matching.
26797
- return tagName === NG_TEMPLATE_TAG_NAME ? null : tagName;
26798
- }
26799
- return null;
26800
- }
26801
-
26802
- /*!
26803
- * @license
26804
- * Copyright Google LLC All Rights Reserved.
26805
- *
26806
- * Use of this source code is governed by an MIT-style license that can be
26807
- * found in the LICENSE file at https://angular.dev/license
26808
- */
26809
- /**
26810
- * Whether to produce instructions that will attach the source location to each DOM node.
26811
- *
26812
- * !!!Important!!! at the time of writing this flag isn't exposed externally, but internal debug
26813
- * tools enable it via a local change. Any modifications to this flag need to update the
26814
- * internal tooling as well.
26815
- */
26816
- let ENABLE_TEMPLATE_SOURCE_LOCATIONS = false;
26817
- /** Gets whether template source locations are enabled. */
26818
- function getTemplateSourceLocationsEnabled() {
26819
- return ENABLE_TEMPLATE_SOURCE_LOCATIONS;
26820
- }
26821
-
26822
- // if (rf & flags) { .. }
26823
- function renderFlagCheckIfStmt(flags, statements) {
26824
- return ifStmt(variable(RENDER_FLAGS).bitwiseAnd(literal(flags), null), statements);
26825
- }
26826
- /**
26827
- * Translates query flags into `TQueryFlags` type in
26828
- * packages/core/src/render3/interfaces/query.ts
26829
- * @param query
26830
- */
26831
- function toQueryFlags(query) {
26832
- return ((query.descendants ? 1 /* QueryFlags.descendants */ : 0 /* QueryFlags.none */) |
26833
- (query.static ? 2 /* QueryFlags.isStatic */ : 0 /* QueryFlags.none */) |
26834
- (query.emitDistinctChangesOnly ? 4 /* QueryFlags.emitDistinctChangesOnly */ : 0 /* QueryFlags.none */));
26835
- }
26836
- function getQueryPredicate(query, constantPool) {
26837
- if (Array.isArray(query.predicate)) {
26838
- let predicate = [];
26839
- query.predicate.forEach((selector) => {
26840
- // Each item in predicates array may contain strings with comma-separated refs
26841
- // (for ex. 'ref, ref1, ..., refN'), thus we extract individual refs and store them
26842
- // as separate array entities
26843
- const selectors = selector.split(',').map((token) => literal(token.trim()));
26844
- predicate.push(...selectors);
26845
- });
26846
- return constantPool.getConstLiteral(literalArr(predicate), true);
26847
- }
26848
- else {
26849
- // The original predicate may have been wrapped in a `forwardRef()` call.
26850
- switch (query.predicate.forwardRef) {
26851
- case 0 /* ForwardRefHandling.None */:
26852
- case 2 /* ForwardRefHandling.Unwrapped */:
26853
- return query.predicate.expression;
26854
- case 1 /* ForwardRefHandling.Wrapped */:
26855
- return importExpr(Identifiers.resolveForwardRef).callFn([query.predicate.expression]);
26856
- }
26857
- }
26858
- }
26859
- function createQueryCreateCall(query, constantPool, queryTypeFns, prependParams) {
26860
- const parameters = [];
26861
- if (prependParams !== undefined) {
26862
- parameters.push(...prependParams);
26863
- }
26864
- if (query.isSignal) {
26865
- parameters.push(new ReadPropExpr(variable(CONTEXT_NAME), query.propertyName));
26866
- }
26867
- parameters.push(getQueryPredicate(query, constantPool), literal(toQueryFlags(query)));
26868
- if (query.read) {
26869
- parameters.push(query.read);
26870
- }
26871
- const queryCreateFn = query.isSignal ? queryTypeFns.signalBased : queryTypeFns.nonSignal;
26872
- return importExpr(queryCreateFn).callFn(parameters);
26873
- }
26874
- const queryAdvancePlaceholder = Symbol('queryAdvancePlaceholder');
26875
- /**
26876
- * Collapses query advance placeholders in a list of statements.
26877
- *
26878
- * This allows for less generated code because multiple sibling query advance
26879
- * statements can be collapsed into a single call with the count as argument.
26880
- *
26881
- * e.g.
26882
- *
26883
- * ```ts
26884
- * bla();
26885
- * queryAdvance();
26886
- * queryAdvance();
26887
- * bla();
26888
- * ```
26889
- *
26890
- * --> will turn into
26891
- *
26892
- * ```ts
26893
- * bla();
26894
- * queryAdvance(2);
26895
- * bla();
26896
- * ```
26897
- */
26898
- function collapseAdvanceStatements(statements) {
26899
- const result = [];
26900
- let advanceCollapseCount = 0;
26901
- const flushAdvanceCount = () => {
26902
- if (advanceCollapseCount > 0) {
26903
- result.unshift(importExpr(Identifiers.queryAdvance)
26904
- .callFn(advanceCollapseCount === 1 ? [] : [literal(advanceCollapseCount)])
26905
- .toStmt());
26906
- advanceCollapseCount = 0;
26907
- }
26908
- };
26909
- // Iterate through statements in reverse and collapse advance placeholders.
26910
- for (let i = statements.length - 1; i >= 0; i--) {
26911
- const st = statements[i];
26912
- if (st === queryAdvancePlaceholder) {
26913
- advanceCollapseCount++;
26914
- }
26915
- else {
26916
- flushAdvanceCount();
26917
- result.unshift(st);
26918
- }
26919
- }
26920
- flushAdvanceCount();
26921
- return result;
26922
- }
26923
- // Define and update any view queries
26924
- function createViewQueriesFunction(viewQueries, constantPool, name) {
26925
- const createStatements = [];
26926
- const updateStatements = [];
26927
- const tempAllocator = temporaryAllocator((st) => updateStatements.push(st), TEMPORARY_NAME);
26928
- viewQueries.forEach((query) => {
26929
- // creation call, e.g. r3.viewQuery(somePredicate, true) or
26930
- // r3.viewQuerySignal(ctx.prop, somePredicate, true);
26931
- const queryDefinitionCall = createQueryCreateCall(query, constantPool, {
26932
- signalBased: Identifiers.viewQuerySignal,
26933
- nonSignal: Identifiers.viewQuery,
26934
- });
26935
- createStatements.push(queryDefinitionCall.toStmt());
26936
- // Signal queries update lazily and we just advance the index.
26937
- if (query.isSignal) {
26938
- updateStatements.push(queryAdvancePlaceholder);
26939
- return;
26940
- }
26941
- // update, e.g. (r3.queryRefresh(tmp = r3.loadQuery()) && (ctx.someDir = tmp));
26942
- const temporary = tempAllocator();
26943
- const getQueryList = importExpr(Identifiers.loadQuery).callFn([]);
26944
- const refresh = importExpr(Identifiers.queryRefresh).callFn([temporary.set(getQueryList)]);
26945
- const updateDirective = variable(CONTEXT_NAME)
26946
- .prop(query.propertyName)
26947
- .set(query.first ? temporary.prop('first') : temporary);
26948
- updateStatements.push(refresh.and(updateDirective).toStmt());
26949
- });
26950
- const viewQueryFnName = name ? `${name}_Query` : null;
26951
- return fn([new FnParam(RENDER_FLAGS, NUMBER_TYPE), new FnParam(CONTEXT_NAME, null)], [
26952
- renderFlagCheckIfStmt(1 /* core.RenderFlags.Create */, createStatements),
26953
- renderFlagCheckIfStmt(2 /* core.RenderFlags.Update */, collapseAdvanceStatements(updateStatements)),
26954
- ], INFERRED_TYPE, null, viewQueryFnName);
26955
- }
26956
- // Define and update any content queries
26957
- function createContentQueriesFunction(queries, constantPool, name) {
26958
- const createStatements = [];
26959
- const updateStatements = [];
26960
- const tempAllocator = temporaryAllocator((st) => updateStatements.push(st), TEMPORARY_NAME);
26961
- for (const query of queries) {
26962
- // creation, e.g. r3.contentQuery(dirIndex, somePredicate, true, null) or
26963
- // r3.contentQuerySignal(dirIndex, propName, somePredicate, <flags>, <read>).
26964
- createStatements.push(createQueryCreateCall(query, constantPool, { nonSignal: Identifiers.contentQuery, signalBased: Identifiers.contentQuerySignal },
26965
- /* prependParams */ [variable('dirIndex')]).toStmt());
26966
- // Signal queries update lazily and we just advance the index.
26967
- if (query.isSignal) {
26968
- updateStatements.push(queryAdvancePlaceholder);
26969
- continue;
26970
- }
26971
- // update, e.g. (r3.queryRefresh(tmp = r3.loadQuery()) && (ctx.someDir = tmp));
26972
- const temporary = tempAllocator();
26973
- const getQueryList = importExpr(Identifiers.loadQuery).callFn([]);
26974
- const refresh = importExpr(Identifiers.queryRefresh).callFn([temporary.set(getQueryList)]);
26975
- const updateDirective = variable(CONTEXT_NAME)
26976
- .prop(query.propertyName)
26977
- .set(query.first ? temporary.prop('first') : temporary);
26978
- updateStatements.push(refresh.and(updateDirective).toStmt());
26979
- }
26980
- const contentQueriesFnName = name ? `${name}_ContentQueries` : null;
26981
- return fn([
26982
- new FnParam(RENDER_FLAGS, NUMBER_TYPE),
26983
- new FnParam(CONTEXT_NAME, null),
26984
- new FnParam('dirIndex', null),
26985
- ], [
26986
- renderFlagCheckIfStmt(1 /* core.RenderFlags.Create */, createStatements),
26987
- renderFlagCheckIfStmt(2 /* core.RenderFlags.Update */, collapseAdvanceStatements(updateStatements)),
26988
- ], INFERRED_TYPE, null, contentQueriesFnName);
26989
- }
26990
-
26991
- class HtmlParser extends Parser$1 {
26992
- constructor() {
26993
- super(getHtmlTagDefinition);
26994
- }
26995
- parse(source, url, options) {
26996
- return super.parse(source, url, options);
26997
- }
26998
- }
26999
-
27000
- const PROPERTY_PARTS_SEPARATOR = '.';
27001
- const ATTRIBUTE_PREFIX = 'attr';
27002
- const ANIMATE_PREFIX = 'animate';
27003
- const CLASS_PREFIX = 'class';
27004
- const STYLE_PREFIX = 'style';
27005
- const TEMPLATE_ATTR_PREFIX$1 = '*';
27006
- const LEGACY_ANIMATE_PROP_PREFIX = 'animate-';
27007
- /**
27008
- * Parses bindings in templates and in the directive host area.
27009
- */
27010
- class BindingParser {
27011
- _exprParser;
27012
- _interpolationConfig;
27013
- _schemaRegistry;
27014
- errors;
27015
- constructor(_exprParser, _interpolationConfig, _schemaRegistry, errors) {
27016
- this._exprParser = _exprParser;
27017
- this._interpolationConfig = _interpolationConfig;
27018
- this._schemaRegistry = _schemaRegistry;
27019
- this.errors = errors;
27020
- }
27021
- get interpolationConfig() {
27022
- return this._interpolationConfig;
27023
- }
27024
- createBoundHostProperties(properties, sourceSpan) {
27025
- const boundProps = [];
27026
- for (const propName of Object.keys(properties)) {
27027
- const expression = properties[propName];
27028
- if (typeof expression === 'string') {
27029
- this.parsePropertyBinding(propName, expression, true, false, sourceSpan, sourceSpan.start.offset, undefined, [],
27030
- // Use the `sourceSpan` for `keySpan`. This isn't really accurate, but neither is the
27031
- // sourceSpan, as it represents the sourceSpan of the host itself rather than the
27032
- // source of the host binding (which doesn't exist in the template). Regardless,
27033
- // neither of these values are used in Ivy but are only here to satisfy the function
27034
- // signature. This should likely be refactored in the future so that `sourceSpan`
27035
- // isn't being used inaccurately.
27036
- boundProps, sourceSpan);
27037
- }
27038
- else {
27039
- this._reportError(`Value of the host property binding "${propName}" needs to be a string representing an expression but got "${expression}" (${typeof expression})`, sourceSpan);
27040
- }
27041
- }
27042
- return boundProps;
27043
- }
27044
- createDirectiveHostEventAsts(hostListeners, sourceSpan) {
27045
- const targetEvents = [];
27046
- for (const propName of Object.keys(hostListeners)) {
27047
- const expression = hostListeners[propName];
27048
- if (typeof expression === 'string') {
27049
- // Use the `sourceSpan` for `keySpan` and `handlerSpan`. This isn't really accurate, but
27050
- // neither is the `sourceSpan`, as it represents the `sourceSpan` of the host itself
27051
- // rather than the source of the host binding (which doesn't exist in the template).
27052
- // Regardless, neither of these values are used in Ivy but are only here to satisfy the
27053
- // function signature. This should likely be refactored in the future so that `sourceSpan`
27054
- // isn't being used inaccurately.
27055
- this.parseEvent(propName, expression,
27056
- /* isAssignmentEvent */ false, sourceSpan, sourceSpan, [], targetEvents, sourceSpan);
27057
- }
27058
- else {
27059
- this._reportError(`Value of the host listener "${propName}" needs to be a string representing an expression but got "${expression}" (${typeof expression})`, sourceSpan);
27060
- }
27061
- }
27062
- return targetEvents;
27063
- }
27064
- parseInterpolation(value, sourceSpan, interpolatedTokens) {
27065
- const absoluteOffset = sourceSpan.fullStart.offset;
27066
- try {
27067
- const ast = this._exprParser.parseInterpolation(value, sourceSpan, absoluteOffset, interpolatedTokens, this._interpolationConfig);
27068
- if (ast) {
27069
- this.errors.push(...ast.errors);
27070
- }
27071
- return ast;
27072
- }
27073
- catch (e) {
27074
- this._reportError(`${e}`, sourceSpan);
27075
- return this._exprParser.wrapLiteralPrimitive('ERROR', sourceSpan, absoluteOffset);
27076
- }
27077
- }
27078
- /**
27079
- * Similar to `parseInterpolation`, but treats the provided string as a single expression
27080
- * element that would normally appear within the interpolation prefix and suffix (`{{` and `}}`).
27081
- * This is used for parsing the switch expression in ICUs.
27082
- */
27083
- parseInterpolationExpression(expression, sourceSpan) {
27084
- const absoluteOffset = sourceSpan.start.offset;
27085
- try {
27086
- const ast = this._exprParser.parseInterpolationExpression(expression, sourceSpan, absoluteOffset);
27087
- if (ast) {
27088
- this.errors.push(...ast.errors);
27089
- }
27090
- return ast;
27091
- }
27092
- catch (e) {
27093
- this._reportError(`${e}`, sourceSpan);
27094
- return this._exprParser.wrapLiteralPrimitive('ERROR', sourceSpan, absoluteOffset);
27095
- }
27096
- }
27097
- /**
27098
- * Parses the bindings in a microsyntax expression, and converts them to
27099
- * `ParsedProperty` or `ParsedVariable`.
27100
- *
27101
- * @param tplKey template binding name
27102
- * @param tplValue template binding value
27103
- * @param sourceSpan span of template binding relative to entire the template
27104
- * @param absoluteValueOffset start of the tplValue relative to the entire template
27105
- * @param targetMatchableAttrs potential attributes to match in the template
27106
- * @param targetProps target property bindings in the template
27107
- * @param targetVars target variables in the template
27108
- */
27109
- parseInlineTemplateBinding(tplKey, tplValue, sourceSpan, absoluteValueOffset, targetMatchableAttrs, targetProps, targetVars, isIvyAst) {
27110
- const absoluteKeyOffset = sourceSpan.start.offset + TEMPLATE_ATTR_PREFIX$1.length;
27111
- const bindings = this._parseTemplateBindings(tplKey, tplValue, sourceSpan, absoluteKeyOffset, absoluteValueOffset);
27112
- for (const binding of bindings) {
27113
- // sourceSpan is for the entire HTML attribute. bindingSpan is for a particular
27114
- // binding within the microsyntax expression so it's more narrow than sourceSpan.
27115
- const bindingSpan = moveParseSourceSpan(sourceSpan, binding.sourceSpan);
27116
- const key = binding.key.source;
27117
- const keySpan = moveParseSourceSpan(sourceSpan, binding.key.span);
27118
- if (binding instanceof VariableBinding) {
27119
- const value = binding.value ? binding.value.source : '$implicit';
27120
- const valueSpan = binding.value
27121
- ? moveParseSourceSpan(sourceSpan, binding.value.span)
27122
- : undefined;
27123
- targetVars.push(new ParsedVariable(key, value, bindingSpan, keySpan, valueSpan));
27124
- }
27125
- else if (binding.value) {
27126
- const srcSpan = isIvyAst ? bindingSpan : sourceSpan;
27127
- const valueSpan = moveParseSourceSpan(sourceSpan, binding.value.ast.sourceSpan);
27128
- this._parsePropertyAst(key, binding.value, false, srcSpan, keySpan, valueSpan, targetMatchableAttrs, targetProps);
27129
- }
27130
- else {
27131
- targetMatchableAttrs.push([key, '' /* value */]);
27132
- // Since this is a literal attribute with no RHS, source span should be
27133
- // just the key span.
27134
- this.parseLiteralAttr(key, null /* value */, keySpan, absoluteValueOffset, undefined /* valueSpan */, targetMatchableAttrs, targetProps, keySpan);
27135
- }
27136
- }
27137
- }
27138
- /**
27139
- * Parses the bindings in a microsyntax expression, e.g.
27140
- * ```html
27141
- * <tag *tplKey="let value1 = prop; let value2 = localVar">
27142
- * ```
27143
- *
27144
- * @param tplKey template binding name
27145
- * @param tplValue template binding value
27146
- * @param sourceSpan span of template binding relative to entire the template
27147
- * @param absoluteKeyOffset start of the `tplKey`
27148
- * @param absoluteValueOffset start of the `tplValue`
27149
- */
27150
- _parseTemplateBindings(tplKey, tplValue, sourceSpan, absoluteKeyOffset, absoluteValueOffset) {
27151
- try {
27152
- const bindingsResult = this._exprParser.parseTemplateBindings(tplKey, tplValue, sourceSpan, absoluteKeyOffset, absoluteValueOffset);
27153
- bindingsResult.errors.forEach((e) => this.errors.push(e));
27154
- bindingsResult.warnings.forEach((warning) => {
27155
- this._reportError(warning, sourceSpan, ParseErrorLevel.WARNING);
27156
- });
27157
- return bindingsResult.templateBindings;
27158
- }
27159
- catch (e) {
27160
- this._reportError(`${e}`, sourceSpan);
27161
- return [];
27162
- }
27163
- }
27164
- parseLiteralAttr(name, value, sourceSpan, absoluteOffset, valueSpan, targetMatchableAttrs, targetProps, keySpan) {
27165
- if (isLegacyAnimationLabel(name)) {
27166
- name = name.substring(1);
27167
- if (keySpan !== undefined) {
27168
- keySpan = moveParseSourceSpan(keySpan, new AbsoluteSourceSpan(keySpan.start.offset + 1, keySpan.end.offset));
27169
- }
27170
- if (value) {
27171
- this._reportError(`Assigning animation triggers via @prop="exp" attributes with an expression is invalid.` +
27172
- ` Use property bindings (e.g. [@prop]="exp") or use an attribute without a value (e.g. @prop) instead.`, sourceSpan, ParseErrorLevel.ERROR);
27173
- }
27174
- this._parseLegacyAnimation(name, value, sourceSpan, absoluteOffset, keySpan, valueSpan, targetMatchableAttrs, targetProps);
27175
- }
27176
- else {
27177
- targetProps.push(new ParsedProperty(name, this._exprParser.wrapLiteralPrimitive(value, '', absoluteOffset), ParsedPropertyType.LITERAL_ATTR, sourceSpan, keySpan, valueSpan));
27178
- }
27179
- }
27180
- parsePropertyBinding(name, expression, isHost, isPartOfAssignmentBinding, sourceSpan, absoluteOffset, valueSpan, targetMatchableAttrs, targetProps, keySpan) {
27181
- if (name.length === 0) {
27182
- this._reportError(`Property name is missing in binding`, sourceSpan);
27183
- }
27184
- let isLegacyAnimationProp = false;
27185
- if (name.startsWith(LEGACY_ANIMATE_PROP_PREFIX)) {
27186
- isLegacyAnimationProp = true;
27187
- name = name.substring(LEGACY_ANIMATE_PROP_PREFIX.length);
27188
- if (keySpan !== undefined) {
27189
- keySpan = moveParseSourceSpan(keySpan, new AbsoluteSourceSpan(keySpan.start.offset + LEGACY_ANIMATE_PROP_PREFIX.length, keySpan.end.offset));
27190
- }
27191
- }
27192
- else if (isLegacyAnimationLabel(name)) {
27193
- isLegacyAnimationProp = true;
27194
- name = name.substring(1);
27195
- if (keySpan !== undefined) {
27196
- keySpan = moveParseSourceSpan(keySpan, new AbsoluteSourceSpan(keySpan.start.offset + 1, keySpan.end.offset));
27197
- }
27198
- }
27199
- if (isLegacyAnimationProp) {
27200
- this._parseLegacyAnimation(name, expression, sourceSpan, absoluteOffset, keySpan, valueSpan, targetMatchableAttrs, targetProps);
27201
- }
27202
- else if (name.startsWith(`${ANIMATE_PREFIX}${PROPERTY_PARTS_SEPARATOR}`)) {
27203
- this._parseAnimation(name, this.parseBinding(expression, isHost, valueSpan || sourceSpan, absoluteOffset), sourceSpan, keySpan, valueSpan, targetMatchableAttrs, targetProps);
27204
- }
27205
- else {
27206
- this._parsePropertyAst(name, this.parseBinding(expression, isHost, valueSpan || sourceSpan, absoluteOffset), isPartOfAssignmentBinding, sourceSpan, keySpan, valueSpan, targetMatchableAttrs, targetProps);
27207
- }
27208
- }
27209
- parsePropertyInterpolation(name, value, sourceSpan, valueSpan, targetMatchableAttrs, targetProps, keySpan, interpolatedTokens) {
27210
- const expr = this.parseInterpolation(value, valueSpan || sourceSpan, interpolatedTokens);
27211
- if (expr) {
27212
- this._parsePropertyAst(name, expr, false, sourceSpan, keySpan, valueSpan, targetMatchableAttrs, targetProps);
27213
- return true;
27214
- }
27215
- return false;
27216
- }
27217
- _parsePropertyAst(name, ast, isPartOfAssignmentBinding, sourceSpan, keySpan, valueSpan, targetMatchableAttrs, targetProps) {
27218
- targetMatchableAttrs.push([name, ast.source]);
27219
- targetProps.push(new ParsedProperty(name, ast, isPartOfAssignmentBinding ? ParsedPropertyType.TWO_WAY : ParsedPropertyType.DEFAULT, sourceSpan, keySpan, valueSpan));
27220
- }
27221
- _parseAnimation(name, ast, sourceSpan, keySpan, valueSpan, targetMatchableAttrs, targetProps) {
27222
- targetMatchableAttrs.push([name, ast.source]);
27223
- targetProps.push(new ParsedProperty(name, ast, ParsedPropertyType.ANIMATION, sourceSpan, keySpan, valueSpan));
27224
- }
27225
- _parseLegacyAnimation(name, expression, sourceSpan, absoluteOffset, keySpan, valueSpan, targetMatchableAttrs, targetProps) {
27226
- if (name.length === 0) {
27227
- this._reportError('Animation trigger is missing', sourceSpan);
27228
- }
27229
- // This will occur when a @trigger is not paired with an expression.
27230
- // For animations it is valid to not have an expression since */void
27231
- // states will be applied by angular when the element is attached/detached
27232
- const ast = this.parseBinding(expression || 'undefined', false, valueSpan || sourceSpan, absoluteOffset);
27233
- targetMatchableAttrs.push([name, ast.source]);
27234
- targetProps.push(new ParsedProperty(name, ast, ParsedPropertyType.LEGACY_ANIMATION, sourceSpan, keySpan, valueSpan));
27235
- }
27236
- parseBinding(value, isHostBinding, sourceSpan, absoluteOffset) {
27237
- try {
27238
- const ast = isHostBinding
27239
- ? this._exprParser.parseSimpleBinding(value, sourceSpan, absoluteOffset, this._interpolationConfig)
27240
- : this._exprParser.parseBinding(value, sourceSpan, absoluteOffset, this._interpolationConfig);
27241
- if (ast) {
27242
- this.errors.push(...ast.errors);
27243
- }
27244
- return ast;
27245
- }
27246
- catch (e) {
27247
- this._reportError(`${e}`, sourceSpan);
27248
- return this._exprParser.wrapLiteralPrimitive('ERROR', sourceSpan, absoluteOffset);
27249
- }
27250
- }
27251
- createBoundElementProperty(elementSelector, boundProp, skipValidation = false, mapPropertyName = true) {
27252
- if (boundProp.isLegacyAnimation) {
27253
- return new BoundElementProperty(boundProp.name, BindingType.LegacyAnimation, SecurityContext$1.NONE, boundProp.expression, null, boundProp.sourceSpan, boundProp.keySpan, boundProp.valueSpan);
27254
- }
27255
- let unit = null;
27256
- let bindingType = undefined;
27257
- let boundPropertyName = null;
27258
- const parts = boundProp.name.split(PROPERTY_PARTS_SEPARATOR);
27259
- let securityContexts = undefined;
27260
- // Check for special cases (prefix style, attr, class)
27261
- if (parts.length > 1) {
27262
- if (parts[0] == ATTRIBUTE_PREFIX) {
27263
- boundPropertyName = parts.slice(1).join(PROPERTY_PARTS_SEPARATOR);
27264
- if (!skipValidation) {
27265
- this._validatePropertyOrAttributeName(boundPropertyName, boundProp.sourceSpan, true);
27266
- }
27267
- securityContexts = calcPossibleSecurityContexts(this._schemaRegistry, elementSelector, boundPropertyName, true);
27268
- const nsSeparatorIdx = boundPropertyName.indexOf(':');
27269
- if (nsSeparatorIdx > -1) {
27270
- const ns = boundPropertyName.substring(0, nsSeparatorIdx);
27271
- const name = boundPropertyName.substring(nsSeparatorIdx + 1);
27272
- boundPropertyName = mergeNsAndName(ns, name);
27273
- }
27274
- bindingType = BindingType.Attribute;
27275
- }
27276
- else if (parts[0] == CLASS_PREFIX) {
27277
- boundPropertyName = parts[1];
27278
- bindingType = BindingType.Class;
27279
- securityContexts = [SecurityContext$1.NONE];
27280
- }
27281
- else if (parts[0] == STYLE_PREFIX) {
27282
- unit = parts.length > 2 ? parts[2] : null;
27283
- boundPropertyName = parts[1];
27284
- bindingType = BindingType.Style;
27285
- securityContexts = [SecurityContext$1.STYLE];
27286
- }
27287
- else if (parts[0] == ANIMATE_PREFIX) {
27288
- boundPropertyName = boundProp.name;
27289
- bindingType = BindingType.Animation;
27290
- securityContexts = [SecurityContext$1.NONE];
27291
- }
27292
- }
27293
- // If not a special case, use the full property name
27294
- if (boundPropertyName === null) {
27295
- const mappedPropName = this._schemaRegistry.getMappedPropName(boundProp.name);
27296
- boundPropertyName = mapPropertyName ? mappedPropName : boundProp.name;
27297
- securityContexts = calcPossibleSecurityContexts(this._schemaRegistry, elementSelector, mappedPropName, false);
27298
- bindingType =
27299
- boundProp.type === ParsedPropertyType.TWO_WAY ? BindingType.TwoWay : BindingType.Property;
27300
- if (!skipValidation) {
27301
- this._validatePropertyOrAttributeName(mappedPropName, boundProp.sourceSpan, false);
27302
- }
27303
- }
27304
- return new BoundElementProperty(boundPropertyName, bindingType, securityContexts[0], boundProp.expression, unit, boundProp.sourceSpan, boundProp.keySpan, boundProp.valueSpan);
27305
- }
27306
- parseEvent(name, expression, isAssignmentEvent, sourceSpan, handlerSpan, targetMatchableAttrs, targetEvents, keySpan) {
27307
- if (name.length === 0) {
27308
- this._reportError(`Event name is missing in binding`, sourceSpan);
27309
- }
27310
- if (isLegacyAnimationLabel(name)) {
27311
- name = name.slice(1);
27312
- if (keySpan !== undefined) {
27313
- keySpan = moveParseSourceSpan(keySpan, new AbsoluteSourceSpan(keySpan.start.offset + 1, keySpan.end.offset));
27314
- }
27315
- this._parseLegacyAnimationEvent(name, expression, sourceSpan, handlerSpan, targetEvents, keySpan);
27316
- }
27317
- else {
27318
- this._parseRegularEvent(name, expression, isAssignmentEvent, sourceSpan, handlerSpan, targetMatchableAttrs, targetEvents, keySpan);
27319
- }
27320
- }
27321
- calcPossibleSecurityContexts(selector, propName, isAttribute) {
27322
- const prop = this._schemaRegistry.getMappedPropName(propName);
27323
- return calcPossibleSecurityContexts(this._schemaRegistry, selector, prop, isAttribute);
27324
- }
27325
- parseEventListenerName(rawName) {
27326
- const [target, eventName] = splitAtColon(rawName, [null, rawName]);
27327
- return { eventName: eventName, target };
27328
- }
27329
- parseLegacyAnimationEventName(rawName) {
27330
- const matches = splitAtPeriod(rawName, [rawName, null]);
27331
- return { eventName: matches[0], phase: matches[1] === null ? null : matches[1].toLowerCase() };
27332
- }
27333
- _parseLegacyAnimationEvent(name, expression, sourceSpan, handlerSpan, targetEvents, keySpan) {
27334
- const { eventName, phase } = this.parseLegacyAnimationEventName(name);
27335
- const ast = this._parseAction(expression, handlerSpan);
27336
- targetEvents.push(new ParsedEvent(eventName, phase, ParsedEventType.LegacyAnimation, ast, sourceSpan, handlerSpan, keySpan));
27337
- if (eventName.length === 0) {
27338
- this._reportError(`Animation event name is missing in binding`, sourceSpan);
27339
- }
27340
- if (phase) {
27341
- if (phase !== 'start' && phase !== 'done') {
27342
- this._reportError(`The provided animation output phase value "${phase}" for "@${eventName}" is not supported (use start or done)`, sourceSpan);
27343
- }
27344
- }
27345
- else {
27346
- this._reportError(`The animation trigger output event (@${eventName}) is missing its phase value name (start or done are currently supported)`, sourceSpan);
27347
- }
27348
- }
27349
- _parseRegularEvent(name, expression, isAssignmentEvent, sourceSpan, handlerSpan, targetMatchableAttrs, targetEvents, keySpan) {
27350
- // long format: 'target: eventName'
27351
- const { eventName, target } = this.parseEventListenerName(name);
27352
- const prevErrorCount = this.errors.length;
27353
- const ast = this._parseAction(expression, handlerSpan);
27354
- const isValid = this.errors.length === prevErrorCount;
27355
- targetMatchableAttrs.push([name, ast.source]);
27356
- // Don't try to validate assignment events if there were other
27357
- // parsing errors to avoid adding more noise to the error logs.
27358
- if (isAssignmentEvent && isValid && !this._isAllowedAssignmentEvent(ast)) {
27359
- this._reportError('Unsupported expression in a two-way binding', sourceSpan);
27360
- }
27361
- let eventType = ParsedEventType.Regular;
27362
- if (isAssignmentEvent) {
27363
- eventType = ParsedEventType.TwoWay;
27364
- }
27365
- if (name.startsWith(`${ANIMATE_PREFIX}${PROPERTY_PARTS_SEPARATOR}`)) {
27366
- eventType = ParsedEventType.Animation;
27373
+ else {
27374
+ return null;
27367
27375
  }
27368
- targetEvents.push(new ParsedEvent(eventName, target, eventType, ast, sourceSpan, handlerSpan, keySpan));
27369
- // Don't detect directives for event names for now,
27370
- // so don't add the event name to the matchableAttrs
27371
27376
  }
27372
- _parseAction(value, sourceSpan) {
27373
- const absoluteOffset = sourceSpan && sourceSpan.start ? sourceSpan.start.offset : 0;
27374
- try {
27375
- const ast = this._exprParser.parseAction(value, sourceSpan, absoluteOffset, this._interpolationConfig);
27376
- if (ast) {
27377
- this.errors.push(...ast.errors);
27378
- }
27379
- if (!ast || ast.ast instanceof EmptyExpr$1) {
27380
- this._reportError(`Empty expressions are not allowed`, sourceSpan);
27381
- return this._exprParser.wrapLiteralPrimitive('ERROR', sourceSpan, absoluteOffset);
27377
+ // If we've found a single root node, its tag name and attributes can be
27378
+ // copied to the surrounding template to be used for content projection.
27379
+ if (root !== null) {
27380
+ // Collect the static attributes for content projection purposes.
27381
+ for (const attr of root.attributes) {
27382
+ if (!attr.name.startsWith(ANIMATE_PREFIX)) {
27383
+ const securityContext = domSchema.securityContext(NG_TEMPLATE_TAG_NAME, attr.name, true);
27384
+ unit.update.push(createBindingOp(xref, BindingKind.Attribute, attr.name, literal(attr.value), null, securityContext, true, false, null, asMessage(attr.i18n), attr.sourceSpan));
27382
27385
  }
27383
- return ast;
27384
27386
  }
27385
- catch (e) {
27386
- this._reportError(`${e}`, sourceSpan);
27387
- return this._exprParser.wrapLiteralPrimitive('ERROR', sourceSpan, absoluteOffset);
27387
+ // Also collect the inputs since they participate in content projection as well.
27388
+ // Note that TDB used to collect the outputs as well, but it wasn't passing them into
27389
+ // the template instruction. Here we just don't collect them.
27390
+ for (const attr of root.inputs) {
27391
+ if (attr.type !== BindingType.LegacyAnimation &&
27392
+ attr.type !== BindingType.Animation &&
27393
+ attr.type !== BindingType.Attribute) {
27394
+ const securityContext = domSchema.securityContext(NG_TEMPLATE_TAG_NAME, attr.name, true);
27395
+ unit.create.push(createExtractedAttributeOp(xref, BindingKind.Property, null, attr.name, null, null, null, securityContext));
27396
+ }
27388
27397
  }
27398
+ const tagName = root instanceof Element$1 ? root.name : root.tagName;
27399
+ // Don't pass along `ng-template` tag name since it enables directive matching.
27400
+ return tagName === NG_TEMPLATE_TAG_NAME ? null : tagName;
27389
27401
  }
27390
- _reportError(message, sourceSpan, level = ParseErrorLevel.ERROR) {
27391
- this.errors.push(new ParseError(sourceSpan, message, level));
27392
- }
27393
- /**
27394
- * @param propName the name of the property / attribute
27395
- * @param sourceSpan
27396
- * @param isAttr true when binding to an attribute
27397
- */
27398
- _validatePropertyOrAttributeName(propName, sourceSpan, isAttr) {
27399
- const report = isAttr
27400
- ? this._schemaRegistry.validateAttribute(propName)
27401
- : this._schemaRegistry.validateProperty(propName);
27402
- if (report.error) {
27403
- this._reportError(report.msg, sourceSpan, ParseErrorLevel.ERROR);
27404
- }
27402
+ return null;
27403
+ }
27404
+
27405
+ /*!
27406
+ * @license
27407
+ * Copyright Google LLC All Rights Reserved.
27408
+ *
27409
+ * Use of this source code is governed by an MIT-style license that can be
27410
+ * found in the LICENSE file at https://angular.dev/license
27411
+ */
27412
+ /**
27413
+ * Whether to produce instructions that will attach the source location to each DOM node.
27414
+ *
27415
+ * !!!Important!!! at the time of writing this flag isn't exposed externally, but internal debug
27416
+ * tools enable it via a local change. Any modifications to this flag need to update the
27417
+ * internal tooling as well.
27418
+ */
27419
+ let ENABLE_TEMPLATE_SOURCE_LOCATIONS = false;
27420
+ /** Gets whether template source locations are enabled. */
27421
+ function getTemplateSourceLocationsEnabled() {
27422
+ return ENABLE_TEMPLATE_SOURCE_LOCATIONS;
27423
+ }
27424
+
27425
+ // if (rf & flags) { .. }
27426
+ function renderFlagCheckIfStmt(flags, statements) {
27427
+ return ifStmt(variable(RENDER_FLAGS).bitwiseAnd(literal(flags), null), statements);
27428
+ }
27429
+ /**
27430
+ * Translates query flags into `TQueryFlags` type in
27431
+ * packages/core/src/render3/interfaces/query.ts
27432
+ * @param query
27433
+ */
27434
+ function toQueryFlags(query) {
27435
+ return ((query.descendants ? 1 /* QueryFlags.descendants */ : 0 /* QueryFlags.none */) |
27436
+ (query.static ? 2 /* QueryFlags.isStatic */ : 0 /* QueryFlags.none */) |
27437
+ (query.emitDistinctChangesOnly ? 4 /* QueryFlags.emitDistinctChangesOnly */ : 0 /* QueryFlags.none */));
27438
+ }
27439
+ function getQueryPredicate(query, constantPool) {
27440
+ if (Array.isArray(query.predicate)) {
27441
+ let predicate = [];
27442
+ query.predicate.forEach((selector) => {
27443
+ // Each item in predicates array may contain strings with comma-separated refs
27444
+ // (for ex. 'ref, ref1, ..., refN'), thus we extract individual refs and store them
27445
+ // as separate array entities
27446
+ const selectors = selector.split(',').map((token) => literal(token.trim()));
27447
+ predicate.push(...selectors);
27448
+ });
27449
+ return constantPool.getConstLiteral(literalArr(predicate), true);
27405
27450
  }
27406
- /**
27407
- * Returns whether a parsed AST is allowed to be used within the event side of a two-way binding.
27408
- * @param ast Parsed AST to be checked.
27409
- */
27410
- _isAllowedAssignmentEvent(ast) {
27411
- if (ast instanceof ASTWithSource) {
27412
- return this._isAllowedAssignmentEvent(ast.ast);
27413
- }
27414
- if (ast instanceof NonNullAssert) {
27415
- return this._isAllowedAssignmentEvent(ast.expression);
27416
- }
27417
- if (ast instanceof Call &&
27418
- ast.args.length === 1 &&
27419
- ast.receiver instanceof PropertyRead &&
27420
- ast.receiver.name === '$any' &&
27421
- ast.receiver.receiver instanceof ImplicitReceiver &&
27422
- !(ast.receiver.receiver instanceof ThisReceiver)) {
27423
- return this._isAllowedAssignmentEvent(ast.args[0]);
27424
- }
27425
- if (ast instanceof PropertyRead || ast instanceof KeyedRead) {
27426
- if (!hasRecursiveSafeReceiver(ast)) {
27427
- return true;
27428
- }
27451
+ else {
27452
+ // The original predicate may have been wrapped in a `forwardRef()` call.
27453
+ switch (query.predicate.forwardRef) {
27454
+ case 0 /* ForwardRefHandling.None */:
27455
+ case 2 /* ForwardRefHandling.Unwrapped */:
27456
+ return query.predicate.expression;
27457
+ case 1 /* ForwardRefHandling.Wrapped */:
27458
+ return importExpr(Identifiers.resolveForwardRef).callFn([query.predicate.expression]);
27429
27459
  }
27430
- return false;
27431
27460
  }
27432
27461
  }
27433
- function hasRecursiveSafeReceiver(ast) {
27434
- if (ast instanceof SafePropertyRead || ast instanceof SafeKeyedRead) {
27435
- return true;
27462
+ function createQueryCreateCall(query, constantPool, queryTypeFns, prependParams) {
27463
+ const parameters = [];
27464
+ if (prependParams !== undefined) {
27465
+ parameters.push(...prependParams);
27436
27466
  }
27437
- if (ast instanceof ParenthesizedExpression) {
27438
- return hasRecursiveSafeReceiver(ast.expression);
27467
+ if (query.isSignal) {
27468
+ parameters.push(new ReadPropExpr(variable(CONTEXT_NAME), query.propertyName));
27439
27469
  }
27440
- if (ast instanceof PropertyRead || ast instanceof KeyedRead || ast instanceof Call) {
27441
- return hasRecursiveSafeReceiver(ast.receiver);
27470
+ parameters.push(getQueryPredicate(query, constantPool), literal(toQueryFlags(query)));
27471
+ if (query.read) {
27472
+ parameters.push(query.read);
27442
27473
  }
27443
- return false;
27444
- }
27445
- function isLegacyAnimationLabel(name) {
27446
- return name[0] == '@';
27474
+ const queryCreateFn = query.isSignal ? queryTypeFns.signalBased : queryTypeFns.nonSignal;
27475
+ return importExpr(queryCreateFn).callFn(parameters);
27447
27476
  }
27448
- function calcPossibleSecurityContexts(registry, selector, propName, isAttribute) {
27449
- let ctxs;
27450
- const nameToContext = (elName) => registry.securityContext(elName, propName, isAttribute);
27451
- if (selector === null) {
27452
- ctxs = registry.allKnownElementNames().map(nameToContext);
27477
+ const queryAdvancePlaceholder = Symbol('queryAdvancePlaceholder');
27478
+ /**
27479
+ * Collapses query advance placeholders in a list of statements.
27480
+ *
27481
+ * This allows for less generated code because multiple sibling query advance
27482
+ * statements can be collapsed into a single call with the count as argument.
27483
+ *
27484
+ * e.g.
27485
+ *
27486
+ * ```ts
27487
+ * bla();
27488
+ * queryAdvance();
27489
+ * queryAdvance();
27490
+ * bla();
27491
+ * ```
27492
+ *
27493
+ * --> will turn into
27494
+ *
27495
+ * ```ts
27496
+ * bla();
27497
+ * queryAdvance(2);
27498
+ * bla();
27499
+ * ```
27500
+ */
27501
+ function collapseAdvanceStatements(statements) {
27502
+ const result = [];
27503
+ let advanceCollapseCount = 0;
27504
+ const flushAdvanceCount = () => {
27505
+ if (advanceCollapseCount > 0) {
27506
+ result.unshift(importExpr(Identifiers.queryAdvance)
27507
+ .callFn(advanceCollapseCount === 1 ? [] : [literal(advanceCollapseCount)])
27508
+ .toStmt());
27509
+ advanceCollapseCount = 0;
27510
+ }
27511
+ };
27512
+ // Iterate through statements in reverse and collapse advance placeholders.
27513
+ for (let i = statements.length - 1; i >= 0; i--) {
27514
+ const st = statements[i];
27515
+ if (st === queryAdvancePlaceholder) {
27516
+ advanceCollapseCount++;
27517
+ }
27518
+ else {
27519
+ flushAdvanceCount();
27520
+ result.unshift(st);
27521
+ }
27453
27522
  }
27454
- else {
27455
- ctxs = [];
27456
- CssSelector.parse(selector).forEach((selector) => {
27457
- const elementNames = selector.element ? [selector.element] : registry.allKnownElementNames();
27458
- const notElementNames = new Set(selector.notSelectors
27459
- .filter((selector) => selector.isElementSelector())
27460
- .map((selector) => selector.element));
27461
- const possibleElementNames = elementNames.filter((elName) => !notElementNames.has(elName));
27462
- ctxs.push(...possibleElementNames.map(nameToContext));
27523
+ flushAdvanceCount();
27524
+ return result;
27525
+ }
27526
+ // Define and update any view queries
27527
+ function createViewQueriesFunction(viewQueries, constantPool, name) {
27528
+ const createStatements = [];
27529
+ const updateStatements = [];
27530
+ const tempAllocator = temporaryAllocator((st) => updateStatements.push(st), TEMPORARY_NAME);
27531
+ viewQueries.forEach((query) => {
27532
+ // creation call, e.g. r3.viewQuery(somePredicate, true) or
27533
+ // r3.viewQuerySignal(ctx.prop, somePredicate, true);
27534
+ const queryDefinitionCall = createQueryCreateCall(query, constantPool, {
27535
+ signalBased: Identifiers.viewQuerySignal,
27536
+ nonSignal: Identifiers.viewQuery,
27463
27537
  });
27538
+ createStatements.push(queryDefinitionCall.toStmt());
27539
+ // Signal queries update lazily and we just advance the index.
27540
+ if (query.isSignal) {
27541
+ updateStatements.push(queryAdvancePlaceholder);
27542
+ return;
27543
+ }
27544
+ // update, e.g. (r3.queryRefresh(tmp = r3.loadQuery()) && (ctx.someDir = tmp));
27545
+ const temporary = tempAllocator();
27546
+ const getQueryList = importExpr(Identifiers.loadQuery).callFn([]);
27547
+ const refresh = importExpr(Identifiers.queryRefresh).callFn([temporary.set(getQueryList)]);
27548
+ const updateDirective = variable(CONTEXT_NAME)
27549
+ .prop(query.propertyName)
27550
+ .set(query.first ? temporary.prop('first') : temporary);
27551
+ updateStatements.push(refresh.and(updateDirective).toStmt());
27552
+ });
27553
+ const viewQueryFnName = name ? `${name}_Query` : null;
27554
+ return fn([new FnParam(RENDER_FLAGS, NUMBER_TYPE), new FnParam(CONTEXT_NAME, null)], [
27555
+ renderFlagCheckIfStmt(1 /* core.RenderFlags.Create */, createStatements),
27556
+ renderFlagCheckIfStmt(2 /* core.RenderFlags.Update */, collapseAdvanceStatements(updateStatements)),
27557
+ ], INFERRED_TYPE, null, viewQueryFnName);
27558
+ }
27559
+ // Define and update any content queries
27560
+ function createContentQueriesFunction(queries, constantPool, name) {
27561
+ const createStatements = [];
27562
+ const updateStatements = [];
27563
+ const tempAllocator = temporaryAllocator((st) => updateStatements.push(st), TEMPORARY_NAME);
27564
+ for (const query of queries) {
27565
+ // creation, e.g. r3.contentQuery(dirIndex, somePredicate, true, null) or
27566
+ // r3.contentQuerySignal(dirIndex, propName, somePredicate, <flags>, <read>).
27567
+ createStatements.push(createQueryCreateCall(query, constantPool, { nonSignal: Identifiers.contentQuery, signalBased: Identifiers.contentQuerySignal },
27568
+ /* prependParams */ [variable('dirIndex')]).toStmt());
27569
+ // Signal queries update lazily and we just advance the index.
27570
+ if (query.isSignal) {
27571
+ updateStatements.push(queryAdvancePlaceholder);
27572
+ continue;
27573
+ }
27574
+ // update, e.g. (r3.queryRefresh(tmp = r3.loadQuery()) && (ctx.someDir = tmp));
27575
+ const temporary = tempAllocator();
27576
+ const getQueryList = importExpr(Identifiers.loadQuery).callFn([]);
27577
+ const refresh = importExpr(Identifiers.queryRefresh).callFn([temporary.set(getQueryList)]);
27578
+ const updateDirective = variable(CONTEXT_NAME)
27579
+ .prop(query.propertyName)
27580
+ .set(query.first ? temporary.prop('first') : temporary);
27581
+ updateStatements.push(refresh.and(updateDirective).toStmt());
27464
27582
  }
27465
- return ctxs.length === 0 ? [SecurityContext$1.NONE] : Array.from(new Set(ctxs)).sort();
27583
+ const contentQueriesFnName = name ? `${name}_ContentQueries` : null;
27584
+ return fn([
27585
+ new FnParam(RENDER_FLAGS, NUMBER_TYPE),
27586
+ new FnParam(CONTEXT_NAME, null),
27587
+ new FnParam('dirIndex', null),
27588
+ ], [
27589
+ renderFlagCheckIfStmt(1 /* core.RenderFlags.Create */, createStatements),
27590
+ renderFlagCheckIfStmt(2 /* core.RenderFlags.Update */, collapseAdvanceStatements(updateStatements)),
27591
+ ], INFERRED_TYPE, null, contentQueriesFnName);
27466
27592
  }
27467
- /**
27468
- * Compute a new ParseSourceSpan based off an original `sourceSpan` by using
27469
- * absolute offsets from the specified `absoluteSpan`.
27470
- *
27471
- * @param sourceSpan original source span
27472
- * @param absoluteSpan absolute source span to move to
27473
- */
27474
- function moveParseSourceSpan(sourceSpan, absoluteSpan) {
27475
- // The difference of two absolute offsets provide the relative offset
27476
- const startDiff = absoluteSpan.start - sourceSpan.start.offset;
27477
- const endDiff = absoluteSpan.end - sourceSpan.end.offset;
27478
- return new ParseSourceSpan(sourceSpan.start.moveBy(startDiff), sourceSpan.end.moveBy(endDiff), sourceSpan.fullStart.moveBy(startDiff), sourceSpan.details);
27593
+
27594
+ class HtmlParser extends Parser$1 {
27595
+ constructor() {
27596
+ super(getHtmlTagDefinition);
27597
+ }
27598
+ parse(source, url, options) {
27599
+ return super.parse(source, url, options);
27600
+ }
27479
27601
  }
27480
27602
 
27481
27603
  // Some of the code comes from WebComponents.JS
@@ -27494,7 +27616,7 @@ const LINK_STYLE_REL_ATTR = 'rel';
27494
27616
  const LINK_STYLE_HREF_ATTR = 'href';
27495
27617
  const LINK_STYLE_REL_VALUE = 'stylesheet';
27496
27618
  const STYLE_ELEMENT = 'style';
27497
- const SCRIPT_ELEMENT = 'script';
27619
+ const SCRIPT_ELEMENTS = new Set([':svg:script', 'script']);
27498
27620
  const NG_NON_BINDABLE_ATTR = 'ngNonBindable';
27499
27621
  const NG_PROJECT_AS = 'ngProjectAs';
27500
27622
  function preparseElement(ast) {
@@ -27503,7 +27625,7 @@ function preparseElement(ast) {
27503
27625
  let relAttr = null;
27504
27626
  let nonBindable = false;
27505
27627
  let projectAs = '';
27506
- ast.attrs.forEach((attr) => {
27628
+ for (const attr of ast.attrs) {
27507
27629
  const lcAttrName = attr.name.toLowerCase();
27508
27630
  if (lcAttrName == NG_CONTENT_SELECT_ATTR) {
27509
27631
  selectAttr = attr.value;
@@ -27522,17 +27644,18 @@ function preparseElement(ast) {
27522
27644
  projectAs = attr.value;
27523
27645
  }
27524
27646
  }
27525
- });
27526
- selectAttr = normalizeNgContentSelect(selectAttr);
27647
+ }
27648
+ // Normalize selector to '*' if empty
27649
+ selectAttr ||= '*';
27527
27650
  const nodeName = ast.name.toLowerCase();
27528
27651
  let type = PreparsedElementType.OTHER;
27529
27652
  if (isNgContent(nodeName)) {
27530
27653
  type = PreparsedElementType.NG_CONTENT;
27531
27654
  }
27532
- else if (nodeName == STYLE_ELEMENT) {
27655
+ else if (STYLE_ELEMENT === nodeName) {
27533
27656
  type = PreparsedElementType.STYLE;
27534
27657
  }
27535
- else if (nodeName == SCRIPT_ELEMENT) {
27658
+ else if (SCRIPT_ELEMENTS.has(nodeName)) {
27536
27659
  type = PreparsedElementType.SCRIPT;
27537
27660
  }
27538
27661
  else if (nodeName == LINK_ELEMENT && relAttr == LINK_STYLE_REL_VALUE) {
@@ -27562,12 +27685,6 @@ class PreparsedElement {
27562
27685
  this.projectAs = projectAs;
27563
27686
  }
27564
27687
  }
27565
- function normalizeNgContentSelect(selectAttr) {
27566
- if (selectAttr === null || selectAttr.length === 0) {
27567
- return '*';
27568
- }
27569
- return selectAttr;
27570
- }
27571
27688
 
27572
27689
  /** Pattern for the expression in a for loop block. */
27573
27690
  const FOR_LOOP_EXPRESSION_PATTERN = /^\s*([0-9A-Za-z_$]*)\s+of\s+([\S\s]*)/;
@@ -28855,8 +28972,9 @@ class HtmlAstToIvyAst {
28855
28972
  // Note that validation is skipped and property mapping is disabled
28856
28973
  // due to the fact that we need to make sure a given prop is not an
28857
28974
  // input of a directive and directive matching happens at runtime.
28975
+ const isAttrOn = prop.name.toLowerCase().startsWith('attr.on');
28858
28976
  const bep = this.bindingParser.createBoundElementProperty(elementName, prop,
28859
- /* skipValidation */ true,
28977
+ /* skipValidation */ !isAttrOn,
28860
28978
  /* mapPropertyName */ false);
28861
28979
  bound.push(BoundAttribute.fromBoundElementProperty(bep, i18n));
28862
28980
  }
@@ -29752,8 +29870,30 @@ function verifyHostBindings(bindings, sourceSpan) {
29752
29870
  const bindingParser = makeBindingParser();
29753
29871
  bindingParser.createDirectiveHostEventAsts(bindings.listeners, sourceSpan);
29754
29872
  bindingParser.createBoundHostProperties(bindings.properties, sourceSpan);
29873
+ validateNoEventBindings(bindings, bindingParser, sourceSpan);
29755
29874
  return bindingParser.errors;
29756
29875
  }
29876
+ /**
29877
+ * Validates that there are no event attribute bindings in the host bindings.
29878
+ * @param bindings - Map of host bindings for the component.
29879
+ * @param bindingParser - Binding parser used to create the binding expression.
29880
+ * @param sourceSpan - Source span where the host bindings were defined.
29881
+ */
29882
+ function validateNoEventBindings(bindings, bindingParser, sourceSpan) {
29883
+ for (const prop in bindings.properties) {
29884
+ const isAttr = prop.startsWith('attr.');
29885
+ const boundName = isAttr ? prop.slice(5) : prop;
29886
+ if (boundName.toLowerCase().startsWith('on')) {
29887
+ const errorType = isAttr ? 'attribute' : 'property';
29888
+ const suggestion = `(${boundName.slice(2)})=...`;
29889
+ let msg = `Binding to event ${errorType} '${boundName}' is disallowed for security reasons, please use ${suggestion}`;
29890
+ if (!isAttr) {
29891
+ msg += `\nIf '${prop}' is a directive input, make sure the directive is imported by the current module.`;
29892
+ }
29893
+ bindingParser.errors.push(new ParseError(sourceSpan, msg));
29894
+ }
29895
+ }
29896
+ }
29757
29897
  function compileStyles(styles, selector, hostSelector) {
29758
29898
  const shadowCss = new ShadowCss();
29759
29899
  return styles.map((style) => {
@@ -31357,11 +31497,6 @@ function createR3ComponentDeferMetadata(boundTarget, deferBlockDependencies) {
31357
31497
  function extractHostBindings(propMetadata, sourceSpan, host) {
31358
31498
  // First parse the declarations from the metadata.
31359
31499
  const bindings = parseHostBindings(host || {});
31360
- // After that check host bindings for errors
31361
- const errors = verifyHostBindings(bindings, sourceSpan);
31362
- if (errors.length) {
31363
- throw new Error(errors.map((error) => error.msg).join('\n'));
31364
- }
31365
31500
  // Next, loop over the properties of the object, looking for @HostBinding and @HostListener.
31366
31501
  for (const field in propMetadata) {
31367
31502
  if (propMetadata.hasOwnProperty(field)) {
@@ -31378,6 +31513,11 @@ function extractHostBindings(propMetadata, sourceSpan, host) {
31378
31513
  });
31379
31514
  }
31380
31515
  }
31516
+ // After that check host bindings for errors
31517
+ const errors = verifyHostBindings(bindings, sourceSpan);
31518
+ if (errors.length) {
31519
+ throw new Error(errors.map((error) => error.msg).join('\n'));
31520
+ }
31381
31521
  return bindings;
31382
31522
  }
31383
31523
  function isHostBinding(value) {
@@ -31512,7 +31652,7 @@ var _VisitorMode;
31512
31652
  * @description
31513
31653
  * Entry point for all public APIs of the compiler package.
31514
31654
  */
31515
- new Version$1('20.3.19');
31655
+ new Version$1('20.3.28');
31516
31656
 
31517
31657
  //////////////////////////////////////
31518
31658
  // THIS FILE HAS GLOBAL SIDE EFFECT //
@@ -40750,11 +40890,22 @@ function requireConventions () {
40750
40890
  XMLNS: 'http://www.w3.org/2000/xmlns/',
40751
40891
  });
40752
40892
 
40893
+ //[4] NameStartChar ::= ":" | [A-Z] | "_" | [a-z] | [#xC0-#xD6] | [#xD8-#xF6] | [#xF8-#x2FF] | [#x370-#x37D] | [#x37F-#x1FFF] | [#x200C-#x200D] | [#x2070-#x218F] | [#x2C00-#x2FEF] | [#x3001-#xD7FF] | [#xF900-#xFDCF] | [#xFDF0-#xFFFD] | [#x10000-#xEFFFF]
40894
+ //[4a] NameChar ::= NameStartChar | "-" | "." | [0-9] | #xB7 | [#x0300-#x036F] | [#x203F-#x2040]
40895
+ //[5] Name ::= NameStartChar (NameChar)*
40896
+ var nameStartChar = /[A-Z_a-z\xC0-\xD6\xD8-\xF6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD]/;//\u10000-\uEFFFF
40897
+ var nameChar = new RegExp("[\\-\\.0-9"+nameStartChar.source.slice(1,-1)+"\\u00B7\\u0300-\\u036F\\u203F-\\u2040]");
40898
+ var tagNamePattern = new RegExp('^'+nameStartChar.source+nameChar.source+'*(?:\:'+nameStartChar.source+nameChar.source+'*)?$');
40899
+ //var tagNamePattern = /^[a-zA-Z_][\w\-\.]*(?:\:[a-zA-Z_][\w\-\.]*)?$/
40900
+
40753
40901
  conventions.assign = assign;
40754
40902
  conventions.find = find;
40755
40903
  conventions.freeze = freeze;
40756
40904
  conventions.MIME_TYPE = MIME_TYPE;
40757
40905
  conventions.NAMESPACE = NAMESPACE;
40906
+ conventions.nameStartChar = nameStartChar;
40907
+ conventions.nameChar = nameChar;
40908
+ conventions.tagNamePattern = tagNamePattern;
40758
40909
  return conventions;
40759
40910
  }
40760
40911
 
@@ -40767,6 +40918,7 @@ function requireDom () {
40767
40918
 
40768
40919
  var find = conventions.find;
40769
40920
  var NAMESPACE = conventions.NAMESPACE;
40921
+ var tagNamePattern = conventions.tagNamePattern;
40770
40922
 
40771
40923
  /**
40772
40924
  * A prerequisite for `[].filter`, to drop elements that are empty
@@ -40998,6 +41150,13 @@ function requireDom () {
40998
41150
  * used for attributes or DocumentType entities
40999
41151
  */
41000
41152
  function NamedNodeMap() {
41153
+ // nodeName -> Attr membership index; lets the parse-time de-duplication in
41154
+ // setNamedItem resolve an existing attribute in O(1) instead of scanning the
41155
+ // list, so building an element with M attributes costs O(M) rather than O(M^2).
41156
+ // The numbered entries and length remain the sole authority for attribute order.
41157
+ // Object.create(null) so an attribute named __proto__ or constructor is an
41158
+ // ordinary key.
41159
+ this._nameIndex = Object.create(null);
41001
41160
  }
41002
41161
  function _findNodeIndex(list,node){
41003
41162
  var i = list.length;
@@ -41006,12 +41165,27 @@ function requireDom () {
41006
41165
  }
41007
41166
  }
41008
41167
 
41168
+ function _nnmIndexAdd(list, attr) {
41169
+ list._nameIndex[attr.nodeName] = attr;
41170
+ }
41171
+ function _nnmIndexRemove(list, attr) {
41172
+ // Only drop the entry if it still points at this attribute; a replacement with
41173
+ // a different nodeName may already have re-keyed it.
41174
+ if (list._nameIndex[attr.nodeName] === attr) {
41175
+ delete list._nameIndex[attr.nodeName];
41176
+ }
41177
+ }
41178
+
41009
41179
  function _addNamedNode(el,list,newAttr,oldAttr){
41010
41180
  if(oldAttr){
41011
41181
  list[_findNodeIndex(list,oldAttr)] = newAttr;
41182
+ // oldAttr leaves the list; drop its index entry (its nodeName may differ
41183
+ // from newAttr's when the replacement came via setNamedItemNS).
41184
+ _nnmIndexRemove(list, oldAttr);
41012
41185
  }else {
41013
41186
  list[list.length++] = newAttr;
41014
41187
  }
41188
+ _nnmIndexAdd(list, newAttr);
41015
41189
  if(el){
41016
41190
  newAttr.ownerElement = el;
41017
41191
  var doc = el.ownerDocument;
@@ -41030,6 +41204,7 @@ function requireDom () {
41030
41204
  list[i] = list[++i];
41031
41205
  }
41032
41206
  list.length = lastIndex;
41207
+ _nnmIndexRemove(list, attr);
41033
41208
  if(el){
41034
41209
  var doc = el.ownerDocument;
41035
41210
  if(doc){
@@ -41063,7 +41238,11 @@ function requireDom () {
41063
41238
  if(el && el!=this._ownerElement){
41064
41239
  throw new DOMException(INUSE_ATTRIBUTE_ERR);
41065
41240
  }
41066
- var oldAttr = this.getNamedItem(attr.nodeName);
41241
+ // Resolve any existing attribute with the same nodeName through the O(1)
41242
+ // membership index rather than an O(M) scan — this is the parse-dedup hot
41243
+ // path (setAttributeNode per attribute during parse). Absent -> undefined,
41244
+ // matching getNamedItem's contract.
41245
+ var oldAttr = this._nameIndex[attr.nodeName];
41067
41246
  _addNamedNode(this._ownerElement,this,attr,oldAttr);
41068
41247
  return oldAttr;
41069
41248
  },
@@ -41296,9 +41475,38 @@ function requireDom () {
41296
41475
  while (child) {
41297
41476
  var next = child.nextSibling;
41298
41477
  if (next !== null && next.nodeType === TEXT_NODE && child.nodeType === TEXT_NODE) {
41299
- node.removeChild(next);
41300
- child.appendData(next.data);
41301
- // Do not advance child: re-check new nextSibling for another text run
41478
+ // Merge the whole run of adjacent text nodes at once: gather the
41479
+ // following text siblings' data, unlink them in a single pass, and
41480
+ // re-index the child list a single time. Per-sibling `removeChild`
41481
+ // (each an O(K) re-index) plus per-sibling `appendData` (each an O(K)
41482
+ // string rebuild) is O(K^2) over a long run of single-character text
41483
+ // nodes; this keeps it O(K). The first text node of the run survives
41484
+ // and carries the concatenated data, preserving node identity and
41485
+ // locator semantics.
41486
+ var tail = [];
41487
+ var sibling = next;
41488
+ while (sibling !== null && sibling.nodeType === TEXT_NODE) {
41489
+ tail.push(sibling.data);
41490
+ sibling = sibling.nextSibling;
41491
+ }
41492
+ // `sibling` is now the first non-text node after the run, or null.
41493
+ var removed = child.nextSibling;
41494
+ while (removed !== sibling) {
41495
+ var following = removed.nextSibling;
41496
+ removed.parentNode = null;
41497
+ removed.previousSibling = null;
41498
+ removed.nextSibling = null;
41499
+ removed = following;
41500
+ }
41501
+ child.nextSibling = sibling;
41502
+ if (sibling !== null) {
41503
+ sibling.previousSibling = child;
41504
+ } else {
41505
+ node.lastChild = child;
41506
+ }
41507
+ child.appendData(tail.join('')); // single O(K) string rebuild
41508
+ _onUpdateChild(node.ownerDocument, node); // single O(K) re-index
41509
+ child = sibling;
41302
41510
  } else {
41303
41511
  child = next;
41304
41512
  }
@@ -42109,8 +42317,10 @@ function requireDom () {
42109
42317
  * - it does not do any input validation on the arguments and doesn't throw "InvalidCharacterError".
42110
42318
  *
42111
42319
  * Note: When the resulting document is serialized with `requireWellFormed: true`, the
42112
- * serializer throws with code `INVALID_STATE_ERR` if `.data` contains `?>` (W3C DOM Parsing
42113
- * §3.2.1.7). Without that option the data is emitted verbatim.
42320
+ * serializer throws with code `INVALID_STATE_ERR` if `.target` is not a valid XML `NCName`
42321
+ * (a `Name` with no colon) or is an ASCII case-insensitive match for `"xml"`, or if `.data`
42322
+ * contains `?>` (W3C DOM Parsing §3.2.1.7). Without that option the target and data are
42323
+ * emitted verbatim.
42114
42324
  *
42115
42325
  * @param {string} target
42116
42326
  * @param {string} data
@@ -42135,7 +42345,27 @@ function requireDom () {
42135
42345
  node.specified = true;
42136
42346
  return node;
42137
42347
  },
42348
+ /**
42349
+ * Creates an EntityReference object, serialized as `&name;`.
42350
+ *
42351
+ * The `name` is validated against the XML `Name` production at creation time; an invalid name
42352
+ * throws a `DOMException` with code `INVALID_CHARACTER_ERR`. When the resulting node is
42353
+ * serialized with `requireWellFormed: true`, the serializer re-validates `nodeName` and throws
42354
+ * a `DOMException` with code `INVALID_STATE_ERR` if a later `nodeName` mutation made it invalid;
42355
+ * without that option the name is emitted verbatim.
42356
+ *
42357
+ * Note: xmldom does not expand entities — the parser resolves entity references inline and never
42358
+ * constructs `EntityReference` nodes, so this method is the only producer.
42359
+ *
42360
+ * @param {string} name The name of the entity to reference.
42361
+ * @returns {EntityReference}
42362
+ * @throws {DOMException} With code `INVALID_CHARACTER_ERR` when `name` is not a valid XML `Name`.
42363
+ * @see https://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-392B75AE
42364
+ */
42138
42365
  createEntityReference : function(name){
42366
+ if (!tagNamePattern.test(name)) {
42367
+ throw new DOMException(INVALID_CHARACTER_ERR, 'not a valid xml name "' + name + '"');
42368
+ }
42139
42369
  var node = new EntityReference();
42140
42370
  node.ownerDocument = this;
42141
42371
  node.nodeName = name;
@@ -42347,15 +42577,16 @@ function requireDom () {
42347
42577
  /**
42348
42578
  * Represents a DocumentType node (the `<!DOCTYPE ...>` declaration).
42349
42579
  *
42350
- * `publicId`, `systemId`, and `internalSubset` are plain own-property assignments.
42580
+ * `name`, `publicId`, `systemId`, and `internalSubset` are plain own-property assignments.
42351
42581
  * xmldom does not enforce the `readonly` constraint declared by the WHATWG DOM spec —
42352
42582
  * direct property writes succeed silently. Values are serialized verbatim when
42353
42583
  * `requireWellFormed` is false (the default). When the serializer is invoked with
42354
42584
  * `requireWellFormed: true` (via the 4th-parameter options object), it validates each
42355
- * field and throws `DOMException` with code `INVALID_STATE_ERR` on invalid values.
42585
+ * field including `name`, which is checked against the XML `Name` production and throws
42586
+ * `DOMException` with code `INVALID_STATE_ERR` on invalid values.
42356
42587
  *
42357
42588
  * @class
42358
- * @see https://developer.mozilla.org/en-US/docs/Web/API/DocumentType MDN
42589
+ * @see https://developer.mozilla.org/docs/Web/API/DocumentType MDN
42359
42590
  */
42360
42591
  function DocumentType() {
42361
42592
  } DocumentType.prototype.nodeType = DOCUMENT_TYPE_NODE;
@@ -42369,6 +42600,20 @@ function requireDom () {
42369
42600
  } Entity.prototype.nodeType = ENTITY_NODE;
42370
42601
  _extends(Entity,Node);
42371
42602
 
42603
+ /**
42604
+ * Represents an EntityReference node, serialized as `&nodeName;`.
42605
+ *
42606
+ * `nodeName` is the referenced entity's name, stored verbatim. When serialized with
42607
+ * `requireWellFormed: true`, the serializer validates `nodeName` against the XML `Name` production
42608
+ * and throws a `DOMException` with code `INVALID_STATE_ERR` if it does not match; without that
42609
+ * option the name is emitted verbatim between `&` and `;`.
42610
+ *
42611
+ * Note: xmldom does not expand entities — the parser resolves entity references inline and never
42612
+ * constructs `EntityReference` nodes, so the only producer is `Document.createEntityReference`.
42613
+ *
42614
+ * @class
42615
+ * @see https://www.w3.org/TR/xml/#NT-Name
42616
+ */
42372
42617
  function EntityReference() {
42373
42618
  } EntityReference.prototype.nodeType = ENTITY_REFERENCE_NODE;
42374
42619
  _extends(EntityReference,Node);
@@ -42406,14 +42651,20 @@ function requireDom () {
42406
42651
  * @returns {string}
42407
42652
  * @throws {DOMException}
42408
42653
  * With code `INVALID_STATE_ERR` when `requireWellFormed` is `true` and:
42654
+ * - an Element's qualified name (including any namespace prefix) is not a valid XML QName,
42655
+ * - an attribute's qualified name (including a synthesized `xmlns:` namespace declaration) is
42656
+ * not a valid XML QName,
42409
42657
  * - a CDATASection node's data contains `"]]>"`,
42410
42658
  * - a Comment node's data contains `"-->"` (bare `"--"` does not throw on this branch),
42411
- * - a ProcessingInstruction's data contains `"?>"`,
42659
+ * - a ProcessingInstruction's target is not a valid XML `NCName` (a `Name` with no colon) or is
42660
+ * an ASCII case-insensitive match for `"xml"`, or its data contains `"?>"`,
42661
+ * - a DocumentType's `name` is not a valid XML `Name` (XML 1.0 production [5]),
42412
42662
  * - a DocumentType's `publicId` is non-empty and does not match the XML `PubidLiteral`
42413
42663
  * production,
42414
42664
  * - a DocumentType's `systemId` is non-empty and does not match the XML `SystemLiteral`
42415
- * production, or
42416
- * - a DocumentType's `internalSubset` contains `"]>"`.
42665
+ * production,
42666
+ * - a DocumentType's `internalSubset` contains `"]>"`, or
42667
+ * - an EntityReference's `nodeName` is not a valid XML `Name` (XML 1.0 production [5]).
42417
42668
  * Note: xmldom does not enforce `readonly` on DocumentType fields — direct property
42418
42669
  * writes succeed and are covered by the serializer-level checks above.
42419
42670
  * @see https://html.spec.whatwg.org/#dom-xmlserializer-serializetostring
@@ -42487,7 +42738,10 @@ function requireDom () {
42487
42738
  * @see https://www.w3.org/TR/xml11/#AVNormalize
42488
42739
  * @see https://w3c.github.io/DOM-Parsing/#serializing-an-element-s-attributes
42489
42740
  */
42490
- function addSerializedAttribute(buf, qualifiedName, value) {
42741
+ function addSerializedAttribute(buf, qualifiedName, value, requireWellFormed) {
42742
+ if (requireWellFormed && !tagNamePattern.test(qualifiedName)) {
42743
+ throw new DOMException(INVALID_STATE_ERR, 'The attribute name "' + qualifiedName + '" is not a valid XML QName');
42744
+ }
42491
42745
  buf.push(' ', qualifiedName, '="', value.replace(/[<>&"\t\n\r]/g, _xmlEncoder), '"');
42492
42746
  }
42493
42747
 
@@ -42553,6 +42807,9 @@ function requireDom () {
42553
42807
  }
42554
42808
  }
42555
42809
 
42810
+ if (requireWellFormed && !tagNamePattern.test(prefixedNodeName)) {
42811
+ throw new DOMException(INVALID_STATE_ERR, 'The element name "' + prefixedNodeName + '" is not a valid XML QName');
42812
+ }
42556
42813
  buf.push('<', prefixedNodeName);
42557
42814
 
42558
42815
  // Build a fresh namespace snapshot for this element's children.
@@ -42572,7 +42829,7 @@ function requireDom () {
42572
42829
  if (needNamespaceDefine(attr, html, childNs)) {
42573
42830
  var attrPrefix = attr.prefix || '';
42574
42831
  var uri = attr.namespaceURI;
42575
- addSerializedAttribute(buf, attrPrefix ? 'xmlns:' + attrPrefix : 'xmlns', uri);
42832
+ addSerializedAttribute(buf, attrPrefix ? 'xmlns:' + attrPrefix : 'xmlns', uri, requireWellFormed);
42576
42833
  childNs.push({ prefix: attrPrefix, namespace: uri });
42577
42834
  }
42578
42835
  // Apply nodeFilter and serialize the attribute.
@@ -42581,7 +42838,7 @@ function requireDom () {
42581
42838
  if (typeof filteredAttr === 'string') {
42582
42839
  buf.push(filteredAttr);
42583
42840
  } else {
42584
- addSerializedAttribute(buf, filteredAttr.name, filteredAttr.value);
42841
+ addSerializedAttribute(buf, filteredAttr.name, filteredAttr.value, requireWellFormed);
42585
42842
  }
42586
42843
  }
42587
42844
  }
@@ -42590,7 +42847,7 @@ function requireDom () {
42590
42847
  if (nodeName === prefixedNodeName && needNamespaceDefine(n, html, childNs)) {
42591
42848
  var nodePrefix = n.prefix || '';
42592
42849
  var uri = n.namespaceURI;
42593
- addSerializedAttribute(buf, nodePrefix ? 'xmlns:' + nodePrefix : 'xmlns', uri);
42850
+ addSerializedAttribute(buf, nodePrefix ? 'xmlns:' + nodePrefix : 'xmlns', uri, requireWellFormed);
42594
42851
  childNs.push({ prefix: nodePrefix, namespace: uri });
42595
42852
  }
42596
42853
 
@@ -42623,7 +42880,7 @@ function requireDom () {
42623
42880
  return { ns: ns.slice(), isHTML: html, tag: null };
42624
42881
 
42625
42882
  case ATTRIBUTE_NODE:
42626
- addSerializedAttribute(buf, n.name, n.value);
42883
+ addSerializedAttribute(buf, n.name, n.value, requireWellFormed);
42627
42884
  return null;
42628
42885
 
42629
42886
  case TEXT_NODE:
@@ -42662,6 +42919,9 @@ function requireDom () {
42662
42919
 
42663
42920
  case DOCUMENT_TYPE_NODE:
42664
42921
  if (requireWellFormed) {
42922
+ if (!tagNamePattern.test(n.name)) {
42923
+ throw new DOMException(INVALID_STATE_ERR, 'The doctype name "' + n.name + '" is not a valid XML Name');
42924
+ }
42665
42925
  if (n.publicId && !/^("[\x20\r\na-zA-Z0-9\-()+,.\/:=?;!*#@$_%']*"|'[\x20\r\na-zA-Z0-9\-()+,.\/:=?;!*#@$_%'"]*')$/.test(n.publicId)) {
42666
42926
  throw new DOMException(INVALID_STATE_ERR, 'DocumentType publicId is not a valid PubidLiteral');
42667
42927
  }
@@ -42693,13 +42953,27 @@ function requireDom () {
42693
42953
  return null;
42694
42954
 
42695
42955
  case PROCESSING_INSTRUCTION_NODE:
42696
- if (requireWellFormed && n.data.indexOf('?>') !== -1) {
42697
- throw new DOMException(INVALID_STATE_ERR, 'The ProcessingInstruction data contains "?>"');
42956
+ if (requireWellFormed) {
42957
+ if (!tagNamePattern.test(n.target) || n.target.indexOf(':') !== -1 || n.target.toLowerCase() === 'xml') {
42958
+ throw new DOMException(
42959
+ INVALID_STATE_ERR,
42960
+ 'The processing instruction target "' + n.target + '" is not a valid XML NCName or is reserved'
42961
+ );
42962
+ }
42963
+ if (n.data.indexOf('?>') !== -1) {
42964
+ throw new DOMException(INVALID_STATE_ERR, 'The ProcessingInstruction data contains "?>"');
42965
+ }
42698
42966
  }
42699
42967
  buf.push('<?', n.target, ' ', n.data, '?>');
42700
42968
  return null;
42701
42969
 
42702
42970
  case ENTITY_REFERENCE_NODE:
42971
+ if (requireWellFormed && !tagNamePattern.test(n.nodeName)) {
42972
+ throw new DOMException(
42973
+ INVALID_STATE_ERR,
42974
+ 'The entity reference name "' + n.nodeName + '" is not a valid XML Name'
42975
+ );
42976
+ }
42703
42977
  buf.push('&', n.nodeName, ';');
42704
42978
  return null;
42705
42979
 
@@ -45080,14 +45354,8 @@ function requireSax () {
45080
45354
  if (hasRequiredSax) return sax;
45081
45355
  hasRequiredSax = 1;
45082
45356
  var NAMESPACE = requireConventions().NAMESPACE;
45357
+ var tagNamePattern = requireConventions().tagNamePattern;
45083
45358
 
45084
- //[4] NameStartChar ::= ":" | [A-Z] | "_" | [a-z] | [#xC0-#xD6] | [#xD8-#xF6] | [#xF8-#x2FF] | [#x370-#x37D] | [#x37F-#x1FFF] | [#x200C-#x200D] | [#x2070-#x218F] | [#x2C00-#x2FEF] | [#x3001-#xD7FF] | [#xF900-#xFDCF] | [#xFDF0-#xFFFD] | [#x10000-#xEFFFF]
45085
- //[4a] NameChar ::= NameStartChar | "-" | "." | [0-9] | #xB7 | [#x0300-#x036F] | [#x203F-#x2040]
45086
- //[5] Name ::= NameStartChar (NameChar)*
45087
- var nameStartChar = /[A-Z_a-z\xC0-\xD6\xD8-\xF6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD]/;//\u10000-\uEFFFF
45088
- var nameChar = new RegExp("[\\-\\.0-9"+nameStartChar.source.slice(1,-1)+"\\u00B7\\u0300-\\u036F\\u203F-\\u2040]");
45089
- var tagNamePattern = new RegExp('^'+nameStartChar.source+nameChar.source+'*(?:\:'+nameStartChar.source+nameChar.source+'*)?$');
45090
- //var tagNamePattern = /^[a-zA-Z_][\w\-\.]*(?:\:[a-zA-Z_][\w\-\.]*)?$/
45091
45359
  //var handlers = 'resolveEntity,getExternalSubset,characters,endDocument,endElement,endPrefixMapping,ignorableWhitespace,processingInstruction,setDocumentLocator,skippedEntity,startDocument,startElement,startPrefixMapping,notationDecl,unparsedEntityDecl,error,fatalError,warning,attributeDecl,elementDecl,externalEntityDecl,internalEntityDecl,comment,endCDATA,endDTD,endEntity,startCDATA,startDTD,startEntity'.split(',')
45092
45360
 
45093
45361
  //S_TAG, S_ATTR, S_EQ, S_ATTR_NOQUOT_VALUE
@@ -45198,7 +45466,13 @@ function requireSax () {
45198
45466
  switch(source.charAt(tagStart+1)){
45199
45467
  case '/':
45200
45468
  var end = source.indexOf('>',tagStart+3);
45201
- var tagName = source.substring(tagStart + 2, end).replace(/[ \t\n\r]+$/g, '');
45469
+ // Anchored trailing-whitespace trim. The former `/[ \t\n\r]+$/g` backtracked
45470
+ // quadratically on a name shaped `whitespace-run + non-whitespace char`
45471
+ // (an end tag `</ … x>`): from every start position it extended `[ws]+`
45472
+ // to the end and then failed the `$` anchor. This anchored form matches the
45473
+ // whole string once and captures everything up to the last non-whitespace
45474
+ // character, so it trims in linear time with byte-identical output.
45475
+ var tagName = source.substring(tagStart + 2, end).replace(/^([\s\S]*?[^ \t\n\r])?[ \t\n\r]*$/, '$1');
45202
45476
  var config = parseStack.pop();
45203
45477
  if(end<0){
45204
45478
 
@@ -45209,6 +45483,14 @@ function requireSax () {
45209
45483
  tagName = tagName.replace(/[\s<].*/,'');
45210
45484
  errorHandler.error("end tag name: "+tagName+' maybe not complete');
45211
45485
  end = tagStart+1+tagName.length;
45486
+ }else if(/[ \t\n\r]/.test(tagName) && tagNamePattern.test(tagName.split(/[ \t\n\r]/)[0])){
45487
+ // The XML `ETag` production is `'</' Name S? '>'`: only optional whitespace may follow
45488
+ // the `Name`. A valid `Name` followed by whitespace and non-whitespace residue (e.g.
45489
+ // `</a\nbogus>` or `</a bogus>`) is not well-formed, but historically it was silently
45490
+ // accepted (the malformed end tag ignored, the residue dropped, the element left on the
45491
+ // stack). Report it as a recoverable `error` (which a custom errorHandler may escalate to
45492
+ // fatal) while keeping the existing recovery so the parsed DOM stays byte-identical.
45493
+ errorHandler.error('end tag name is followed by whitespace and trailing content: "'+tagName+'"');
45212
45494
  }
45213
45495
  var localNSMap = config.localNSMap;
45214
45496
  var endMatch = config.tagName == tagName;
@@ -45332,6 +45614,15 @@ function requireSax () {
45332
45614
  var s = S_TAG;//status
45333
45615
  while(true){
45334
45616
  var c = source.charAt(p);
45617
+ if (s === S_TAG && c === '<') {
45618
+ // A `<` can never occur inside a tag name. Without this guard the scan runs
45619
+ // on to the next `>` (or EOF) before the tag name is rejected, so a document
45620
+ // with many `<` inside a malformed tag makes each one-character recovery step
45621
+ // re-scan to the distant `>` — O(n^2). Stopping at the `<` keeps each recovery
45622
+ // step bounded. The candidate scanned so far is reported raw, consistent with
45623
+ // the sibling invalid-tag-name throw below.
45624
+ throw new Error('unexpected < in tag name: ' + source.slice(start, p));
45625
+ }
45335
45626
  switch(c){
45336
45627
  case '=':
45337
45628
  if(s === S_ATTR){//attrName
@@ -45524,9 +45815,13 @@ function requireSax () {
45524
45815
  if(nsPrefix !== false){//hack!!
45525
45816
  if(localNSMap == null){
45526
45817
  localNSMap = {};
45527
- //console.log(currentNSMap,0)
45528
- _copy(currentNSMap,currentNSMap={});
45529
- //console.log(currentNSMap,1)
45818
+ // Derive the child scope's namespace map by prototype-chain inheritance
45819
+ // instead of a flat copy: lookups inherit ancestor prefixes transparently,
45820
+ // so a document nesting N scopes retains O(N) map entries rather than
45821
+ // sum(1..N) = O(N^2). localNSMap stays a flat own-only record of the
45822
+ // prefixes declared at THIS element, so own-property enumeration
45823
+ // (endPrefixMapping below) still reports only local declarations.
45824
+ currentNSMap = Object.create(currentNSMap);
45530
45825
  }
45531
45826
  currentNSMap[nsPrefix] = localNSMap[nsPrefix] = value;
45532
45827
  a.uri = NAMESPACE.XMLNS;
@@ -53297,7 +53592,7 @@ var momentTimezoneExports = requireMomentTimezone();
53297
53592
  var momentTimezone = /*@__PURE__*/getDefaultExportFromCjs(momentTimezoneExports);
53298
53593
 
53299
53594
  /**
53300
- * @license Angular v20.3.19
53595
+ * @license Angular v20.3.28
53301
53596
  * (c) 2010-2025 Google LLC. https://angular.dev/
53302
53597
  * License: MIT
53303
53598
  */
@@ -53331,7 +53626,7 @@ function isNotFound(e) {
53331
53626
  }
53332
53627
 
53333
53628
  /**
53334
- * @license Angular v20.3.19
53629
+ * @license Angular v20.3.28
53335
53630
  * (c) 2010-2025 Google LLC. https://angular.dev/
53336
53631
  * License: MIT
53337
53632
  */
@@ -53876,7 +54171,7 @@ function signalValueChanged(node) {
53876
54171
  }
53877
54172
 
53878
54173
  /**
53879
- * @license Angular v20.3.19
54174
+ * @license Angular v20.3.28
53880
54175
  * (c) 2010-2025 Google LLC. https://angular.dev/
53881
54176
  * License: MIT
53882
54177
  */
@@ -54013,7 +54308,7 @@ function runEffect(node) {
54013
54308
  }
54014
54309
 
54015
54310
  /**
54016
- * @license Angular v20.3.19
54311
+ * @license Angular v20.3.28
54017
54312
  * (c) 2010-2025 Google LLC. https://angular.dev/
54018
54313
  * License: MIT
54019
54314
  */
@@ -54023,7 +54318,7 @@ function setAlternateWeakRefImpl(impl) {
54023
54318
  }
54024
54319
 
54025
54320
  /**
54026
- * @license Angular v20.3.19
54321
+ * @license Angular v20.3.28
54027
54322
  * (c) 2010-2025 Google LLC. https://angular.dev/
54028
54323
  * License: MIT
54029
54324
  */
@@ -54163,7 +54458,7 @@ if (typeof ngDevMode !== 'undefined' && ngDevMode) {
54163
54458
  }
54164
54459
 
54165
54460
  /**
54166
- * @license Angular v20.3.19
54461
+ * @license Angular v20.3.28
54167
54462
  * (c) 2010-2025 Google LLC. https://angular.dev/
54168
54463
  * License: MIT
54169
54464
  */
@@ -54190,7 +54485,7 @@ class Version {
54190
54485
  /**
54191
54486
  * @publicApi
54192
54487
  */
54193
- const VERSION = /* @__PURE__ */ new Version('20.3.19');
54488
+ const VERSION = /* @__PURE__ */ new Version('20.3.28');
54194
54489
 
54195
54490
  /**
54196
54491
  * Base URL for the error details page.
@@ -56800,8 +57095,166 @@ function assertNodeInjector(lView, injectorIndex) {
56800
57095
  assertNumber(lView[injectorIndex + 8 /* NodeInjectorOffset.PARENT */], 'injectorIndex should point to parent injector');
56801
57096
  }
56802
57097
 
56803
- const SVG_NAMESPACE = 'svg';
56804
- const MATH_ML_NAMESPACE = 'math';
57098
+ /**
57099
+ * A SecurityContext marks a location that has dangerous security implications, e.g. a DOM property
57100
+ * like `innerHTML` that could cause Cross Site Scripting (XSS) security bugs when improperly
57101
+ * handled.
57102
+ *
57103
+ * See DomSanitizer for more details on security in Angular applications.
57104
+ *
57105
+ * @publicApi
57106
+ */
57107
+ var SecurityContext;
57108
+ (function (SecurityContext) {
57109
+ SecurityContext[SecurityContext["NONE"] = 0] = "NONE";
57110
+ SecurityContext[SecurityContext["HTML"] = 1] = "HTML";
57111
+ SecurityContext[SecurityContext["STYLE"] = 2] = "STYLE";
57112
+ SecurityContext[SecurityContext["SCRIPT"] = 3] = "SCRIPT";
57113
+ SecurityContext[SecurityContext["URL"] = 4] = "URL";
57114
+ SecurityContext[SecurityContext["RESOURCE_URL"] = 5] = "RESOURCE_URL";
57115
+ SecurityContext[SecurityContext["ATTRIBUTE_NO_BINDING"] = 6] = "ATTRIBUTE_NO_BINDING";
57116
+ })(SecurityContext || (SecurityContext = {}));
57117
+ // =================================================================================================
57118
+ // =================================================================================================
57119
+ // =========== S T O P - S T O P - S T O P - S T O P - S T O P - S T O P ===========
57120
+ // =================================================================================================
57121
+ // =================================================================================================
57122
+ //
57123
+ // DO NOT EDIT THIS LIST OF SECURITY SENSITIVE PROPERTIES WITHOUT A SECURITY REVIEW!
57124
+ //
57125
+ // =================================================================================================
57126
+ /**
57127
+ * Map from tagName|propertyName to SecurityContext. Properties applying to all tags use '*'.
57128
+ */
57129
+ let _SECURITY_SCHEMA;
57130
+ const SVG_NAMESPACE$1 = 'svg';
57131
+ const MATH_ML_NAMESPACE$1 = 'math';
57132
+ /**
57133
+ * @remarks Keep is a copy of DOM Security Schema.
57134
+ * @see [SECURITY_SCHEMA](../../../compiler/src/schema/dom_security_schema.ts)
57135
+ */
57136
+ function SECURITY_SCHEMA() {
57137
+ if (!_SECURITY_SCHEMA) {
57138
+ _SECURITY_SCHEMA = {};
57139
+ // Case is insignificant below, all element and attribute names are lower-cased for lookup.
57140
+ registerContext(SecurityContext.HTML, /** Namespace */ undefined, [
57141
+ ['iframe', ['srcdoc']],
57142
+ ['*', ['innerHTML', 'outerHTML']],
57143
+ ]);
57144
+ registerContext(SecurityContext.STYLE, /** Namespace */ undefined, [['*', ['style']]]);
57145
+ // NB: no SCRIPT contexts here, they are never allowed due to the parser stripping them.
57146
+ registerContext(SecurityContext.URL, /** Namespace */ undefined, [
57147
+ ['*', ['formAction']],
57148
+ ['area', ['href']],
57149
+ ['a', ['href', 'xlink:href']],
57150
+ ['form', ['action']],
57151
+ // The below two items are safe and should be removed but they require a G3 clean-up as a small number of tests fail.
57152
+ ['img', ['src']],
57153
+ ['video', ['src']],
57154
+ ]);
57155
+ registerContext(SecurityContext.URL, MATH_ML_NAMESPACE$1, [
57156
+ // MathML namespace
57157
+ // https://crsrc.org/c/third_party/blink/renderer/core/sanitizer/sanitizer.cc;l=753-768;drc=b3eb16372dcd3317d65e9e0265015e322494edcd;bpv=1;bpt=1
57158
+ ['*', ['href', 'xlink:href']],
57159
+ ['annotation', ['href', 'xlink:href']],
57160
+ ['annotation-xml', ['href', 'xlink:href']],
57161
+ ['maction', ['href', 'xlink:href']],
57162
+ ['malignmark', ['href', 'xlink:href']],
57163
+ ['math', ['href', 'xlink:href']],
57164
+ ['mroot', ['href', 'xlink:href']],
57165
+ ['msqrt', ['href', 'xlink:href']],
57166
+ ['merror', ['href', 'xlink:href']],
57167
+ ['mfrac', ['href', 'xlink:href']],
57168
+ ['mglyph', ['href', 'xlink:href']],
57169
+ ['msub', ['href', 'xlink:href']],
57170
+ ['msup', ['href', 'xlink:href']],
57171
+ ['msubsup', ['href', 'xlink:href']],
57172
+ ['mmultiscripts', ['href', 'xlink:href']],
57173
+ ['mprescripts', ['href', 'xlink:href']],
57174
+ ['mi', ['href', 'xlink:href']],
57175
+ ['mn', ['href', 'xlink:href']],
57176
+ ['mo', ['href', 'xlink:href']],
57177
+ ['mpadded', ['href', 'xlink:href']],
57178
+ ['mphantom', ['href', 'xlink:href']],
57179
+ ['mrow', ['href', 'xlink:href']],
57180
+ ['ms', ['href', 'xlink:href']],
57181
+ ['mspace', ['href', 'xlink:href']],
57182
+ ['mstyle', ['href', 'xlink:href']],
57183
+ ['mtable', ['href', 'xlink:href']],
57184
+ ['mtd', ['href', 'xlink:href']],
57185
+ ['mtr', ['href', 'xlink:href']],
57186
+ ['mtext', ['href', 'xlink:href']],
57187
+ ['mover', ['href', 'xlink:href']],
57188
+ ['munder', ['href', 'xlink:href']],
57189
+ ['munderover', ['href', 'xlink:href']],
57190
+ ['semantics', ['href', 'xlink:href']],
57191
+ ['none', ['href', 'xlink:href']],
57192
+ ]);
57193
+ registerContext(SecurityContext.RESOURCE_URL, /** Namespace */ undefined, [
57194
+ ['base', ['href']],
57195
+ ['embed', ['src']],
57196
+ ['frame', ['src']],
57197
+ ['iframe', ['src']],
57198
+ ['link', ['href']],
57199
+ ['object', ['codebase', 'data']],
57200
+ ]);
57201
+ registerContext(SecurityContext.URL, SVG_NAMESPACE$1, [['a', ['href', 'xlink:href']]]);
57202
+ // Keep this in sync with SECURITY_SENSITIVE_ELEMENTS in packages/core/src/sanitization/sanitization.ts
57203
+ // Unknown is the internal tag name for unknown elements example used for host-bindings.
57204
+ // These are unsafe as `attributeName` can be `href` or `xlink:href`
57205
+ // See: http://b/463880509#comment7
57206
+ registerContext(SecurityContext.ATTRIBUTE_NO_BINDING, SVG_NAMESPACE$1, [
57207
+ ['animate', ['attributeName', 'values', 'to', 'from']],
57208
+ ['set', ['to', 'attributeName']],
57209
+ ['animateMotion', ['attributeName']],
57210
+ ['animateTransform', ['attributeName']],
57211
+ ]);
57212
+ registerContext(SecurityContext.ATTRIBUTE_NO_BINDING, /** Namespace */ undefined, [
57213
+ [
57214
+ 'unknown',
57215
+ [
57216
+ 'attributeName',
57217
+ 'values',
57218
+ 'to',
57219
+ 'from',
57220
+ 'sandbox',
57221
+ 'allow',
57222
+ 'allowFullscreen',
57223
+ 'referrerPolicy',
57224
+ 'csp',
57225
+ 'fetchPriority',
57226
+ ],
57227
+ ],
57228
+ ['iframe', ['sandbox', 'allow', 'allowFullscreen', 'referrerPolicy', 'csp', 'fetchPriority']],
57229
+ ]);
57230
+ }
57231
+ return _SECURITY_SCHEMA;
57232
+ }
57233
+ function registerContext(ctx, namespace, specs) {
57234
+ for (const [element, attributeNames] of specs) {
57235
+ let tagName = namespace && element !== 'unknown' ? `:${namespace}:${element}` : element;
57236
+ tagName = tagName.toLowerCase();
57237
+ for (const attr of attributeNames) {
57238
+ _SECURITY_SCHEMA[`${tagName}|${attr.toLowerCase()}`] = ctx;
57239
+ }
57240
+ }
57241
+ }
57242
+ function checkSecurityContext(tagName, propName, namespace) {
57243
+ const schema = SECURITY_SCHEMA();
57244
+ const normalizedTagName = tagName.toLowerCase();
57245
+ const normalizedPropName = propName.toLowerCase();
57246
+ const namespacedContext = namespace && normalizedTagName !== '*' && normalizedTagName !== 'unknown'
57247
+ ? schema[`:${namespace}:${normalizedTagName}|${normalizedPropName}`]
57248
+ : undefined;
57249
+ const namespacedWildcardContext = namespace
57250
+ ? schema[`:${namespace}:*|${normalizedPropName}`]
57251
+ : undefined;
57252
+ return (namespacedContext ??
57253
+ namespacedWildcardContext ??
57254
+ schema[`${normalizedTagName}|${normalizedPropName}`] ??
57255
+ schema[`*|${normalizedPropName}`] ??
57256
+ SecurityContext.NONE);
57257
+ }
56805
57258
 
56806
57259
  /**
56807
57260
  * For efficiency reasons we often put several different data types (`RNode`, `LView`, `LContainer`)
@@ -57586,7 +58039,7 @@ function getSelectedTNode() {
57586
58039
  * @codeGenApi
57587
58040
  */
57588
58041
  function ɵɵnamespaceSVG() {
57589
- instructionState.lFrame.currentNamespace = SVG_NAMESPACE;
58042
+ instructionState.lFrame.currentNamespace = SVG_NAMESPACE$1;
57590
58043
  }
57591
58044
  /**
57592
58045
  * Sets the namespace used to create elements to `'http://www.w3.org/1998/MathML/'` in global state.
@@ -57594,7 +58047,7 @@ function ɵɵnamespaceSVG() {
57594
58047
  * @codeGenApi
57595
58048
  */
57596
58049
  function ɵɵnamespaceMathML() {
57597
- instructionState.lFrame.currentNamespace = MATH_ML_NAMESPACE;
58050
+ instructionState.lFrame.currentNamespace = MATH_ML_NAMESPACE$1;
57598
58051
  }
57599
58052
  /**
57600
58053
  * Sets the namespace used to create elements to `null`, which forces element creation to use
@@ -58209,7 +58662,7 @@ class ZoneAwareEffectScheduler {
58209
58662
  }
58210
58663
 
58211
58664
  /**
58212
- * @license Angular v20.3.19
58665
+ * @license Angular v20.3.28
58213
58666
  * (c) 2010-2025 Google LLC. https://angular.dev/
58214
58667
  * License: MIT
58215
58668
  */
@@ -58231,7 +58684,7 @@ const Attribute$1 = {
58231
58684
  };
58232
58685
 
58233
58686
  /**
58234
- * @license Angular v20.3.19
58687
+ * @license Angular v20.3.28
58235
58688
  * (c) 2010-2025 Google LLC. https://angular.dev/
58236
58689
  * License: MIT
58237
58690
  */
@@ -61997,7 +62450,7 @@ function retrieveTransferredState(doc, appId) {
61997
62450
  // Locate the script tag with the JSON data transferred from the server.
61998
62451
  // The id of the script tag is set to the Angular appId + 'state'.
61999
62452
  const script = doc.getElementById(appId + '-state');
62000
- if (script?.textContent) {
62453
+ if (script?.tagName === 'SCRIPT' && script.textContent) {
62001
62454
  try {
62002
62455
  // Avoid using any here as it triggers lint errors in google3 (any is not allowed).
62003
62456
  // Decoding of `<` is done of the box by browsers and node.js, same behaviour as G3
@@ -63419,6 +63872,13 @@ function matchingSchemas(schemas, tagName) {
63419
63872
  return false;
63420
63873
  }
63421
63874
 
63875
+ const SVG_NAMESPACE = 'svg';
63876
+ const MATH_ML_NAMESPACE = 'math';
63877
+ const NAMESPACE_URIS = {
63878
+ 'http://www.w3.org/2000/svg': SVG_NAMESPACE,
63879
+ 'http://www.w3.org/1998/Math/MathML': MATH_ML_NAMESPACE,
63880
+ };
63881
+
63422
63882
  /**
63423
63883
  * @fileoverview
63424
63884
  * A module to facilitate use of a Trusted Types policy internally within
@@ -63848,13 +64308,6 @@ const VALID_ATTRS = merge(URI_ATTRS, HTML_ATTRS, ARIA_ATTRS);
63848
64308
  // `Some content`, but strip `invalid-element` opening/closing tags. For some elements, though, we
63849
64309
  // don't want to preserve the content, if the elements themselves are going to be removed.
63850
64310
  const SKIP_TRAVERSING_CONTENT_IF_INVALID_ELEMENTS = tagSet('script,style,template');
63851
- /**
63852
- * Attributes that are potential attach vectors and may need to be sanitized.
63853
- */
63854
- const SENSITIVE_ATTRS = merge(URI_ATTRS,
63855
- // Note: we don't include these attributes in `URI_ATTRS`, because `URI_ATTRS` also
63856
- // determines whether an attribute should be dropped when sanitizing an HTML string.
63857
- tagSet('action,formaction,data,codebase'));
63858
64311
  /**
63859
64312
  * SanitizingHtmlSerializer serializes a DOM fragment, stripping out any unsafe elements and unsafe
63860
64313
  * attributes.
@@ -64242,23 +64695,27 @@ function enforceIframeSecurity(iframe) {
64242
64695
  }
64243
64696
 
64244
64697
  /**
64245
- * A SecurityContext marks a location that has dangerous security implications, e.g. a DOM property
64246
- * like `innerHTML` that could cause Cross Site Scripting (XSS) security bugs when improperly
64247
- * handled.
64698
+ * Splits an element name into its namespace and local name.
64248
64699
  *
64249
- * See DomSanitizer for more details on security in Angular applications.
64250
- *
64251
- * @publicApi
64700
+ * @param elementName The element name to split, in the format ":namespace:name".
64701
+ * @param fatal If true, throws an error if the element name is not in the correct format.
64702
+ * @returns A tuple containing the namespace and local name.
64252
64703
  */
64253
- var SecurityContext;
64254
- (function (SecurityContext) {
64255
- SecurityContext[SecurityContext["NONE"] = 0] = "NONE";
64256
- SecurityContext[SecurityContext["HTML"] = 1] = "HTML";
64257
- SecurityContext[SecurityContext["STYLE"] = 2] = "STYLE";
64258
- SecurityContext[SecurityContext["SCRIPT"] = 3] = "SCRIPT";
64259
- SecurityContext[SecurityContext["URL"] = 4] = "URL";
64260
- SecurityContext[SecurityContext["RESOURCE_URL"] = 5] = "RESOURCE_URL";
64261
- })(SecurityContext || (SecurityContext = {}));
64704
+ function splitNsName(elementName, fatal = true) {
64705
+ if (elementName[0] != ':') {
64706
+ return [null, elementName];
64707
+ }
64708
+ const colonIndex = elementName.indexOf(':', 1);
64709
+ if (colonIndex === -1) {
64710
+ if (fatal) {
64711
+ throw new Error(`Unsupported format "${elementName}" expecting ":namespace:name"`);
64712
+ }
64713
+ else {
64714
+ return [null, elementName];
64715
+ }
64716
+ }
64717
+ return [elementName.slice(1, colonIndex), elementName.slice(colonIndex + 1)];
64718
+ }
64262
64719
 
64263
64720
  /**
64264
64721
  * An `html` sanitizer which converts untrusted `html` **string** into trusted string by removing
@@ -64275,7 +64732,12 @@ var SecurityContext;
64275
64732
  *
64276
64733
  * @codeGenApi
64277
64734
  */
64278
- function ɵɵsanitizeHtml(unsafeHtml) {
64735
+ function ɵɵsanitizeHtml(unsafeHtml, tagName, propName) {
64736
+ if (tagName !== undefined &&
64737
+ propName !== undefined &&
64738
+ getSecurityContext(tagName, propName) !== SecurityContext.HTML) {
64739
+ return unsafeHtml;
64740
+ }
64279
64741
  const sanitizer = getSanitizer();
64280
64742
  if (sanitizer) {
64281
64743
  return trustedHTMLFromStringBypass(sanitizer.sanitize(SecurityContext.HTML, unsafeHtml) || '');
@@ -64425,21 +64887,22 @@ function ɵɵtrustConstantResourceUrl(url) {
64425
64887
  }
64426
64888
  return trustedScriptURLFromString(url[0]);
64427
64889
  }
64428
- // Define sets outside the function for O(1) lookups and memory efficiency
64429
- const SRC_RESOURCE_TAGS = new Set(['embed', 'frame', 'iframe', 'media', 'script']);
64430
- const HREF_RESOURCE_TAGS = new Set(['base', 'link', 'script']);
64431
64890
  /**
64432
64891
  * Detects which sanitizer to use for URL property, based on tag name and prop name.
64433
64892
  *
64434
- * The rules are based on the RESOURCE_URL context config from
64893
+ * The rules are based on the URL and RESOURCE_URL context config from
64435
64894
  * `packages/compiler/src/schema/dom_security_schema.ts`.
64436
- * If tag and prop names don't match Resource URL schema, use URL sanitizer.
64895
+ * If tag and prop names don't match URL or Resource URL schema, no sanitizer is required.
64437
64896
  */
64438
64897
  function getUrlSanitizer(tag, prop) {
64439
- const isResource = (prop === 'src' && SRC_RESOURCE_TAGS.has(tag)) ||
64440
- (prop === 'href' && HREF_RESOURCE_TAGS.has(tag)) ||
64441
- (prop === 'xlink:href' && tag === 'script');
64442
- return isResource ? ɵɵsanitizeResourceUrl : ɵɵsanitizeUrl;
64898
+ switch (getSecurityContext(tag, prop)) {
64899
+ case SecurityContext.RESOURCE_URL:
64900
+ return ɵɵsanitizeResourceUrl;
64901
+ case SecurityContext.URL:
64902
+ return ɵɵsanitizeUrl;
64903
+ default:
64904
+ return null;
64905
+ }
64443
64906
  }
64444
64907
  /**
64445
64908
  * Sanitizes URL, selecting sanitizer function based on tag and property names.
@@ -64457,7 +64920,7 @@ function getUrlSanitizer(tag, prop) {
64457
64920
  * @codeGenApi
64458
64921
  */
64459
64922
  function ɵɵsanitizeUrlOrResourceUrl(unsafeUrl, tag, prop) {
64460
- return getUrlSanitizer(tag, prop)(unsafeUrl);
64923
+ return getUrlSanitizer(tag, prop)?.(unsafeUrl) ?? unsafeUrl;
64461
64924
  }
64462
64925
  function validateAgainstEventProperties(name) {
64463
64926
  if (name.toLowerCase().startsWith('on')) {
@@ -64468,35 +64931,50 @@ function validateAgainstEventProperties(name) {
64468
64931
  throw new RuntimeError(306 /* RuntimeErrorCode.INVALID_EVENT_BINDING */, errorMessage);
64469
64932
  }
64470
64933
  }
64471
- function validateAgainstEventAttributes(name) {
64472
- if (name.toLowerCase().startsWith('on')) {
64473
- const errorMessage = `Binding to event attribute '${name}' is disallowed for security reasons, ` +
64474
- `please use (${name.slice(2)})=...`;
64475
- throw new RuntimeError(306 /* RuntimeErrorCode.INVALID_EVENT_BINDING */, errorMessage);
64476
- }
64477
- }
64478
64934
  function getSanitizer() {
64479
64935
  const lView = getLView();
64480
64936
  return lView && lView[ENVIRONMENT].sanitizer;
64481
64937
  }
64482
- const attributeName = new Set(['attributename']);
64938
+ function getSecurityContext(tagName, propName) {
64939
+ const [namespace, resolvedTagName] = resolveElement(tagName);
64940
+ return checkSecurityContext(resolvedTagName, propName, namespace);
64941
+ }
64942
+ function resolveElement(tagName) {
64943
+ tagName = tagName.toLowerCase();
64944
+ const splitResult = splitNsName(tagName, false);
64945
+ if (splitResult[0]) {
64946
+ return splitResult;
64947
+ }
64948
+ const index = getSelectedIndex();
64949
+ const tNode = index === -1 ? null : getSelectedTNode();
64950
+ let namespace = tNode?.namespace;
64951
+ if (tagName === "#host" /* TNodeName.DynamicHost */ && tNode?.type === 2 /* TNodeType.Element */) {
64952
+ const element = getNativeByTNode(tNode, getLView());
64953
+ if (element.tagName) {
64954
+ tagName = element.tagName.toLowerCase();
64955
+ }
64956
+ if (namespace == null) {
64957
+ const namespaceURI = element.namespaceURI;
64958
+ namespace = namespaceURI && NAMESPACE_URIS[namespaceURI];
64959
+ }
64960
+ }
64961
+ return [namespace, tagName];
64962
+ }
64963
+ /**
64964
+ * Set of attributes that are sensitive and should be sanitized.
64965
+ */
64966
+ const SECURITY_SENSITIVE_ATTRIBUTE_NAMES = new Set(['href', 'xlink:href']);
64483
64967
  /**
64484
64968
  * @remarks Keep this in sync with DOM Security Schema.
64485
64969
  * @see [SECURITY_SCHEMA](../../../compiler/src/schema/dom_security_schema.ts)
64486
64970
  */
64487
- const SECURITY_SENSITIVE_ELEMENTS = {
64488
- 'iframe': new Set([
64489
- 'sandbox',
64490
- 'allow',
64491
- 'allowfullscreen',
64492
- 'referrerpolicy',
64493
- 'csp',
64494
- 'fetchpriority',
64495
- ]),
64496
- 'animate': attributeName,
64497
- 'set': attributeName,
64498
- 'animatemotion': attributeName,
64499
- 'animatetransform': attributeName,
64971
+ const SVG_ANIMATION_SENSITIVE_STATIC_VALUES = {
64972
+ 'animate': {
64973
+ 'to': SECURITY_SENSITIVE_ATTRIBUTE_NAMES,
64974
+ 'values': SECURITY_SENSITIVE_ATTRIBUTE_NAMES,
64975
+ 'from': SECURITY_SENSITIVE_ATTRIBUTE_NAMES,
64976
+ },
64977
+ 'set': { 'to': SECURITY_SENSITIVE_ATTRIBUTE_NAMES },
64500
64978
  };
64501
64979
  /**
64502
64980
  * Validates that the attribute binding is safe to use.
@@ -64506,29 +64984,62 @@ const SECURITY_SENSITIVE_ELEMENTS = {
64506
64984
  * @param attributeName The name of the attribute.
64507
64985
  */
64508
64986
  function ɵɵvalidateAttribute(value, tagName, attributeName) {
64509
- const lowerCaseTagName = tagName.toLowerCase();
64510
- const lowerCaseAttrName = attributeName.toLowerCase();
64511
- if (!SECURITY_SENSITIVE_ELEMENTS[lowerCaseTagName]?.has(lowerCaseAttrName)) {
64987
+ const index = getSelectedIndex();
64988
+ const tNode = index === -1 ? null : getSelectedTNode();
64989
+ if (tNode && tNode.type !== 2 /* TNodeType.Element */) {
64512
64990
  return value;
64513
64991
  }
64514
- const tNode = getSelectedTNode();
64515
- if (tNode.type !== 2 /* TNodeType.Element */) {
64992
+ const [namespace, resolvedTagName] = resolveElement(tagName);
64993
+ const securityContext = checkSecurityContext(resolvedTagName, attributeName, namespace);
64994
+ if (securityContext !== SecurityContext.ATTRIBUTE_NO_BINDING) {
64516
64995
  return value;
64517
64996
  }
64518
64997
  const lView = getLView();
64519
- if (lowerCaseTagName === 'iframe') {
64520
- const element = getNativeByTNode(tNode, lView);
64521
- enforceIframeSecurity(element);
64998
+ if (tNode) {
64999
+ if (resolvedTagName === 'iframe') {
65000
+ const element = getNativeByTNode(tNode, lView);
65001
+ enforceIframeSecurity(element);
65002
+ }
65003
+ else if (namespace === SVG_NAMESPACE$1) {
65004
+ const config = SVG_ANIMATION_SENSITIVE_STATIC_VALUES[resolvedTagName]?.[attributeName.toLowerCase()];
65005
+ if (config) {
65006
+ const element = getNativeByTNode(tNode, lView);
65007
+ const attributeNameValue = getSecuritySensitiveSVGAnimationAttributeName(element, config);
65008
+ if (attributeNameValue) {
65009
+ const errorMessage = ngDevMode &&
65010
+ `Angular has detected that the \`${attributeName}\` was applied ` +
65011
+ `as a binding to the <${resolvedTagName}> element${getTemplateLocationDetails(lView)}. ` +
65012
+ `For security reasons, the \`${attributeName}\` can be set on the <${resolvedTagName}> element ` +
65013
+ `as a static attribute only when the "attributeName" is set to \'${attributeNameValue}\'. \n` +
65014
+ `To fix this, switch the \`${attributeNameValue}\` binding to a static attribute ` +
65015
+ `in a template or in host bindings section.`;
65016
+ throw new RuntimeError(-910 /* RuntimeErrorCode.UNSAFE_ATTRIBUTE_BINDING */, errorMessage);
65017
+ }
65018
+ return value;
65019
+ }
65020
+ }
64522
65021
  }
64523
65022
  const errorMessage = ngDevMode &&
64524
65023
  `Angular has detected that the \`${attributeName}\` was applied ` +
64525
- `as a binding to the <${tagName}> element${getTemplateLocationDetails(lView)}. ` +
64526
- `For security reasons, the \`${attributeName}\` can be set on the <${tagName}> element ` +
65024
+ `as a binding to the <${resolvedTagName}> element${tNode ? getTemplateLocationDetails(lView) : ''}. ` +
65025
+ `For security reasons, the \`${attributeName}\` can be set on the <${resolvedTagName}> element ` +
64527
65026
  `as a static attribute only. \n` +
64528
65027
  `To fix this, switch the \`${attributeName}\` binding to a static attribute ` +
64529
65028
  `in a template or in host bindings section.`;
64530
65029
  throw new RuntimeError(-910 /* RuntimeErrorCode.UNSAFE_ATTRIBUTE_BINDING */, errorMessage);
64531
65030
  }
65031
+ function getSecuritySensitiveSVGAnimationAttributeName(element, validationConfig) {
65032
+ for (const attributeName of element.getAttributeNames()) {
65033
+ if (attributeName.toLowerCase() !== 'attributename') {
65034
+ continue;
65035
+ }
65036
+ const attributeNameValue = element.getAttribute(attributeName);
65037
+ if (attributeNameValue !== null && validationConfig.has(attributeNameValue.toLowerCase())) {
65038
+ return attributeNameValue;
65039
+ }
65040
+ }
65041
+ return null;
65042
+ }
64532
65043
 
64533
65044
  /** Defines the default value of the `NG_REFLECT_ATTRS_FLAG` flag. */
64534
65045
  const NG_REFLECT_ATTRS_FLAG_DEFAULT = false;
@@ -67507,7 +68018,9 @@ function setDomProperty(tNode, lView, propName, value, renderer, sanitizer) {
67507
68018
  if (tNode.type & 3 /* TNodeType.AnyRNode */) {
67508
68019
  const element = getNativeByTNode(tNode, lView);
67509
68020
  if (ngDevMode) {
67510
- validateAgainstEventProperties(propName);
68021
+ if (lView[TVIEW].firstUpdatePass) {
68022
+ validateAgainstEventProperties(propName);
68023
+ }
67511
68024
  if (!isPropertyValid(element, propName, tNode.value, lView[TVIEW].schemas)) {
67512
68025
  handleUnknownPropertyError(propName, tNode.value, tNode.type, lView);
67513
68026
  }
@@ -67674,7 +68187,6 @@ function findDirectiveDefMatches(tView, tNode) {
67674
68187
  function elementAttributeInternal(tNode, lView, name, value, sanitizer, namespace) {
67675
68188
  if (ngDevMode) {
67676
68189
  assertNotSame(value, NO_CHANGE, 'Incoming value should never be NO_CHANGE.');
67677
- validateAgainstEventAttributes(name);
67678
68190
  assertTNodeType(tNode, 2 /* TNodeType.Element */, `Attempted to set attribute \`${name}\` on a container node. ` +
67679
68191
  `Host bindings are not valid on ng-container or ng-template.`);
67680
68192
  }
@@ -69830,6 +70342,7 @@ function createTNode(tView, tParent, type, index, value, attrs) {
69830
70342
  flags,
69831
70343
  providerIndexes: 0,
69832
70344
  value: value,
70345
+ namespace: getNamespace(),
69833
70346
  attrs: attrs,
69834
70347
  mergedAttrs: null,
69835
70348
  localNames: null,
@@ -72845,9 +73358,14 @@ function createHostElement(componentDef, renderer) {
72845
73358
  // dynamically. Default to 'div' if this component did not specify any tag name in its
72846
73359
  // selector.
72847
73360
  const tagName = inferTagNameFromDefinition(componentDef);
72848
- const namespace = tagName === 'svg' ? SVG_NAMESPACE : tagName === 'math' ? MATH_ML_NAMESPACE : null;
73361
+ const namespace = tagName === 'svg' ? SVG_NAMESPACE$1 : tagName === 'math' ? MATH_ML_NAMESPACE$1 : null;
72849
73362
  return createElementNode(renderer, tagName, namespace);
72850
73363
  }
73364
+ function assertNotScriptHostElement(tagName) {
73365
+ if (tagName?.toLowerCase() === 'script') {
73366
+ throw new RuntimeError(905 /* RuntimeErrorCode.UNSAFE_VALUE_IN_SCRIPT */, ngDevMode && `"<script>" tag is not allowed as a component host element.`);
73367
+ }
73368
+ }
72851
73369
  /**
72852
73370
  * Infers the tag name that should be used for a component based on its definition.
72853
73371
  * @param componentDef Definition for which to resolve the tag name.
@@ -72903,6 +73421,7 @@ class ComponentFactory extends ComponentFactory$1 {
72903
73421
  const hostElement = rootSelectorOrNode
72904
73422
  ? locateHostElement(hostRenderer, rootSelectorOrNode, cmpDef.encapsulation, rootViewInjector)
72905
73423
  : createHostElement(cmpDef, hostRenderer);
73424
+ assertNotScriptHostElement(hostElement?.tagName);
72906
73425
  const hasInputBindings = componentBindings?.some(isInputBinding) ||
72907
73426
  directives?.some((d) => typeof d !== 'function' && d.bindings.some(isInputBinding));
72908
73427
  const rootLView = createLView(null, rootTView, null, 512 /* LViewFlags.IsRoot */ | getInitialLViewFlagsFromDef(cmpDef), null, null, environment, hostRenderer, rootViewInjector, null, retrieveHydrationInfo(hostElement, rootViewInjector, true /* isRootView */));
@@ -72915,7 +73434,7 @@ class ComponentFactory extends ComponentFactory$1 {
72915
73434
  enterView(rootLView);
72916
73435
  let componentView = null;
72917
73436
  try {
72918
- const hostTNode = directiveHostFirstCreatePass(HEADER_OFFSET, rootLView, 2 /* TNodeType.Element */, '#host', () => rootTView.directiveRegistry, true, 0);
73437
+ const hostTNode = directiveHostFirstCreatePass(HEADER_OFFSET, rootLView, 2 /* TNodeType.Element */, "#host" /* TNodeName.DynamicHost */, () => rootTView.directiveRegistry, true, 0);
72919
73438
  // ---- element instruction
72920
73439
  setupStaticAttributes(hostRenderer, hostElement, hostTNode);
72921
73440
  attachPatchData(hostElement, rootLView);
@@ -72953,7 +73472,7 @@ class ComponentFactory extends ComponentFactory$1 {
72953
73472
  }
72954
73473
  function createRootTView(rootSelectorOrNode, componentDef, componentBindings, directives) {
72955
73474
  const tAttributes = rootSelectorOrNode
72956
- ? ['ng-version', '20.3.19']
73475
+ ? ['ng-version', '20.3.28']
72957
73476
  : // Extract attributes and classes from the first selector only to match VE behavior.
72958
73477
  extractAttrsAndClassesFromSelector(componentDef.selectors[0]);
72959
73478
  let creationBindings = null;
@@ -82146,11 +82665,19 @@ function getLocalePluralCase(locale) {
82146
82665
  */
82147
82666
  function getLocaleData(normalizedLocale) {
82148
82667
  if (!(normalizedLocale in LOCALE_DATA)) {
82149
- LOCALE_DATA[normalizedLocale] =
82150
- _global.ng &&
82151
- _global.ng.common &&
82152
- _global.ng.common.locales &&
82153
- _global.ng.common.locales[normalizedLocale];
82668
+ const globalLocaleData = _global.ng &&
82669
+ _global.ng.common &&
82670
+ _global.ng.common.locales &&
82671
+ _global.ng.common.locales[normalizedLocale];
82672
+ // Only cache global locale data when an entry is actually found, to avoid
82673
+ // caching missing lookups. In SSR this cache is process-wide across requests,
82674
+ // so caching `undefined` would retain attacker-controlled locale identifiers
82675
+ // indefinitely. It would also make the `in` check above short-circuit on
82676
+ // subsequent lookups and skip the global fallback.
82677
+ if (globalLocaleData !== undefined) {
82678
+ LOCALE_DATA[normalizedLocale] = globalLocaleData;
82679
+ }
82680
+ return globalLocaleData;
82154
82681
  }
82155
82682
  return LOCALE_DATA[normalizedLocale];
82156
82683
  }
@@ -82570,7 +83097,14 @@ function applyUpdateOpCodes(tView, lView, updateOpCodes, bindingsStartIndex, cha
82570
83097
  setElementAttribute(lView[RENDERER], lView[nodeIndex], null, tNodeOrTagName, propName, value, sanitizeFn);
82571
83098
  }
82572
83099
  else {
82573
- setPropertyAndInputs(tNodeOrTagName, lView, propName, value, lView[RENDERER], sanitizeFn);
83100
+ const prevSelectedIndex = getSelectedIndex();
83101
+ setSelectedIndex(nodeIndex);
83102
+ try {
83103
+ setPropertyAndInputs(tNodeOrTagName, lView, propName, value, lView[RENDERER], sanitizeFn);
83104
+ }
83105
+ finally {
83106
+ setSelectedIndex(prevSelectedIndex);
83107
+ }
82574
83108
  }
82575
83109
  break;
82576
83110
  case 0 /* I18nUpdateOpCode.Text */:
@@ -83150,7 +83684,10 @@ function i18nAttributesFirstPass(tView, index, values) {
83150
83684
  // the compiler treats static i18n attributes as regular attribute bindings.
83151
83685
  // Since this may not be the first i18n attribute on this element we need to pass in how
83152
83686
  // many previous bindings there have already been.
83153
- generateBindingUpdateOpCodes(updateOpCodes, message, previousElementIndex, attrName, countBindings(updateOpCodes), SENSITIVE_ATTRS[attrName.toLowerCase()] ? _sanitizeUrl : null);
83687
+ const tagName = previousElement.namespace
83688
+ ? `:${previousElement.namespace}:${previousElement.value}`
83689
+ : previousElement.value;
83690
+ generateBindingUpdateOpCodes(updateOpCodes, message, previousElementIndex, attrName, countBindings(updateOpCodes), i18nResolveSanitizer(attrName, tagName));
83154
83691
  }
83155
83692
  }
83156
83693
  tView.data[index] = updateOpCodes;
@@ -83476,9 +84013,12 @@ function walkIcuTree(ast, tView, tIcu, lView, sharedUpdateOpCodes, create, remov
83476
84013
  const attr = elAttrs.item(i);
83477
84014
  const lowerAttrName = attr.name.toLowerCase();
83478
84015
  const hasBinding = !!attr.value.match(BINDING_REGEXP);
84016
+ const namespaceUri = element.namespaceURI;
84017
+ const namespace = namespaceUri && NAMESPACE_URIS[namespaceUri];
84018
+ const tagNameWithNamespace = namespace ? `:${namespace}:${tagName}` : tagName;
83479
84019
  if (hasBinding) {
83480
84020
  if (VALID_ATTRS.hasOwnProperty(lowerAttrName)) {
83481
- generateBindingUpdateOpCodes(update, attr.value, newIndex, attr.name, 0, SENSITIVE_ATTRS[lowerAttrName] ? _sanitizeUrl : null);
84021
+ generateBindingUpdateOpCodes(update, attr.value, newIndex, attr.name, 0, i18nResolveSanitizer(lowerAttrName, tagNameWithNamespace));
83482
84022
  }
83483
84023
  else {
83484
84024
  ngDevMode &&
@@ -83488,9 +84028,9 @@ function walkIcuTree(ast, tView, tIcu, lView, sharedUpdateOpCodes, create, remov
83488
84028
  }
83489
84029
  }
83490
84030
  else if (VALID_ATTRS[lowerAttrName]) {
83491
- if (SENSITIVE_ATTRS[lowerAttrName]) {
83492
- // Don't sanitize, because no value is acceptable in sensitive attributes.
83493
- // Translators are not allowed to create URIs.
84031
+ let val = attr.value;
84032
+ const sanitizer = i18nResolveSanitizer(lowerAttrName, tagNameWithNamespace);
84033
+ if (sanitizer) {
83494
84034
  if (typeof ngDevMode !== 'undefined' && ngDevMode) {
83495
84035
  console.warn(`WARNING: ignoring unsafe attribute ` +
83496
84036
  `${lowerAttrName} on element ${tagName} ` +
@@ -83499,7 +84039,7 @@ function walkIcuTree(ast, tView, tIcu, lView, sharedUpdateOpCodes, create, remov
83499
84039
  addCreateAttribute(create, newIndex, attr.name, 'unsafe:blocked');
83500
84040
  }
83501
84041
  else {
83502
- addCreateAttribute(create, newIndex, attr.name, attr.value);
84042
+ addCreateAttribute(create, newIndex, attr.name, val);
83503
84043
  }
83504
84044
  }
83505
84045
  else {
@@ -83579,6 +84119,37 @@ function addCreateNodeAndAppend(create, marker, text, appendToParentIdx, createA
83579
84119
  function addCreateAttribute(create, newIndex, attrName, attrValue) {
83580
84120
  create.push((newIndex << 1 /* IcuCreateOpCode.SHIFT_REF */) | 1 /* IcuCreateOpCode.Attr */, attrName, attrValue);
83581
84121
  }
84122
+ function normalizeTagName(tagName) {
84123
+ const tagNameLower = tagName.toLowerCase();
84124
+ const [ns, name] = splitNsName(tagNameLower, false);
84125
+ return ns === SVG_NAMESPACE || ns === MATH_ML_NAMESPACE ? `:${ns}:${name}` : name;
84126
+ }
84127
+ function i18nResolveSanitizer(attrName, tagName) {
84128
+ const lowerAttrName = attrName.toLowerCase();
84129
+ const lowerTagName = tagName ? normalizeTagName(tagName) : '*';
84130
+ const [namespace] = splitNsName(lowerTagName, false);
84131
+ const schema = SECURITY_SCHEMA();
84132
+ const schemaContext = schema[`${lowerTagName}|${lowerAttrName}`] ||
84133
+ (namespace ? schema[`:${namespace}:*|${lowerAttrName}`] : undefined) ||
84134
+ schema[`*|${lowerAttrName}`] ||
84135
+ SecurityContext.NONE;
84136
+ switch (schemaContext) {
84137
+ case SecurityContext.HTML:
84138
+ return ɵɵsanitizeHtml;
84139
+ case SecurityContext.STYLE:
84140
+ return ɵɵsanitizeStyle;
84141
+ case SecurityContext.SCRIPT:
84142
+ return ɵɵsanitizeScript;
84143
+ case SecurityContext.URL:
84144
+ return _sanitizeUrl;
84145
+ case SecurityContext.RESOURCE_URL:
84146
+ return ɵɵsanitizeResourceUrl;
84147
+ case SecurityContext.ATTRIBUTE_NO_BINDING:
84148
+ return ɵɵvalidateAttribute;
84149
+ default:
84150
+ return null;
84151
+ }
84152
+ }
83582
84153
 
83583
84154
  // i18nPostprocess consts
83584
84155
  const ROOT_TEMPLATE_ID = 0;
@@ -90294,7 +90865,7 @@ function getDebugNode(nativeNode) {
90294
90865
  }
90295
90866
 
90296
90867
  /**
90297
- * @license Angular v20.3.19
90868
+ * @license Angular v20.3.28
90298
90869
  * (c) 2010-2025 Google LLC. https://angular.dev/
90299
90870
  * License: MIT
90300
90871
  */
@@ -90909,7 +91480,7 @@ class ResourceWrappedError extends Error {
90909
91480
  }
90910
91481
 
90911
91482
  /**
90912
- * @license Angular v20.3.19
91483
+ * @license Angular v20.3.28
90913
91484
  * (c) 2010-2025 Google LLC. https://angular.dev/
90914
91485
  * License: MIT
90915
91486
  */
@@ -92368,7 +92939,7 @@ function clearAppScopedEarlyEventContract(appId, dataContainer = window) {
92368
92939
  }
92369
92940
 
92370
92941
  /**
92371
- * @license Angular v20.3.19
92942
+ * @license Angular v20.3.28
92372
92943
  * (c) 2010-2025 Google LLC. https://angular.dev/
92373
92944
  * License: MIT
92374
92945
  */
@@ -97404,7 +97975,7 @@ var i0 = /*#__PURE__*/Object.freeze({
97404
97975
  });
97405
97976
 
97406
97977
  /**
97407
- * @license Angular v20.3.19
97978
+ * @license Angular v20.3.28
97408
97979
  * (c) 2010-2025 Google LLC. https://angular.dev/
97409
97980
  * License: MIT
97410
97981
  */
@@ -97430,7 +98001,7 @@ class XhrFactory {
97430
98001
  }
97431
98002
 
97432
98003
  /**
97433
- * @license Angular v20.3.19
98004
+ * @license Angular v20.3.28
97434
98005
  * (c) 2010-2025 Google LLC. https://angular.dev/
97435
98006
  * License: MIT
97436
98007
  */
@@ -97627,10 +98198,10 @@ class HttpHeaders {
97627
98198
  }
97628
98199
  copyFrom(other) {
97629
98200
  other.init();
97630
- Array.from(other.headers.keys()).forEach((key) => {
97631
- this.headers.set(key, other.headers.get(key));
98201
+ for (const [key, values] of other.headers.entries()) {
98202
+ this.headers.set(key, values);
97632
98203
  this.normalizedNames.set(key, other.normalizedNames.get(key));
97633
- });
98204
+ }
97634
98205
  }
97635
98206
  clone(update) {
97636
98207
  const clone = new HttpHeaders();
@@ -97651,22 +98222,23 @@ class HttpHeaders {
97651
98222
  return;
97652
98223
  }
97653
98224
  this.maybeSetNormalizedName(update.name, key);
97654
- const base = (update.op === 'a' ? this.headers.get(key) : undefined) || [];
98225
+ const base = update.op === 'a' ? (this.headers.get(key) || []).slice() : [];
97655
98226
  base.push(...value);
97656
98227
  this.headers.set(key, base);
97657
98228
  break;
97658
98229
  case 'd':
97659
98230
  const toDelete = update.value;
97660
- if (!toDelete) {
98231
+ if (toDelete === undefined) {
97661
98232
  this.headers.delete(key);
97662
98233
  this.normalizedNames.delete(key);
97663
98234
  }
97664
98235
  else {
98236
+ const valuesToDelete = Array.isArray(toDelete) ? toDelete : [toDelete];
97665
98237
  let existing = this.headers.get(key);
97666
98238
  if (!existing) {
97667
98239
  return;
97668
98240
  }
97669
- existing = existing.filter((value) => toDelete.indexOf(value) === -1);
98241
+ existing = existing.filter((value) => valuesToDelete.indexOf(value) === -1);
97670
98242
  if (existing.length === 0) {
97671
98243
  this.headers.delete(key);
97672
98244
  this.normalizedNames.delete(key);
@@ -97955,18 +98527,20 @@ class HttpParams {
97955
98527
  }
97956
98528
  if (this.cloneFrom !== null) {
97957
98529
  this.cloneFrom.init();
97958
- this.cloneFrom.keys().forEach((key) => this.map.set(key, this.cloneFrom.map.get(key)));
98530
+ for (const [key, values] of this.cloneFrom.map.entries()) {
98531
+ this.map.set(key, values);
98532
+ }
97959
98533
  this.updates.forEach((update) => {
97960
98534
  switch (update.op) {
97961
98535
  case 'a':
97962
98536
  case 's':
97963
- const base = (update.op === 'a' ? this.map.get(update.param) : undefined) || [];
98537
+ const base = update.op === 'a' ? (this.map.get(update.param) || []).slice() : [];
97964
98538
  base.push(valueToString(update.value));
97965
98539
  this.map.set(update.param, base);
97966
98540
  break;
97967
98541
  case 'd':
97968
98542
  if (update.value !== undefined) {
97969
- let base = this.map.get(update.param) || [];
98543
+ const base = (this.map.get(update.param) || []).slice();
97970
98544
  const idx = base.indexOf(valueToString(update.value));
97971
98545
  if (idx !== -1) {
97972
98546
  base.splice(idx, 1);
@@ -98337,7 +98911,7 @@ class HttpRequest {
98337
98911
  if (options.integrity) {
98338
98912
  this.integrity = options.integrity;
98339
98913
  }
98340
- if (options.referrer) {
98914
+ if (options.referrer !== undefined) {
98341
98915
  this.referrer = options.referrer;
98342
98916
  }
98343
98917
  // We do want to assign transferCache even if it's falsy (false is valid value)
@@ -98459,7 +99033,7 @@ class HttpRequest {
98459
99033
  const mode = update.mode || this.mode;
98460
99034
  const redirect = update.redirect || this.redirect;
98461
99035
  const credentials = update.credentials || this.credentials;
98462
- const referrer = update.referrer || this.referrer;
99036
+ const referrer = update.referrer ?? this.referrer;
98463
99037
  const integrity = update.integrity || this.integrity;
98464
99038
  // Carefully handle the transferCache to differentiate between
98465
99039
  // `false` and `undefined` in the update args.
@@ -99108,8 +99682,8 @@ class HttpClient {
99108
99682
  put(url, body, options = {}) {
99109
99683
  return this.request('PUT', url, addBody(options, body));
99110
99684
  }
99111
- static ɵfac = ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: HttpClient, deps: [{ token: HttpHandler }], target: FactoryTarget.Injectable });
99112
- static ɵprov = ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: HttpClient });
99685
+ static ɵfac = ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: HttpClient, deps: [{ token: HttpHandler }], target: FactoryTarget.Injectable });
99686
+ static ɵprov = ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: HttpClient });
99113
99687
  }
99114
99688
  ɵɵngDeclareClassMetadata({ type: HttpClient, decorators: [{
99115
99689
  type: Injectable
@@ -99398,8 +99972,8 @@ class FetchBackend {
99398
99972
  }
99399
99973
  return chunksAll;
99400
99974
  }
99401
- static ɵfac = ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FetchBackend, deps: [], target: FactoryTarget.Injectable });
99402
- static ɵprov = ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FetchBackend });
99975
+ static ɵfac = ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: FetchBackend, deps: [], target: FactoryTarget.Injectable });
99976
+ static ɵprov = ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: FetchBackend });
99403
99977
  }
99404
99978
  ɵɵngDeclareClassMetadata({ type: FetchBackend, decorators: [{
99405
99979
  type: Injectable
@@ -99529,10 +100103,10 @@ class HttpInterceptorHandler extends HttpHandler {
99529
100103
  }
99530
100104
  handle(initialRequest) {
99531
100105
  if (this.chain === null) {
99532
- const dedupedInterceptorFns = Array.from(new Set([
99533
- ...this.injector.get(HTTP_INTERCEPTOR_FNS),
99534
- ...this.injector.get(HTTP_ROOT_INTERCEPTOR_FNS, []),
99535
- ]));
100106
+ const parentHandler = this.injector.get(HttpHandler, null, { skipSelf: true });
100107
+ const isDelegating = parentHandler !== null && this.backend === parentHandler;
100108
+ const rootInterceptorFns = this.injector.get(HTTP_ROOT_INTERCEPTOR_FNS, [], isDelegating ? { self: true } : undefined);
100109
+ const dedupedInterceptorFns = Array.from(new Set([...this.injector.get(HTTP_INTERCEPTOR_FNS), ...rootInterceptorFns]));
99536
100110
  // Note: interceptors are wrapped right-to-left so that final execution order is
99537
100111
  // left-to-right. That is, if `dedupedInterceptorFns` is the array `[a, b, c]`, we want to
99538
100112
  // produce a chain that is conceptually `c(b(a(end)))`, which we build from the inside
@@ -99547,8 +100121,8 @@ class HttpInterceptorHandler extends HttpHandler {
99547
100121
  return this.chain(initialRequest, (downstreamRequest) => this.backend.handle(downstreamRequest));
99548
100122
  }
99549
100123
  }
99550
- static ɵfac = ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: HttpInterceptorHandler, deps: [{ token: HttpBackend }, { token: EnvironmentInjector }], target: FactoryTarget.Injectable });
99551
- static ɵprov = ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: HttpInterceptorHandler });
100124
+ static ɵfac = ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: HttpInterceptorHandler, deps: [{ token: HttpBackend }, { token: EnvironmentInjector }], target: FactoryTarget.Injectable });
100125
+ static ɵprov = ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: HttpInterceptorHandler });
99552
100126
  }
99553
100127
  ɵɵngDeclareClassMetadata({ type: HttpInterceptorHandler, decorators: [{
99554
100128
  type: Injectable
@@ -99574,6 +100148,8 @@ const JSONP_ERR_WRONG_RESPONSE_TYPE = 'JSONP requests must use Json response typ
99574
100148
  // Error text given when a request is passed to the JsonpClientBackend that has
99575
100149
  // headers set
99576
100150
  const JSONP_ERR_HEADERS_NOT_SUPPORTED = 'JSONP requests do not support headers.';
100151
+ // Error text given when a JSONP request URL is not absolute HTTP(S).
100152
+ const JSONP_ERR_UNSAFE_URL = 'JSONP requests only support absolute URLs with HTTP(S) protocols.';
99577
100153
  /**
99578
100154
  * DI token/abstract type representing a map of JSONP callbacks.
99579
100155
  *
@@ -99642,6 +100218,9 @@ class JsonpClientBackend {
99642
100218
  if (req.headers.keys().length > 0) {
99643
100219
  throw new RuntimeError(2812 /* RuntimeErrorCode.JSONP_HEADERS_NOT_SUPPORTED */, ngDevMode && JSONP_ERR_HEADERS_NOT_SUPPORTED);
99644
100220
  }
100221
+ if (!this.isAllowedJsonpUrl(req.urlWithParams)) {
100222
+ throw new RuntimeError(2826 /* RuntimeErrorCode.JSONP_UNSAFE_URL */, ngDevMode && JSONP_ERR_UNSAFE_URL);
100223
+ }
99645
100224
  // Everything else happens inside the Observable boundary.
99646
100225
  return new Observable((observer) => {
99647
100226
  // The first step to make a request is to generate the callback name, and replace the
@@ -99752,8 +100331,11 @@ class JsonpClientBackend {
99752
100331
  foreignDocument ??= this.document.implementation.createHTMLDocument();
99753
100332
  foreignDocument.adoptNode(script);
99754
100333
  }
99755
- static ɵfac = ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: JsonpClientBackend, deps: [{ token: JsonpCallbackContext }, { token: DOCUMENT$1 }], target: FactoryTarget.Injectable });
99756
- static ɵprov = ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: JsonpClientBackend });
100334
+ isAllowedJsonpUrl(url) {
100335
+ return /^https?:\/\//i.test(url);
100336
+ }
100337
+ static ɵfac = ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: JsonpClientBackend, deps: [{ token: JsonpCallbackContext }, { token: DOCUMENT$1 }], target: FactoryTarget.Injectable });
100338
+ static ɵprov = ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: JsonpClientBackend });
99757
100339
  }
99758
100340
  ɵɵngDeclareClassMetadata({ type: JsonpClientBackend, decorators: [{
99759
100341
  type: Injectable
@@ -99794,8 +100376,8 @@ class JsonpInterceptor {
99794
100376
  intercept(initialRequest, next) {
99795
100377
  return runInInjectionContext(this.injector, () => jsonpInterceptorFn(initialRequest, (downstreamRequest) => next.handle(downstreamRequest)));
99796
100378
  }
99797
- static ɵfac = ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: JsonpInterceptor, deps: [{ token: EnvironmentInjector }], target: FactoryTarget.Injectable });
99798
- static ɵprov = ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: JsonpInterceptor });
100379
+ static ɵfac = ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: JsonpInterceptor, deps: [{ token: EnvironmentInjector }], target: FactoryTarget.Injectable });
100380
+ static ɵprov = ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: JsonpInterceptor });
99799
100381
  }
99800
100382
  ɵɵngDeclareClassMetadata({ type: JsonpInterceptor, decorators: [{
99801
100383
  type: Injectable
@@ -100149,8 +100731,8 @@ class HttpXhrBackend {
100149
100731
  });
100150
100732
  }));
100151
100733
  }
100152
- static ɵfac = ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: HttpXhrBackend, deps: [{ token: XhrFactory }], target: FactoryTarget.Injectable });
100153
- static ɵprov = ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: HttpXhrBackend });
100734
+ static ɵfac = ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: HttpXhrBackend, deps: [{ token: XhrFactory }], target: FactoryTarget.Injectable });
100735
+ static ɵprov = ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: HttpXhrBackend });
100154
100736
  }
100155
100737
  ɵɵngDeclareClassMetadata({ type: HttpXhrBackend, decorators: [{
100156
100738
  type: Injectable
@@ -100202,8 +100784,8 @@ class HttpXsrfCookieExtractor {
100202
100784
  }
100203
100785
  return this.lastToken;
100204
100786
  }
100205
- static ɵfac = ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: HttpXsrfCookieExtractor, deps: [{ token: DOCUMENT$1 }, { token: XSRF_COOKIE_NAME }], target: FactoryTarget.Injectable });
100206
- static ɵprov = ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: HttpXsrfCookieExtractor });
100787
+ static ɵfac = ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: HttpXsrfCookieExtractor, deps: [{ token: DOCUMENT$1 }, { token: XSRF_COOKIE_NAME }], target: FactoryTarget.Injectable });
100788
+ static ɵprov = ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: HttpXsrfCookieExtractor });
100207
100789
  }
100208
100790
  ɵɵngDeclareClassMetadata({ type: HttpXsrfCookieExtractor, decorators: [{
100209
100791
  type: Injectable
@@ -100248,8 +100830,8 @@ class HttpXsrfInterceptor {
100248
100830
  intercept(initialRequest, next) {
100249
100831
  return runInInjectionContext(this.injector, () => xsrfInterceptorFn(initialRequest, (downstreamRequest) => next.handle(downstreamRequest)));
100250
100832
  }
100251
- static ɵfac = ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: HttpXsrfInterceptor, deps: [{ token: EnvironmentInjector }], target: FactoryTarget.Injectable });
100252
- static ɵprov = ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: HttpXsrfInterceptor });
100833
+ static ɵfac = ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: HttpXsrfInterceptor, deps: [{ token: EnvironmentInjector }], target: FactoryTarget.Injectable });
100834
+ static ɵprov = ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: HttpXsrfInterceptor });
100253
100835
  }
100254
100836
  ɵɵngDeclareClassMetadata({ type: HttpXsrfInterceptor, decorators: [{
100255
100837
  type: Injectable
@@ -100310,9 +100892,11 @@ function provideHttpClient(...features) {
100310
100892
  const featureKinds = new Set(features.map((f) => f.ɵkind));
100311
100893
  if (featureKinds.has(HttpFeatureKind.NoXsrfProtection) &&
100312
100894
  featureKinds.has(HttpFeatureKind.CustomXsrfConfiguration)) {
100313
- throw new Error(ngDevMode
100314
- ? `Configuration error: found both withXsrfConfiguration() and withNoXsrfProtection() in the same call to provideHttpClient(), which is a contradiction.`
100315
- : '');
100895
+ throw new Error(`Configuration error: found both withXsrfConfiguration() and withNoXsrfProtection() in the same call to provideHttpClient(), which is a contradiction.`);
100896
+ }
100897
+ if (featureKinds.has(HttpFeatureKind.RequestsMadeViaParent) &&
100898
+ featureKinds.has(HttpFeatureKind.Fetch)) {
100899
+ throw new Error(`Configuration error: withRequestsMadeViaParent() cannot be combined with withFetch() in the same call to provideHttpClient().`);
100316
100900
  }
100317
100901
  }
100318
100902
  const providers = [
@@ -100452,9 +101036,9 @@ class HttpClientXsrfModule {
100452
101036
  providers: withXsrfConfiguration(options).ɵproviders,
100453
101037
  };
100454
101038
  }
100455
- static ɵfac = ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: HttpClientXsrfModule, deps: [], target: FactoryTarget.NgModule });
100456
- static ɵmod = ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.19", ngImport: i0, type: HttpClientXsrfModule });
100457
- static ɵinj = ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: HttpClientXsrfModule, providers: [
101039
+ static ɵfac = ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: HttpClientXsrfModule, deps: [], target: FactoryTarget.NgModule });
101040
+ static ɵmod = ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.28", ngImport: i0, type: HttpClientXsrfModule });
101041
+ static ɵinj = ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: HttpClientXsrfModule, providers: [
100458
101042
  HttpXsrfInterceptor,
100459
101043
  { provide: HTTP_INTERCEPTORS, useExisting: HttpXsrfInterceptor, multi: true },
100460
101044
  { provide: HttpXsrfTokenExtractor, useClass: HttpXsrfCookieExtractor },
@@ -100491,9 +101075,9 @@ class HttpClientXsrfModule {
100491
101075
  * @deprecated use `provideHttpClient(withInterceptorsFromDi())` as providers instead
100492
101076
  */
100493
101077
  class HttpClientModule {
100494
- static ɵfac = ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: HttpClientModule, deps: [], target: FactoryTarget.NgModule });
100495
- static ɵmod = ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.19", ngImport: i0, type: HttpClientModule });
100496
- static ɵinj = ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: HttpClientModule, providers: [provideHttpClient(withInterceptorsFromDi())] });
101078
+ static ɵfac = ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: HttpClientModule, deps: [], target: FactoryTarget.NgModule });
101079
+ static ɵmod = ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.28", ngImport: i0, type: HttpClientModule });
101080
+ static ɵinj = ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: HttpClientModule, providers: [provideHttpClient(withInterceptorsFromDi())] });
100497
101081
  }
100498
101082
  ɵɵngDeclareClassMetadata({ type: HttpClientModule, decorators: [{
100499
101083
  type: NgModule,
@@ -100515,9 +101099,9 @@ class HttpClientModule {
100515
101099
  * @deprecated `withJsonpSupport()` as providers instead
100516
101100
  */
100517
101101
  class HttpClientJsonpModule {
100518
- static ɵfac = ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: HttpClientJsonpModule, deps: [], target: FactoryTarget.NgModule });
100519
- static ɵmod = ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.19", ngImport: i0, type: HttpClientJsonpModule });
100520
- static ɵinj = ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: HttpClientJsonpModule, providers: [withJsonpSupport().ɵproviders] });
101102
+ static ɵfac = ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: HttpClientJsonpModule, deps: [], target: FactoryTarget.NgModule });
101103
+ static ɵmod = ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.28", ngImport: i0, type: HttpClientJsonpModule });
101104
+ static ɵinj = ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: HttpClientJsonpModule, providers: [withJsonpSupport().ɵproviders] });
100521
101105
  }
100522
101106
  ɵɵngDeclareClassMetadata({ type: HttpClientJsonpModule, decorators: [{
100523
101107
  type: NgModule,
@@ -103327,8 +103911,8 @@ class Viewport {
103327
103911
  }
103328
103912
  this.mediaQuery = null;
103329
103913
  }
103330
- static { this.ɵfac = ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: Viewport, deps: [], target: FactoryTarget.Injectable }); }
103331
- static { this.ɵprov = ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: Viewport, providedIn: 'root' }); }
103914
+ static { this.ɵfac = ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: Viewport, deps: [], target: FactoryTarget.Injectable }); }
103915
+ static { this.ɵprov = ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: Viewport, providedIn: 'root' }); }
103332
103916
  }
103333
103917
  ɵɵngDeclareClassMetadata({ type: Viewport, decorators: [{
103334
103918
  type: Injectable,
@@ -103349,8 +103933,8 @@ class ConstantService {
103349
103933
  };
103350
103934
  this.VALIDATOR = VALIDATOR;
103351
103935
  }
103352
- static { this.ɵfac = ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: ConstantService, deps: [], target: FactoryTarget.Injectable }); }
103353
- static { this.ɵprov = ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: ConstantService, providedIn: 'root' }); }
103936
+ static { this.ɵfac = ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: ConstantService, deps: [], target: FactoryTarget.Injectable }); }
103937
+ static { this.ɵprov = ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: ConstantService, providedIn: 'root' }); }
103354
103938
  }
103355
103939
  ɵɵngDeclareClassMetadata({ type: ConstantService, decorators: [{
103356
103940
  type: Injectable,
@@ -103361,8 +103945,8 @@ class UtilsService {
103361
103945
  constructor() {
103362
103946
  assign(this, Utils);
103363
103947
  }
103364
- static { this.ɵfac = ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: UtilsService, deps: [], target: FactoryTarget.Injectable }); }
103365
- static { this.ɵprov = ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: UtilsService, providedIn: 'root' }); }
103948
+ static { this.ɵfac = ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: UtilsService, deps: [], target: FactoryTarget.Injectable }); }
103949
+ static { this.ɵprov = ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: UtilsService, providedIn: 'root' }); }
103366
103950
  }
103367
103951
  ɵɵngDeclareClassMetadata({ type: UtilsService, decorators: [{
103368
103952
  type: Injectable,
@@ -103393,8 +103977,8 @@ class FieldTypeService {
103393
103977
  BLOB: 'blob'
103394
103978
  });
103395
103979
  }
103396
- static { this.ɵfac = ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FieldTypeService, deps: [], target: FactoryTarget.Injectable }); }
103397
- static { this.ɵprov = ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FieldTypeService, providedIn: 'root' }); }
103980
+ static { this.ɵfac = ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: FieldTypeService, deps: [], target: FactoryTarget.Injectable }); }
103981
+ static { this.ɵprov = ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: FieldTypeService, providedIn: 'root' }); }
103398
103982
  }
103399
103983
  ɵɵngDeclareClassMetadata({ type: FieldTypeService, decorators: [{
103400
103984
  type: Injectable,
@@ -103427,8 +104011,8 @@ class FieldWidgetService {
103427
104011
  COLORPICKER: 'colorpicker'
103428
104012
  });
103429
104013
  }
103430
- static { this.ɵfac = ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FieldWidgetService, deps: [], target: FactoryTarget.Injectable }); }
103431
- static { this.ɵprov = ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FieldWidgetService, providedIn: 'root' }); }
104014
+ static { this.ɵfac = ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: FieldWidgetService, deps: [], target: FactoryTarget.Injectable }); }
104015
+ static { this.ɵprov = ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: FieldWidgetService, providedIn: 'root' }); }
103432
104016
  }
103433
104017
  ɵɵngDeclareClassMetadata({ type: FieldWidgetService, decorators: [{
103434
104018
  type: Injectable,
@@ -103497,8 +104081,8 @@ class ScriptLoaderService {
103497
104081
  document.getElementsByTagName('head')[0].appendChild(script);
103498
104082
  });
103499
104083
  }
103500
- static { this.ɵfac = ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: ScriptLoaderService, deps: [{ token: HttpClient }], target: FactoryTarget.Injectable }); }
103501
- static { this.ɵprov = ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: ScriptLoaderService, providedIn: 'root' }); }
104084
+ static { this.ɵfac = ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: ScriptLoaderService, deps: [{ token: HttpClient }], target: FactoryTarget.Injectable }); }
104085
+ static { this.ɵprov = ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: ScriptLoaderService, providedIn: 'root' }); }
103502
104086
  }
103503
104087
  ɵɵngDeclareClassMetadata({ type: ScriptLoaderService, decorators: [{
103504
104088
  type: Injectable,
@@ -103518,8 +104102,8 @@ class CustomPipeManager {
103518
104102
  hasCustomPipe(key) {
103519
104103
  return this.customPipes.has(key);
103520
104104
  }
103521
- static { this.ɵfac = ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: CustomPipeManager, deps: [], target: FactoryTarget.Injectable }); }
103522
- static { this.ɵprov = ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: CustomPipeManager, providedIn: 'root' }); }
104105
+ static { this.ɵfac = ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: CustomPipeManager, deps: [], target: FactoryTarget.Injectable }); }
104106
+ static { this.ɵprov = ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: CustomPipeManager, providedIn: 'root' }); }
103523
104107
  }
103524
104108
  ɵɵngDeclareClassMetadata({ type: CustomPipeManager, decorators: [{
103525
104109
  type: Injectable,
@@ -103535,8 +104119,8 @@ class CustomIconsLoaderService {
103535
104119
  .map(font => font.csspath);
103536
104120
  loadStyleSheets(cssPaths);
103537
104121
  }
103538
- static { this.ɵfac = ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: CustomIconsLoaderService, deps: [], target: FactoryTarget.Injectable }); }
103539
- static { this.ɵprov = ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: CustomIconsLoaderService, providedIn: 'root' }); }
104122
+ static { this.ɵfac = ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: CustomIconsLoaderService, deps: [], target: FactoryTarget.Injectable }); }
104123
+ static { this.ɵprov = ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: CustomIconsLoaderService, providedIn: 'root' }); }
103540
104124
  }
103541
104125
  ɵɵngDeclareClassMetadata({ type: CustomIconsLoaderService, decorators: [{
103542
104126
  type: Injectable,
@@ -104032,8 +104616,8 @@ class StatePersistence {
104032
104616
  }
104033
104617
  return response;
104034
104618
  }
104035
- static { this.ɵfac = ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: StatePersistence, deps: [], target: FactoryTarget.Injectable }); }
104036
- static { this.ɵprov = ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: StatePersistence, providedIn: 'root' }); }
104619
+ static { this.ɵfac = ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: StatePersistence, deps: [], target: FactoryTarget.Injectable }); }
104620
+ static { this.ɵprov = ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: StatePersistence, providedIn: 'root' }); }
104037
104621
  }
104038
104622
  ɵɵngDeclareClassMetadata({ type: StatePersistence, decorators: [{
104039
104623
  type: Injectable,
@@ -104364,8 +104948,8 @@ class PaginationService {
104364
104948
  lastScrollTop = scrollTop;
104365
104949
  });
104366
104950
  }
104367
- static { this.ɵfac = ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: PaginationService, deps: [], target: FactoryTarget.Injectable }); }
104368
- static { this.ɵprov = ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: PaginationService, providedIn: 'root' }); }
104951
+ static { this.ɵfac = ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: PaginationService, deps: [], target: FactoryTarget.Injectable }); }
104952
+ static { this.ɵprov = ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: PaginationService, providedIn: 'root' }); }
104369
104953
  }
104370
104954
  ɵɵngDeclareClassMetadata({ type: PaginationService, decorators: [{
104371
104955
  type: Injectable,