@lwc/ssr-compiler 8.5.0 → 8.6.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/estree/validators.d.ts +7 -1
- package/dist/index.cjs.js +89 -38
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.js +89 -38
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
|
@@ -14,9 +14,15 @@ type RenderCall = CallExpression & {
|
|
|
14
14
|
callee: RenderMemberExpression;
|
|
15
15
|
};
|
|
16
16
|
/** Returns `true` if the node is an identifier or `<something>.render()`. */
|
|
17
|
-
export declare const isIdentOrRenderCall:
|
|
17
|
+
export declare const isIdentOrRenderCall: {
|
|
18
|
+
(node: Node | null | undefined): node is Identifier | RenderCall;
|
|
19
|
+
__debugName: string;
|
|
20
|
+
};
|
|
18
21
|
/** A validator that returns `true` if the node is `null`. */
|
|
19
22
|
type NullableChecker<T extends Node> = (node: Node | null | undefined) => node is T | null;
|
|
20
23
|
/** Extends a validator to return `true` if the node is `null`. */
|
|
21
24
|
export declare function isNullableOf<T extends Node>(validator: Checker<T>): NullableChecker<T>;
|
|
25
|
+
export declare namespace isNullableOf {
|
|
26
|
+
var __debugName: string;
|
|
27
|
+
}
|
|
22
28
|
export {};
|
package/dist/index.cjs.js
CHANGED
|
@@ -11,9 +11,9 @@ var meriyah = require('meriyah');
|
|
|
11
11
|
var immer = require('immer');
|
|
12
12
|
var node_path = require('node:path');
|
|
13
13
|
var acorn = require('acorn');
|
|
14
|
+
var shared = require('@lwc/shared');
|
|
14
15
|
var templateCompiler = require('@lwc/template-compiler');
|
|
15
16
|
var builders = require('estree-toolkit/dist/builders');
|
|
16
|
-
var shared = require('@lwc/shared');
|
|
17
17
|
var util = require('util');
|
|
18
18
|
|
|
19
19
|
/*
|
|
@@ -297,10 +297,13 @@ const getReplacementNode = (state, placeholderId) => {
|
|
|
297
297
|
!(Array.isArray(replacementNode)
|
|
298
298
|
? replacementNode.every(validateReplacement)
|
|
299
299
|
: validateReplacement(replacementNode))) {
|
|
300
|
-
const
|
|
300
|
+
const expectedType = validateReplacement.__debugName ||
|
|
301
|
+
validateReplacement.name ||
|
|
302
|
+
'(could not determine)';
|
|
303
|
+
const actualType = Array.isArray(replacementNode)
|
|
301
304
|
? `[${replacementNode.map((n) => n.type)}.join(', ')]`
|
|
302
305
|
: replacementNode?.type;
|
|
303
|
-
throw new Error(`Validation failed for templated node
|
|
306
|
+
throw new Error(`Validation failed for templated node. Expected type ${expectedType}, but received ${actualType}.`);
|
|
304
307
|
}
|
|
305
308
|
return replacementNode;
|
|
306
309
|
};
|
|
@@ -431,6 +434,24 @@ const isIdentOrRenderCall = (node) => {
|
|
|
431
434
|
estreeToolkit.is.identifier(node.callee.property) &&
|
|
432
435
|
node.callee.property.name === 'render'));
|
|
433
436
|
};
|
|
437
|
+
isIdentOrRenderCall.__debugName = 'identifier or .render() call';
|
|
438
|
+
/** Extends a validator to return `true` if the node is `null`. */
|
|
439
|
+
function isNullableOf(validator) {
|
|
440
|
+
const nullableValidator = (node) => {
|
|
441
|
+
return node === null || validator(node);
|
|
442
|
+
};
|
|
443
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
444
|
+
nullableValidator.__debugName = `nullable(${validator.__debugName || validator.name || 'unknown validator'})`;
|
|
445
|
+
}
|
|
446
|
+
return nullableValidator;
|
|
447
|
+
}
|
|
448
|
+
isNullableOf.__debugName = 'isNullableOf';
|
|
449
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
450
|
+
// Modifying another package's exports is a code smell!
|
|
451
|
+
for (const [key, val] of shared.entries(estreeToolkit.is)) {
|
|
452
|
+
val.__debugName = key;
|
|
453
|
+
}
|
|
454
|
+
}
|
|
434
455
|
|
|
435
456
|
/*
|
|
436
457
|
* Copyright (c) 2024, salesforce.com, inc.
|
|
@@ -1787,6 +1808,12 @@ var DiagnosticLevel;
|
|
|
1787
1808
|
level: DiagnosticLevel.Error,
|
|
1788
1809
|
url: '',
|
|
1789
1810
|
},
|
|
1811
|
+
IGNORED_SLOT_ATTRIBUTE_IN_CHILD: {
|
|
1812
|
+
code: 1201,
|
|
1813
|
+
message: 'The slot attribute in {0} will be ignored due to its ancestor {1}. It must be a direct child of the containing component.',
|
|
1814
|
+
level: DiagnosticLevel.Warning,
|
|
1815
|
+
url: '',
|
|
1816
|
+
},
|
|
1790
1817
|
});
|
|
1791
1818
|
|
|
1792
1819
|
/**
|
|
@@ -1799,7 +1826,7 @@ var CompilerMetrics;
|
|
|
1799
1826
|
CompilerMetrics["LWCSpreadDirective"] = "lwc-spread-directive";
|
|
1800
1827
|
CompilerMetrics["DynamicImportTransform"] = "dynamic-import-transform";
|
|
1801
1828
|
})(CompilerMetrics || (CompilerMetrics = {}));
|
|
1802
|
-
/** version: 8.
|
|
1829
|
+
/** version: 8.6.0 */
|
|
1803
1830
|
|
|
1804
1831
|
/*
|
|
1805
1832
|
* Copyright (c) 2024, Salesforce, Inc.
|
|
@@ -1976,13 +2003,16 @@ const bYieldFromChildGenerator = (esTemplateWithYield `
|
|
|
1976
2003
|
slottedContent.light[name] = [fn]
|
|
1977
2004
|
}
|
|
1978
2005
|
}
|
|
1979
|
-
${ /* addContent statements */estreeToolkit.is.callExpression}
|
|
2006
|
+
${ /* light DOM addContent statements */estreeToolkit.is.callExpression}
|
|
2007
|
+
${ /* scoped slot addContent statements */estreeToolkit.is.callExpression}
|
|
1980
2008
|
yield* ${estreeToolkit.is.identifier}(${estreeToolkit.is.literal}, childProps, childAttrs, slottedContent);
|
|
1981
2009
|
}
|
|
1982
2010
|
`);
|
|
1983
2011
|
const bAddContent = (esTemplate `
|
|
1984
|
-
addContent(${ /* slot name */estreeToolkit.is.expression} ?? "", async function* (
|
|
1985
|
-
|
|
2012
|
+
addContent(${ /* slot name */estreeToolkit.is.expression} ?? "", async function* (${
|
|
2013
|
+
/* scoped slot data variable */ isNullableOf(estreeToolkit.is.identifier)}) {
|
|
2014
|
+
// FIXME: make validation work again
|
|
2015
|
+
${ /* slot content */false}
|
|
1986
2016
|
});
|
|
1987
2017
|
`);
|
|
1988
2018
|
const bImportGenerateMarkup = (localName, importPath) => estreeToolkit.builders.importDeclaration([estreeToolkit.builders.importSpecifier(estreeToolkit.builders.identifier('generateMarkup'), estreeToolkit.builders.identifier(localName))], estreeToolkit.builders.literal(importPath));
|
|
@@ -2006,20 +2036,6 @@ function getChildAttrsOrProps(attrs, cxt) {
|
|
|
2006
2036
|
});
|
|
2007
2037
|
return estreeToolkit.builders.objectExpression(objectAttrsOrProps);
|
|
2008
2038
|
}
|
|
2009
|
-
function reflectAriaPropsAsAttrs(props) {
|
|
2010
|
-
return props
|
|
2011
|
-
.map((prop) => {
|
|
2012
|
-
if (prop.attributeName.startsWith('aria-') || prop.attributeName === 'role') {
|
|
2013
|
-
return {
|
|
2014
|
-
type: 'Attribute',
|
|
2015
|
-
name: prop.attributeName,
|
|
2016
|
-
value: prop.value,
|
|
2017
|
-
};
|
|
2018
|
-
}
|
|
2019
|
-
return null;
|
|
2020
|
-
})
|
|
2021
|
-
.filter((el) => el !== null);
|
|
2022
|
-
}
|
|
2023
2039
|
const Component = function Component(node, cxt) {
|
|
2024
2040
|
// Import the custom component's generateMarkup export.
|
|
2025
2041
|
const childGeneratorLocalName = `generateMarkup_${templateCompiler.toPropertyName(node.name)}`;
|
|
@@ -2027,25 +2043,35 @@ const Component = function Component(node, cxt) {
|
|
|
2027
2043
|
const componentImport = bImportGenerateMarkup(childGeneratorLocalName, importPath);
|
|
2028
2044
|
cxt.hoist(componentImport, childGeneratorLocalName);
|
|
2029
2045
|
const childTagName = node.name;
|
|
2030
|
-
|
|
2031
|
-
const
|
|
2032
|
-
const
|
|
2046
|
+
// Anything inside the slotted content is a normal slotted content except for `<template lwc:slot-data>` which is a scoped slot.
|
|
2047
|
+
const slottableChildren = node.children.filter((child) => child.type !== 'ScopedSlotFragment');
|
|
2048
|
+
const scopedSlottableChildren = node.children.filter((child) => child.type === 'ScopedSlotFragment');
|
|
2049
|
+
const shadowSlotContent = optimizeAdjacentYieldStmts(irChildrenToEs(slottableChildren, cxt));
|
|
2050
|
+
const lightSlotContent = slottableChildren.map((child) => {
|
|
2033
2051
|
if ('attributes' in child) {
|
|
2034
2052
|
const slotName = bAttributeValue(child, 'slot');
|
|
2035
|
-
// FIXME: We don't know what happens for slot attributes inside an lwc:if block
|
|
2036
2053
|
// Light DOM slots do not actually render the `slot` attribute.
|
|
2037
2054
|
const clone = immer.produce(child, (draft) => {
|
|
2038
2055
|
draft.attributes = draft.attributes.filter((attr) => attr.name !== 'slot');
|
|
2039
2056
|
});
|
|
2040
2057
|
const slotContent = irToEs(clone, cxt);
|
|
2041
|
-
return bAddContent(slotName, slotContent);
|
|
2058
|
+
return bAddContent(slotName, null, slotContent);
|
|
2042
2059
|
}
|
|
2043
2060
|
else {
|
|
2044
|
-
return bAddContent(estreeToolkit.builders.literal(''), irToEs(child, cxt));
|
|
2061
|
+
return bAddContent(estreeToolkit.builders.literal(''), null, irToEs(child, cxt));
|
|
2045
2062
|
}
|
|
2046
2063
|
});
|
|
2064
|
+
const scopedSlotContent = scopedSlottableChildren.map((child) => {
|
|
2065
|
+
const boundVariableName = child.slotData.value.name;
|
|
2066
|
+
const boundVariable = estreeToolkit.builders.identifier(boundVariableName);
|
|
2067
|
+
cxt.pushLocalVars([boundVariableName]);
|
|
2068
|
+
// TODO [#4768]: what if the bound variable is `generateMarkup` or some framework-specific identifier?
|
|
2069
|
+
const addContentExpr = bAddContent(child.slotName, boundVariable, irChildrenToEs(child.children, cxt));
|
|
2070
|
+
cxt.popLocalVars();
|
|
2071
|
+
return addContentExpr;
|
|
2072
|
+
});
|
|
2047
2073
|
return [
|
|
2048
|
-
bYieldFromChildGenerator(getChildAttrsOrProps(node.properties, cxt), getChildAttrsOrProps(attributes, cxt), shadowSlotContent, lightSlotContent, estreeToolkit.builders.identifier(childGeneratorLocalName), estreeToolkit.builders.literal(childTagName)),
|
|
2074
|
+
bYieldFromChildGenerator(getChildAttrsOrProps(node.properties, cxt), getChildAttrsOrProps(node.attributes, cxt), shadowSlotContent, lightSlotContent, scopedSlotContent, estreeToolkit.builders.identifier(childGeneratorLocalName), estreeToolkit.builders.literal(childTagName)),
|
|
2049
2075
|
];
|
|
2050
2076
|
};
|
|
2051
2077
|
|
|
@@ -2091,6 +2117,9 @@ const bConditionallyYieldScopeTokenClass = (esTemplateWithYield `
|
|
|
2091
2117
|
}
|
|
2092
2118
|
}
|
|
2093
2119
|
`);
|
|
2120
|
+
const bYieldSanitizedHtml = esTemplateWithYield `
|
|
2121
|
+
yield sanitizeHtmlContent(${ /* lwc:inner-html content */estreeToolkit.is.expression})
|
|
2122
|
+
`;
|
|
2094
2123
|
function yieldAttrOrPropLiteralValue(name, valueNode, isClass) {
|
|
2095
2124
|
const { value, type } = valueNode;
|
|
2096
2125
|
if (typeof value === 'string') {
|
|
@@ -2143,10 +2172,15 @@ const Element = function Element(node, cxt) {
|
|
|
2143
2172
|
let hasClassAttribute = false;
|
|
2144
2173
|
const yieldAttrsAndProps = attrsAndProps.flatMap((attr) => {
|
|
2145
2174
|
const { name, value, type } = attr;
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2175
|
+
let isClass = false;
|
|
2176
|
+
if (type === 'Attribute') {
|
|
2177
|
+
if (name === 'inner-h-t-m-l' || name === 'outer-h-t-m-l') {
|
|
2178
|
+
throw new Error(`Cannot set attribute "${name}" on <${node.name}>.`);
|
|
2179
|
+
}
|
|
2180
|
+
else if (name === 'class') {
|
|
2181
|
+
isClass = true;
|
|
2182
|
+
hasClassAttribute = true;
|
|
2183
|
+
}
|
|
2150
2184
|
}
|
|
2151
2185
|
cxt.hoist(bImportHtmlEscape(), importHtmlEscapeKey);
|
|
2152
2186
|
if (value.type === 'Literal') {
|
|
@@ -2168,7 +2202,8 @@ const Element = function Element(node, cxt) {
|
|
|
2168
2202
|
else if (innerHtmlDirective) {
|
|
2169
2203
|
const value = innerHtmlDirective.value;
|
|
2170
2204
|
const unsanitizedHtmlExpression = value.type === 'Literal' ? estreeToolkit.builders.literal(value.value) : expressionIrToEs(value, cxt);
|
|
2171
|
-
childContent = [
|
|
2205
|
+
childContent = [bYieldSanitizedHtml(unsanitizedHtmlExpression)];
|
|
2206
|
+
cxt.hoist(bImportDeclaration(['sanitizeHtmlContent']), 'import:sanitizeHtmlContent');
|
|
2172
2207
|
}
|
|
2173
2208
|
else {
|
|
2174
2209
|
childContent = [];
|
|
@@ -2294,13 +2329,19 @@ const IfBlock = function IfBlock(node, cxt) {
|
|
|
2294
2329
|
*/
|
|
2295
2330
|
const bConditionalSlot = (esTemplateWithYield `
|
|
2296
2331
|
if (isLightDom) {
|
|
2297
|
-
|
|
2332
|
+
const isScopedSlot = ${ /* isScopedSlot */estreeToolkit.is.literal};
|
|
2333
|
+
// start bookend HTML comment for light DOM slot vfragment
|
|
2298
2334
|
yield '<!---->';
|
|
2299
2335
|
|
|
2336
|
+
// scoped slot factory has its own vfragment hence its own bookend
|
|
2337
|
+
if (isScopedSlot) {
|
|
2338
|
+
yield '<!---->';
|
|
2339
|
+
}
|
|
2340
|
+
|
|
2300
2341
|
const generators = slottedContent?.light[${ /* slotName */estreeToolkit.is.expression} ?? ""];
|
|
2301
2342
|
if (generators) {
|
|
2302
2343
|
for (const generator of generators) {
|
|
2303
|
-
yield* generator();
|
|
2344
|
+
yield* generator(${ /* scoped slot data */isNullableOf(estreeToolkit.is.expression)});
|
|
2304
2345
|
}
|
|
2305
2346
|
} else {
|
|
2306
2347
|
// If we're in this else block, then the generator _must_ have yielded
|
|
@@ -2310,19 +2351,29 @@ const bConditionalSlot = (esTemplateWithYield `
|
|
|
2310
2351
|
// TODO: default/fallback slot content
|
|
2311
2352
|
${ /* slot fallback content */estreeToolkit.is.statement}
|
|
2312
2353
|
}
|
|
2354
|
+
|
|
2355
|
+
// scoped slot factory has its own vfragment hence its own bookend
|
|
2356
|
+
if (isScopedSlot) {
|
|
2357
|
+
yield '<!---->';
|
|
2358
|
+
}
|
|
2313
2359
|
|
|
2314
|
-
// end bookend HTML comment
|
|
2360
|
+
// end bookend HTML comment for light DOM slot vfragment
|
|
2315
2361
|
yield '<!---->';
|
|
2316
2362
|
} else {
|
|
2317
2363
|
${ /* slot element AST */estreeToolkit.is.statement}
|
|
2318
2364
|
}
|
|
2319
2365
|
`);
|
|
2320
2366
|
const Slot = function Slot(node, ctx) {
|
|
2367
|
+
const slotBindDirective = node.directives.find((dir) => dir.name === 'SlotBind');
|
|
2368
|
+
const slotBound = slotBindDirective?.value
|
|
2369
|
+
? getScopedExpression(slotBindDirective.value, ctx)
|
|
2370
|
+
: null;
|
|
2321
2371
|
const slotName = bAttributeValue(node, 'name');
|
|
2322
2372
|
// FIXME: avoid serializing the slot's children twice
|
|
2323
2373
|
const slotAst = Element(node, ctx);
|
|
2324
2374
|
const slotChildren = irChildrenToEs(node.children, ctx);
|
|
2325
|
-
|
|
2375
|
+
const isScopedSlot = estreeToolkit.builders.literal(Boolean(slotBound));
|
|
2376
|
+
return [bConditionalSlot(isScopedSlot, slotName, slotBound, slotChildren, slotAst)];
|
|
2326
2377
|
};
|
|
2327
2378
|
|
|
2328
2379
|
/*
|
|
@@ -2572,5 +2623,5 @@ function compileTemplateForSSR(src, filename, options, mode = 'asyncYield') {
|
|
|
2572
2623
|
|
|
2573
2624
|
exports.compileComponentForSSR = compileComponentForSSR;
|
|
2574
2625
|
exports.compileTemplateForSSR = compileTemplateForSSR;
|
|
2575
|
-
/** version: 8.
|
|
2626
|
+
/** version: 8.6.0 */
|
|
2576
2627
|
//# sourceMappingURL=index.cjs.js.map
|