@lwc/template-compiler 8.6.0 → 8.8.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.cjs.js CHANGED
@@ -12902,8 +12902,30 @@ function isStaticNode(node, apiVersion) {
12902
12902
  });
12903
12903
  // all directives are static-safe
12904
12904
  result &&= !directives.some((directive) => !STATIC_SAFE_DIRECTIVES.has(directive.name));
12905
- // all properties are static
12906
- result &&= properties.every((prop) => isLiteral(prop.value));
12905
+ // Sanity check to ensure that only `<input value>`/`<input checked>` are treated as props for elements
12906
+ /* v8 ignore start */
12907
+ if (process.env.NODE_ENV === 'test' && isElement(node)) {
12908
+ for (const { attributeName } of properties) {
12909
+ if (node.name !== 'input' &&
12910
+ !(attributeName === 'checked' || attributeName === 'value')) {
12911
+ throw new Error(`Expected to only see <input value>/<input checked> treated as an element prop. ` +
12912
+ `Instead found <${node.name} ${attributeName}>`);
12913
+ }
12914
+ }
12915
+ }
12916
+ /* v8 ignore stop */
12917
+ // `<input checked="...">` and `<input value="...">` have a peculiar attr/prop relationship, so the engine
12918
+ // has historically treated them as props rather than attributes:
12919
+ // https://github.com/salesforce/lwc/blob/b584d39/packages/%40lwc/template-compiler/src/parser/attribute.ts#L217-L221
12920
+ // For example, an element might be rendered as `<input type=checkbox>` but `input.checked` could
12921
+ // still return true. `value` behaves similarly. `value` and `checked` behave surprisingly
12922
+ // because the attributes actually represent the "default" value rather than the current one:
12923
+ // - https://jakearchibald.com/2024/attributes-vs-properties/#value-on-input-fields
12924
+ // - https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/checkbox#checked
12925
+ // For this reason, we currently avoid the static content optimization, and treat `value`/`checked` only as
12926
+ // runtime props.
12927
+ // TODO [#4775]: allow static optimization for `<input value>`/`<input checked>`
12928
+ result &&= properties.length === 0;
12907
12929
  return result;
12908
12930
  }
