@lwc/ssr-compiler 8.12.6 → 8.12.7
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/compile-js/types.d.ts +2 -2
- package/dist/compile-template/ir-to-es.d.ts +1 -1
- package/dist/index.cjs.js +75 -18
- package/dist/index.js +75 -18
- package/package.json +6 -6
|
@@ -20,8 +20,8 @@ export interface ComponentMetaState {
|
|
|
20
20
|
tmplExplicitImports: Map<string, string> | null;
|
|
21
21
|
cssExplicitImports: Map<string, string> | null;
|
|
22
22
|
staticStylesheetIds: Set<string> | null;
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
publicProperties: Array<string>;
|
|
24
|
+
privateProperties: Array<string>;
|
|
25
25
|
wireAdapters: WireAdapter[];
|
|
26
26
|
experimentalDynamicComponent: ComponentTransformOptions['experimentalDynamicComponent'];
|
|
27
27
|
importManager: ImportManager;
|
|
@@ -4,7 +4,7 @@ import type { TemplateOpts, TransformerContext } from './types';
|
|
|
4
4
|
export declare function irChildrenToEs(children: IrChildNode[], cxt: TransformerContext, cb?: (child: IrChildNode) => (() => void) | void): EsStatement[];
|
|
5
5
|
export declare function irToEs<T extends IrNode>(node: T, cxt: TransformerContext): EsStatement[];
|
|
6
6
|
export declare function templateIrToEsTree(node: IrNode, contextOpts: TemplateOpts): {
|
|
7
|
-
addImport: (imports: string | string[] | Record<string, string | undefined>, source?: string
|
|
7
|
+
addImport: (imports: string | string[] | Record<string, string | undefined>, source?: string) => void;
|
|
8
8
|
getImports: () => import("estree").ImportDeclaration[];
|
|
9
9
|
statements: EsStatement[];
|
|
10
10
|
};
|
package/dist/index.cjs.js
CHANGED
|
@@ -738,8 +738,8 @@ function bWireAdaptersPlumbing(adapters) {
|
|
|
738
738
|
*/
|
|
739
739
|
const bGenerateMarkup = (esTemplate `
|
|
740
740
|
// These variables may mix with component-authored variables, so should be reasonably unique
|
|
741
|
-
const
|
|
742
|
-
const
|
|
741
|
+
const __lwcPublicProperties__ = new Set(${ /*api*/estreeToolkit.is.arrayExpression});
|
|
742
|
+
const __lwcPrivateProperties__ = new Set(${ /*private fields*/estreeToolkit.is.arrayExpression});
|
|
743
743
|
|
|
744
744
|
async function* generateMarkup(
|
|
745
745
|
tagName,
|
|
@@ -765,8 +765,8 @@ const bGenerateMarkup = (esTemplate `
|
|
|
765
765
|
instance[__SYMBOL__SET_INTERNALS](
|
|
766
766
|
props,
|
|
767
767
|
attrs,
|
|
768
|
-
|
|
769
|
-
|
|
768
|
+
__lwcPublicProperties__,
|
|
769
|
+
__lwcPrivateProperties__,
|
|
770
770
|
);
|
|
771
771
|
instance.isConnected = true;
|
|
772
772
|
if (instance.connectedCallback) {
|
|
@@ -816,7 +816,7 @@ const bExposeTemplate = (esTemplate `
|
|
|
816
816
|
* - deferring to the template function for yielding child content
|
|
817
817
|
*/
|
|
818
818
|
function addGenerateMarkupFunction(program, state, tagName, filename) {
|
|
819
|
-
const {
|
|
819
|
+
const { privateProperties, publicProperties, tmplExplicitImports } = state;
|
|
820
820
|
// The default tag name represents the component name that's passed to the transformer.
|
|
821
821
|
// This is needed to generate markup for dynamic components which are invoked through
|
|
822
822
|
// the generateMarkup function on the constructor.
|
|
@@ -846,7 +846,7 @@ function addGenerateMarkupFunction(program, state, tagName, filename) {
|
|
|
846
846
|
SYMBOL__SET_INTERNALS: '__SYMBOL__SET_INTERNALS',
|
|
847
847
|
establishContextfulRelationship: '__establishContextfulRelationship',
|
|
848
848
|
}));
|
|
849
|
-
program.body.push(...bGenerateMarkup(estreeToolkit.builders.arrayExpression(
|
|
849
|
+
program.body.push(...bGenerateMarkup(estreeToolkit.builders.arrayExpression(publicProperties.map(estreeToolkit.builders.literal)), estreeToolkit.builders.arrayExpression(privateProperties.map(estreeToolkit.builders.literal)), defaultTagName, classIdentifier, connectWireAdapterCode));
|
|
850
850
|
if (exposeTemplateBlock) {
|
|
851
851
|
program.body.push(exposeTemplateBlock);
|
|
852
852
|
}
|
|
@@ -939,23 +939,31 @@ const visitors = {
|
|
|
939
939
|
},
|
|
940
940
|
PropertyDefinition(path, state) {
|
|
941
941
|
const node = path.node;
|
|
942
|
-
if (!
|
|
942
|
+
if (!node?.key) {
|
|
943
|
+
// Seems to occur for `@wire() [symbol];` -- not sure why
|
|
944
|
+
throw new Error('Unknown state: property definition has no key');
|
|
945
|
+
}
|
|
946
|
+
if (!estreeToolkit.is.identifier(node.key)) {
|
|
943
947
|
return;
|
|
944
948
|
}
|
|
945
949
|
const { decorators } = node;
|
|
946
950
|
validateUniqueDecorator(decorators);
|
|
947
951
|
const decoratedExpression = decorators?.[0]?.expression;
|
|
948
952
|
if (estreeToolkit.is.identifier(decoratedExpression) && decoratedExpression.name === 'api') {
|
|
949
|
-
state.
|
|
953
|
+
state.publicProperties.push(node.key.name);
|
|
950
954
|
}
|
|
951
955
|
else if (estreeToolkit.is.callExpression(decoratedExpression) &&
|
|
952
956
|
estreeToolkit.is.identifier(decoratedExpression.callee) &&
|
|
953
957
|
decoratedExpression.callee.name === 'wire') {
|
|
958
|
+
if (node.computed) {
|
|
959
|
+
// TODO [#5032]: Harmonize errors thrown in `@lwc/ssr-compiler`
|
|
960
|
+
throw new Error('@wire cannot be used on computed properties in SSR context.');
|
|
961
|
+
}
|
|
954
962
|
catalogWireAdapters(path, state);
|
|
955
|
-
state.
|
|
963
|
+
state.privateProperties.push(node.key.name);
|
|
956
964
|
}
|
|
957
965
|
else {
|
|
958
|
-
state.
|
|
966
|
+
state.privateProperties.push(node.key.name);
|
|
959
967
|
}
|
|
960
968
|
if (node.static &&
|
|
961
969
|
node.key.name === 'stylesheets' &&
|
|
@@ -981,9 +989,15 @@ const visitors = {
|
|
|
981
989
|
if (estreeToolkit.is.callExpression(decoratedExpression) &&
|
|
982
990
|
estreeToolkit.is.identifier(decoratedExpression.callee) &&
|
|
983
991
|
decoratedExpression.callee.name === 'wire') {
|
|
992
|
+
// not a getter/setter
|
|
993
|
+
const isRealMethod = node.kind === 'method';
|
|
994
|
+
if (node.computed) {
|
|
995
|
+
// TODO [#5032]: Harmonize errors thrown in `@lwc/ssr-compiler`
|
|
996
|
+
throw new Error(`@wire cannot be used on computed ${isRealMethod ? 'method' : 'properties'} in SSR context.`);
|
|
997
|
+
}
|
|
984
998
|
// Getters and setters are methods in the AST, but treated as properties by @wire
|
|
985
999
|
// Note that this means that their implementations are ignored!
|
|
986
|
-
if (
|
|
1000
|
+
if (!isRealMethod) {
|
|
987
1001
|
const methodAsProp = estreeToolkit.builders.propertyDefinition(structuredClone(node.key), null, node.computed, node.static);
|
|
988
1002
|
methodAsProp.decorators = structuredClone(decorators);
|
|
989
1003
|
path.replaceWith(methodAsProp);
|
|
@@ -996,6 +1010,13 @@ const visitors = {
|
|
|
996
1010
|
catalogWireAdapters(path, state);
|
|
997
1011
|
}
|
|
998
1012
|
}
|
|
1013
|
+
else if (estreeToolkit.is.identifier(decoratedExpression) && decoratedExpression.name === 'api') {
|
|
1014
|
+
if (state.publicProperties.includes(node.key.name)) {
|
|
1015
|
+
// TODO [#5032]: Harmonize errors thrown in `@lwc/ssr-compiler`
|
|
1016
|
+
throw new Error(`LWC1112: @api get ${node.key.name} and @api set ${node.key.name} detected in class declaration. Only one of the two needs to be decorated with @api.`);
|
|
1017
|
+
}
|
|
1018
|
+
state.publicProperties.push(node.key.name);
|
|
1019
|
+
}
|
|
999
1020
|
switch (node.key.name) {
|
|
1000
1021
|
case 'constructor':
|
|
1001
1022
|
// add our own custom arg after any pre-existing constructor args
|
|
@@ -1080,8 +1101,8 @@ function compileJS(src, filename, tagName, options, compilationMode) {
|
|
|
1080
1101
|
tmplExplicitImports: null,
|
|
1081
1102
|
cssExplicitImports: null,
|
|
1082
1103
|
staticStylesheetIds: null,
|
|
1083
|
-
|
|
1084
|
-
|
|
1104
|
+
publicProperties: [],
|
|
1105
|
+
privateProperties: [],
|
|
1085
1106
|
wireAdapters: [],
|
|
1086
1107
|
experimentalDynamicComponent: options.experimentalDynamicComponent,
|
|
1087
1108
|
importManager: new ImportManager(),
|
|
@@ -1476,7 +1497,7 @@ const bGenerateSlottedContent = (esTemplateWithYield `
|
|
|
1476
1497
|
// than a function _declaration_, so it isn't available to be referenced anywhere.
|
|
1477
1498
|
const bAddSlottedContent = (esTemplate `
|
|
1478
1499
|
addSlottedContent(${ /* slot name */estreeToolkit.is.expression} ?? "", async function* generateSlottedContent(contextfulParent, ${
|
|
1479
|
-
/* scoped slot data variable */ isNullableOf(estreeToolkit.is.identifier)}) {
|
|
1500
|
+
/* scoped slot data variable */ isNullableOf(estreeToolkit.is.identifier)}, slotAttributeValue) {
|
|
1480
1501
|
// FIXME: make validation work again
|
|
1481
1502
|
${ /* slot content */false}
|
|
1482
1503
|
}, ${ /* content map */estreeToolkit.is.identifier});
|
|
@@ -1624,6 +1645,13 @@ const bYieldFromChildGenerator = (esTemplateWithYield `
|
|
|
1624
1645
|
{
|
|
1625
1646
|
const childProps = ${ /* child props */estreeToolkit.is.objectExpression};
|
|
1626
1647
|
const childAttrs = ${ /* child attrs */estreeToolkit.is.objectExpression};
|
|
1648
|
+
/*
|
|
1649
|
+
If 'slotAttributeValue' is set, it references a slot that does not exist, and the 'slot' attribute should be set in the DOM. This behavior aligns with engine-server and engine-dom.
|
|
1650
|
+
See: engine-server/src/__tests__/fixtures/slot-forwarding/slots/dangling/ for example case.
|
|
1651
|
+
*/
|
|
1652
|
+
if (slotAttributeValue) {
|
|
1653
|
+
childAttrs.slot = slotAttributeValue;
|
|
1654
|
+
}
|
|
1627
1655
|
${
|
|
1628
1656
|
/*
|
|
1629
1657
|
Slotted content is inserted here.
|
|
@@ -1677,6 +1705,13 @@ const bYieldFromDynamicComponentConstructorGenerator = (esTemplateWithYield `
|
|
|
1677
1705
|
}
|
|
1678
1706
|
const childProps = ${ /* child props */estreeToolkit.is.objectExpression};
|
|
1679
1707
|
const childAttrs = ${ /* child attrs */estreeToolkit.is.objectExpression};
|
|
1708
|
+
/*
|
|
1709
|
+
If 'slotAttributeValue' is set, it references a slot that does not exist, and the 'slot' attribute should be set in the DOM. This behavior aligns with engine-server and engine-dom.
|
|
1710
|
+
See: engine-server/src/__tests__/fixtures/slot-forwarding/slots/dangling/ for example case.
|
|
1711
|
+
*/
|
|
1712
|
+
if (slotAttributeValue) {
|
|
1713
|
+
childAttrs.slot = slotAttributeValue;
|
|
1714
|
+
}
|
|
1680
1715
|
${
|
|
1681
1716
|
/*
|
|
1682
1717
|
Slotted content is inserted here.
|
|
@@ -1802,6 +1837,15 @@ const bConditionallyYieldScopeTokenClass = (esTemplateWithYield `
|
|
|
1802
1837
|
yield \` class="\${stylesheetScopeToken}"\`;
|
|
1803
1838
|
}
|
|
1804
1839
|
`);
|
|
1840
|
+
/*
|
|
1841
|
+
If `slotAttributeValue` is set, it references a slot that does not exist, and the `slot` attribute should be set in the DOM. This behavior aligns with engine-server and engine-dom.
|
|
1842
|
+
See: engine-server/src/__tests__/fixtures/slot-forwarding/slots/dangling/ for example case.
|
|
1843
|
+
*/
|
|
1844
|
+
const bConditionallyYieldDanglingSlotName = (esTemplateWithYield `
|
|
1845
|
+
if (slotAttributeValue) {
|
|
1846
|
+
yield \` slot="\${slotAttributeValue}"\`;
|
|
1847
|
+
}
|
|
1848
|
+
`);
|
|
1805
1849
|
const bYieldSanitizedHtml = esTemplateWithYield `
|
|
1806
1850
|
yield sanitizeHtmlContent(${ /* lwc:inner-html content */estreeToolkit.is.expression})
|
|
1807
1851
|
`;
|
|
@@ -1916,6 +1960,7 @@ const Element = function Element(node, cxt) {
|
|
|
1916
1960
|
const isSelfClosingElement = shared.isVoidElement(node.name, shared.HTML_NAMESPACE) || isForeignSelfClosingElement;
|
|
1917
1961
|
return [
|
|
1918
1962
|
bYield(estreeToolkit.builders.literal(`<${node.name}`)),
|
|
1963
|
+
bConditionallyYieldDanglingSlotName(),
|
|
1919
1964
|
// If we haven't already prefixed the scope token to an existing class, add an explicit class here
|
|
1920
1965
|
...(hasClassAttribute ? [] : [bConditionallyYieldScopeTokenClass()]),
|
|
1921
1966
|
...yieldAttrsAndProps,
|
|
@@ -2015,7 +2060,13 @@ const bConditionalSlot = (esTemplateWithYield `
|
|
|
2015
2060
|
const scopedGenerators = scopedSlottedContent?.[slotName ?? ""];
|
|
2016
2061
|
const mismatchedSlots = isScopedSlot ? lightGenerators : scopedGenerators;
|
|
2017
2062
|
const generators = isScopedSlot ? scopedGenerators : lightGenerators;
|
|
2018
|
-
|
|
2063
|
+
/*
|
|
2064
|
+
If a slotAttributeValue is present, it should be provided for assignment to any slotted content. This behavior aligns with v1 and engine-dom.
|
|
2065
|
+
See: engine-server/src/__tests__/fixtures/slot-forwarding/slots/dangling/ for example.
|
|
2066
|
+
Note the slot mapping does not work for scoped slots, so the slot name is not rendered in this case.
|
|
2067
|
+
See: engine-server/src/__tests__/fixtures/slot-forwarding/scoped-slots for example.
|
|
2068
|
+
*/
|
|
2069
|
+
const danglingSlotName = !isScopedSlot ? ${ /* slotAttributeValue */estreeToolkit.is.expression} || slotAttributeValue : null;
|
|
2019
2070
|
// start bookend HTML comment for light DOM slot vfragment
|
|
2020
2071
|
if (!isSlotted) {
|
|
2021
2072
|
yield '<!---->';
|
|
@@ -2028,7 +2079,7 @@ const bConditionalSlot = (esTemplateWithYield `
|
|
|
2028
2079
|
|
|
2029
2080
|
if (generators) {
|
|
2030
2081
|
for (let i = 0; i < generators.length; i++) {
|
|
2031
|
-
yield* generators[i](contextfulParent, ${ /* scoped slot data */isNullableOf(estreeToolkit.is.expression)});
|
|
2082
|
+
yield* generators[i](contextfulParent, ${ /* scoped slot data */isNullableOf(estreeToolkit.is.expression)}, danglingSlotName);
|
|
2032
2083
|
// Scoped slotted data is separated by bookends. Final bookends are added outside of the loop below.
|
|
2033
2084
|
if (isScopedSlot && i < generators.length - 1) {
|
|
2034
2085
|
yield '<!---->';
|
|
@@ -2074,7 +2125,10 @@ const Slot = function Slot(node, ctx) {
|
|
|
2074
2125
|
const slotChildren = irChildrenToEs(node.children, ctx);
|
|
2075
2126
|
const isScopedSlot = estreeToolkit.builders.literal(Boolean(slotBound));
|
|
2076
2127
|
const isSlotted = estreeToolkit.builders.literal(Boolean(ctx.isSlotted));
|
|
2077
|
-
|
|
2128
|
+
const slotAttributeValue = bAttributeValue(node, 'slot');
|
|
2129
|
+
return [
|
|
2130
|
+
bConditionalSlot(isScopedSlot, isSlotted, slotName, slotAttributeValue, slotBound, slotChildren, slotAst),
|
|
2131
|
+
];
|
|
2078
2132
|
};
|
|
2079
2133
|
|
|
2080
2134
|
/*
|
|
@@ -2260,6 +2314,9 @@ const bExportTemplate = (esTemplate `
|
|
|
2260
2314
|
let textContentBuffer = '';
|
|
2261
2315
|
let didBufferTextContent = false;
|
|
2262
2316
|
|
|
2317
|
+
// This will get overridden but requires initialization.
|
|
2318
|
+
const slotAttributeValue = null;
|
|
2319
|
+
|
|
2263
2320
|
// Establishes a contextual relationship between two components for ContextProviders.
|
|
2264
2321
|
// This variable will typically get overridden (shadowed) within slotted content.
|
|
2265
2322
|
const contextfulParent = instance;
|
|
@@ -2365,5 +2422,5 @@ function compileTemplateForSSR(src, filename, options, mode = shared.DEFAULT_SSR
|
|
|
2365
2422
|
|
|
2366
2423
|
exports.compileComponentForSSR = compileComponentForSSR;
|
|
2367
2424
|
exports.compileTemplateForSSR = compileTemplateForSSR;
|
|
2368
|
-
/** version: 8.12.
|
|
2425
|
+
/** version: 8.12.7 */
|
|
2369
2426
|
//# sourceMappingURL=index.cjs.js.map
|
package/dist/index.js
CHANGED
|
@@ -734,8 +734,8 @@ function bWireAdaptersPlumbing(adapters) {
|
|
|
734
734
|
*/
|
|
735
735
|
const bGenerateMarkup = (esTemplate `
|
|
736
736
|
// These variables may mix with component-authored variables, so should be reasonably unique
|
|
737
|
-
const
|
|
738
|
-
const
|
|
737
|
+
const __lwcPublicProperties__ = new Set(${ /*api*/is.arrayExpression});
|
|
738
|
+
const __lwcPrivateProperties__ = new Set(${ /*private fields*/is.arrayExpression});
|
|
739
739
|
|
|
740
740
|
async function* generateMarkup(
|
|
741
741
|
tagName,
|
|
@@ -761,8 +761,8 @@ const bGenerateMarkup = (esTemplate `
|
|
|
761
761
|
instance[__SYMBOL__SET_INTERNALS](
|
|
762
762
|
props,
|
|
763
763
|
attrs,
|
|
764
|
-
|
|
765
|
-
|
|
764
|
+
__lwcPublicProperties__,
|
|
765
|
+
__lwcPrivateProperties__,
|
|
766
766
|
);
|
|
767
767
|
instance.isConnected = true;
|
|
768
768
|
if (instance.connectedCallback) {
|
|
@@ -812,7 +812,7 @@ const bExposeTemplate = (esTemplate `
|
|
|
812
812
|
* - deferring to the template function for yielding child content
|
|
813
813
|
*/
|
|
814
814
|
function addGenerateMarkupFunction(program, state, tagName, filename) {
|
|
815
|
-
const {
|
|
815
|
+
const { privateProperties, publicProperties, tmplExplicitImports } = state;
|
|
816
816
|
// The default tag name represents the component name that's passed to the transformer.
|
|
817
817
|
// This is needed to generate markup for dynamic components which are invoked through
|
|
818
818
|
// the generateMarkup function on the constructor.
|
|
@@ -842,7 +842,7 @@ function addGenerateMarkupFunction(program, state, tagName, filename) {
|
|
|
842
842
|
SYMBOL__SET_INTERNALS: '__SYMBOL__SET_INTERNALS',
|
|
843
843
|
establishContextfulRelationship: '__establishContextfulRelationship',
|
|
844
844
|
}));
|
|
845
|
-
program.body.push(...bGenerateMarkup(builders.arrayExpression(
|
|
845
|
+
program.body.push(...bGenerateMarkup(builders.arrayExpression(publicProperties.map(builders.literal)), builders.arrayExpression(privateProperties.map(builders.literal)), defaultTagName, classIdentifier, connectWireAdapterCode));
|
|
846
846
|
if (exposeTemplateBlock) {
|
|
847
847
|
program.body.push(exposeTemplateBlock);
|
|
848
848
|
}
|
|
@@ -935,23 +935,31 @@ const visitors = {
|
|
|
935
935
|
},
|
|
936
936
|
PropertyDefinition(path, state) {
|
|
937
937
|
const node = path.node;
|
|
938
|
-
if (!
|
|
938
|
+
if (!node?.key) {
|
|
939
|
+
// Seems to occur for `@wire() [symbol];` -- not sure why
|
|
940
|
+
throw new Error('Unknown state: property definition has no key');
|
|
941
|
+
}
|
|
942
|
+
if (!is.identifier(node.key)) {
|
|
939
943
|
return;
|
|
940
944
|
}
|
|
941
945
|
const { decorators } = node;
|
|
942
946
|
validateUniqueDecorator(decorators);
|
|
943
947
|
const decoratedExpression = decorators?.[0]?.expression;
|
|
944
948
|
if (is.identifier(decoratedExpression) && decoratedExpression.name === 'api') {
|
|
945
|
-
state.
|
|
949
|
+
state.publicProperties.push(node.key.name);
|
|
946
950
|
}
|
|
947
951
|
else if (is.callExpression(decoratedExpression) &&
|
|
948
952
|
is.identifier(decoratedExpression.callee) &&
|
|
949
953
|
decoratedExpression.callee.name === 'wire') {
|
|
954
|
+
if (node.computed) {
|
|
955
|
+
// TODO [#5032]: Harmonize errors thrown in `@lwc/ssr-compiler`
|
|
956
|
+
throw new Error('@wire cannot be used on computed properties in SSR context.');
|
|
957
|
+
}
|
|
950
958
|
catalogWireAdapters(path, state);
|
|
951
|
-
state.
|
|
959
|
+
state.privateProperties.push(node.key.name);
|
|
952
960
|
}
|
|
953
961
|
else {
|
|
954
|
-
state.
|
|
962
|
+
state.privateProperties.push(node.key.name);
|
|
955
963
|
}
|
|
956
964
|
if (node.static &&
|
|
957
965
|
node.key.name === 'stylesheets' &&
|
|
@@ -977,9 +985,15 @@ const visitors = {
|
|
|
977
985
|
if (is.callExpression(decoratedExpression) &&
|
|
978
986
|
is.identifier(decoratedExpression.callee) &&
|
|
979
987
|
decoratedExpression.callee.name === 'wire') {
|
|
988
|
+
// not a getter/setter
|
|
989
|
+
const isRealMethod = node.kind === 'method';
|
|
990
|
+
if (node.computed) {
|
|
991
|
+
// TODO [#5032]: Harmonize errors thrown in `@lwc/ssr-compiler`
|
|
992
|
+
throw new Error(`@wire cannot be used on computed ${isRealMethod ? 'method' : 'properties'} in SSR context.`);
|
|
993
|
+
}
|
|
980
994
|
// Getters and setters are methods in the AST, but treated as properties by @wire
|
|
981
995
|
// Note that this means that their implementations are ignored!
|
|
982
|
-
if (
|
|
996
|
+
if (!isRealMethod) {
|
|
983
997
|
const methodAsProp = builders.propertyDefinition(structuredClone(node.key), null, node.computed, node.static);
|
|
984
998
|
methodAsProp.decorators = structuredClone(decorators);
|
|
985
999
|
path.replaceWith(methodAsProp);
|
|
@@ -992,6 +1006,13 @@ const visitors = {
|
|
|
992
1006
|
catalogWireAdapters(path, state);
|
|
993
1007
|
}
|
|
994
1008
|
}
|
|
1009
|
+
else if (is.identifier(decoratedExpression) && decoratedExpression.name === 'api') {
|
|
1010
|
+
if (state.publicProperties.includes(node.key.name)) {
|
|
1011
|
+
// TODO [#5032]: Harmonize errors thrown in `@lwc/ssr-compiler`
|
|
1012
|
+
throw new Error(`LWC1112: @api get ${node.key.name} and @api set ${node.key.name} detected in class declaration. Only one of the two needs to be decorated with @api.`);
|
|
1013
|
+
}
|
|
1014
|
+
state.publicProperties.push(node.key.name);
|
|
1015
|
+
}
|
|
995
1016
|
switch (node.key.name) {
|
|
996
1017
|
case 'constructor':
|
|
997
1018
|
// add our own custom arg after any pre-existing constructor args
|
|
@@ -1076,8 +1097,8 @@ function compileJS(src, filename, tagName, options, compilationMode) {
|
|
|
1076
1097
|
tmplExplicitImports: null,
|
|
1077
1098
|
cssExplicitImports: null,
|
|
1078
1099
|
staticStylesheetIds: null,
|
|
1079
|
-
|
|
1080
|
-
|
|
1100
|
+
publicProperties: [],
|
|
1101
|
+
privateProperties: [],
|
|
1081
1102
|
wireAdapters: [],
|
|
1082
1103
|
experimentalDynamicComponent: options.experimentalDynamicComponent,
|
|
1083
1104
|
importManager: new ImportManager(),
|
|
@@ -1472,7 +1493,7 @@ const bGenerateSlottedContent = (esTemplateWithYield `
|
|
|
1472
1493
|
// than a function _declaration_, so it isn't available to be referenced anywhere.
|
|
1473
1494
|
const bAddSlottedContent = (esTemplate `
|
|
1474
1495
|
addSlottedContent(${ /* slot name */is.expression} ?? "", async function* generateSlottedContent(contextfulParent, ${
|
|
1475
|
-
/* scoped slot data variable */ isNullableOf(is.identifier)}) {
|
|
1496
|
+
/* scoped slot data variable */ isNullableOf(is.identifier)}, slotAttributeValue) {
|
|
1476
1497
|
// FIXME: make validation work again
|
|
1477
1498
|
${ /* slot content */false}
|
|
1478
1499
|
}, ${ /* content map */is.identifier});
|
|
@@ -1620,6 +1641,13 @@ const bYieldFromChildGenerator = (esTemplateWithYield `
|
|
|
1620
1641
|
{
|
|
1621
1642
|
const childProps = ${ /* child props */is.objectExpression};
|
|
1622
1643
|
const childAttrs = ${ /* child attrs */is.objectExpression};
|
|
1644
|
+
/*
|
|
1645
|
+
If 'slotAttributeValue' is set, it references a slot that does not exist, and the 'slot' attribute should be set in the DOM. This behavior aligns with engine-server and engine-dom.
|
|
1646
|
+
See: engine-server/src/__tests__/fixtures/slot-forwarding/slots/dangling/ for example case.
|
|
1647
|
+
*/
|
|
1648
|
+
if (slotAttributeValue) {
|
|
1649
|
+
childAttrs.slot = slotAttributeValue;
|
|
1650
|
+
}
|
|
1623
1651
|
${
|
|
1624
1652
|
/*
|
|
1625
1653
|
Slotted content is inserted here.
|
|
@@ -1673,6 +1701,13 @@ const bYieldFromDynamicComponentConstructorGenerator = (esTemplateWithYield `
|
|
|
1673
1701
|
}
|
|
1674
1702
|
const childProps = ${ /* child props */is.objectExpression};
|
|
1675
1703
|
const childAttrs = ${ /* child attrs */is.objectExpression};
|
|
1704
|
+
/*
|
|
1705
|
+
If 'slotAttributeValue' is set, it references a slot that does not exist, and the 'slot' attribute should be set in the DOM. This behavior aligns with engine-server and engine-dom.
|
|
1706
|
+
See: engine-server/src/__tests__/fixtures/slot-forwarding/slots/dangling/ for example case.
|
|
1707
|
+
*/
|
|
1708
|
+
if (slotAttributeValue) {
|
|
1709
|
+
childAttrs.slot = slotAttributeValue;
|
|
1710
|
+
}
|
|
1676
1711
|
${
|
|
1677
1712
|
/*
|
|
1678
1713
|
Slotted content is inserted here.
|
|
@@ -1798,6 +1833,15 @@ const bConditionallyYieldScopeTokenClass = (esTemplateWithYield `
|
|
|
1798
1833
|
yield \` class="\${stylesheetScopeToken}"\`;
|
|
1799
1834
|
}
|
|
1800
1835
|
`);
|
|
1836
|
+
/*
|
|
1837
|
+
If `slotAttributeValue` is set, it references a slot that does not exist, and the `slot` attribute should be set in the DOM. This behavior aligns with engine-server and engine-dom.
|
|
1838
|
+
See: engine-server/src/__tests__/fixtures/slot-forwarding/slots/dangling/ for example case.
|
|
1839
|
+
*/
|
|
1840
|
+
const bConditionallyYieldDanglingSlotName = (esTemplateWithYield `
|
|
1841
|
+
if (slotAttributeValue) {
|
|
1842
|
+
yield \` slot="\${slotAttributeValue}"\`;
|
|
1843
|
+
}
|
|
1844
|
+
`);
|
|
1801
1845
|
const bYieldSanitizedHtml = esTemplateWithYield `
|
|
1802
1846
|
yield sanitizeHtmlContent(${ /* lwc:inner-html content */is.expression})
|
|
1803
1847
|
`;
|
|
@@ -1912,6 +1956,7 @@ const Element = function Element(node, cxt) {
|
|
|
1912
1956
|
const isSelfClosingElement = isVoidElement(node.name, HTML_NAMESPACE) || isForeignSelfClosingElement;
|
|
1913
1957
|
return [
|
|
1914
1958
|
bYield(builders.literal(`<${node.name}`)),
|
|
1959
|
+
bConditionallyYieldDanglingSlotName(),
|
|
1915
1960
|
// If we haven't already prefixed the scope token to an existing class, add an explicit class here
|
|
1916
1961
|
...(hasClassAttribute ? [] : [bConditionallyYieldScopeTokenClass()]),
|
|
1917
1962
|
...yieldAttrsAndProps,
|
|
@@ -2011,7 +2056,13 @@ const bConditionalSlot = (esTemplateWithYield `
|
|
|
2011
2056
|
const scopedGenerators = scopedSlottedContent?.[slotName ?? ""];
|
|
2012
2057
|
const mismatchedSlots = isScopedSlot ? lightGenerators : scopedGenerators;
|
|
2013
2058
|
const generators = isScopedSlot ? scopedGenerators : lightGenerators;
|
|
2014
|
-
|
|
2059
|
+
/*
|
|
2060
|
+
If a slotAttributeValue is present, it should be provided for assignment to any slotted content. This behavior aligns with v1 and engine-dom.
|
|
2061
|
+
See: engine-server/src/__tests__/fixtures/slot-forwarding/slots/dangling/ for example.
|
|
2062
|
+
Note the slot mapping does not work for scoped slots, so the slot name is not rendered in this case.
|
|
2063
|
+
See: engine-server/src/__tests__/fixtures/slot-forwarding/scoped-slots for example.
|
|
2064
|
+
*/
|
|
2065
|
+
const danglingSlotName = !isScopedSlot ? ${ /* slotAttributeValue */is.expression} || slotAttributeValue : null;
|
|
2015
2066
|
// start bookend HTML comment for light DOM slot vfragment
|
|
2016
2067
|
if (!isSlotted) {
|
|
2017
2068
|
yield '<!---->';
|
|
@@ -2024,7 +2075,7 @@ const bConditionalSlot = (esTemplateWithYield `
|
|
|
2024
2075
|
|
|
2025
2076
|
if (generators) {
|
|
2026
2077
|
for (let i = 0; i < generators.length; i++) {
|
|
2027
|
-
yield* generators[i](contextfulParent, ${ /* scoped slot data */isNullableOf(is.expression)});
|
|
2078
|
+
yield* generators[i](contextfulParent, ${ /* scoped slot data */isNullableOf(is.expression)}, danglingSlotName);
|
|
2028
2079
|
// Scoped slotted data is separated by bookends. Final bookends are added outside of the loop below.
|
|
2029
2080
|
if (isScopedSlot && i < generators.length - 1) {
|
|
2030
2081
|
yield '<!---->';
|
|
@@ -2070,7 +2121,10 @@ const Slot = function Slot(node, ctx) {
|
|
|
2070
2121
|
const slotChildren = irChildrenToEs(node.children, ctx);
|
|
2071
2122
|
const isScopedSlot = builders.literal(Boolean(slotBound));
|
|
2072
2123
|
const isSlotted = builders.literal(Boolean(ctx.isSlotted));
|
|
2073
|
-
|
|
2124
|
+
const slotAttributeValue = bAttributeValue(node, 'slot');
|
|
2125
|
+
return [
|
|
2126
|
+
bConditionalSlot(isScopedSlot, isSlotted, slotName, slotAttributeValue, slotBound, slotChildren, slotAst),
|
|
2127
|
+
];
|
|
2074
2128
|
};
|
|
2075
2129
|
|
|
2076
2130
|
/*
|
|
@@ -2256,6 +2310,9 @@ const bExportTemplate = (esTemplate `
|
|
|
2256
2310
|
let textContentBuffer = '';
|
|
2257
2311
|
let didBufferTextContent = false;
|
|
2258
2312
|
|
|
2313
|
+
// This will get overridden but requires initialization.
|
|
2314
|
+
const slotAttributeValue = null;
|
|
2315
|
+
|
|
2259
2316
|
// Establishes a contextual relationship between two components for ContextProviders.
|
|
2260
2317
|
// This variable will typically get overridden (shadowed) within slotted content.
|
|
2261
2318
|
const contextfulParent = instance;
|
|
@@ -2360,5 +2417,5 @@ function compileTemplateForSSR(src, filename, options, mode = DEFAULT_SSR_MODE)
|
|
|
2360
2417
|
}
|
|
2361
2418
|
|
|
2362
2419
|
export { compileComponentForSSR, compileTemplateForSSR };
|
|
2363
|
-
/** version: 8.12.
|
|
2420
|
+
/** version: 8.12.7 */
|
|
2364
2421
|
//# sourceMappingURL=index.js.map
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"You can safely modify dependencies, devDependencies, keywords, etc., but other props will be overwritten."
|
|
5
5
|
],
|
|
6
6
|
"name": "@lwc/ssr-compiler",
|
|
7
|
-
"version": "8.12.
|
|
7
|
+
"version": "8.12.7",
|
|
8
8
|
"description": "Compile component for use during server-side rendering",
|
|
9
9
|
"keywords": [
|
|
10
10
|
"compiler",
|
|
@@ -48,10 +48,10 @@
|
|
|
48
48
|
}
|
|
49
49
|
},
|
|
50
50
|
"dependencies": {
|
|
51
|
-
"@babel/types": "7.26.
|
|
52
|
-
"@lwc/shared": "8.12.
|
|
53
|
-
"@lwc/errors": "8.12.
|
|
54
|
-
"@lwc/template-compiler": "8.12.
|
|
51
|
+
"@babel/types": "7.26.7",
|
|
52
|
+
"@lwc/shared": "8.12.7",
|
|
53
|
+
"@lwc/errors": "8.12.7",
|
|
54
|
+
"@lwc/template-compiler": "8.12.7",
|
|
55
55
|
"acorn": "8.14.0",
|
|
56
56
|
"astring": "^1.9.0",
|
|
57
57
|
"estree-toolkit": "^1.7.8",
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
"meriyah": "^5.0.0"
|
|
60
60
|
},
|
|
61
61
|
"devDependencies": {
|
|
62
|
-
"@lwc/babel-plugin-component": "8.12.
|
|
62
|
+
"@lwc/babel-plugin-component": "8.12.7",
|
|
63
63
|
"@types/estree": "^1.0.6"
|
|
64
64
|
}
|
|
65
65
|
}
|