@jsenv/core 38.4.15 → 38.4.17
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.
|
@@ -129,422 +129,441 @@ export const jsenvPluginHtmlReferenceAnalysis = ({
|
|
|
129
129
|
let importmapFound = false;
|
|
130
130
|
const importmapLoaded = startLoadingImportmap(urlInfo);
|
|
131
131
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
const mutations = [];
|
|
138
|
-
const actions = [];
|
|
139
|
-
const finalizeCallbacks = [];
|
|
132
|
+
try {
|
|
133
|
+
const htmlAst = parseHtml({
|
|
134
|
+
html: urlInfo.content,
|
|
135
|
+
url: urlInfo.url,
|
|
136
|
+
});
|
|
140
137
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
attributeValue,
|
|
145
|
-
{ type, subtype, expectedType, ...rest },
|
|
146
|
-
) => {
|
|
147
|
-
let position;
|
|
148
|
-
if (getHtmlNodeAttribute(node, "jsenv-cooked-by")) {
|
|
149
|
-
// when generated from inline content,
|
|
150
|
-
// line, column is not "src" nor "inlined-from-src" but "original-position"
|
|
151
|
-
position = getHtmlNodePosition(node);
|
|
152
|
-
} else {
|
|
153
|
-
position = getHtmlNodeAttributePosition(node, attributeName);
|
|
154
|
-
}
|
|
155
|
-
const {
|
|
156
|
-
line,
|
|
157
|
-
column,
|
|
158
|
-
// originalLine, originalColumn
|
|
159
|
-
} = position;
|
|
160
|
-
const debug = getHtmlNodeAttribute(node, "jsenv-debug") !== undefined;
|
|
138
|
+
const mutations = [];
|
|
139
|
+
const actions = [];
|
|
140
|
+
const finalizeCallbacks = [];
|
|
161
141
|
|
|
162
|
-
const
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
"dns-prefetch",
|
|
166
|
-
"prefetch",
|
|
167
|
-
"preload",
|
|
168
|
-
"modulepreload",
|
|
169
|
-
].includes(subtype);
|
|
170
|
-
let attributeLocation = node.sourceCodeLocation.attrs[attributeName];
|
|
171
|
-
if (
|
|
172
|
-
!attributeLocation &&
|
|
173
|
-
attributeName === "href" &&
|
|
174
|
-
(node.tagName === "use" || node.tagName === "image")
|
|
175
|
-
) {
|
|
176
|
-
attributeLocation = node.sourceCodeLocation.attrs["xlink:href"];
|
|
177
|
-
}
|
|
178
|
-
const attributeStart = attributeLocation.startOffset;
|
|
179
|
-
const attributeValueStart = urlInfo.content.indexOf(
|
|
142
|
+
const createExternalReference = (
|
|
143
|
+
node,
|
|
144
|
+
attributeName,
|
|
180
145
|
attributeValue,
|
|
181
|
-
|
|
182
|
-
)
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
146
|
+
{ type, subtype, expectedType, ...rest },
|
|
147
|
+
) => {
|
|
148
|
+
let position;
|
|
149
|
+
if (getHtmlNodeAttribute(node, "jsenv-cooked-by")) {
|
|
150
|
+
// when generated from inline content,
|
|
151
|
+
// line, column is not "src" nor "inlined-from-src" but "original-position"
|
|
152
|
+
position = getHtmlNodePosition(node);
|
|
153
|
+
} else {
|
|
154
|
+
position = getHtmlNodeAttributePosition(node, attributeName);
|
|
155
|
+
}
|
|
156
|
+
const {
|
|
157
|
+
line,
|
|
158
|
+
column,
|
|
159
|
+
// originalLine, originalColumn
|
|
160
|
+
} = position;
|
|
161
|
+
const debug =
|
|
162
|
+
getHtmlNodeAttribute(node, "jsenv-debug") !== undefined;
|
|
163
|
+
|
|
164
|
+
const { crossorigin, integrity } = readFetchMetas(node);
|
|
165
|
+
const isResourceHint = [
|
|
166
|
+
"preconnect",
|
|
167
|
+
"dns-prefetch",
|
|
168
|
+
"prefetch",
|
|
169
|
+
"preload",
|
|
170
|
+
"modulepreload",
|
|
171
|
+
].includes(subtype);
|
|
172
|
+
let attributeLocation =
|
|
173
|
+
node.sourceCodeLocation.attrs[attributeName];
|
|
174
|
+
if (
|
|
175
|
+
!attributeLocation &&
|
|
176
|
+
attributeName === "href" &&
|
|
177
|
+
(node.tagName === "use" || node.tagName === "image")
|
|
178
|
+
) {
|
|
179
|
+
attributeLocation = node.sourceCodeLocation.attrs["xlink:href"];
|
|
180
|
+
}
|
|
181
|
+
const attributeStart = attributeLocation.startOffset;
|
|
182
|
+
const attributeValueStart = urlInfo.content.indexOf(
|
|
183
|
+
attributeValue,
|
|
184
|
+
attributeStart + `${attributeName}=`.length,
|
|
185
|
+
);
|
|
186
|
+
const attributeValueEnd =
|
|
187
|
+
attributeValueStart + attributeValue.length;
|
|
188
|
+
const reference = urlInfo.dependencies.found({
|
|
189
|
+
type,
|
|
190
|
+
subtype,
|
|
191
|
+
expectedType,
|
|
192
|
+
specifier: attributeValue,
|
|
193
|
+
specifierLine: line,
|
|
194
|
+
specifierColumn: column,
|
|
195
|
+
specifierStart: attributeValueStart,
|
|
196
|
+
specifierEnd: attributeValueEnd,
|
|
197
|
+
isResourceHint,
|
|
198
|
+
isWeak: isResourceHint,
|
|
199
|
+
crossorigin,
|
|
200
|
+
integrity,
|
|
201
|
+
debug,
|
|
202
|
+
astInfo: { node, attributeName },
|
|
203
|
+
...rest,
|
|
204
|
+
});
|
|
205
|
+
actions.push(async () => {
|
|
206
|
+
await reference.readGeneratedSpecifier();
|
|
207
|
+
mutations.push(() => {
|
|
208
|
+
setHtmlNodeAttributes(node, {
|
|
209
|
+
[attributeName]: reference.generatedSpecifier,
|
|
210
|
+
});
|
|
206
211
|
});
|
|
207
212
|
});
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
if (href) {
|
|
214
|
-
return createExternalReference(node, "href", href, referenceProps);
|
|
215
|
-
}
|
|
216
|
-
return null;
|
|
217
|
-
};
|
|
218
|
-
const visitSrc = (node, referenceProps) => {
|
|
219
|
-
const src = getHtmlNodeAttribute(node, "src");
|
|
220
|
-
if (src) {
|
|
221
|
-
return createExternalReference(node, "src", src, referenceProps);
|
|
222
|
-
}
|
|
223
|
-
return null;
|
|
224
|
-
};
|
|
225
|
-
const visitSrcset = (node, referenceProps) => {
|
|
226
|
-
const srcset = getHtmlNodeAttribute(node, "srcset");
|
|
227
|
-
if (srcset) {
|
|
228
|
-
const srcCandidates = parseSrcSet(srcset);
|
|
229
|
-
return srcCandidates.map((srcCandidate) => {
|
|
213
|
+
return reference;
|
|
214
|
+
};
|
|
215
|
+
const visitHref = (node, referenceProps) => {
|
|
216
|
+
const href = getHtmlNodeAttribute(node, "href");
|
|
217
|
+
if (href) {
|
|
230
218
|
return createExternalReference(
|
|
231
219
|
node,
|
|
232
|
-
"
|
|
233
|
-
|
|
220
|
+
"href",
|
|
221
|
+
href,
|
|
234
222
|
referenceProps,
|
|
235
223
|
);
|
|
224
|
+
}
|
|
225
|
+
return null;
|
|
226
|
+
};
|
|
227
|
+
const visitSrc = (node, referenceProps) => {
|
|
228
|
+
const src = getHtmlNodeAttribute(node, "src");
|
|
229
|
+
if (src) {
|
|
230
|
+
return createExternalReference(node, "src", src, referenceProps);
|
|
231
|
+
}
|
|
232
|
+
return null;
|
|
233
|
+
};
|
|
234
|
+
const visitSrcset = (node, referenceProps) => {
|
|
235
|
+
const srcset = getHtmlNodeAttribute(node, "srcset");
|
|
236
|
+
if (srcset) {
|
|
237
|
+
const srcCandidates = parseSrcSet(srcset);
|
|
238
|
+
return srcCandidates.map((srcCandidate) => {
|
|
239
|
+
return createExternalReference(
|
|
240
|
+
node,
|
|
241
|
+
"srcset",
|
|
242
|
+
srcCandidate.specifier,
|
|
243
|
+
referenceProps,
|
|
244
|
+
);
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
return null;
|
|
248
|
+
};
|
|
249
|
+
const createInlineReference = (
|
|
250
|
+
node,
|
|
251
|
+
inlineContent,
|
|
252
|
+
{ type, expectedType, contentType },
|
|
253
|
+
) => {
|
|
254
|
+
const hotAccept =
|
|
255
|
+
getHtmlNodeAttribute(node, "hot-accept") !== undefined;
|
|
256
|
+
const { line, column, isOriginal } = getHtmlNodePosition(node, {
|
|
257
|
+
preferOriginal: true,
|
|
236
258
|
});
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
};
|
|
240
|
-
|
|
241
|
-
const createInlineReference = (
|
|
242
|
-
node,
|
|
243
|
-
inlineContent,
|
|
244
|
-
{ type, expectedType, contentType },
|
|
245
|
-
) => {
|
|
246
|
-
const hotAccept =
|
|
247
|
-
getHtmlNodeAttribute(node, "hot-accept") !== undefined;
|
|
248
|
-
const { line, column, isOriginal } = getHtmlNodePosition(node, {
|
|
249
|
-
preferOriginal: true,
|
|
250
|
-
});
|
|
251
|
-
const inlineContentUrl = getUrlForContentInsideHtml(node, {
|
|
252
|
-
htmlUrl: urlInfo.url,
|
|
253
|
-
});
|
|
254
|
-
const debug = getHtmlNodeAttribute(node, "jsenv-debug") !== undefined;
|
|
255
|
-
const inlineReference = urlInfo.dependencies.foundInline({
|
|
256
|
-
type,
|
|
257
|
-
expectedType,
|
|
258
|
-
isOriginalPosition: isOriginal,
|
|
259
|
-
// we remove 1 to the line because imagine the following html:
|
|
260
|
-
// <style>body { color: red; }</style>
|
|
261
|
-
// -> content starts same line as <style> (same for <script>)
|
|
262
|
-
specifierLine: line - 1,
|
|
263
|
-
specifierColumn: column,
|
|
264
|
-
specifier: inlineContentUrl,
|
|
265
|
-
contentType,
|
|
266
|
-
content: inlineContent,
|
|
267
|
-
debug,
|
|
268
|
-
astInfo: { node },
|
|
269
|
-
});
|
|
270
|
-
|
|
271
|
-
actions.push(async () => {
|
|
272
|
-
await inlineReference.urlInfo.cook();
|
|
273
|
-
mutations.push(() => {
|
|
274
|
-
if (hotAccept) {
|
|
275
|
-
removeHtmlNodeText(node);
|
|
276
|
-
setHtmlNodeAttributes(node, {
|
|
277
|
-
"jsenv-cooked-by": "jsenv:html_inline_content_analysis",
|
|
278
|
-
});
|
|
279
|
-
} else {
|
|
280
|
-
setHtmlNodeText(node, inlineReference.urlInfo.content, {
|
|
281
|
-
indentation: false, // indentation would decrease stack trace precision
|
|
282
|
-
});
|
|
283
|
-
setHtmlNodeAttributes(node, {
|
|
284
|
-
"jsenv-cooked-by": "jsenv:html_inline_content_analysis",
|
|
285
|
-
});
|
|
286
|
-
}
|
|
259
|
+
const inlineContentUrl = getUrlForContentInsideHtml(node, {
|
|
260
|
+
htmlUrl: urlInfo.url,
|
|
287
261
|
});
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
});
|
|
305
|
-
};
|
|
306
|
-
|
|
307
|
-
visitHtmlNodes(htmlAst, {
|
|
308
|
-
link: (linkNode) => {
|
|
309
|
-
const rel = getHtmlNodeAttribute(linkNode, "rel");
|
|
310
|
-
const type = getHtmlNodeAttribute(linkNode, "type");
|
|
311
|
-
const ref = visitHref(linkNode, {
|
|
312
|
-
type: "link_href",
|
|
313
|
-
subtype: rel,
|
|
314
|
-
// https://developer.mozilla.org/en-US/docs/Web/HTML/Link_types/preload#including_a_mime_type
|
|
315
|
-
expectedContentType: type,
|
|
262
|
+
const debug =
|
|
263
|
+
getHtmlNodeAttribute(node, "jsenv-debug") !== undefined;
|
|
264
|
+
const inlineReference = urlInfo.dependencies.foundInline({
|
|
265
|
+
type,
|
|
266
|
+
expectedType,
|
|
267
|
+
isOriginalPosition: isOriginal,
|
|
268
|
+
// we remove 1 to the line because imagine the following html:
|
|
269
|
+
// <style>body { color: red; }</style>
|
|
270
|
+
// -> content starts same line as <style> (same for <script>)
|
|
271
|
+
specifierLine: line - 1,
|
|
272
|
+
specifierColumn: column,
|
|
273
|
+
specifier: inlineContentUrl,
|
|
274
|
+
contentType,
|
|
275
|
+
content: inlineContent,
|
|
276
|
+
debug,
|
|
277
|
+
astInfo: { node },
|
|
316
278
|
});
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
279
|
+
|
|
280
|
+
actions.push(async () => {
|
|
281
|
+
await inlineReference.urlInfo.cook();
|
|
282
|
+
mutations.push(() => {
|
|
283
|
+
if (hotAccept) {
|
|
284
|
+
removeHtmlNodeText(node);
|
|
285
|
+
setHtmlNodeAttributes(node, {
|
|
286
|
+
"jsenv-cooked-by": "jsenv:html_inline_content_analysis",
|
|
287
|
+
});
|
|
321
288
|
} else {
|
|
322
|
-
|
|
289
|
+
setHtmlNodeText(node, inlineReference.urlInfo.content, {
|
|
290
|
+
indentation: false, // indentation would decrease stack trace precision
|
|
291
|
+
});
|
|
292
|
+
setHtmlNodeAttributes(node, {
|
|
293
|
+
"jsenv-cooked-by": "jsenv:html_inline_content_analysis",
|
|
294
|
+
});
|
|
323
295
|
}
|
|
324
296
|
});
|
|
297
|
+
});
|
|
298
|
+
return inlineReference;
|
|
299
|
+
};
|
|
300
|
+
const visitTextContent = (
|
|
301
|
+
node,
|
|
302
|
+
{ type, subtype, expectedType, contentType },
|
|
303
|
+
) => {
|
|
304
|
+
const inlineContent = getHtmlNodeText(node);
|
|
305
|
+
if (!inlineContent) {
|
|
306
|
+
return null;
|
|
325
307
|
}
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
});
|
|
334
|
-
}
|
|
335
|
-
: null,
|
|
336
|
-
script: (scriptNode) => {
|
|
337
|
-
const { type, subtype, contentType, extension } =
|
|
338
|
-
analyzeScriptNode(scriptNode);
|
|
339
|
-
if (type === "text") {
|
|
340
|
-
// ignore <script type="whatever">foobar</script>
|
|
341
|
-
// per HTML spec https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script#attr-type
|
|
342
|
-
return;
|
|
343
|
-
}
|
|
344
|
-
if (type === "importmap") {
|
|
345
|
-
importmapFound = true;
|
|
308
|
+
return createInlineReference(node, inlineContent, {
|
|
309
|
+
type,
|
|
310
|
+
subtype,
|
|
311
|
+
expectedType,
|
|
312
|
+
contentType,
|
|
313
|
+
});
|
|
314
|
+
};
|
|
346
315
|
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
{
|
|
365
|
-
preferOriginal: true,
|
|
366
|
-
},
|
|
367
|
-
);
|
|
368
|
-
const importmapInlineUrl = getUrlForContentInsideHtml(
|
|
369
|
-
scriptNode,
|
|
370
|
-
{
|
|
371
|
-
htmlUrl: urlInfo.url,
|
|
372
|
-
},
|
|
373
|
-
);
|
|
374
|
-
const importmapReferenceInlined = importmapReference.inline({
|
|
375
|
-
line: line - 1,
|
|
376
|
-
column,
|
|
377
|
-
isOriginal,
|
|
378
|
-
specifier: importmapInlineUrl,
|
|
379
|
-
contentType: "application/importmap+json",
|
|
316
|
+
visitHtmlNodes(htmlAst, {
|
|
317
|
+
link: (linkNode) => {
|
|
318
|
+
const rel = getHtmlNodeAttribute(linkNode, "rel");
|
|
319
|
+
const type = getHtmlNodeAttribute(linkNode, "type");
|
|
320
|
+
const ref = visitHref(linkNode, {
|
|
321
|
+
type: "link_href",
|
|
322
|
+
subtype: rel,
|
|
323
|
+
// https://developer.mozilla.org/en-US/docs/Web/HTML/Link_types/preload#including_a_mime_type
|
|
324
|
+
expectedContentType: type,
|
|
325
|
+
});
|
|
326
|
+
if (ref) {
|
|
327
|
+
finalizeCallbacks.push(() => {
|
|
328
|
+
if (ref.expectedType) {
|
|
329
|
+
// might be set by other plugins, in that case respect it
|
|
330
|
+
} else {
|
|
331
|
+
ref.expectedType = decideLinkExpectedType(ref, urlInfo);
|
|
332
|
+
}
|
|
380
333
|
});
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
importmapInlineUrlInfo.content,
|
|
390
|
-
{
|
|
391
|
-
indentation: "auto",
|
|
392
|
-
},
|
|
393
|
-
);
|
|
394
|
-
setHtmlNodeAttributes(scriptNode, {
|
|
395
|
-
"src": undefined,
|
|
396
|
-
"jsenv-inlined-by": "jsenv:html_reference_analysis",
|
|
397
|
-
"inlined-from-src": src,
|
|
398
|
-
});
|
|
334
|
+
}
|
|
335
|
+
},
|
|
336
|
+
style: inlineContent
|
|
337
|
+
? (styleNode) => {
|
|
338
|
+
visitTextContent(styleNode, {
|
|
339
|
+
type: "style",
|
|
340
|
+
expectedType: "css",
|
|
341
|
+
contentType: "text/css",
|
|
399
342
|
});
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
343
|
+
}
|
|
344
|
+
: null,
|
|
345
|
+
script: (scriptNode) => {
|
|
346
|
+
const { type, subtype, contentType, extension } =
|
|
347
|
+
analyzeScriptNode(scriptNode);
|
|
348
|
+
if (type === "text") {
|
|
349
|
+
// ignore <script type="whatever">foobar</script>
|
|
350
|
+
// per HTML spec https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script#attr-type
|
|
351
|
+
return;
|
|
352
|
+
}
|
|
353
|
+
if (type === "importmap") {
|
|
354
|
+
importmapFound = true;
|
|
355
|
+
|
|
356
|
+
const src = getHtmlNodeAttribute(scriptNode, "src");
|
|
357
|
+
if (src) {
|
|
358
|
+
// Browser would throw on remote importmap
|
|
359
|
+
// and won't sent a request to the server for it
|
|
360
|
+
// We must precook the importmap to know its content and inline it into the HTML
|
|
361
|
+
const importmapReference = createExternalReference(
|
|
405
362
|
scriptNode,
|
|
406
|
-
|
|
363
|
+
"src",
|
|
364
|
+
src,
|
|
407
365
|
{
|
|
408
366
|
type: "script",
|
|
367
|
+
subtype: "importmap",
|
|
409
368
|
expectedType: "importmap",
|
|
410
|
-
contentType: "application/importmap+json",
|
|
411
369
|
},
|
|
412
370
|
);
|
|
413
|
-
const
|
|
371
|
+
const { line, column, isOriginal } = getHtmlNodePosition(
|
|
372
|
+
scriptNode,
|
|
373
|
+
{
|
|
374
|
+
preferOriginal: true,
|
|
375
|
+
},
|
|
376
|
+
);
|
|
377
|
+
const importmapInlineUrl = getUrlForContentInsideHtml(
|
|
378
|
+
scriptNode,
|
|
379
|
+
{
|
|
380
|
+
htmlUrl: urlInfo.url,
|
|
381
|
+
},
|
|
382
|
+
);
|
|
383
|
+
const importmapReferenceInlined = importmapReference.inline({
|
|
384
|
+
line: line - 1,
|
|
385
|
+
column,
|
|
386
|
+
isOriginal,
|
|
387
|
+
specifier: importmapInlineUrl,
|
|
388
|
+
contentType: "application/importmap+json",
|
|
389
|
+
});
|
|
390
|
+
const importmapInlineUrlInfo =
|
|
391
|
+
importmapReferenceInlined.urlInfo;
|
|
414
392
|
actions.push(async () => {
|
|
415
|
-
|
|
416
|
-
|
|
393
|
+
try {
|
|
394
|
+
await importmapInlineUrlInfo.cook();
|
|
395
|
+
} finally {
|
|
396
|
+
importmapLoaded(importmapInlineUrlInfo);
|
|
397
|
+
}
|
|
417
398
|
mutations.push(() => {
|
|
418
399
|
setHtmlNodeText(
|
|
419
400
|
scriptNode,
|
|
420
|
-
|
|
401
|
+
importmapInlineUrlInfo.content,
|
|
421
402
|
{
|
|
422
403
|
indentation: "auto",
|
|
423
404
|
},
|
|
424
405
|
);
|
|
425
406
|
setHtmlNodeAttributes(scriptNode, {
|
|
426
|
-
"
|
|
407
|
+
"src": undefined,
|
|
408
|
+
"jsenv-inlined-by": "jsenv:html_reference_analysis",
|
|
409
|
+
"inlined-from-src": src,
|
|
427
410
|
});
|
|
428
411
|
});
|
|
429
412
|
});
|
|
413
|
+
} else {
|
|
414
|
+
const htmlNodeText = getHtmlNodeText(scriptNode);
|
|
415
|
+
if (htmlNodeText) {
|
|
416
|
+
const importmapReference = createInlineReference(
|
|
417
|
+
scriptNode,
|
|
418
|
+
htmlNodeText,
|
|
419
|
+
{
|
|
420
|
+
type: "script",
|
|
421
|
+
expectedType: "importmap",
|
|
422
|
+
contentType: "application/importmap+json",
|
|
423
|
+
},
|
|
424
|
+
);
|
|
425
|
+
const inlineImportmapUrlInfo = importmapReference.urlInfo;
|
|
426
|
+
actions.push(async () => {
|
|
427
|
+
try {
|
|
428
|
+
await inlineImportmapUrlInfo.cook();
|
|
429
|
+
} finally {
|
|
430
|
+
importmapLoaded(inlineImportmapUrlInfo);
|
|
431
|
+
}
|
|
432
|
+
mutations.push(() => {
|
|
433
|
+
setHtmlNodeText(
|
|
434
|
+
scriptNode,
|
|
435
|
+
inlineImportmapUrlInfo.content,
|
|
436
|
+
{
|
|
437
|
+
indentation: "auto",
|
|
438
|
+
},
|
|
439
|
+
);
|
|
440
|
+
setHtmlNodeAttributes(scriptNode, {
|
|
441
|
+
"jsenv-cooked-by": "jsenv:html_reference_analysis",
|
|
442
|
+
});
|
|
443
|
+
});
|
|
444
|
+
});
|
|
445
|
+
}
|
|
430
446
|
}
|
|
447
|
+
// once this plugin knows the importmap, it will use it
|
|
448
|
+
// to map imports. These import specifiers will be normalized
|
|
449
|
+
// by "formatReference" making the importmap presence useless.
|
|
450
|
+
// In dev/test we keep importmap into the HTML to see it even if useless
|
|
451
|
+
// Duing build we get rid of it
|
|
452
|
+
if (urlInfo.context.build) {
|
|
453
|
+
mutations.push(() => {
|
|
454
|
+
removeHtmlNode(scriptNode);
|
|
455
|
+
});
|
|
456
|
+
}
|
|
457
|
+
return;
|
|
431
458
|
}
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
if (
|
|
438
|
-
|
|
439
|
-
removeHtmlNode(scriptNode);
|
|
440
|
-
});
|
|
459
|
+
const externalRef = visitSrc(scriptNode, {
|
|
460
|
+
type: "script",
|
|
461
|
+
subtype: type,
|
|
462
|
+
expectedType: type,
|
|
463
|
+
});
|
|
464
|
+
if (externalRef) {
|
|
465
|
+
return;
|
|
441
466
|
}
|
|
442
|
-
return;
|
|
443
|
-
}
|
|
444
|
-
const externalRef = visitSrc(scriptNode, {
|
|
445
|
-
type: "script",
|
|
446
|
-
subtype: type,
|
|
447
|
-
expectedType: type,
|
|
448
|
-
});
|
|
449
|
-
if (externalRef) {
|
|
450
|
-
return;
|
|
451
|
-
}
|
|
452
467
|
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
468
|
+
// now visit the content, if any
|
|
469
|
+
if (!inlineContent) {
|
|
470
|
+
return;
|
|
471
|
+
}
|
|
472
|
+
// If the inline script was already handled by an other plugin, ignore it
|
|
473
|
+
// - we want to preserve inline scripts generated by html supervisor during dev
|
|
474
|
+
// - we want to avoid cooking twice a script during build
|
|
475
|
+
if (
|
|
476
|
+
!inlineConvertedScript &&
|
|
477
|
+
getHtmlNodeAttribute(scriptNode, "jsenv-injected-by") ===
|
|
478
|
+
"jsenv:js_module_fallback"
|
|
479
|
+
) {
|
|
480
|
+
return;
|
|
481
|
+
}
|
|
467
482
|
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
483
|
+
const inlineRef = visitTextContent(scriptNode, {
|
|
484
|
+
type: "script",
|
|
485
|
+
subtype,
|
|
486
|
+
expectedType: type,
|
|
487
|
+
contentType,
|
|
488
|
+
});
|
|
489
|
+
if (inlineRef) {
|
|
490
|
+
// 1. <script type="jsx"> becomes <script>
|
|
491
|
+
if (type === "js_classic" && extension !== ".js") {
|
|
492
|
+
mutations.push(() => {
|
|
493
|
+
setHtmlNodeAttributes(scriptNode, {
|
|
494
|
+
type: undefined,
|
|
495
|
+
});
|
|
480
496
|
});
|
|
481
|
-
}
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
497
|
+
}
|
|
498
|
+
// 2. <script type="module/jsx"> becomes <script type="module">
|
|
499
|
+
if (type === "js_module" && extension !== ".js") {
|
|
500
|
+
mutations.push(() => {
|
|
501
|
+
setHtmlNodeAttributes(scriptNode, {
|
|
502
|
+
type: "module",
|
|
503
|
+
});
|
|
488
504
|
});
|
|
489
|
-
}
|
|
505
|
+
}
|
|
490
506
|
}
|
|
491
|
-
}
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
}
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
}
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
}
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
}
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
}
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
}
|
|
529
|
-
}
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
});
|
|
507
|
+
},
|
|
508
|
+
a: (aNode) => {
|
|
509
|
+
visitHref(aNode, {
|
|
510
|
+
type: "a_href",
|
|
511
|
+
});
|
|
512
|
+
},
|
|
513
|
+
iframe: (iframeNode) => {
|
|
514
|
+
visitSrc(iframeNode, {
|
|
515
|
+
type: "iframe_src",
|
|
516
|
+
});
|
|
517
|
+
},
|
|
518
|
+
img: (imgNode) => {
|
|
519
|
+
visitSrc(imgNode, {
|
|
520
|
+
type: "img_src",
|
|
521
|
+
});
|
|
522
|
+
visitSrcset(imgNode, {
|
|
523
|
+
type: "img_srcset",
|
|
524
|
+
});
|
|
525
|
+
},
|
|
526
|
+
source: (sourceNode) => {
|
|
527
|
+
visitSrc(sourceNode, {
|
|
528
|
+
type: "source_src",
|
|
529
|
+
});
|
|
530
|
+
visitSrcset(sourceNode, {
|
|
531
|
+
type: "source_srcset",
|
|
532
|
+
});
|
|
533
|
+
},
|
|
534
|
+
// svg <image> tag
|
|
535
|
+
image: (imageNode) => {
|
|
536
|
+
visitHref(imageNode, {
|
|
537
|
+
type: "image_href",
|
|
538
|
+
});
|
|
539
|
+
},
|
|
540
|
+
use: (useNode) => {
|
|
541
|
+
visitHref(useNode, {
|
|
542
|
+
type: "use_href",
|
|
543
|
+
});
|
|
544
|
+
},
|
|
545
|
+
});
|
|
546
|
+
if (!importmapFound) {
|
|
547
|
+
importmapLoaded();
|
|
548
|
+
}
|
|
549
|
+
finalizeCallbacks.forEach((finalizeCallback) => {
|
|
550
|
+
finalizeCallback();
|
|
551
|
+
});
|
|
537
552
|
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
553
|
+
if (actions.length > 0) {
|
|
554
|
+
await Promise.all(actions.map((action) => action()));
|
|
555
|
+
actions.length = 0;
|
|
556
|
+
}
|
|
557
|
+
if (mutations.length === 0) {
|
|
558
|
+
return null;
|
|
559
|
+
}
|
|
560
|
+
mutations.forEach((mutation) => mutation());
|
|
561
|
+
mutations.length = 0;
|
|
562
|
+
return stringifyHtmlAst(htmlAst);
|
|
563
|
+
} catch (e) {
|
|
564
|
+
importmapLoaded();
|
|
565
|
+
throw e;
|
|
544
566
|
}
|
|
545
|
-
mutations.forEach((mutation) => mutation());
|
|
546
|
-
mutations.length = 0;
|
|
547
|
-
return stringifyHtmlAst(htmlAst);
|
|
548
567
|
},
|
|
549
568
|
},
|
|
550
569
|
};
|