@jsenv/ast 6.9.1 → 6.9.3
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/package.json
CHANGED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// "import.meta.<name>" as parsed by acorn: a member expression whose object
|
|
2
|
+
// is the "import.meta" meta property. Returns <name>, or null for any other node.
|
|
3
|
+
export const getImportMetaPropertyName = (node) => {
|
|
4
|
+
if (node.type !== "MemberExpression" || node.computed) {
|
|
5
|
+
return null;
|
|
6
|
+
}
|
|
7
|
+
const { object, property } = node;
|
|
8
|
+
if (
|
|
9
|
+
object.type !== "MetaProperty" ||
|
|
10
|
+
object.meta.name !== "import" ||
|
|
11
|
+
object.property.name !== "meta"
|
|
12
|
+
) {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
return property.name;
|
|
16
|
+
};
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
// A "${}" inside a css template hides the whole css from the build: nothing can
|
|
2
|
+
// be parsed, so nothing can be checked, rewritten or stripped.
|
|
3
|
+
// It can be kept readable when the expression stands exactly where a css value
|
|
4
|
+
// stands: "var(--jsenv-css-substitution-0)" is a value the css parser accepts
|
|
5
|
+
// anywhere a value is expected, so the css around it stays css, and the
|
|
6
|
+
// expression takes the placeholder's place back once the css is transformed.
|
|
7
|
+
// Anywhere else — a selector, an at-rule prelude, a property name, inside a
|
|
8
|
+
// string or inside url() — nothing can stand for the expression, and the
|
|
9
|
+
// template is left alone.
|
|
10
|
+
|
|
11
|
+
const PLACEHOLDER = (index) => `var(--jsenv-css-substitution-${index})`;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @param {Object} templateLiteralNode a TemplateLiteral acorn node
|
|
15
|
+
* @param {string} js the source the node comes from
|
|
16
|
+
* @returns {{ content: string, substitutions: Array<{placeholder: string, expression: string}> }|null}
|
|
17
|
+
* null when at least one expression is not in a css value position
|
|
18
|
+
*/
|
|
19
|
+
export const buildCssTemplateSubstitutions = (templateLiteralNode, js) => {
|
|
20
|
+
const { quasis, expressions } = templateLiteralNode;
|
|
21
|
+
const parts = [];
|
|
22
|
+
for (const quasi of quasis) {
|
|
23
|
+
const { cooked } = quasi.value;
|
|
24
|
+
if (cooked === undefined) {
|
|
25
|
+
// an escape sequence acorn could not cook: what the css is cannot be told
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
parts.push(cooked);
|
|
29
|
+
}
|
|
30
|
+
const substitutions = [];
|
|
31
|
+
let content = parts[0];
|
|
32
|
+
const positions = [];
|
|
33
|
+
for (let i = 0; i < expressions.length; i++) {
|
|
34
|
+
const placeholder = PLACEHOLDER(i);
|
|
35
|
+
positions.push(content.length);
|
|
36
|
+
substitutions.push({
|
|
37
|
+
placeholder,
|
|
38
|
+
expression: js.slice(expressions[i].start, expressions[i].end),
|
|
39
|
+
});
|
|
40
|
+
content += placeholder + parts[i + 1];
|
|
41
|
+
}
|
|
42
|
+
for (const position of positions) {
|
|
43
|
+
if (!isCssValuePosition(content, position)) {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return { content, substitutions };
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
// Reads the css from its start up to "position", keeping just enough state to
|
|
51
|
+
// tell what the placeholder sitting there would be part of.
|
|
52
|
+
const isCssValuePosition = (css, position) => {
|
|
53
|
+
let braceDepth = 0;
|
|
54
|
+
let stringQuote = null;
|
|
55
|
+
let inComment = false;
|
|
56
|
+
// the functions the position is nested in, innermost last ("" for a plain
|
|
57
|
+
// parenthesis); only url() has to be told apart, its argument is not a value
|
|
58
|
+
const functionStack = [];
|
|
59
|
+
// what has been read since the last "{", "}" or ";": a declaration value
|
|
60
|
+
// starts after a ":", and an at-rule prelude starts with "@"
|
|
61
|
+
let statementStart = 0;
|
|
62
|
+
let colonSeen = false;
|
|
63
|
+
let i = 0;
|
|
64
|
+
while (i < position) {
|
|
65
|
+
const char = css[i];
|
|
66
|
+
if (inComment) {
|
|
67
|
+
if (char === "*" && css[i + 1] === "/") {
|
|
68
|
+
inComment = false;
|
|
69
|
+
i += 2;
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
i++;
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
if (stringQuote) {
|
|
76
|
+
if (char === "\\") {
|
|
77
|
+
i += 2;
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
if (char === stringQuote) {
|
|
81
|
+
stringQuote = null;
|
|
82
|
+
}
|
|
83
|
+
i++;
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
if (char === "/" && css[i + 1] === "*") {
|
|
87
|
+
inComment = true;
|
|
88
|
+
i += 2;
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
if (char === '"' || char === "'") {
|
|
92
|
+
stringQuote = char;
|
|
93
|
+
i++;
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
if (char === "(") {
|
|
97
|
+
functionStack.push(readFunctionNameBefore(css, i));
|
|
98
|
+
i++;
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
if (char === ")") {
|
|
102
|
+
functionStack.pop();
|
|
103
|
+
i++;
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
if (char === "{") {
|
|
107
|
+
braceDepth++;
|
|
108
|
+
statementStart = i + 1;
|
|
109
|
+
colonSeen = false;
|
|
110
|
+
i++;
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
if (char === "}") {
|
|
114
|
+
braceDepth--;
|
|
115
|
+
statementStart = i + 1;
|
|
116
|
+
colonSeen = false;
|
|
117
|
+
i++;
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
if (char === ";") {
|
|
121
|
+
statementStart = i + 1;
|
|
122
|
+
colonSeen = false;
|
|
123
|
+
i++;
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
if (char === ":" && functionStack.length === 0) {
|
|
127
|
+
colonSeen = true;
|
|
128
|
+
i++;
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
i++;
|
|
132
|
+
}
|
|
133
|
+
if (inComment || stringQuote) {
|
|
134
|
+
return false;
|
|
135
|
+
}
|
|
136
|
+
if (braceDepth === 0) {
|
|
137
|
+
// outside any rule: a selector, or an at-rule prelude
|
|
138
|
+
return false;
|
|
139
|
+
}
|
|
140
|
+
if (!colonSeen) {
|
|
141
|
+
// a property name, or a nested selector
|
|
142
|
+
return false;
|
|
143
|
+
}
|
|
144
|
+
if (css.slice(statementStart, position).trimStart().startsWith("@")) {
|
|
145
|
+
// an at-rule prelude nested in a rule, "@media (min-width: ...)"
|
|
146
|
+
return false;
|
|
147
|
+
}
|
|
148
|
+
if (functionStack[functionStack.length - 1] === "url") {
|
|
149
|
+
// url() takes an url, and an url built at runtime is not one the build
|
|
150
|
+
// can follow to a file
|
|
151
|
+
return false;
|
|
152
|
+
}
|
|
153
|
+
// A ":" also opens a pseudo class, so what looks like a value here can still
|
|
154
|
+
// be the end of a nested selector; that is settled by what closes it.
|
|
155
|
+
return closedByDeclarationEnd(css, position);
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
const readFunctionNameBefore = (css, parenthesisIndex) => {
|
|
159
|
+
let start = parenthesisIndex;
|
|
160
|
+
while (start > 0 && /[a-zA-Z0-9_-]/.test(css[start - 1])) {
|
|
161
|
+
start--;
|
|
162
|
+
}
|
|
163
|
+
return css.slice(start, parenthesisIndex).toLowerCase();
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
// A declaration ends on ";" or "}"; reaching "{" first means what was read is
|
|
167
|
+
// a selector.
|
|
168
|
+
const closedByDeclarationEnd = (css, position) => {
|
|
169
|
+
let stringQuote = null;
|
|
170
|
+
let inComment = false;
|
|
171
|
+
let i = position;
|
|
172
|
+
while (i < css.length) {
|
|
173
|
+
const char = css[i];
|
|
174
|
+
if (inComment) {
|
|
175
|
+
if (char === "*" && css[i + 1] === "/") {
|
|
176
|
+
inComment = false;
|
|
177
|
+
i += 2;
|
|
178
|
+
continue;
|
|
179
|
+
}
|
|
180
|
+
i++;
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
if (stringQuote) {
|
|
184
|
+
if (char === "\\") {
|
|
185
|
+
i += 2;
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
if (char === stringQuote) {
|
|
189
|
+
stringQuote = null;
|
|
190
|
+
}
|
|
191
|
+
i++;
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
if (char === "/" && css[i + 1] === "*") {
|
|
195
|
+
inComment = true;
|
|
196
|
+
i += 2;
|
|
197
|
+
continue;
|
|
198
|
+
}
|
|
199
|
+
if (char === '"' || char === "'") {
|
|
200
|
+
stringQuote = char;
|
|
201
|
+
i++;
|
|
202
|
+
continue;
|
|
203
|
+
}
|
|
204
|
+
if (char === ";" || char === "}") {
|
|
205
|
+
return true;
|
|
206
|
+
}
|
|
207
|
+
if (char === "{") {
|
|
208
|
+
return false;
|
|
209
|
+
}
|
|
210
|
+
i++;
|
|
211
|
+
}
|
|
212
|
+
// the last declaration of the template may end without ";"
|
|
213
|
+
return true;
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Puts the expressions back where their placeholder stands and renders the
|
|
218
|
+
* template literal to write in place of the original one.
|
|
219
|
+
* @returns {string|null} null when a placeholder did not survive the css
|
|
220
|
+
* transformation as it was written: what would be given back would
|
|
221
|
+
* not be what the source said
|
|
222
|
+
*/
|
|
223
|
+
export const renderCssTemplateLiteral = (content, substitutions) => {
|
|
224
|
+
for (const { placeholder } of substitutions) {
|
|
225
|
+
const index = content.indexOf(placeholder);
|
|
226
|
+
if (index === -1) {
|
|
227
|
+
return null;
|
|
228
|
+
}
|
|
229
|
+
if (content.indexOf(placeholder, index + placeholder.length) !== -1) {
|
|
230
|
+
return null;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
let escaped = content
|
|
234
|
+
.replace(/\\/g, "\\\\")
|
|
235
|
+
.replace(/`/g, "\\`")
|
|
236
|
+
.replace(/\$/g, "\\$");
|
|
237
|
+
for (const { placeholder, expression } of substitutions) {
|
|
238
|
+
escaped = escaped.replace(placeholder, () => `\${${expression}}`);
|
|
239
|
+
}
|
|
240
|
+
return `\`${escaped}\``;
|
|
241
|
+
};
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import { getImportMetaPropertyName } from "../import_meta.js";
|
|
2
|
+
import { buildCssTemplateSubstitutions } from "./css_template_substitutions.js";
|
|
3
|
+
import { extractContentInfo } from "./helpers.js";
|
|
4
|
+
|
|
5
|
+
export const isImportMetaCssAssignment = (node) => {
|
|
6
|
+
return (
|
|
7
|
+
node.type === "AssignmentExpression" &&
|
|
8
|
+
node.operator === "=" &&
|
|
9
|
+
getImportMetaPropertyName(node.left) === "css"
|
|
10
|
+
);
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export const analyzeImportMetaCssAssignment = (
|
|
14
|
+
node,
|
|
15
|
+
{ js, ast, ancestors, onInlineContent },
|
|
16
|
+
) => {
|
|
17
|
+
// "import.meta.css = [css, url]": the array form a pre-built file ships
|
|
18
|
+
// (see jsenv:import_meta_css); the css is the first element.
|
|
19
|
+
const assignedNode =
|
|
20
|
+
node.right.type === "ArrayExpression" ? node.right.elements[0] : node.right;
|
|
21
|
+
if (!assignedNode) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
// "const css = `...`; import.meta.css = css;" — the css is where the constant
|
|
25
|
+
// is declared, and that is where it is read and rewritten.
|
|
26
|
+
const nodeHoldingContent =
|
|
27
|
+
assignedNode.type === "Identifier"
|
|
28
|
+
? findModuleConstantValue(assignedNode.name, { ast, ancestors })
|
|
29
|
+
: assignedNode;
|
|
30
|
+
if (!nodeHoldingContent) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
const position = {
|
|
34
|
+
start: nodeHoldingContent.start,
|
|
35
|
+
end: nodeHoldingContent.end,
|
|
36
|
+
line: nodeHoldingContent.loc.start.line,
|
|
37
|
+
column: nodeHoldingContent.loc.start.column,
|
|
38
|
+
lineEnd: nodeHoldingContent.loc.end.line,
|
|
39
|
+
columnEnd: nodeHoldingContent.loc.end.column,
|
|
40
|
+
};
|
|
41
|
+
const contentInfo = extractContentInfo(nodeHoldingContent);
|
|
42
|
+
if (contentInfo) {
|
|
43
|
+
onInlineContent({
|
|
44
|
+
type: "import_meta_css_assignment",
|
|
45
|
+
contentType: "text/css",
|
|
46
|
+
...position,
|
|
47
|
+
nodeType: contentInfo.nodeType,
|
|
48
|
+
quote: contentInfo.quote,
|
|
49
|
+
content: contentInfo.content,
|
|
50
|
+
astInfo: { node: nodeHoldingContent },
|
|
51
|
+
});
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
if (nodeHoldingContent.type !== "TemplateLiteral") {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
const substitutionInfo = buildCssTemplateSubstitutions(
|
|
58
|
+
nodeHoldingContent,
|
|
59
|
+
js,
|
|
60
|
+
);
|
|
61
|
+
if (!substitutionInfo) {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
onInlineContent({
|
|
65
|
+
type: "import_meta_css_assignment",
|
|
66
|
+
contentType: "text/css",
|
|
67
|
+
...position,
|
|
68
|
+
nodeType: "TemplateLiteral",
|
|
69
|
+
quote: "`",
|
|
70
|
+
content: substitutionInfo.content,
|
|
71
|
+
substitutions: substitutionInfo.substitutions,
|
|
72
|
+
astInfo: { node: nodeHoldingContent },
|
|
73
|
+
});
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
const findModuleConstantValue = (name, { ast, ancestors }) => {
|
|
77
|
+
if (isShadowed(name, ancestors)) {
|
|
78
|
+
// the name stands for something declared closer than the module
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
for (const node of ast.body) {
|
|
82
|
+
const declaration =
|
|
83
|
+
node.type === "ExportNamedDeclaration" ? node.declaration : node;
|
|
84
|
+
if (!declaration || declaration.type !== "VariableDeclaration") {
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
if (declaration.kind !== "const") {
|
|
88
|
+
// the value read at assignment time is not the one written here
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
for (const declarator of declaration.declarations) {
|
|
92
|
+
if (declarator.id.type === "Identifier" && declarator.id.name === name) {
|
|
93
|
+
return declarator.init;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return null;
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
// Walks out from the assignment towards the module: a name declared on the way
|
|
101
|
+
// is not the module constant, whatever the module declares under it.
|
|
102
|
+
const isShadowed = (name, ancestors) => {
|
|
103
|
+
for (let i = ancestors.length - 1; i >= 0; i--) {
|
|
104
|
+
const node = ancestors[i];
|
|
105
|
+
if (node.type === "Program") {
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
if (
|
|
109
|
+
node.type === "FunctionDeclaration" ||
|
|
110
|
+
node.type === "FunctionExpression" ||
|
|
111
|
+
node.type === "ArrowFunctionExpression"
|
|
112
|
+
) {
|
|
113
|
+
for (const param of node.params) {
|
|
114
|
+
if (patternDeclares(param, name)) {
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
if (node.type === "CatchClause") {
|
|
121
|
+
if (node.param && patternDeclares(node.param, name)) {
|
|
122
|
+
return true;
|
|
123
|
+
}
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
if (node.type === "BlockStatement" || node.type === "StaticBlock") {
|
|
127
|
+
if (bodyDeclares(node.body, name)) {
|
|
128
|
+
return true;
|
|
129
|
+
}
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
if (
|
|
133
|
+
node.type === "ForStatement" ||
|
|
134
|
+
node.type === "ForInStatement" ||
|
|
135
|
+
node.type === "ForOfStatement"
|
|
136
|
+
) {
|
|
137
|
+
const init = node.init || node.left;
|
|
138
|
+
if (init && init.type === "VariableDeclaration") {
|
|
139
|
+
for (const declarator of init.declarations) {
|
|
140
|
+
if (patternDeclares(declarator.id, name)) {
|
|
141
|
+
return true;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return false;
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
const bodyDeclares = (body, name) => {
|
|
152
|
+
for (const node of body) {
|
|
153
|
+
if (node.type === "VariableDeclaration") {
|
|
154
|
+
for (const declarator of node.declarations) {
|
|
155
|
+
if (patternDeclares(declarator.id, name)) {
|
|
156
|
+
return true;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
if (
|
|
162
|
+
(node.type === "FunctionDeclaration" ||
|
|
163
|
+
node.type === "ClassDeclaration") &&
|
|
164
|
+
node.id &&
|
|
165
|
+
node.id.name === name
|
|
166
|
+
) {
|
|
167
|
+
return true;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return false;
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
const patternDeclares = (pattern, name) => {
|
|
174
|
+
if (!pattern) {
|
|
175
|
+
return false;
|
|
176
|
+
}
|
|
177
|
+
if (pattern.type === "Identifier") {
|
|
178
|
+
return pattern.name === name;
|
|
179
|
+
}
|
|
180
|
+
if (pattern.type === "AssignmentPattern") {
|
|
181
|
+
return patternDeclares(pattern.left, name);
|
|
182
|
+
}
|
|
183
|
+
if (pattern.type === "RestElement") {
|
|
184
|
+
return patternDeclares(pattern.argument, name);
|
|
185
|
+
}
|
|
186
|
+
if (pattern.type === "ArrayPattern") {
|
|
187
|
+
return pattern.elements.some((element) => patternDeclares(element, name));
|
|
188
|
+
}
|
|
189
|
+
if (pattern.type === "ObjectPattern") {
|
|
190
|
+
return pattern.properties.some((property) =>
|
|
191
|
+
patternDeclares(
|
|
192
|
+
property.type === "RestElement" ? property.argument : property.value,
|
|
193
|
+
name,
|
|
194
|
+
),
|
|
195
|
+
);
|
|
196
|
+
}
|
|
197
|
+
return false;
|
|
198
|
+
};
|
package/src/js/parse_js_urls.js
CHANGED
|
@@ -6,6 +6,10 @@ import {
|
|
|
6
6
|
analyzeImportDeclaration,
|
|
7
7
|
analyzeImportExpression,
|
|
8
8
|
} from "./js_static_analysis/import_export.js";
|
|
9
|
+
import {
|
|
10
|
+
analyzeImportMetaCssAssignment,
|
|
11
|
+
isImportMetaCssAssignment,
|
|
12
|
+
} from "./js_static_analysis/import_meta_css.js";
|
|
9
13
|
import {
|
|
10
14
|
analyzeImportMetaResolveCall,
|
|
11
15
|
isImportMetaResolveCall,
|
|
@@ -130,6 +134,16 @@ export const parseJsUrls = ({
|
|
|
130
134
|
ExportAllDeclaration: (node) => {
|
|
131
135
|
analyzeExportAllDeclaration(node, { onUrl });
|
|
132
136
|
},
|
|
137
|
+
AssignmentExpression: (node, ancestors) => {
|
|
138
|
+
if (inlineContent && isJsModule && isImportMetaCssAssignment(node)) {
|
|
139
|
+
analyzeImportMetaCssAssignment(node, {
|
|
140
|
+
js,
|
|
141
|
+
ast,
|
|
142
|
+
ancestors,
|
|
143
|
+
onInlineContent,
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
},
|
|
133
147
|
CallExpression: (node) => {
|
|
134
148
|
if (isJsModule && isImportMetaResolveCall(node)) {
|
|
135
149
|
analyzeImportMetaResolveCall(node, { onUrl });
|
package/src/main.js
CHANGED
|
@@ -49,6 +49,9 @@ export { injectJsImport } from "./js/babel_utils.js";
|
|
|
49
49
|
export { parseJsWithAcorn } from "./js/parse_js_with_acorn.js";
|
|
50
50
|
export { parseJsUrls } from "./js/parse_js_urls.js";
|
|
51
51
|
export { visitJsAstUntil } from "./js/visit_js_ast_until.js";
|
|
52
|
+
export { visitJsAst } from "./js/visit_js_ast.js";
|
|
53
|
+
export { getImportMetaPropertyName } from "./js/import_meta.js";
|
|
52
54
|
export { getUrlForContentInsideJs } from "./js/js_inline_content_url.js";
|
|
55
|
+
export { renderCssTemplateLiteral } from "./js/js_static_analysis/css_template_substitutions.js";
|
|
53
56
|
|
|
54
57
|
export { generateUrlForInlineContent } from "./inline_content_url.js";
|