@lwc/ssr-compiler 8.3.0 → 8.5.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/compile-js/generate-markup.d.ts +5 -0
- package/dist/compile-js/index.d.ts +2 -1
- package/dist/compile-js/stylesheets.d.ts +1 -1
- package/dist/compile-js/types.d.ts +0 -1
- package/dist/compile-template/index.d.ts +2 -1
- package/dist/compile-template/shared.d.ts +13 -2
- package/dist/estree/builders.d.ts +9 -5
- package/dist/estree/validators.d.ts +1 -6
- package/dist/index.cjs.js +408 -236
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +4 -3
- package/dist/index.js +411 -239
- package/dist/index.js.map +1 -1
- package/dist/shared.d.ts +1 -0
- package/dist/transmogrify.d.ts +50 -0
- package/package.json +4 -4
package/dist/index.cjs.js
CHANGED
|
@@ -8,14 +8,155 @@ Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
8
8
|
var astring = require('astring');
|
|
9
9
|
var estreeToolkit = require('estree-toolkit');
|
|
10
10
|
var meriyah = require('meriyah');
|
|
11
|
-
var shared = require('@lwc/shared');
|
|
12
|
-
var acorn = require('acorn');
|
|
13
11
|
var immer = require('immer');
|
|
14
12
|
var node_path = require('node:path');
|
|
13
|
+
var acorn = require('acorn');
|
|
15
14
|
var templateCompiler = require('@lwc/template-compiler');
|
|
16
15
|
var builders = require('estree-toolkit/dist/builders');
|
|
16
|
+
var shared = require('@lwc/shared');
|
|
17
17
|
var util = require('util');
|
|
18
18
|
|
|
19
|
+
/*
|
|
20
|
+
* Copyright (c) 2024, Salesforce, Inc.
|
|
21
|
+
* All rights reserved.
|
|
22
|
+
* SPDX-License-Identifier: MIT
|
|
23
|
+
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
|
|
24
|
+
*/
|
|
25
|
+
const EMIT_IDENT = estreeToolkit.builders.identifier('$$emit');
|
|
26
|
+
// Rollup may rename variables to prevent shadowing. When it does, it uses the format `foo$0`, `foo$1`, etc.
|
|
27
|
+
const TMPL_FN_PATTERN = /tmpl($\d+)?/;
|
|
28
|
+
const GEN_MARKUP_PATTERN = /generateMarkup($\d+)?/;
|
|
29
|
+
const isWithinFn = (pattern, nodePath) => {
|
|
30
|
+
const { node } = nodePath;
|
|
31
|
+
if (!node) {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
if (node.type === 'FunctionDeclaration' && pattern.test(node.id.name)) {
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
if (nodePath.parentPath) {
|
|
38
|
+
return isWithinFn(pattern, nodePath.parentPath);
|
|
39
|
+
}
|
|
40
|
+
return false;
|
|
41
|
+
};
|
|
42
|
+
const visitors$2 = {
|
|
43
|
+
FunctionDeclaration(path, state) {
|
|
44
|
+
const { node } = path;
|
|
45
|
+
if (!node?.async || !node?.generator) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
// Component authors might conceivably use async generator functions in their own code. Therefore,
|
|
49
|
+
// when traversing & transforming written+generated code, we need to disambiguate generated async
|
|
50
|
+
// generator functions from those that were written by the component author.
|
|
51
|
+
if (!isWithinFn(GEN_MARKUP_PATTERN, path) && !isWithinFn(TMPL_FN_PATTERN, path)) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
node.generator = false;
|
|
55
|
+
node.async = state.mode === 'async';
|
|
56
|
+
node.params.unshift(EMIT_IDENT);
|
|
57
|
+
},
|
|
58
|
+
YieldExpression(path, state) {
|
|
59
|
+
const { node } = path;
|
|
60
|
+
if (!node) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
// Component authors might conceivably use generator functions within their own code. Therefore,
|
|
64
|
+
// when traversing & transforming written+generated code, we need to disambiguate generated yield
|
|
65
|
+
// expressions from those that were written by the component author.
|
|
66
|
+
if (!isWithinFn(TMPL_FN_PATTERN, path) && !isWithinFn(GEN_MARKUP_PATTERN, path)) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
if (node.delegate) {
|
|
70
|
+
// transform `yield* foo(arg)` into `foo($$emit, arg)` or `await foo($$emit, arg)`
|
|
71
|
+
if (node.argument?.type !== 'CallExpression') {
|
|
72
|
+
throw new Error('Implementation error: cannot transmogrify complex yield-from expressions');
|
|
73
|
+
}
|
|
74
|
+
const callExpr = node.argument;
|
|
75
|
+
callExpr.arguments.unshift(EMIT_IDENT);
|
|
76
|
+
path.replaceWith(state.mode === 'sync' ? callExpr : estreeToolkit.builders.awaitExpression(callExpr));
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
// transform `yield foo` into `$$emit(foo)`
|
|
80
|
+
const emittedExpression = node.argument;
|
|
81
|
+
if (!emittedExpression) {
|
|
82
|
+
throw new Error('Implementation error: cannot transform a yield expression that yields nothing');
|
|
83
|
+
}
|
|
84
|
+
path.replaceWith(estreeToolkit.builders.callExpression(EMIT_IDENT, [emittedExpression]));
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
ImportSpecifier(path, _state) {
|
|
88
|
+
// @lwc/ssr-runtime has a couple of helper functions that need to conform to either the generator or
|
|
89
|
+
// no-generator compilation mode/paradigm. Since these are simple helper functions, we can maintain
|
|
90
|
+
// two implementations of each helper method:
|
|
91
|
+
//
|
|
92
|
+
// - renderAttrs vs renderAttrsNoYield
|
|
93
|
+
// - fallbackTmpl vs fallbackTmplNoYield
|
|
94
|
+
//
|
|
95
|
+
// If this becomes too burdensome to maintain, we can officially deprecate the generator-based approach
|
|
96
|
+
// and switch the @lwc/ssr-runtime implementation wholesale over to the no-generator paradigm.
|
|
97
|
+
const { node } = path;
|
|
98
|
+
if (!node || node.imported.type !== 'Identifier') {
|
|
99
|
+
throw new Error('Implementation error: unexpected missing identifier in import specifier');
|
|
100
|
+
}
|
|
101
|
+
if (path.parent?.type !== 'ImportDeclaration' ||
|
|
102
|
+
path.parent.source.value !== '@lwc/ssr-runtime') {
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
if (node.imported.name === 'fallbackTmpl') {
|
|
106
|
+
node.imported.name = 'fallbackTmplNoYield';
|
|
107
|
+
}
|
|
108
|
+
else if (node.imported.name === 'renderAttrs') {
|
|
109
|
+
node.imported.name = 'renderAttrsNoYield';
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
};
|
|
113
|
+
/**
|
|
114
|
+
* Transforms async-generator code into either the async or synchronous alternatives that are
|
|
115
|
+
* ~semantically equivalent. For example, this template:
|
|
116
|
+
*
|
|
117
|
+
* <template>
|
|
118
|
+
* <div>foobar</div>
|
|
119
|
+
* <x-child></x-child>
|
|
120
|
+
* </template>
|
|
121
|
+
*
|
|
122
|
+
* Is compiled into the following JavaScript, intended for execution during SSR & stripped down
|
|
123
|
+
* for the purposes of this example:
|
|
124
|
+
*
|
|
125
|
+
* async function* tmpl(props, attrs, slottedContent, Cmp, instance) {
|
|
126
|
+
* yield '<div>foobar</div>';
|
|
127
|
+
* const childProps = {};
|
|
128
|
+
* const childAttrs = {};
|
|
129
|
+
* yield* generateChildMarkup("x-child", childProps, childAttrs, childSlottedContentGenerator);
|
|
130
|
+
* }
|
|
131
|
+
*
|
|
132
|
+
* When transmogrified in async-mode, the above generated template function becomes the following:
|
|
133
|
+
*
|
|
134
|
+
* async function tmpl($$emit, props, attrs, slottedContent, Cmp, instance) {
|
|
135
|
+
* $$emit('<div>foobar</div>');
|
|
136
|
+
* const childProps = {};
|
|
137
|
+
* const childAttrs = {};
|
|
138
|
+
* await generateChildMarkup($$emit, "x-child", childProps, childAttrs, childSlottedContentGenerator);
|
|
139
|
+
* }
|
|
140
|
+
*
|
|
141
|
+
* When transmogrified in sync-mode, the template function becomes the following:
|
|
142
|
+
*
|
|
143
|
+
* function tmpl($$emit, props, attrs, slottedContent, Cmp, instance) {
|
|
144
|
+
* $$emit('<div>foobar</div>');
|
|
145
|
+
* const childProps = {};
|
|
146
|
+
* const childAttrs = {};
|
|
147
|
+
* generateChildMarkup($$emit, "x-child", childProps, childAttrs, childSlottedContentGenerator);
|
|
148
|
+
* }
|
|
149
|
+
*
|
|
150
|
+
* There are tradeoffs for each of these modes. Notably, the async-yield variety is the easiest to transform
|
|
151
|
+
* into either of the other varieties and, for that reason, is the variety that is "authored" by the SSR compiler.
|
|
152
|
+
*/
|
|
153
|
+
function transmogrify(compiledComponentAst, mode = 'sync') {
|
|
154
|
+
const state = {
|
|
155
|
+
mode,
|
|
156
|
+
};
|
|
157
|
+
return immer.produce(compiledComponentAst, (astDraft) => estreeToolkit.traverse(astDraft, visitors$2, state));
|
|
158
|
+
}
|
|
159
|
+
|
|
19
160
|
/*
|
|
20
161
|
* Copyright (c) 2024, salesforce.com, inc.
|
|
21
162
|
* All rights reserved.
|
|
@@ -69,6 +210,72 @@ function catalogTmplImport(path, state) {
|
|
|
69
210
|
state.tmplExplicitImports.set(specifier.local.name, source.value);
|
|
70
211
|
}
|
|
71
212
|
|
|
213
|
+
/*
|
|
214
|
+
* Copyright (c) 2024, salesforce.com, inc.
|
|
215
|
+
* All rights reserved.
|
|
216
|
+
* SPDX-License-Identifier: MIT
|
|
217
|
+
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
|
|
218
|
+
*/
|
|
219
|
+
/** Creates a default import statement, e.g. `import pkg from "pkg"` */
|
|
220
|
+
const bImportDefaultDeclaration = (name, source) => estreeToolkit.builders.importDeclaration([estreeToolkit.builders.importDefaultSpecifier(estreeToolkit.builders.identifier(name))], estreeToolkit.builders.literal(source));
|
|
221
|
+
/**
|
|
222
|
+
* Creates an import statement, e.g. `import { foo, bar as $bar$ } from "pkg"`.
|
|
223
|
+
* Does not support default or namespace imports (`import pkg` or `import * as pkg`).
|
|
224
|
+
* @param imports names to be imported; values can be a string (plain import) or object (aliased)
|
|
225
|
+
* @param source source location to import from; defaults to @lwc/ssr-runtime
|
|
226
|
+
*/
|
|
227
|
+
const bImportDeclaration = (imports, source = '@lwc/ssr-runtime') => {
|
|
228
|
+
const specifiers = imports
|
|
229
|
+
.flatMap((imp) => (typeof imp === 'string' ? [[imp, imp]] : Object.entries(imp)))
|
|
230
|
+
.map(([imported, local]) => estreeToolkit.builders.importSpecifier(estreeToolkit.builders.identifier(imported), estreeToolkit.builders.identifier(local)));
|
|
231
|
+
return estreeToolkit.builders.importDeclaration(specifiers, estreeToolkit.builders.literal(source));
|
|
232
|
+
};
|
|
233
|
+
|
|
234
|
+
/*
|
|
235
|
+
* Copyright (c) 2024, salesforce.com, inc.
|
|
236
|
+
* All rights reserved.
|
|
237
|
+
* SPDX-License-Identifier: MIT
|
|
238
|
+
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
|
|
239
|
+
*/
|
|
240
|
+
function catalogAndReplaceStyleImports(path, state) {
|
|
241
|
+
const specifier = path.node.specifiers[0];
|
|
242
|
+
if (typeof path.node.source.value !== 'string' ||
|
|
243
|
+
!path.node.source.value.endsWith('.css') ||
|
|
244
|
+
path.node.specifiers.length !== 1 ||
|
|
245
|
+
specifier.type !== 'ImportDefaultSpecifier') {
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
// Any file ending in `*.scoped.css` which is directly imported into a Component `*.js` file (and assumed
|
|
249
|
+
// to be used for `static stylesheets`) is assumed to be scoped, so needs to be marked as such with a query param.
|
|
250
|
+
// Outside of SSR, this is done by `@lwc/babel-plugin-component`, so we need to emulate its behavior. The goal here
|
|
251
|
+
// is for `@lwc/template-compiler` to know to add `stylesheet.$scoped$ = true` to its compiled output, which it
|
|
252
|
+
// detects using the query param.
|
|
253
|
+
if (path.node?.source.value.endsWith('.scoped.css')) {
|
|
254
|
+
path.replaceWith(estreeToolkit.builders.importDeclaration(path.node.specifiers, estreeToolkit.builders.literal(path.node.source.value + '?scoped=true')));
|
|
255
|
+
}
|
|
256
|
+
state.cssExplicitImports = state.cssExplicitImports ?? new Map();
|
|
257
|
+
state.cssExplicitImports.set(specifier.local.name, path.node.source.value);
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* This adds implicit style imports to the compiled component artifact.
|
|
261
|
+
*/
|
|
262
|
+
function getStylesheetImports(filepath) {
|
|
263
|
+
const moduleName = /(?<moduleName>[^/]+)\.html$/.exec(filepath)?.groups?.moduleName;
|
|
264
|
+
if (!moduleName) {
|
|
265
|
+
throw new Error(`Could not determine module name from file path: ${filepath}`);
|
|
266
|
+
}
|
|
267
|
+
return [
|
|
268
|
+
bImportDefaultDeclaration('defaultStylesheets', `./${moduleName}.css`),
|
|
269
|
+
bImportDefaultDeclaration('defaultScopedStylesheets', `./${moduleName}.scoped.css?scoped=true`),
|
|
270
|
+
];
|
|
271
|
+
}
|
|
272
|
+
function catalogStaticStylesheets(ids, state) {
|
|
273
|
+
state.staticStylesheetIds = state.staticStylesheetIds ?? new Set();
|
|
274
|
+
for (const id of ids) {
|
|
275
|
+
state.staticStylesheetIds.add(id);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
72
279
|
/*
|
|
73
280
|
* Copyright (c) 2024, salesforce.com, inc.
|
|
74
281
|
* All rights reserved.
|
|
@@ -78,7 +285,7 @@ function catalogTmplImport(path, state) {
|
|
|
78
285
|
/** Placeholder value to use to opt out of validation. */
|
|
79
286
|
const NO_VALIDATION = false;
|
|
80
287
|
const PLACEHOLDER_PREFIX = `__ESTEMPLATE_${Math.random().toString().slice(2)}_PLACEHOLDER__`;
|
|
81
|
-
const getReplacementNode = (state, placeholderId
|
|
288
|
+
const getReplacementNode = (state, placeholderId) => {
|
|
82
289
|
const key = Number(placeholderId.slice(PLACEHOLDER_PREFIX.length));
|
|
83
290
|
const nodeCount = state.replacementNodes.length;
|
|
84
291
|
if (key >= nodeCount) {
|
|
@@ -90,6 +297,9 @@ const getReplacementNode = (state, placeholderId, nodeType) => {
|
|
|
90
297
|
!(Array.isArray(replacementNode)
|
|
91
298
|
? replacementNode.every(validateReplacement)
|
|
92
299
|
: validateReplacement(replacementNode))) {
|
|
300
|
+
const nodeType = Array.isArray(replacementNode)
|
|
301
|
+
? `[${replacementNode.map((n) => n.type)}.join(', ')]`
|
|
302
|
+
: replacementNode?.type;
|
|
93
303
|
throw new Error(`Validation failed for templated node of type ${nodeType}`);
|
|
94
304
|
}
|
|
95
305
|
return replacementNode;
|
|
@@ -97,7 +307,7 @@ const getReplacementNode = (state, placeholderId, nodeType) => {
|
|
|
97
307
|
const visitors$1 = {
|
|
98
308
|
Identifier(path, state) {
|
|
99
309
|
if (path.node?.name.startsWith(PLACEHOLDER_PREFIX)) {
|
|
100
|
-
const replacementNode = getReplacementNode(state, path.node.name
|
|
310
|
+
const replacementNode = getReplacementNode(state, path.node.name);
|
|
101
311
|
if (replacementNode === null) {
|
|
102
312
|
path.remove();
|
|
103
313
|
}
|
|
@@ -123,7 +333,7 @@ const visitors$1 = {
|
|
|
123
333
|
if (typeof path.node?.value === 'string' &&
|
|
124
334
|
path.node.value.startsWith(PLACEHOLDER_PREFIX)) {
|
|
125
335
|
// A literal can only be replaced with a single node
|
|
126
|
-
const replacementNode = getReplacementNode(state, path.node.value
|
|
336
|
+
const replacementNode = getReplacementNode(state, path.node.value);
|
|
127
337
|
path.replaceWith(replacementNode);
|
|
128
338
|
}
|
|
129
339
|
},
|
|
@@ -213,52 +423,6 @@ function esTemplateWithYield(javascriptSegments, ...validators) {
|
|
|
213
423
|
* SPDX-License-Identifier: MIT
|
|
214
424
|
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
|
|
215
425
|
*/
|
|
216
|
-
const bDefaultStyleImport = (esTemplate `
|
|
217
|
-
import defaultStylesheets from '${estreeToolkit.is.literal}';
|
|
218
|
-
`);
|
|
219
|
-
const bDefaultScopedStyleImport = (esTemplate `
|
|
220
|
-
import defaultScopedStylesheets from '${estreeToolkit.is.literal}';
|
|
221
|
-
`);
|
|
222
|
-
function catalogStyleImport(path, state) {
|
|
223
|
-
const specifier = path.node.specifiers[0];
|
|
224
|
-
if (typeof path.node.source.value !== 'string' ||
|
|
225
|
-
!path.node.source.value.endsWith('.css') ||
|
|
226
|
-
path.node.specifiers.length !== 1 ||
|
|
227
|
-
specifier.type !== 'ImportDefaultSpecifier') {
|
|
228
|
-
return;
|
|
229
|
-
}
|
|
230
|
-
state.cssExplicitImports = state.cssExplicitImports ?? new Map();
|
|
231
|
-
state.cssExplicitImports.set(specifier.local.name, path.node.source.value);
|
|
232
|
-
}
|
|
233
|
-
/**
|
|
234
|
-
* This adds implicit style imports to the compiled component artifact.
|
|
235
|
-
*/
|
|
236
|
-
function getStylesheetImports(filepath) {
|
|
237
|
-
const moduleName = /(?<moduleName>[^/]+)\.html$/.exec(filepath)?.groups?.moduleName;
|
|
238
|
-
if (!moduleName) {
|
|
239
|
-
throw new Error(`Could not determine module name from file path: ${filepath}`);
|
|
240
|
-
}
|
|
241
|
-
return [
|
|
242
|
-
bDefaultStyleImport(estreeToolkit.builders.literal(`./${moduleName}.css`)),
|
|
243
|
-
bDefaultScopedStyleImport(estreeToolkit.builders.literal(`./${moduleName}.scoped.css?scoped=true`)),
|
|
244
|
-
];
|
|
245
|
-
}
|
|
246
|
-
function catalogStaticStylesheets(ids, state) {
|
|
247
|
-
state.staticStylesheetIds = state.staticStylesheetIds ?? new Set();
|
|
248
|
-
for (const id of ids) {
|
|
249
|
-
state.staticStylesheetIds.add(id);
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
/*
|
|
254
|
-
* Copyright (c) 2024, salesforce.com, inc.
|
|
255
|
-
* All rights reserved.
|
|
256
|
-
* SPDX-License-Identifier: MIT
|
|
257
|
-
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
|
|
258
|
-
*/
|
|
259
|
-
const isStringLiteral = (node) => {
|
|
260
|
-
return estreeToolkit.is.literal(node) && typeof node.value === 'string';
|
|
261
|
-
};
|
|
262
426
|
/** Returns `true` if the node is an identifier or `<something>.render()`. */
|
|
263
427
|
const isIdentOrRenderCall = (node) => {
|
|
264
428
|
return (estreeToolkit.is.identifier(node) ||
|
|
@@ -267,20 +431,6 @@ const isIdentOrRenderCall = (node) => {
|
|
|
267
431
|
estreeToolkit.is.identifier(node.callee.property) &&
|
|
268
432
|
node.callee.property.name === 'render'));
|
|
269
433
|
};
|
|
270
|
-
/** Extends a validator to return `true` if the node is `null`. */
|
|
271
|
-
function isNullableOf(validator) {
|
|
272
|
-
return (node) => node === null || validator(node);
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
/*
|
|
276
|
-
* Copyright (c) 2024, salesforce.com, inc.
|
|
277
|
-
* All rights reserved.
|
|
278
|
-
* SPDX-License-Identifier: MIT
|
|
279
|
-
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
|
|
280
|
-
*/
|
|
281
|
-
const bImportDeclaration = (esTemplate `
|
|
282
|
-
import ${estreeToolkit.is.identifier} from "${isStringLiteral}";
|
|
283
|
-
`);
|
|
284
434
|
|
|
285
435
|
/*
|
|
286
436
|
* Copyright (c) 2024, salesforce.com, inc.
|
|
@@ -291,11 +441,10 @@ const bImportDeclaration = (esTemplate `
|
|
|
291
441
|
const bGenerateMarkup = (esTemplate `
|
|
292
442
|
export async function* generateMarkup(tagName, props, attrs, slotted) {
|
|
293
443
|
attrs = attrs ?? {};
|
|
294
|
-
${
|
|
295
|
-
const instance = new ${estreeToolkit.is.identifier}({
|
|
444
|
+
const instance = new ${ /* Component class */estreeToolkit.is.identifier}({
|
|
296
445
|
tagName: tagName.toUpperCase(),
|
|
297
446
|
});
|
|
298
|
-
instance[__SYMBOL__SET_INTERNALS](props,
|
|
447
|
+
instance[__SYMBOL__SET_INTERNALS](props, attrs);
|
|
299
448
|
instance.isConnected = true;
|
|
300
449
|
if (instance.connectedCallback) {
|
|
301
450
|
__mutationTracker.enable(instance);
|
|
@@ -304,55 +453,21 @@ const bGenerateMarkup = (esTemplate `
|
|
|
304
453
|
}
|
|
305
454
|
const tmplFn = ${isIdentOrRenderCall} ?? __fallbackTmpl;
|
|
306
455
|
yield \`<\${tagName}\`;
|
|
307
|
-
|
|
308
|
-
|
|
456
|
+
const shouldRenderScopeToken = tmplFn.hasScopedStylesheets || hasScopedStaticStylesheets(${ /*Component class */0});
|
|
457
|
+
if (shouldRenderScopeToken) {
|
|
458
|
+
yield \` class="\${tmplFn.stylesheetScopeToken}-host"\`;
|
|
459
|
+
}
|
|
460
|
+
yield* __renderAttrs(instance, attrs);
|
|
309
461
|
yield '>';
|
|
310
|
-
yield* tmplFn(props, attrs, slotted, ${
|
|
462
|
+
yield* tmplFn(props, attrs, slotted, ${0}, instance);
|
|
311
463
|
yield \`</\${tagName}>\`;
|
|
312
464
|
}
|
|
313
465
|
`);
|
|
314
|
-
const
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
mutationTracker as __mutationTracker,
|
|
318
|
-
renderAttrs as __renderAttrs,
|
|
319
|
-
SYMBOL__SET_INTERNALS as __SYMBOL__SET_INTERNALS,
|
|
320
|
-
} from '@lwc/ssr-runtime';
|
|
321
|
-
`);
|
|
322
|
-
const bCreateReflectedPropArr = (esTemplate `
|
|
323
|
-
const __REFLECTED_PROPS__ = ${estreeToolkit.is.arrayExpression};
|
|
324
|
-
`);
|
|
325
|
-
function bReflectedAttrsObj(reflectedPropNames) {
|
|
326
|
-
// This will build getter properties for each reflected property. It'll look
|
|
327
|
-
// something like this:
|
|
328
|
-
//
|
|
329
|
-
// get ['aria-checked']() {
|
|
330
|
-
// return props.ariaChecked;
|
|
331
|
-
// }
|
|
332
|
-
//
|
|
333
|
-
// The props object will be kept up-to-date with any new values set on the corresponding
|
|
334
|
-
// property name in the component instance.
|
|
335
|
-
const reflectedAttrAccessors = [];
|
|
336
|
-
for (const propName of reflectedPropNames) {
|
|
337
|
-
reflectedAttrAccessors.push(estreeToolkit.builders.property('get', estreeToolkit.builders.literal(shared.AriaPropNameToAttrNameMap[propName]), estreeToolkit.builders.functionExpression(null, [], estreeToolkit.builders.blockStatement([
|
|
338
|
-
estreeToolkit.builders.returnStatement(estreeToolkit.builders.callExpression(estreeToolkit.builders.identifier('String'), [
|
|
339
|
-
estreeToolkit.builders.memberExpression(estreeToolkit.builders.identifier('props'), estreeToolkit.builders.identifier(propName)),
|
|
340
|
-
])),
|
|
341
|
-
]))), estreeToolkit.builders.property('set', estreeToolkit.builders.literal(shared.AriaPropNameToAttrNameMap[propName]), estreeToolkit.builders.functionExpression(null, [estreeToolkit.builders.identifier('val')], estreeToolkit.builders.blockStatement([
|
|
342
|
-
estreeToolkit.builders.expressionStatement(estreeToolkit.builders.assignmentExpression('=', estreeToolkit.builders.memberExpression(estreeToolkit.builders.identifier('props'), estreeToolkit.builders.identifier(propName)), estreeToolkit.builders.identifier('val'))),
|
|
343
|
-
]))));
|
|
466
|
+
const bAssignGenerateMarkupToComponentClass = (esTemplate `
|
|
467
|
+
{
|
|
468
|
+
${ /* lwcClassName */estreeToolkit.is.identifier}[__SYMBOL__GENERATE_MARKUP] = generateMarkup;
|
|
344
469
|
}
|
|
345
|
-
|
|
346
|
-
// detected. Example:
|
|
347
|
-
//
|
|
348
|
-
// attrs = {
|
|
349
|
-
// ...attrs,
|
|
350
|
-
// get ['aria-checked']() {
|
|
351
|
-
// return props.ariaChecked;
|
|
352
|
-
// }
|
|
353
|
-
// }
|
|
354
|
-
return estreeToolkit.builders.expressionStatement(estreeToolkit.builders.assignmentExpression('=', estreeToolkit.builders.identifier('attrs'), estreeToolkit.builders.objectExpression([estreeToolkit.builders.spreadElement(estreeToolkit.builders.identifier('attrs')), ...reflectedAttrAccessors])));
|
|
355
|
-
}
|
|
470
|
+
`);
|
|
356
471
|
/**
|
|
357
472
|
* This builds a generator function `generateMarkup` and adds it to the component JS's
|
|
358
473
|
* compilation output. `generateMarkup` acts as the glue between component JS and its
|
|
@@ -372,17 +487,31 @@ function addGenerateMarkupExport(program, state, filename) {
|
|
|
372
487
|
? estreeToolkit.builders.callExpression(estreeToolkit.builders.memberExpression(estreeToolkit.builders.identifier('instance'), estreeToolkit.builders.identifier('render')), [])
|
|
373
488
|
: estreeToolkit.builders.identifier('tmpl');
|
|
374
489
|
if (!tmplExplicitImports) {
|
|
375
|
-
const defaultTmplPath = `./${node_path.
|
|
376
|
-
program.body.unshift(
|
|
377
|
-
}
|
|
378
|
-
let attrsAugmentation = null;
|
|
379
|
-
if (state.reflectedPropsInPlay.size) {
|
|
380
|
-
attrsAugmentation = bReflectedAttrsObj([...state.reflectedPropsInPlay]);
|
|
490
|
+
const defaultTmplPath = `./${node_path.parse(filename).name}.html`;
|
|
491
|
+
program.body.unshift(bImportDefaultDeclaration('tmpl', defaultTmplPath));
|
|
381
492
|
}
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
493
|
+
program.body.unshift(bImportDeclaration([
|
|
494
|
+
{
|
|
495
|
+
fallbackTmpl: '__fallbackTmpl',
|
|
496
|
+
mutationTracker: '__mutationTracker',
|
|
497
|
+
renderAttrs: '__renderAttrs',
|
|
498
|
+
SYMBOL__SET_INTERNALS: '__SYMBOL__SET_INTERNALS',
|
|
499
|
+
},
|
|
500
|
+
]));
|
|
501
|
+
program.body.unshift(bImportDeclaration(['hasScopedStaticStylesheets']));
|
|
502
|
+
program.body.push(bGenerateMarkup(classIdentifier, renderCall));
|
|
503
|
+
}
|
|
504
|
+
/**
|
|
505
|
+
* Attach the `generateMarkup` function to the Component class so that it can be found later
|
|
506
|
+
* during `renderComponent`.
|
|
507
|
+
*/
|
|
508
|
+
function assignGenerateMarkupToComponent(program, state) {
|
|
509
|
+
program.body.unshift(bImportDeclaration([
|
|
510
|
+
{
|
|
511
|
+
SYMBOL__GENERATE_MARKUP: '__SYMBOL__GENERATE_MARKUP',
|
|
512
|
+
},
|
|
513
|
+
]));
|
|
514
|
+
program.body.push(bAssignGenerateMarkupToComponentClass(estreeToolkit.builders.identifier(state.lwcClassName)));
|
|
386
515
|
}
|
|
387
516
|
|
|
388
517
|
/*
|
|
@@ -393,19 +522,13 @@ function addGenerateMarkupExport(program, state, filename) {
|
|
|
393
522
|
*/
|
|
394
523
|
const visitors = {
|
|
395
524
|
$: { scope: true },
|
|
396
|
-
Identifier(path, state) {
|
|
397
|
-
const reflectedAttrName = shared.AriaPropNameToAttrNameMap[path.node.name];
|
|
398
|
-
if (reflectedAttrName) {
|
|
399
|
-
state.reflectedPropsInPlay.add(path.node.name);
|
|
400
|
-
}
|
|
401
|
-
},
|
|
402
525
|
ImportDeclaration(path, state) {
|
|
403
526
|
if (!path.node || !path.node.source.value || typeof path.node.source.value !== 'string') {
|
|
404
527
|
return;
|
|
405
528
|
}
|
|
406
529
|
replaceLwcImport(path, state);
|
|
407
530
|
catalogTmplImport(path, state);
|
|
408
|
-
|
|
531
|
+
catalogAndReplaceStyleImports(path, state);
|
|
409
532
|
},
|
|
410
533
|
ClassDeclaration(path, state) {
|
|
411
534
|
if (!path.node?.superClass) {
|
|
@@ -474,8 +597,8 @@ const visitors = {
|
|
|
474
597
|
}
|
|
475
598
|
},
|
|
476
599
|
};
|
|
477
|
-
function compileJS(src, filename) {
|
|
478
|
-
|
|
600
|
+
function compileJS(src, filename, compilationMode) {
|
|
601
|
+
let ast = meriyah.parseModule(src, {
|
|
479
602
|
module: true,
|
|
480
603
|
next: true,
|
|
481
604
|
});
|
|
@@ -492,7 +615,6 @@ function compileJS(src, filename) {
|
|
|
492
615
|
tmplExplicitImports: null,
|
|
493
616
|
cssExplicitImports: null,
|
|
494
617
|
staticStylesheetIds: null,
|
|
495
|
-
reflectedPropsInPlay: new Set(),
|
|
496
618
|
};
|
|
497
619
|
estreeToolkit.traverse(ast, visitors, state);
|
|
498
620
|
if (!state.isLWC) {
|
|
@@ -503,10 +625,11 @@ function compileJS(src, filename) {
|
|
|
503
625
|
code: astring.generate(ast, {}),
|
|
504
626
|
};
|
|
505
627
|
}
|
|
506
|
-
if (state.cssExplicitImports || state.staticStylesheetIds) {
|
|
507
|
-
throw new Error(`Unimplemented static stylesheets, but found:\n${[...state.cssExplicitImports].join(' \n')}`);
|
|
508
|
-
}
|
|
509
628
|
addGenerateMarkupExport(ast, state, filename);
|
|
629
|
+
assignGenerateMarkupToComponent(ast, state);
|
|
630
|
+
if (compilationMode === 'async' || compilationMode === 'sync') {
|
|
631
|
+
ast = transmogrify(ast, compilationMode);
|
|
632
|
+
}
|
|
510
633
|
return {
|
|
511
634
|
code: astring.generate(ast, {}),
|
|
512
635
|
};
|
|
@@ -1676,7 +1799,7 @@ var CompilerMetrics;
|
|
|
1676
1799
|
CompilerMetrics["LWCSpreadDirective"] = "lwc-spread-directive";
|
|
1677
1800
|
CompilerMetrics["DynamicImportTransform"] = "dynamic-import-transform";
|
|
1678
1801
|
})(CompilerMetrics || (CompilerMetrics = {}));
|
|
1679
|
-
/** version: 8.
|
|
1802
|
+
/** version: 8.5.0 */
|
|
1680
1803
|
|
|
1681
1804
|
/*
|
|
1682
1805
|
* Copyright (c) 2024, Salesforce, Inc.
|
|
@@ -1687,27 +1810,21 @@ var CompilerMetrics;
|
|
|
1687
1810
|
const bStylesheetTokenDeclaration = (esTemplate `
|
|
1688
1811
|
const stylesheetScopeToken = '${estreeToolkit.is.literal}';
|
|
1689
1812
|
`);
|
|
1690
|
-
const
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
`),
|
|
1694
|
-
(esTemplate `
|
|
1695
|
-
const stylesheetScopeTokenClass = hasScopedStylesheets ? \` class="\${stylesheetScopeToken}"\` : '';
|
|
1696
|
-
`),
|
|
1697
|
-
(esTemplate `
|
|
1698
|
-
const stylesheetScopeTokenHostClass = hasScopedStylesheets ? \` class="\${stylesheetScopeToken}-host"\` : '';
|
|
1699
|
-
`),
|
|
1700
|
-
(esTemplate `
|
|
1701
|
-
const stylesheetScopeTokenClassPrefix = hasScopedStylesheets ? (stylesheetScopeToken + ' ') : '';
|
|
1702
|
-
`),
|
|
1703
|
-
];
|
|
1813
|
+
const bHasScopedStylesheetsDeclaration = (esTemplate `
|
|
1814
|
+
const hasScopedStylesheets = defaultScopedStylesheets !== undefined && defaultScopedStylesheets.length > 0;
|
|
1815
|
+
`);
|
|
1704
1816
|
// Scope tokens are associated with a given template. This is assigned here so that it can be used in `generateMarkup`.
|
|
1817
|
+
// We also need to keep track of whether the template has any scoped styles or not so that we can render (or not) the
|
|
1818
|
+
// scope token.
|
|
1705
1819
|
const tmplAssignmentBlock = (esTemplate `
|
|
1706
|
-
|
|
1820
|
+
{
|
|
1821
|
+
${ /* template */estreeToolkit.is.identifier}.hasScopedStylesheets = hasScopedStylesheets;
|
|
1822
|
+
${ /* template */0}.stylesheetScopeToken = stylesheetScopeToken;
|
|
1823
|
+
}
|
|
1707
1824
|
`);
|
|
1708
1825
|
function addScopeTokenDeclarations(program, filename, namespace, componentName) {
|
|
1709
1826
|
const { scopeToken } = templateCompiler.generateScopeTokens(filename, namespace, componentName);
|
|
1710
|
-
program.body.unshift(bStylesheetTokenDeclaration(builders.builders.literal(scopeToken)),
|
|
1827
|
+
program.body.unshift(bStylesheetTokenDeclaration(builders.builders.literal(scopeToken)), bHasScopedStylesheetsDeclaration());
|
|
1711
1828
|
program.body.push(tmplAssignmentBlock(builders.builders.identifier('tmpl')));
|
|
1712
1829
|
}
|
|
1713
1830
|
|
|
@@ -1717,9 +1834,7 @@ function addScopeTokenDeclarations(program, filename, namespace, componentName)
|
|
|
1717
1834
|
* SPDX-License-Identifier: MIT
|
|
1718
1835
|
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
|
|
1719
1836
|
*/
|
|
1720
|
-
const bImportHtmlEscape = (
|
|
1721
|
-
import { htmlEscape } from '@lwc/shared';
|
|
1722
|
-
`);
|
|
1837
|
+
const bImportHtmlEscape = () => bImportDeclaration(['htmlEscape']);
|
|
1723
1838
|
const importHtmlEscapeKey = 'import:htmlEscape';
|
|
1724
1839
|
// This is a mostly-correct regular expression will only match if the entire string
|
|
1725
1840
|
// provided is a valid ECMAScript identifier. Its imperfections lie in the fact that
|
|
@@ -1756,6 +1871,44 @@ function optimizeAdjacentYieldStmts(statements) {
|
|
|
1756
1871
|
})
|
|
1757
1872
|
.filter((el) => el !== null);
|
|
1758
1873
|
}
|
|
1874
|
+
function bAttributeValue(node, attrName) {
|
|
1875
|
+
if (!('attributes' in node)) {
|
|
1876
|
+
throw new TypeError(`Cannot get attribute value from ${node.type}`);
|
|
1877
|
+
}
|
|
1878
|
+
const nameAttrValue = node.attributes.find((attr) => attr.name === attrName)?.value;
|
|
1879
|
+
if (!nameAttrValue) {
|
|
1880
|
+
return estreeToolkit.builders.literal(null);
|
|
1881
|
+
}
|
|
1882
|
+
else if (nameAttrValue.type === 'Literal') {
|
|
1883
|
+
const name = typeof nameAttrValue.value === 'string' ? nameAttrValue.value : '';
|
|
1884
|
+
return estreeToolkit.builders.literal(name);
|
|
1885
|
+
}
|
|
1886
|
+
else {
|
|
1887
|
+
return estreeToolkit.builders.memberExpression(estreeToolkit.builders.literal('instance'), nameAttrValue);
|
|
1888
|
+
}
|
|
1889
|
+
}
|
|
1890
|
+
function getRootMemberExpression$2(node) {
|
|
1891
|
+
return node.object.type === 'MemberExpression' ? getRootMemberExpression$2(node.object) : node;
|
|
1892
|
+
}
|
|
1893
|
+
function getRootIdentifier$1(node) {
|
|
1894
|
+
const rootMemberExpression = getRootMemberExpression$2(node);
|
|
1895
|
+
return estreeToolkit.is.identifier(rootMemberExpression?.object) ? rootMemberExpression.object : null;
|
|
1896
|
+
}
|
|
1897
|
+
/**
|
|
1898
|
+
* Given an expression in a context, return an expression that may be scoped to that context.
|
|
1899
|
+
* For example, for the expression `foo`, it will typically be `instance.foo`, but if we're
|
|
1900
|
+
* inside a `for:each` block then the `foo` variable may refer to the scoped `foo`,
|
|
1901
|
+
* e.g. `<template for:each={foos} for:item="foo">`
|
|
1902
|
+
* @param expression
|
|
1903
|
+
*/
|
|
1904
|
+
function getScopedExpression(expression, cxt) {
|
|
1905
|
+
const scopeReferencedId = estreeToolkit.is.memberExpression(expression)
|
|
1906
|
+
? getRootIdentifier$1(expression)
|
|
1907
|
+
: null;
|
|
1908
|
+
return cxt.isLocalVar(scopeReferencedId?.name)
|
|
1909
|
+
? expression
|
|
1910
|
+
: estreeToolkit.builders.memberExpression(estreeToolkit.builders.identifier('instance'), expression);
|
|
1911
|
+
}
|
|
1759
1912
|
|
|
1760
1913
|
/*
|
|
1761
1914
|
* Copyright (c) 2024, salesforce.com, inc.
|
|
@@ -1778,8 +1931,8 @@ const Comment = function Comment(node, cxt) {
|
|
|
1778
1931
|
* SPDX-License-Identifier: MIT
|
|
1779
1932
|
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
|
|
1780
1933
|
*/
|
|
1781
|
-
function getRootMemberExpression$
|
|
1782
|
-
return node.object.type === 'MemberExpression' ? getRootMemberExpression$
|
|
1934
|
+
function getRootMemberExpression$1(node) {
|
|
1935
|
+
return node.object.type === 'MemberExpression' ? getRootMemberExpression$1(node.object) : node;
|
|
1783
1936
|
}
|
|
1784
1937
|
function expressionIrToEs(node, cxt) {
|
|
1785
1938
|
if (node.type === 'Identifier') {
|
|
@@ -1790,7 +1943,7 @@ function expressionIrToEs(node, cxt) {
|
|
|
1790
1943
|
}
|
|
1791
1944
|
else if (node.type === 'MemberExpression') {
|
|
1792
1945
|
const nodeClone = structuredClone(node);
|
|
1793
|
-
const rootMemberExpr = getRootMemberExpression$
|
|
1946
|
+
const rootMemberExpr = getRootMemberExpression$1(nodeClone);
|
|
1794
1947
|
if (!cxt.isLocalVar(rootMemberExpr.object.name)) {
|
|
1795
1948
|
rootMemberExpr.object = estreeToolkit.builders.memberExpression(estreeToolkit.builders.identifier('instance'), rootMemberExpr.object);
|
|
1796
1949
|
}
|
|
@@ -1809,12 +1962,29 @@ const bYieldFromChildGenerator = (esTemplateWithYield `
|
|
|
1809
1962
|
{
|
|
1810
1963
|
const childProps = ${estreeToolkit.is.objectExpression};
|
|
1811
1964
|
const childAttrs = ${estreeToolkit.is.objectExpression};
|
|
1812
|
-
|
|
1813
|
-
|
|
1965
|
+
const slottedContent = {
|
|
1966
|
+
light: Object.create(null),
|
|
1967
|
+
shadow: async function* () {
|
|
1968
|
+
${ /* shadow slot content */estreeToolkit.is.statement}
|
|
1969
|
+
}
|
|
1814
1970
|
};
|
|
1815
|
-
|
|
1971
|
+
function addContent(name, fn) {
|
|
1972
|
+
let contentList = slottedContent.light[name]
|
|
1973
|
+
if (contentList) {
|
|
1974
|
+
contentList.push(fn)
|
|
1975
|
+
} else {
|
|
1976
|
+
slottedContent.light[name] = [fn]
|
|
1977
|
+
}
|
|
1978
|
+
}
|
|
1979
|
+
${ /* addContent statements */estreeToolkit.is.callExpression}
|
|
1980
|
+
yield* ${estreeToolkit.is.identifier}(${estreeToolkit.is.literal}, childProps, childAttrs, slottedContent);
|
|
1816
1981
|
}
|
|
1817
1982
|
`);
|
|
1983
|
+
const bAddContent = (esTemplate `
|
|
1984
|
+
addContent(${ /* slot name */estreeToolkit.is.expression} ?? "", async function* () {
|
|
1985
|
+
${ /* slot content */estreeToolkit.is.statement}
|
|
1986
|
+
});
|
|
1987
|
+
`);
|
|
1818
1988
|
const bImportGenerateMarkup = (localName, importPath) => estreeToolkit.builders.importDeclaration([estreeToolkit.builders.importSpecifier(estreeToolkit.builders.identifier('generateMarkup'), estreeToolkit.builders.identifier(localName))], estreeToolkit.builders.literal(importPath));
|
|
1819
1989
|
function getChildAttrsOrProps(attrs, cxt) {
|
|
1820
1990
|
const objectAttrsOrProps = attrs.map((attr) => {
|
|
@@ -1858,8 +2028,24 @@ const Component = function Component(node, cxt) {
|
|
|
1858
2028
|
cxt.hoist(componentImport, childGeneratorLocalName);
|
|
1859
2029
|
const childTagName = node.name;
|
|
1860
2030
|
const attributes = [...node.attributes, ...reflectAriaPropsAsAttrs(node.properties)];
|
|
2031
|
+
const shadowSlotContent = optimizeAdjacentYieldStmts(irChildrenToEs(node.children, cxt));
|
|
2032
|
+
const lightSlotContent = node.children.map((child) => {
|
|
2033
|
+
if ('attributes' in child) {
|
|
2034
|
+
const slotName = bAttributeValue(child, 'slot');
|
|
2035
|
+
// FIXME: We don't know what happens for slot attributes inside an lwc:if block
|
|
2036
|
+
// Light DOM slots do not actually render the `slot` attribute.
|
|
2037
|
+
const clone = immer.produce(child, (draft) => {
|
|
2038
|
+
draft.attributes = draft.attributes.filter((attr) => attr.name !== 'slot');
|
|
2039
|
+
});
|
|
2040
|
+
const slotContent = irToEs(clone, cxt);
|
|
2041
|
+
return bAddContent(slotName, slotContent);
|
|
2042
|
+
}
|
|
2043
|
+
else {
|
|
2044
|
+
return bAddContent(estreeToolkit.builders.literal(''), irToEs(child, cxt));
|
|
2045
|
+
}
|
|
2046
|
+
});
|
|
1861
2047
|
return [
|
|
1862
|
-
bYieldFromChildGenerator(getChildAttrsOrProps(node.properties, cxt), getChildAttrsOrProps(attributes, cxt),
|
|
2048
|
+
bYieldFromChildGenerator(getChildAttrsOrProps(node.properties, cxt), getChildAttrsOrProps(attributes, cxt), shadowSlotContent, lightSlotContent, estreeToolkit.builders.identifier(childGeneratorLocalName), estreeToolkit.builders.literal(childTagName)),
|
|
1863
2049
|
];
|
|
1864
2050
|
};
|
|
1865
2051
|
|
|
@@ -1870,23 +2056,39 @@ const Component = function Component(node, cxt) {
|
|
|
1870
2056
|
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
|
|
1871
2057
|
*/
|
|
1872
2058
|
const bYield$1 = (expr) => estreeToolkit.builders.expressionStatement(estreeToolkit.builders.yieldExpression(expr));
|
|
2059
|
+
// TODO [#4714]: scope token renders as a suffix for literals, but prefix for expressions
|
|
1873
2060
|
const bConditionalLiveYield = (esTemplateWithYield `
|
|
1874
2061
|
{
|
|
1875
|
-
const
|
|
1876
|
-
|
|
1877
|
-
const
|
|
1878
|
-
|
|
1879
|
-
|
|
2062
|
+
const shouldRenderScopeToken = ${ /* isClass */estreeToolkit.is.literal} &&
|
|
2063
|
+
(hasScopedStylesheets || hasScopedStaticStylesheets(Cmp));
|
|
2064
|
+
const prefix = shouldRenderScopeToken ? stylesheetScopeToken + ' ' : '';
|
|
2065
|
+
|
|
2066
|
+
const attrValue = ${ /* attribute value expression */estreeToolkit.is.expression};
|
|
2067
|
+
const valueType = typeof attrValue;
|
|
2068
|
+
|
|
2069
|
+
if (attrValue && (valueType === 'string' || valueType === 'boolean')) {
|
|
2070
|
+
yield ' ' + ${ /* attribute name */estreeToolkit.is.literal};
|
|
1880
2071
|
if (valueType === 'string') {
|
|
1881
|
-
yield \`="\${prefix}\${htmlEscape(
|
|
2072
|
+
yield \`="\${prefix}\${htmlEscape(attrValue, true)}"\`;
|
|
1882
2073
|
}
|
|
1883
2074
|
}
|
|
1884
2075
|
}
|
|
1885
2076
|
`);
|
|
2077
|
+
// TODO [#4714]: scope token renders as a suffix for literals, but prefix for expressions
|
|
1886
2078
|
const bStringLiteralYield = (esTemplateWithYield `
|
|
1887
2079
|
{
|
|
1888
|
-
const
|
|
1889
|
-
|
|
2080
|
+
const shouldRenderScopeToken = ${ /* isClass */estreeToolkit.is.literal} &&
|
|
2081
|
+
(hasScopedStylesheets || hasScopedStaticStylesheets(Cmp));
|
|
2082
|
+
const suffix = shouldRenderScopeToken ? ' ' + stylesheetScopeToken : '';
|
|
2083
|
+
yield ' ' + ${ /* attribute name */estreeToolkit.is.literal} + '="' + "${ /* attribute value */estreeToolkit.is.literal}" + suffix + '"'
|
|
2084
|
+
}
|
|
2085
|
+
`);
|
|
2086
|
+
const bConditionallyYieldScopeTokenClass = (esTemplateWithYield `
|
|
2087
|
+
{
|
|
2088
|
+
const shouldRenderScopeToken = hasScopedStylesheets || hasScopedStaticStylesheets(Cmp);
|
|
2089
|
+
if (shouldRenderScopeToken) {
|
|
2090
|
+
yield \` class="\${stylesheetScopeToken}"\`;
|
|
2091
|
+
}
|
|
1890
2092
|
}
|
|
1891
2093
|
`);
|
|
1892
2094
|
function yieldAttrOrPropLiteralValue(name, valueNode, isClass) {
|
|
@@ -1910,9 +2112,9 @@ function yieldAttrOrPropLiteralValue(name, valueNode, isClass) {
|
|
|
1910
2112
|
}
|
|
1911
2113
|
throw new Error(`Unknown attr/prop literal: ${type}`);
|
|
1912
2114
|
}
|
|
1913
|
-
function yieldAttrOrPropLiveValue(name, value, isClass) {
|
|
1914
|
-
const
|
|
1915
|
-
return [bConditionalLiveYield(estreeToolkit.builders.literal(isClass),
|
|
2115
|
+
function yieldAttrOrPropLiveValue(name, value, isClass, cxt) {
|
|
2116
|
+
const scopedExpression = getScopedExpression(value, cxt);
|
|
2117
|
+
return [bConditionalLiveYield(estreeToolkit.builders.literal(isClass), scopedExpression, estreeToolkit.builders.literal(name))];
|
|
1916
2118
|
}
|
|
1917
2119
|
function reorderAttributes(attrs, props) {
|
|
1918
2120
|
let classAttr = null;
|
|
@@ -1951,7 +2153,7 @@ const Element = function Element(node, cxt) {
|
|
|
1951
2153
|
return yieldAttrOrPropLiteralValue(name, value, isClass);
|
|
1952
2154
|
}
|
|
1953
2155
|
else {
|
|
1954
|
-
return yieldAttrOrPropLiveValue(name, value, isClass);
|
|
2156
|
+
return yieldAttrOrPropLiveValue(name, value, isClass, cxt);
|
|
1955
2157
|
}
|
|
1956
2158
|
});
|
|
1957
2159
|
if (shared.isVoidElement(node.name, shared.HTML_NAMESPACE)) {
|
|
@@ -1974,7 +2176,7 @@ const Element = function Element(node, cxt) {
|
|
|
1974
2176
|
return [
|
|
1975
2177
|
bYield$1(estreeToolkit.builders.literal(`<${node.name}`)),
|
|
1976
2178
|
// If we haven't already prefixed the scope token to an existing class, add an explicit class here
|
|
1977
|
-
...(hasClassAttribute ? [] : [
|
|
2179
|
+
...(hasClassAttribute ? [] : [bConditionallyYieldScopeTokenClass()]),
|
|
1978
2180
|
...yieldAttrsAndProps,
|
|
1979
2181
|
bYield$1(estreeToolkit.builders.literal(`>`)),
|
|
1980
2182
|
...childContent,
|
|
@@ -1988,13 +2190,6 @@ const Element = function Element(node, cxt) {
|
|
|
1988
2190
|
* SPDX-License-Identifier: MIT
|
|
1989
2191
|
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
|
|
1990
2192
|
*/
|
|
1991
|
-
function getRootMemberExpression$1(node) {
|
|
1992
|
-
return node.object.type === 'MemberExpression' ? getRootMemberExpression$1(node.object) : node;
|
|
1993
|
-
}
|
|
1994
|
-
function getRootIdentifier$1(node) {
|
|
1995
|
-
const rootMemberExpression = getRootMemberExpression$1(node);
|
|
1996
|
-
return estreeToolkit.is.identifier(rootMemberExpression?.object) ? rootMemberExpression.object : null;
|
|
1997
|
-
}
|
|
1998
2193
|
const bForOfYieldFrom$1 = (esTemplate `
|
|
1999
2194
|
for (let [${estreeToolkit.is.identifier}, ${estreeToolkit.is.identifier}] of Object.entries(${estreeToolkit.is.expression} ?? {})) {
|
|
2000
2195
|
${estreeToolkit.is.statement};
|
|
@@ -2009,12 +2204,7 @@ const ForEach = function ForEach(node, cxt) {
|
|
|
2009
2204
|
});
|
|
2010
2205
|
cxt.popLocalVars();
|
|
2011
2206
|
const expression = node.expression;
|
|
2012
|
-
const
|
|
2013
|
-
? getRootIdentifier$1(expression)
|
|
2014
|
-
: null;
|
|
2015
|
-
const iterable = cxt.isLocalVar(scopeReferencedId?.name)
|
|
2016
|
-
? node.expression
|
|
2017
|
-
: estreeToolkit.builders.memberExpression(estreeToolkit.builders.identifier('instance'), node.expression);
|
|
2207
|
+
const iterable = getScopedExpression(expression, cxt);
|
|
2018
2208
|
return [
|
|
2019
2209
|
bForOfYieldFrom$1(estreeToolkit.builders.identifier(forIndexId), estreeToolkit.builders.identifier(forItemId), iterable, optimizeAdjacentYieldStmts(forEachStatements)),
|
|
2020
2210
|
];
|
|
@@ -2038,9 +2228,6 @@ const bForOfYieldFrom = (esTemplate `
|
|
|
2038
2228
|
${estreeToolkit.is.statement};
|
|
2039
2229
|
}
|
|
2040
2230
|
`);
|
|
2041
|
-
const bToIteratorDirectiveImport = (esTemplate `
|
|
2042
|
-
import { toIteratorDirective } from '@lwc/ssr-runtime';
|
|
2043
|
-
`);
|
|
2044
2231
|
const ForOf = function ForEach(node, cxt) {
|
|
2045
2232
|
const id = node.iterator.name;
|
|
2046
2233
|
cxt.pushLocalVars([id]);
|
|
@@ -2055,7 +2242,7 @@ const ForOf = function ForEach(node, cxt) {
|
|
|
2055
2242
|
const iterable = cxt.isLocalVar(scopeReferencedId?.name)
|
|
2056
2243
|
? node.expression
|
|
2057
2244
|
: estreeToolkit.builders.memberExpression(estreeToolkit.builders.identifier('instance'), node.expression);
|
|
2058
|
-
cxt.hoist(
|
|
2245
|
+
cxt.hoist(bImportDeclaration(['toIteratorDirective']), 'import:toIteratorDirective');
|
|
2059
2246
|
return [
|
|
2060
2247
|
bForOfYieldFrom(estreeToolkit.builders.identifier(id), iterable, optimizeAdjacentYieldStmts(forEachStatements)),
|
|
2061
2248
|
];
|
|
@@ -2110,9 +2297,11 @@ const bConditionalSlot = (esTemplateWithYield `
|
|
|
2110
2297
|
// start bookend HTML comment
|
|
2111
2298
|
yield '<!---->';
|
|
2112
2299
|
|
|
2113
|
-
const
|
|
2114
|
-
if (
|
|
2115
|
-
|
|
2300
|
+
const generators = slottedContent?.light[${ /* slotName */estreeToolkit.is.expression} ?? ""];
|
|
2301
|
+
if (generators) {
|
|
2302
|
+
for (const generator of generators) {
|
|
2303
|
+
yield* generator();
|
|
2304
|
+
}
|
|
2116
2305
|
} else {
|
|
2117
2306
|
// If we're in this else block, then the generator _must_ have yielded
|
|
2118
2307
|
// something. It's impossible for a slottedContent["foo"] to exist
|
|
@@ -2129,18 +2318,7 @@ const bConditionalSlot = (esTemplateWithYield `
|
|
|
2129
2318
|
}
|
|
2130
2319
|
`);
|
|
2131
2320
|
const Slot = function Slot(node, ctx) {
|
|
2132
|
-
const
|
|
2133
|
-
let slotName;
|
|
2134
|
-
if (!nameAttrValue) {
|
|
2135
|
-
slotName = estreeToolkit.builders.literal('');
|
|
2136
|
-
}
|
|
2137
|
-
else if (nameAttrValue.type === 'Literal') {
|
|
2138
|
-
const name = typeof nameAttrValue.value === 'string' ? nameAttrValue.value : '';
|
|
2139
|
-
slotName = estreeToolkit.builders.literal(name);
|
|
2140
|
-
}
|
|
2141
|
-
else {
|
|
2142
|
-
slotName = estreeToolkit.builders.memberExpression(estreeToolkit.builders.literal('instance'), nameAttrValue);
|
|
2143
|
-
}
|
|
2321
|
+
const slotName = bAttributeValue(node, 'name');
|
|
2144
2322
|
// FIXME: avoid serializing the slot's children twice
|
|
2145
2323
|
const slotAst = Element(node, ctx);
|
|
2146
2324
|
const slotChildren = irChildrenToEs(node.children, ctx);
|
|
@@ -2296,9 +2474,6 @@ function templateIrToEsTree(node, contextOpts) {
|
|
|
2296
2474
|
* SPDX-License-Identifier: MIT
|
|
2297
2475
|
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
|
|
2298
2476
|
*/
|
|
2299
|
-
const bStyleValidationImport = (esTemplate `
|
|
2300
|
-
import { validateStyleTextContents } from '@lwc/ssr-runtime';
|
|
2301
|
-
`);
|
|
2302
2477
|
// TODO [#4663]: Render mode mismatch between template and compiler should throw.
|
|
2303
2478
|
const bExportTemplate = (esTemplate `
|
|
2304
2479
|
export default async function* tmpl(props, attrs, slottedContent, Cmp, instance) {
|
|
@@ -2307,34 +2482,28 @@ const bExportTemplate = (esTemplate `
|
|
|
2307
2482
|
yield \`<template shadowrootmode="open"\${Cmp.delegatesFocus ? ' shadowrootdelegatesfocus' : ''}>\`
|
|
2308
2483
|
}
|
|
2309
2484
|
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
const stylesheets = [defaultStylesheets, defaultScopedStylesheets]
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
const styleContents = stylesheet(token, useActualHostSelector, useNativeDirPseudoclass);
|
|
2320
|
-
validateStyleTextContents(styleContents);
|
|
2321
|
-
yield styleContents;
|
|
2322
|
-
yield '</style>';
|
|
2323
|
-
}
|
|
2485
|
+
const { stylesheets: staticStylesheets } = Cmp;
|
|
2486
|
+
if (defaultStylesheets || defaultScopedStylesheets || staticStylesheets) {
|
|
2487
|
+
const stylesheets = [defaultStylesheets, defaultScopedStylesheets, staticStylesheets];
|
|
2488
|
+
yield renderStylesheets(
|
|
2489
|
+
stylesheets,
|
|
2490
|
+
stylesheetScopeToken,
|
|
2491
|
+
Cmp,
|
|
2492
|
+
hasScopedStylesheets,
|
|
2493
|
+
);
|
|
2324
2494
|
}
|
|
2325
2495
|
|
|
2326
2496
|
${estreeToolkit.is.statement};
|
|
2327
2497
|
|
|
2328
2498
|
if (!isLightDom) {
|
|
2329
2499
|
yield '</template>';
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
yield* slottedContent();
|
|
2500
|
+
if (slottedContent?.shadow) {
|
|
2501
|
+
yield* slottedContent.shadow();
|
|
2502
|
+
}
|
|
2334
2503
|
}
|
|
2335
2504
|
}
|
|
2336
2505
|
`);
|
|
2337
|
-
function compileTemplate(src, filename, options) {
|
|
2506
|
+
function compileTemplate(src, filename, options, compilationMode) {
|
|
2338
2507
|
const { root, warnings } = templateCompiler.parse(src, {
|
|
2339
2508
|
// `options` is from @lwc/compiler, and may have flags that @lwc/template-compiler doesn't
|
|
2340
2509
|
// know about, so we must explicitly extract the relevant props.
|
|
@@ -2371,13 +2540,16 @@ function compileTemplate(src, filename, options) {
|
|
|
2371
2540
|
const { hoisted, statements } = templateIrToEsTree(root, { preserveComments });
|
|
2372
2541
|
const moduleBody = [
|
|
2373
2542
|
...hoisted,
|
|
2374
|
-
|
|
2543
|
+
bImportDeclaration(['renderStylesheets', 'hasScopedStaticStylesheets']),
|
|
2375
2544
|
bExportTemplate(optimizeAdjacentYieldStmts(statements)),
|
|
2376
2545
|
];
|
|
2377
|
-
|
|
2546
|
+
let program = estreeToolkit.builders.program(moduleBody, 'module');
|
|
2378
2547
|
addScopeTokenDeclarations(program, filename, options.namespace, options.name);
|
|
2379
2548
|
const stylesheetImports = getStylesheetImports(filename);
|
|
2380
2549
|
program.body.unshift(...stylesheetImports);
|
|
2550
|
+
if (compilationMode === 'async' || compilationMode === 'sync') {
|
|
2551
|
+
program = transmogrify(program, compilationMode);
|
|
2552
|
+
}
|
|
2381
2553
|
return {
|
|
2382
2554
|
code: astring.generate(program, {}),
|
|
2383
2555
|
};
|
|
@@ -2389,16 +2561,16 @@ function compileTemplate(src, filename, options) {
|
|
|
2389
2561
|
* SPDX-License-Identifier: MIT
|
|
2390
2562
|
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
|
|
2391
2563
|
*/
|
|
2392
|
-
function compileComponentForSSR(src, filename, _options) {
|
|
2393
|
-
const { code } = compileJS(src, filename);
|
|
2564
|
+
function compileComponentForSSR(src, filename, _options, mode = 'asyncYield') {
|
|
2565
|
+
const { code } = compileJS(src, filename, mode);
|
|
2394
2566
|
return { code, map: undefined };
|
|
2395
2567
|
}
|
|
2396
|
-
function compileTemplateForSSR(src, filename, options) {
|
|
2397
|
-
const { code } = compileTemplate(src, filename, options);
|
|
2568
|
+
function compileTemplateForSSR(src, filename, options, mode = 'asyncYield') {
|
|
2569
|
+
const { code } = compileTemplate(src, filename, options, mode);
|
|
2398
2570
|
return { code, map: undefined };
|
|
2399
2571
|
}
|
|
2400
2572
|
|
|
2401
2573
|
exports.compileComponentForSSR = compileComponentForSSR;
|
|
2402
2574
|
exports.compileTemplateForSSR = compileTemplateForSSR;
|
|
2403
|
-
/** version: 8.
|
|
2575
|
+
/** version: 8.5.0 */
|
|
2404
2576
|
//# sourceMappingURL=index.cjs.js.map
|