@lwc/template-compiler 7.0.3-alpha.0 → 7.0.4
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 +77 -45
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.js +77 -45
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.cjs.js
CHANGED
|
@@ -12961,15 +12961,15 @@ function parseStyleText(cssText) {
|
|
|
12961
12961
|
}
|
|
12962
12962
|
return styleMap;
|
|
12963
12963
|
}
|
|
12964
|
+
const IMPORTANT_FLAG = /\s*!\s*important\s*$/i;
|
|
12964
12965
|
// Given a map of CSS property keys to values, return an array AST like:
|
|
12965
12966
|
// ['color', 'blue', false] // { color: 'blue' }
|
|
12966
12967
|
// ['background', 'red', true] // { background: 'red !important' }
|
|
12967
12968
|
function styleMapToStyleDeclsAST(styleMap) {
|
|
12968
12969
|
const styles = Object.entries(styleMap).map(([key, value]) => {
|
|
12969
|
-
const important =
|
|
12970
|
+
const important = IMPORTANT_FLAG.test(value);
|
|
12970
12971
|
if (important) {
|
|
12971
|
-
|
|
12972
|
-
value = value.substring(0, value.length - 10).trim();
|
|
12972
|
+
value = value.replace(IMPORTANT_FLAG, '').trim();
|
|
12973
12973
|
}
|
|
12974
12974
|
return [key, value, important];
|
|
12975
12975
|
});
|
|
@@ -12996,7 +12996,7 @@ const STATIC_ELEMENT_WITH_DYNAMIC_TEXT_SET = new WeakSet();
|
|
|
12996
12996
|
const STATIC_ELEMENT_TO_DYNAMIC_TEXT_CHILDREN_CACHE = new WeakMap();
|
|
12997
12997
|
function isStaticNode(node, apiVersion) {
|
|
12998
12998
|
let result = true;
|
|
12999
|
-
const {
|
|
12999
|
+
const { namespace = '', attributes, directives, properties } = node;
|
|
13000
13000
|
// SVG is excluded from static content optimization in older API versions due to issues with case sensitivity
|
|
13001
13001
|
// in CSS scope tokens. See https://github.com/salesforce/lwc/issues/3313
|
|
13002
13002
|
if (!shared.isAPIFeatureEnabled(0 /* APIFeature.LOWERCASE_SCOPE_TOKENS */, apiVersion) &&
|
|
@@ -13007,23 +13007,10 @@ function isStaticNode(node, apiVersion) {
|
|
|
13007
13007
|
result &&= isElement(node);
|
|
13008
13008
|
// all attrs are static-safe
|
|
13009
13009
|
// the criteria to determine safety can be found in computeAttrValue
|
|
13010
|
-
result &&= attributes.every(({ name
|
|
13011
|
-
|
|
13012
|
-
|
|
13013
|
-
|
|
13014
|
-
name !== 'id' &&
|
|
13015
|
-
!isIdReferencingAttribute(name) &&
|
|
13016
|
-
// svg href needs sanitization.
|
|
13017
|
-
!isSvgUseHref(nodeName, name, namespace) &&
|
|
13018
|
-
// Check for ScopedFragId
|
|
13019
|
-
!(isAllowedFragOnlyUrlsXHTML(nodeName, name, namespace) &&
|
|
13020
|
-
isFragmentOnlyUrl(value.value));
|
|
13021
|
-
const isStaticSafeExpression = isExpression$1(value) &&
|
|
13022
|
-
name !== 'slot' &&
|
|
13023
|
-
// TODO [#3624]: Revisit whether svgs can be included in static content optimization
|
|
13024
|
-
// svg href needs sanitization.
|
|
13025
|
-
!isSvgUseHref(nodeName, name, namespace);
|
|
13026
|
-
return isStaticSafeLiteral || isStaticSafeExpression;
|
|
13010
|
+
result &&= attributes.every(({ name }) => {
|
|
13011
|
+
// Slots are not safe because the VDOM handles them specially in synthetic shadow and light DOM mode
|
|
13012
|
+
// TODO [#4351]: `disableSyntheticShadowSupport` should allow slots to be static-optimized
|
|
13013
|
+
return name !== 'slot';
|
|
13027
13014
|
});
|
|
13028
13015
|
// all directives are static-safe
|
|
13029
13016
|
result &&= !directives.some((directive) => !STATIC_SAFE_DIRECTIVES.has(directive.name));
|
|
@@ -13161,7 +13148,7 @@ function serializeAttrs(element, codeGen) {
|
|
|
13161
13148
|
*/
|
|
13162
13149
|
const attrs = [];
|
|
13163
13150
|
let hasClassAttr = false;
|
|
13164
|
-
const collector = ({ name, value, hasExpression, }) => {
|
|
13151
|
+
const collector = ({ name, value, hasExpression, hasIdOrIdRef, hasSvgUseHref, hasScopedFragmentRef, }) => {
|
|
13165
13152
|
let v = typeof value === 'string' ? templateStringEscape(value) : value;
|
|
13166
13153
|
if (name === 'class') {
|
|
13167
13154
|
hasClassAttr = true;
|
|
@@ -13182,9 +13169,15 @@ function serializeAttrs(element, codeGen) {
|
|
|
13182
13169
|
v = String(v.toLowerCase() !== 'false');
|
|
13183
13170
|
}
|
|
13184
13171
|
if (typeof v === 'string') {
|
|
13172
|
+
// IDs/IDRefs must be handled dynamically at runtime due to synthetic shadow scoping.
|
|
13173
|
+
// Skip serializing here and handle it as if it were a dynamic attribute instead.
|
|
13174
|
+
// Note that, to maintain backwards compatibility with the non-static output, we treat the valueless
|
|
13175
|
+
// "boolean" format (e.g. `<div id>`) as the empty string, which is semantically equivalent.
|
|
13176
|
+
// TODO [#3658]: `disableSyntheticShadowSupport` should also disable this dynamic behavior
|
|
13177
|
+
const needsPlaceholder = hasExpression || hasIdOrIdRef || hasSvgUseHref || hasScopedFragmentRef;
|
|
13185
13178
|
// Inject a placeholder where the staticPartId will go when an expression occurs.
|
|
13186
13179
|
// This is only needed for SSR to inject the expression value during serialization.
|
|
13187
|
-
attrs.push(
|
|
13180
|
+
attrs.push(needsPlaceholder ? `\${"${v}"}` : ` ${name}="${shared.htmlEscape(v, true)}"`);
|
|
13188
13181
|
}
|
|
13189
13182
|
else {
|
|
13190
13183
|
attrs.push(` ${name}`);
|
|
@@ -13192,13 +13185,29 @@ function serializeAttrs(element, codeGen) {
|
|
|
13192
13185
|
};
|
|
13193
13186
|
element.attributes
|
|
13194
13187
|
.map((attr) => {
|
|
13195
|
-
const
|
|
13188
|
+
const { name, value } = attr;
|
|
13189
|
+
const hasExpression = isExpression$1(value);
|
|
13190
|
+
// IDs/IDRefs must be handled dynamically at runtime due to synthetic shadow scoping.
|
|
13191
|
+
// Note that for backwards compat we only consider non-booleans to be dynamic IDs/IDRefs
|
|
13192
|
+
// TODO [#3658]: `disableSyntheticShadowSupport` should also disable this dynamic behavior
|
|
13193
|
+
const hasIdOrIdRef = (name === 'id' || isIdReferencingAttribute(name)) && !isBooleanLiteral(value);
|
|
13194
|
+
// For boolean literals (e.g. `<use xlink:href>`), there is no reason to sanitize since it's empty
|
|
13195
|
+
const hasSvgUseHref = isSvgUseHref(element.name, name, element.namespace) && !isBooleanLiteral(value);
|
|
13196
|
+
// `<a href="#foo">` and `<area href="#foo">` must be dynamic due to synthetic shadow scoping
|
|
13197
|
+
// Note this only applies if there is an `id` attribute somewhere in the template
|
|
13198
|
+
const hasScopedFragmentRef = codeGen.scopeFragmentId &&
|
|
13199
|
+
isStringLiteral(value) &&
|
|
13200
|
+
isAllowedFragOnlyUrlsXHTML(element.name, name, element.namespace) &&
|
|
13201
|
+
isFragmentOnlyUrl(value.value);
|
|
13196
13202
|
return {
|
|
13197
13203
|
hasExpression,
|
|
13198
|
-
|
|
13199
|
-
|
|
13204
|
+
hasIdOrIdRef,
|
|
13205
|
+
hasSvgUseHref,
|
|
13206
|
+
hasScopedFragmentRef,
|
|
13207
|
+
name,
|
|
13208
|
+
value: hasExpression || hasIdOrIdRef || hasSvgUseHref || hasScopedFragmentRef
|
|
13200
13209
|
? codeGen.getStaticExpressionToken(attr)
|
|
13201
|
-
:
|
|
13210
|
+
: value.value,
|
|
13202
13211
|
};
|
|
13203
13212
|
})
|
|
13204
13213
|
.forEach(collector);
|
|
@@ -13452,16 +13461,21 @@ function bindAttributeExpression(attr, element, codeGen, addLegacySanitizationHo
|
|
|
13452
13461
|
return codeGen.genScopedFragId(expression);
|
|
13453
13462
|
}
|
|
13454
13463
|
if (isSvgUseHref(elmName, attrName, namespace)) {
|
|
13464
|
+
// Apply the fragment id scoping transformation if necessary.
|
|
13465
|
+
// This scoping can be skipped if the value is a string literal that doesn't start with a "#"
|
|
13466
|
+
const value = isStringLiteral(attrValue) && !isFragmentOnlyUrl(attrValue.value)
|
|
13467
|
+
? literal$1(attrValue.value)
|
|
13468
|
+
: codeGen.genScopedFragId(expression);
|
|
13455
13469
|
if (addLegacySanitizationHook) {
|
|
13456
13470
|
codeGen.usedLwcApis.add('sanitizeAttribute');
|
|
13457
13471
|
return callExpression(identifier('sanitizeAttribute'), [
|
|
13458
13472
|
literal$1(elmName),
|
|
13459
13473
|
literal$1(namespace),
|
|
13460
13474
|
literal$1(attrName),
|
|
13461
|
-
|
|
13475
|
+
value,
|
|
13462
13476
|
]);
|
|
13463
13477
|
}
|
|
13464
|
-
return
|
|
13478
|
+
return value;
|
|
13465
13479
|
}
|
|
13466
13480
|
return expression;
|
|
13467
13481
|
}
|
|
@@ -13611,7 +13625,7 @@ class CodeGen {
|
|
|
13611
13625
|
}
|
|
13612
13626
|
genClassExpression(value) {
|
|
13613
13627
|
let classExpression = this.bindExpression(value);
|
|
13614
|
-
const isClassNameObjectBindingEnabled = shared.isAPIFeatureEnabled(
|
|
13628
|
+
const isClassNameObjectBindingEnabled = shared.isAPIFeatureEnabled(10 /* APIFeature.TEMPLATE_CLASS_NAME_OBJECT_BINDING */, this.state.config.apiVersion);
|
|
13615
13629
|
if (isClassNameObjectBindingEnabled) {
|
|
13616
13630
|
classExpression = this.genNormalizeClassName(classExpression);
|
|
13617
13631
|
}
|
|
@@ -13867,13 +13881,13 @@ class CodeGen {
|
|
|
13867
13881
|
};
|
|
13868
13882
|
// Depth-first traversal. We assign a partId to each element, which is an integer based on traversal order.
|
|
13869
13883
|
while (stack.length > 0) {
|
|
13870
|
-
const
|
|
13884
|
+
const currentNode = stack.shift();
|
|
13871
13885
|
// Skip comment nodes in parts count, as they will be stripped in production, unless when `lwc:preserve-comments` is enabled
|
|
13872
|
-
if (isContiguousText(
|
|
13886
|
+
if (isContiguousText(currentNode) || !isComment(currentNode) || this.preserveComments) {
|
|
13873
13887
|
partId++;
|
|
13874
13888
|
}
|
|
13875
|
-
if (isContiguousText(
|
|
13876
|
-
const textNodes =
|
|
13889
|
+
if (isContiguousText(currentNode)) {
|
|
13890
|
+
const textNodes = currentNode;
|
|
13877
13891
|
if (hasDynamicText(textNodes)) {
|
|
13878
13892
|
const partToken = `${"t" /* STATIC_PART_TOKEN_ID.TEXT */}${partId}`;
|
|
13879
13893
|
// Use the first text node as the key.
|
|
@@ -13883,25 +13897,38 @@ class CodeGen {
|
|
|
13883
13897
|
setPartIdText(concatenatedText);
|
|
13884
13898
|
}
|
|
13885
13899
|
}
|
|
13886
|
-
else if (isElement(
|
|
13887
|
-
const elm = current;
|
|
13900
|
+
else if (isElement(currentNode)) {
|
|
13888
13901
|
const databag = [];
|
|
13889
13902
|
// has event listeners
|
|
13890
|
-
if (
|
|
13891
|
-
databag.push(this.genEventListeners(
|
|
13903
|
+
if (currentNode.listeners.length) {
|
|
13904
|
+
databag.push(this.genEventListeners(currentNode.listeners));
|
|
13892
13905
|
}
|
|
13893
13906
|
// See STATIC_SAFE_DIRECTIVES for what's allowed here.
|
|
13894
13907
|
// Also note that we don't generate the 'key' here, because we only support it at the top level
|
|
13895
13908
|
// directly passed into the `api_static_fragment` function, not as a part.
|
|
13896
|
-
for (const directive of
|
|
13909
|
+
for (const directive of currentNode.directives) {
|
|
13897
13910
|
if (directive.name === 'Ref') {
|
|
13898
13911
|
databag.push(this.genRef(directive));
|
|
13899
13912
|
}
|
|
13900
13913
|
}
|
|
13901
13914
|
const attributeExpressions = [];
|
|
13902
|
-
for (const attribute of
|
|
13915
|
+
for (const attribute of currentNode.attributes) {
|
|
13903
13916
|
const { name, value } = attribute;
|
|
13904
|
-
|
|
13917
|
+
// IDs/IDRefs must be handled dynamically at runtime due to synthetic shadow scoping.
|
|
13918
|
+
// Note that for backwards compat we only consider non-booleans to be dynamic IDs/IDRefs
|
|
13919
|
+
// TODO [#3658]: `disableSyntheticShadowSupport` should also disable this dynamic behavior
|
|
13920
|
+
const isIdOrIdRef = (name === 'id' || isIdReferencingAttribute(name)) &&
|
|
13921
|
+
!isBooleanLiteral(value);
|
|
13922
|
+
// For boolean literals (e.g. `<use xlink:href>`), there is no reason to sanitize since it's empty
|
|
13923
|
+
const isSvgHref = isSvgUseHref(currentNode.name, name, currentNode.namespace) &&
|
|
13924
|
+
!isBooleanLiteral(value);
|
|
13925
|
+
// `<a href="#foo">` and `<area href="#foo">` must be dynamic due to synthetic shadow scoping
|
|
13926
|
+
// Note this only applies if there is an `id` attribute somewhere in the template
|
|
13927
|
+
const isScopedFragmentRef = this.scopeFragmentId &&
|
|
13928
|
+
isStringLiteral(value) &&
|
|
13929
|
+
isAllowedFragOnlyUrlsXHTML(currentNode.name, name, currentNode.namespace) &&
|
|
13930
|
+
isFragmentOnlyUrl(value.value);
|
|
13931
|
+
if (isExpression$1(value) || isIdOrIdRef || isSvgHref || isScopedFragmentRef) {
|
|
13905
13932
|
let partToken = '';
|
|
13906
13933
|
if (name === 'style') {
|
|
13907
13934
|
partToken = `${"s" /* STATIC_PART_TOKEN_ID.STYLE */}${partId}`;
|
|
@@ -13912,8 +13939,12 @@ class CodeGen {
|
|
|
13912
13939
|
databag.push(property$1(identifier('className'), this.genClassExpression(value)));
|
|
13913
13940
|
}
|
|
13914
13941
|
else {
|
|
13942
|
+
// non-class, non-style (i.e. generic attribute or ID/IDRef or svg use href)
|
|
13915
13943
|
partToken = `${"a" /* STATIC_PART_TOKEN_ID.ATTRIBUTE */}${partId}:${name}`;
|
|
13916
|
-
attributeExpressions.push(property$1(literal$1(name), bindAttributeExpression(attribute,
|
|
13944
|
+
attributeExpressions.push(property$1(literal$1(name), bindAttributeExpression(attribute, currentNode, this,
|
|
13945
|
+
// `addLegacySanitizationHook` is true because `isCustomRendererHookRequired`
|
|
13946
|
+
// being false is a precondition for static nodes.
|
|
13947
|
+
true)));
|
|
13917
13948
|
}
|
|
13918
13949
|
this.staticExpressionMap.set(attribute, partToken);
|
|
13919
13950
|
}
|
|
@@ -13927,7 +13958,7 @@ class CodeGen {
|
|
|
13927
13958
|
// For depth-first traversal, children must be prepended in order, so that they are processed before
|
|
13928
13959
|
// siblings. Note that this is consistent with the order used in the diffing algo as well as
|
|
13929
13960
|
// `traverseAndSetElements` in @lwc/engine-core.
|
|
13930
|
-
stack.unshift(...transformStaticChildren(
|
|
13961
|
+
stack.unshift(...transformStaticChildren(currentNode, this.preserveComments));
|
|
13931
13962
|
}
|
|
13932
13963
|
}
|
|
13933
13964
|
if (partIdsToArgs.size === 0) {
|
|
@@ -14431,7 +14462,8 @@ function transform(codeGen) {
|
|
|
14431
14462
|
return codeGen.genScopedFragId(attrValue.value);
|
|
14432
14463
|
}
|
|
14433
14464
|
if (isSvgUseHref(elmName, attrName, namespace)) {
|
|
14434
|
-
//
|
|
14465
|
+
// Apply the fragment id scoping transformation if necessary.
|
|
14466
|
+
// This scoping can be skipped if the value is a string literal that doesn't start with a "#"
|
|
14435
14467
|
const value = isFragmentOnlyUrl(attrValue.value)
|
|
14436
14468
|
? codeGen.genScopedFragId(attrValue.value)
|
|
14437
14469
|
: literal$1(attrValue.value);
|
|
@@ -14680,5 +14712,5 @@ exports.default = compile;
|
|
|
14680
14712
|
exports.kebabcaseToCamelcase = kebabcaseToCamelcase;
|
|
14681
14713
|
exports.parse = parse;
|
|
14682
14714
|
exports.toPropertyName = toPropertyName;
|
|
14683
|
-
/** version: 7.0.
|
|
14715
|
+
/** version: 7.0.4 */
|
|
14684
14716
|
//# sourceMappingURL=index.cjs.js.map
|