@lwc/template-compiler 8.6.0 → 8.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -12878,8 +12878,30 @@ function isStaticNode(node, apiVersion) {
12878
12878
  });
12879
12879
  // all directives are static-safe
12880
12880
  result &&= !directives.some((directive) => !STATIC_SAFE_DIRECTIVES.has(directive.name));
12881
- // all properties are static
12882
- result &&= properties.every((prop) => isLiteral(prop.value));
12881
+ // Sanity check to ensure that only `<input value>`/`<input checked>` are treated as props for elements
12882
+ /* v8 ignore start */
12883
+ if (process.env.NODE_ENV === 'test' && isElement(node)) {
12884
+ for (const { attributeName } of properties) {
12885
+ if (node.name !== 'input' &&
12886
+ !(attributeName === 'checked' || attributeName === 'value')) {
12887
+ throw new Error(`Expected to only see <input value>/<input checked> treated as an element prop. ` +
12888
+ `Instead found <${node.name} ${attributeName}>`);
12889
+ }
12890
+ }
12891
+ }
12892
+ /* v8 ignore stop */
12893
+ // `<input checked="...">` and `<input value="...">` have a peculiar attr/prop relationship, so the engine
12894
+ // has historically treated them as props rather than attributes:
12895
+ // https://github.com/salesforce/lwc/blob/b584d39/packages/%40lwc/template-compiler/src/parser/attribute.ts#L217-L221
12896
+ // For example, an element might be rendered as `<input type=checkbox>` but `input.checked` could
12897
+ // still return true. `value` behaves similarly. `value` and `checked` behave surprisingly
12898
+ // because the attributes actually represent the "default" value rather than the current one:
12899
+ // - https://jakearchibald.com/2024/attributes-vs-properties/#value-on-input-fields
12900
+ // - https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/checkbox#checked
12901
+ // For this reason, we currently avoid the static content optimization, and treat `value`/`checked` only as
12902
+ // runtime props.
12903
+ // TODO [#4775]: allow static optimization for `<input value>`/`<input checked>`
12904
+ result &&= properties.length === 0;
12883
12905
  return result;
12884
12906
  }
12885
12907
  function collectStaticNodes(node, staticNodes, state) {
@@ -13015,33 +13037,14 @@ function serializeAttrs(element, codeGen) {
13015
13037
  */
13016
13038
  const attrs = [];
13017
13039
  let hasClassAttr = false;
13018
- const collector = ({ name, value, isProp, hasExpression, hasSvgUseHref, needsScoping, }) => {
13040
+ const collector = ({ name, value, hasExpression, hasSvgUseHref, needsScoping, }) => {
13019
13041
  // Do not serialize boolean class/style attribute (consistent with non-static optimized)
13020
13042
  if (typeof value === 'boolean' && (name === 'class' || name === 'style')) {
13021
13043
  return;
13022
13044
  }
13023
13045
  // See W-16614169
13024
13046
  const escapedAttributeName = templateStringEscape(name);
13025
- // `<input checked="...">` and `<input value="...">` have a peculiar attr/prop relationship, so the engine
13026
- // has historically treated them as props rather than attributes:
13027
- // https://github.com/salesforce/lwc/blob/b584d39/packages/%40lwc/template-compiler/src/parser/attribute.ts#L217-L221
13028
- // For example, an element might be rendered as `<input type=checkbox>` but `input.checked` could
13029
- // still return true. `value` behaves similarly. `value` and `checked` behave surprisingly
13030
- // because the attributes actually represent the "default" value rather than the current one:
13031
- // - https://jakearchibald.com/2024/attributes-vs-properties/#value-on-input-fields
13032
- // - https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/checkbox#checked
13033
- if (isProp) {
13034
- // The below logic matches the behavior of non-static-optimized DOM nodes.
13035
- // There is no functional difference between e.g. `checked="checked"` and `checked` but we
13036
- // match byte-for-byte the non-static-optimized HTML that would be rendered.
13037
- if (name === 'checked' || (name === 'value' && value === '')) {
13038
- attrs.push(` ${escapedAttributeName}`);
13039
- }
13040
- else {
13041
- attrs.push(` ${escapedAttributeName}="${htmlEscape(String(value), true)}"`);
13042
- }
13043
- }
13044
- else if (typeof value === 'string') {
13047
+ if (typeof value === 'string') {
13045
13048
  let v = templateStringEscape(value);
13046
13049
  if (name === 'class') {
13047
13050
  // ${0} maps to class token that will be appended to the string.
@@ -13077,7 +13080,6 @@ function serializeAttrs(element, codeGen) {
13077
13080
  // Skip serializing here and handle it as if it were a dynamic attribute instead.
13078
13081
  // Note that, to maintain backwards compatibility with the non-static output, we treat the valueless
13079
13082
  // "boolean" format (e.g. `<div id>`) as the empty string, which is semantically equivalent.
13080
- // `isProp` corresponds to `value` or `checked` on an `<input>` which is treated as a prop at runtime.
13081
13083
  const needsPlaceholder = hasExpression || hasSvgUseHref || needsScoping;
13082
13084
  let nameAndValue;
13083
13085
  if (needsPlaceholder) {
@@ -13122,7 +13124,6 @@ function serializeAttrs(element, codeGen) {
13122
13124
  return {
13123
13125
  hasExpression,
13124
13126
  hasSvgUseHref,
13125
- isProp: false,
13126
13127
  needsScoping,
13127
13128
  name,
13128
13129
  value: hasExpression || hasSvgUseHref || needsScoping
@@ -13132,26 +13133,12 @@ function serializeAttrs(element, codeGen) {
13132
13133
  };
13133
13134
  })
13134
13135
  .forEach(collector);
13135
- // See note above about `<input value>`/`<input checked>`
13136
- element.properties
13137
- .map((prop) => {
13138
- const { attributeName, value } = prop;
13139
- // Sanity check to ensure that only `<input value>`/`<input checked>` are treated as props
13140
- /* v8 ignore start */
13141
- if (process.env.NODE_ENV === 'test') {
13142
- if (element.name !== 'input' &&
13143
- !(attributeName === 'checked' || attributeName === 'value')) {
13144
- throw new Error('Expected to only see `<input value>`/`<input checked>` here; instead found `<${element.name} ${attributeName}>');
13145
- }
13146
- }
13147
- /* v8 ignore stop */
13148
- return {
13149
- name: attributeName,
13150
- value: value.value,
13151
- isProp: true,
13152
- };
13153
- })
13154
- .forEach(collector);
13136
+ /* v8 ignore start */
13137
+ // TODO [#4775]: allow static optimization for `<input value>`/`<input checked>`
13138
+ if (process.env.NODE_ENV === 'test' && element.properties.length > 0) {
13139
+ throw new Error('Expected zero properties at this point, found ' + element.properties.length);
13140
+ }
13141
+ /* v8 ignore stop */
13155
13142
  // ${2} maps to style token attribute
13156
13143
  // ${3} maps to class attribute token + style token attribute
13157
13144
  // See buildParseFragmentFn for details.
@@ -14689,5 +14676,5 @@ function compile(source, filename, config) {
14689
14676
  }
14690
14677
 
14691
14678
  export { ElementDirectiveName, LWCDirectiveDomMode, LWCDirectiveRenderMode, LwcTagName, RootDirectiveName, TemplateDirectiveName, compile, compile as default, generateScopeTokens, kebabcaseToCamelcase, parse, toPropertyName };
14692
- /** version: 8.6.0 */
14679
+ /** version: 8.7.0 */
14693
14680
  //# sourceMappingURL=index.js.map