12909
12931
  function collectStaticNodes(node, staticNodes, state) {
@@ -13039,33 +13061,14 @@ function serializeAttrs(element, codeGen) {
13039
13061
  */
13040
13062
  const attrs = [];
13041
13063
  let hasClassAttr = false;
13042
- const collector = ({ name, value, isProp, hasExpression, hasSvgUseHref, needsScoping, }) => {
13064
+ const collector = ({ name, value, hasExpression, hasSvgUseHref, needsScoping, }) => {
13043
13065
  // Do not serialize boolean class/style attribute (consistent with non-static optimized)
13044
13066
  if (typeof value === 'boolean' && (name === 'class' || name === 'style')) {
13045
13067
  return;
13046
13068
  }
13047
13069
  // See W-16614169
13048
13070
  const escapedAttributeName = templateStringEscape(name);
13049
- // `<input checked="...">` and `<input value="...">` have a peculiar attr/prop relationship, so the engine
13050
- // has historically treated them as props rather than attributes:
13051
- // https://github.com/salesforce/lwc/blob/b584d39/packages/%40lwc/template-compiler/src/parser/attribute.ts#L217-L221
13052
- // For example, an element might be rendered as `<input type=checkbox>` but `input.checked` could
13053
- // still return true. `value` behaves similarly. `value` and `checked` behave surprisingly
13054
- // because the attributes actually represent the "default" value rather than the current one:
13055
- // - https://jakearchibald.com/2024/attributes-vs-properties/#value-on-input-fields
13056
- // - https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/checkbox#checked
13057
- if (isProp) {
13058
- // The below logic matches the behavior of non-static-optimized DOM nodes.
13059
- // There is no functional difference between e.g. `checked="checked"` and `checked` but we
13060
- // match byte-for-byte the non-static-optimized HTML that would be rendered.
13061
- if (name === 'checked' || (name === 'value' && value === '')) {
13062
- attrs.push(` ${escapedAttributeName}`);
13063
- }
13064
- else {
13065
- attrs.push(` ${escapedAttributeName}="${shared.htmlEscape(String(value), true)}"`);
13066
- }
13067
- }
13068
- else if (typeof value === 'string') {
13071
+ if (typeof value === 'string') {
13069
13072
  let v = templateStringEscape(value);
13070
13073
  if (name === 'class') {
13071
13074
  // ${0} maps to class token that will be appended to the string.
@@ -13091,7 +13094,7 @@ function serializeAttrs(element, codeGen) {
13091
13094
  v = String(v.toLowerCase() !== 'false');
13092
13095
  }
13093
13096
  if (name === 'style' && !hasExpression) {
13094
- v = shared.normalizeStyleAttribute(v);
13097
+ v = shared.normalizeStyleAttributeValue(v);
13095
13098
  if (v === '') {
13096
13099
  // Do not serialize empty style attribute (consistent with non-static optimized)
13097
13100
  return;
@@ -13101,7 +13104,6 @@ function serializeAttrs(element, codeGen) {
13101
13104
  // Skip serializing here and handle it as if it were a dynamic attribute instead.
13102
13105
  // Note that, to maintain backwards compatibility with the non-static output, we treat the valueless
13103
13106
  // "boolean" format (e.g. `<div id>`) as the empty string, which is semantically equivalent.
13104
- // `isProp` corresponds to `value` or `checked` on an `<input>` which is treated as a prop at runtime.
13105
13107
  const needsPlaceholder = hasExpression || hasSvgUseHref || needsScoping;
13106
13108
  let nameAndValue;
13107
13109
  if (needsPlaceholder) {
@@ -13146,7 +13148,6 @@ function serializeAttrs(element, codeGen) {
13146
13148
  return {
13147
13149
  hasExpression,
13148
13150
  hasSvgUseHref,
13149
- isProp: false,
13150
13151
  needsScoping,
13151
13152
  name,
13152
13153
  value: hasExpression || hasSvgUseHref || needsScoping
@@ -13156,26 +13157,12 @@ function serializeAttrs(element, codeGen) {
13156
13157
  };
13157
13158
  })
13158
13159
  .forEach(collector);
13159
- // See note above about `<input value>`/`<input checked>`
13160
- element.properties
13161
- .map((prop) => {
13162
- const { attributeName, value } = prop;
13163
- // Sanity check to ensure that only `<input value>`/`<input checked>` are treated as props
13164
- /* v8 ignore start */
13165
- if (process.env.NODE_ENV === 'test') {
13166
- if (element.name !== 'input' &&
13167
- !(attributeName === 'checked' || attributeName === 'value')) {
13168
- throw new Error('Expected to only see `<input value>`/`<input checked>` here; instead found `<${element.name} ${attributeName}>');
13169
- }
13170
- }
13171
- /* v8 ignore stop */
13172
- return {
13173
- name: attributeName,
13174
- value: value.value,
13175
- isProp: true,
13176
- };
13177
- })
13178
- .forEach(collector);
13160
+ /* v8 ignore start */
13161
+ // TODO [#4775]: allow static optimization for `<input value>`/`<input checked>`
13162
+ if (process.env.NODE_ENV === 'test' && element.properties.length > 0) {
13163
+ throw new Error('Expected zero properties at this point, found ' + element.properties.length);
13164
+ }
13165
+ /* v8 ignore stop */
13179
13166
  // ${2} maps to style token attribute
13180
13167
  // ${3} maps to class attribute token + style token attribute
13181
13168
  // See buildParseFragmentFn for details.
@@ -14718,5 +14705,5 @@ exports.generateScopeTokens = generateScopeTokens;
14718
14705
  exports.kebabcaseToCamelcase = kebabcaseToCamelcase;
14719
14706
  exports.parse = parse;
14720
14707
  exports.toPropertyName = toPropertyName;
14721
- /** version: 8.6.0 */
14708
+ /** version: 8.8.0 */
14722
14709
  //# sourceMappingURL=index.cjs.js.map