@jsenv/core 38.2.11 → 38.3.1
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/README.md +3 -3
- package/dist/jsenv_core.js +1388 -1371
- package/package.json +1 -1
- package/src/dev/file_service.js +1 -1
- package/src/kitchen/url_graph/references.js +2 -2
- package/src/kitchen/url_graph/url_graph.js +14 -4
- package/src/plugins/autoreload/jsenv_plugin_autoreload_server.js +10 -2
- package/src/plugins/plugins.js +0 -2
- package/src/plugins/reference_analysis/html/jsenv_plugin_html_reference_analysis.js +505 -310
- package/src/plugins/ribbon/jsenv_plugin_ribbon.js +2 -2
- package/src/plugins/importmap/jsenv_plugin_importmap.js +0 -205
package/dist/jsenv_core.js
CHANGED
|
@@ -13,7 +13,7 @@ import http from "node:http";
|
|
|
13
13
|
import { Readable, Stream, Writable } from "node:stream";
|
|
14
14
|
import { Http2ServerResponse } from "node:http2";
|
|
15
15
|
import { lookup } from "node:dns";
|
|
16
|
-
import { injectJsImport, visitJsAstUntil, applyBabelPlugins, parseHtmlString, visitHtmlNodes, getHtmlNodeAttribute, analyzeScriptNode, getHtmlNodeText, stringifyHtmlAst, setHtmlNodeAttributes, injectHtmlNodeAsEarlyAsPossible, createHtmlNode, generateUrlForInlineContent, parseJsWithAcorn,
|
|
16
|
+
import { injectJsImport, visitJsAstUntil, applyBabelPlugins, parseHtmlString, visitHtmlNodes, getHtmlNodeAttribute, analyzeScriptNode, getHtmlNodeText, stringifyHtmlAst, setHtmlNodeAttributes, injectHtmlNodeAsEarlyAsPossible, createHtmlNode, generateUrlForInlineContent, parseJsWithAcorn, getHtmlNodePosition, getUrlForContentInsideHtml, getHtmlNodeAttributePosition, parseSrcSet, removeHtmlNodeText, setHtmlNodeText, removeHtmlNode, parseCssUrls, parseJsUrls, getUrlForContentInsideJs, analyzeLinkNode, findHtmlNode, insertHtmlNodeAfter } from "@jsenv/ast";
|
|
17
17
|
import { sourcemapConverter, createMagicSource, composeTwoSourcemaps, SOURCEMAP, generateSourcemapFileUrl, generateSourcemapDataUrl } from "@jsenv/sourcemap";
|
|
18
18
|
import { createRequire } from "node:module";
|
|
19
19
|
import { systemJsClientFileUrlDefault, convertJsModuleToJsClassic } from "@jsenv/js-module-fallback";
|
|
@@ -11814,12 +11814,12 @@ const createReference = ({
|
|
|
11814
11814
|
ownerUrlInfo.context.finalizeReference(reference);
|
|
11815
11815
|
};
|
|
11816
11816
|
|
|
11817
|
-
// "
|
|
11817
|
+
// "formatReference" can be async BUT this is an exception
|
|
11818
11818
|
// for most cases it will be sync. We want to favor the sync signature to keep things simpler
|
|
11819
11819
|
// The only case where it needs to be async is when
|
|
11820
11820
|
// the specifier is a `data:*` url
|
|
11821
11821
|
// in this case we'll wait for the promise returned by
|
|
11822
|
-
// "
|
|
11822
|
+
// "formatReference"
|
|
11823
11823
|
reference.readGeneratedSpecifier = () => {
|
|
11824
11824
|
if (reference.generatedSpecifier.then) {
|
|
11825
11825
|
return reference.generatedSpecifier.then((value) => {
|
|
@@ -12398,6 +12398,9 @@ const createUrlInfo = (url, context) => {
|
|
|
12398
12398
|
continue;
|
|
12399
12399
|
}
|
|
12400
12400
|
if (ref.gotInlined()) {
|
|
12401
|
+
if (ref.ownerUrlInfo.isUsed()) {
|
|
12402
|
+
return true;
|
|
12403
|
+
}
|
|
12401
12404
|
// the url info was inlined, an other reference is required
|
|
12402
12405
|
// to consider the non-inlined urlInfo as used
|
|
12403
12406
|
continue;
|
|
@@ -12497,7 +12500,7 @@ const createUrlInfo = (url, context) => {
|
|
|
12497
12500
|
};
|
|
12498
12501
|
urlInfo.onModified = ({ modifiedTimestamp = Date.now() } = {}) => {
|
|
12499
12502
|
const visitedSet = new Set();
|
|
12500
|
-
const
|
|
12503
|
+
const considerModified = (urlInfo) => {
|
|
12501
12504
|
if (visitedSet.has(urlInfo)) {
|
|
12502
12505
|
return;
|
|
12503
12506
|
}
|
|
@@ -12507,14 +12510,21 @@ const createUrlInfo = (url, context) => {
|
|
|
12507
12510
|
for (const referenceToOther of urlInfo.referenceToOthersSet) {
|
|
12508
12511
|
const referencedUrlInfo = referenceToOther.urlInfo;
|
|
12509
12512
|
if (referencedUrlInfo.isInline) {
|
|
12510
|
-
|
|
12513
|
+
considerModified(referencedUrlInfo);
|
|
12514
|
+
}
|
|
12515
|
+
}
|
|
12516
|
+
for (const referenceFromOther of urlInfo.referenceFromOthersSet) {
|
|
12517
|
+
if (referenceFromOther.gotInlined()) {
|
|
12518
|
+
const urlInfoReferencingThisOne = referenceFromOther.ownerUrlInfo;
|
|
12519
|
+
considerModified(urlInfoReferencingThisOne);
|
|
12511
12520
|
}
|
|
12512
12521
|
}
|
|
12513
12522
|
for (const searchParamVariant of urlInfo.searchParamVariantSet) {
|
|
12514
|
-
|
|
12523
|
+
considerModified(searchParamVariant);
|
|
12515
12524
|
}
|
|
12516
12525
|
};
|
|
12517
|
-
|
|
12526
|
+
considerModified(urlInfo);
|
|
12527
|
+
visitedSet.clear();
|
|
12518
12528
|
};
|
|
12519
12529
|
urlInfo.onDereferenced = (lastReferenceFromOther) => {
|
|
12520
12530
|
urlInfo.dereferencedTimestamp = Date.now();
|
|
@@ -15011,922 +15021,228 @@ const base64ToString = (base64String) =>
|
|
|
15011
15021
|
Buffer.from(base64String, "base64").toString("utf8");
|
|
15012
15022
|
const dataToBase64 = (data) => Buffer.from(data).toString("base64");
|
|
15013
15023
|
|
|
15014
|
-
|
|
15015
|
-
|
|
15016
|
-
|
|
15017
|
-
}) => {
|
|
15018
|
-
return {
|
|
15019
|
-
name: "jsenv:html_reference_analysis",
|
|
15020
|
-
appliesDuring: "*",
|
|
15021
|
-
transformUrlContent: {
|
|
15022
|
-
html: (urlInfo) =>
|
|
15023
|
-
parseAndTransformHtmlReferences(urlInfo, {
|
|
15024
|
-
inlineContent,
|
|
15025
|
-
inlineConvertedScript,
|
|
15026
|
-
}),
|
|
15027
|
-
},
|
|
15028
|
-
};
|
|
15029
|
-
};
|
|
15024
|
+
// duplicated from @jsenv/log to avoid the dependency
|
|
15025
|
+
const createDetailedMessage = (message, details = {}) => {
|
|
15026
|
+
let string = `${message}`;
|
|
15030
15027
|
|
|
15031
|
-
|
|
15032
|
-
|
|
15033
|
-
|
|
15034
|
-
|
|
15035
|
-
|
|
15036
|
-
|
|
15028
|
+
Object.keys(details).forEach((key) => {
|
|
15029
|
+
const value = details[key];
|
|
15030
|
+
string += `
|
|
15031
|
+
--- ${key} ---
|
|
15032
|
+
${
|
|
15033
|
+
Array.isArray(value)
|
|
15034
|
+
? value.join(`
|
|
15035
|
+
`)
|
|
15036
|
+
: value
|
|
15037
|
+
}`;
|
|
15038
|
+
});
|
|
15037
15039
|
|
|
15038
|
-
|
|
15039
|
-
|
|
15040
|
-
const finalizeCallbacks = [];
|
|
15040
|
+
return string
|
|
15041
|
+
};
|
|
15041
15042
|
|
|
15042
|
-
|
|
15043
|
-
|
|
15044
|
-
|
|
15045
|
-
|
|
15046
|
-
{ type, subtype, expectedType, ...rest },
|
|
15047
|
-
) => {
|
|
15048
|
-
let position;
|
|
15049
|
-
if (getHtmlNodeAttribute(node, "jsenv-cooked-by")) {
|
|
15050
|
-
// when generated from inline content,
|
|
15051
|
-
// line, column is not "src" nor "inlined-from-src" but "original-position"
|
|
15052
|
-
position = getHtmlNodePosition(node);
|
|
15053
|
-
} else {
|
|
15054
|
-
position = getHtmlNodeAttributePosition(node, attributeName);
|
|
15055
|
-
}
|
|
15056
|
-
const {
|
|
15057
|
-
line,
|
|
15058
|
-
column,
|
|
15059
|
-
// originalLine, originalColumn
|
|
15060
|
-
} = position;
|
|
15061
|
-
const debug = getHtmlNodeAttribute(node, "jsenv-debug") !== undefined;
|
|
15062
|
-
|
|
15063
|
-
const { crossorigin, integrity } = readFetchMetas(node);
|
|
15064
|
-
const isResourceHint = [
|
|
15065
|
-
"preconnect",
|
|
15066
|
-
"dns-prefetch",
|
|
15067
|
-
"prefetch",
|
|
15068
|
-
"preload",
|
|
15069
|
-
"modulepreload",
|
|
15070
|
-
].includes(subtype);
|
|
15071
|
-
let attributeLocation = node.sourceCodeLocation.attrs[attributeName];
|
|
15072
|
-
if (
|
|
15073
|
-
!attributeLocation &&
|
|
15074
|
-
attributeName === "href" &&
|
|
15075
|
-
(node.tagName === "use" || node.tagName === "image")
|
|
15076
|
-
) {
|
|
15077
|
-
attributeLocation = node.sourceCodeLocation.attrs["xlink:href"];
|
|
15078
|
-
}
|
|
15079
|
-
const attributeStart = attributeLocation.startOffset;
|
|
15080
|
-
const attributeValueStart = urlInfo.content.indexOf(
|
|
15081
|
-
attributeValue,
|
|
15082
|
-
attributeStart + `${attributeName}=`.length,
|
|
15083
|
-
);
|
|
15084
|
-
const attributeValueEnd = attributeValueStart + attributeValue.length;
|
|
15085
|
-
const reference = urlInfo.dependencies.found({
|
|
15086
|
-
type,
|
|
15087
|
-
subtype,
|
|
15088
|
-
expectedType,
|
|
15089
|
-
specifier: attributeValue,
|
|
15090
|
-
specifierLine: line,
|
|
15091
|
-
specifierColumn: column,
|
|
15092
|
-
specifierStart: attributeValueStart,
|
|
15093
|
-
specifierEnd: attributeValueEnd,
|
|
15094
|
-
isResourceHint,
|
|
15095
|
-
isWeak: isResourceHint,
|
|
15096
|
-
crossorigin,
|
|
15097
|
-
integrity,
|
|
15098
|
-
debug,
|
|
15099
|
-
astInfo: { node, attributeName },
|
|
15100
|
-
...rest,
|
|
15101
|
-
});
|
|
15102
|
-
actions.push(async () => {
|
|
15103
|
-
await reference.readGeneratedSpecifier();
|
|
15104
|
-
mutations.push(() => {
|
|
15105
|
-
setHtmlNodeAttributes(node, {
|
|
15106
|
-
[attributeName]: reference.generatedSpecifier,
|
|
15107
|
-
});
|
|
15108
|
-
});
|
|
15109
|
-
});
|
|
15110
|
-
return reference;
|
|
15111
|
-
};
|
|
15112
|
-
const visitHref = (node, referenceProps) => {
|
|
15113
|
-
const href = getHtmlNodeAttribute(node, "href");
|
|
15114
|
-
if (href) {
|
|
15115
|
-
return createExternalReference(node, "href", href, referenceProps);
|
|
15116
|
-
}
|
|
15117
|
-
return null;
|
|
15118
|
-
};
|
|
15119
|
-
const visitSrc = (node, referenceProps) => {
|
|
15120
|
-
const src = getHtmlNodeAttribute(node, "src");
|
|
15121
|
-
if (src) {
|
|
15122
|
-
return createExternalReference(node, "src", src, referenceProps);
|
|
15123
|
-
}
|
|
15124
|
-
return null;
|
|
15125
|
-
};
|
|
15126
|
-
const visitSrcset = (node, referenceProps) => {
|
|
15127
|
-
const srcset = getHtmlNodeAttribute(node, "srcset");
|
|
15128
|
-
if (srcset) {
|
|
15129
|
-
const srcCandidates = parseSrcSet(srcset);
|
|
15130
|
-
return srcCandidates.map((srcCandidate) => {
|
|
15131
|
-
return createExternalReference(
|
|
15132
|
-
node,
|
|
15133
|
-
"srcset",
|
|
15134
|
-
srcCandidate.specifier,
|
|
15135
|
-
referenceProps,
|
|
15136
|
-
);
|
|
15137
|
-
});
|
|
15138
|
-
}
|
|
15139
|
-
return null;
|
|
15140
|
-
};
|
|
15043
|
+
const assertImportMap = (value) => {
|
|
15044
|
+
if (value === null) {
|
|
15045
|
+
throw new TypeError(`an importMap must be an object, got null`)
|
|
15046
|
+
}
|
|
15141
15047
|
|
|
15142
|
-
const
|
|
15143
|
-
|
|
15144
|
-
|
|
15145
|
-
|
|
15146
|
-
) => {
|
|
15147
|
-
const hotAccept = getHtmlNodeAttribute(node, "hot-accept") !== undefined;
|
|
15148
|
-
const { line, column, isOriginal } = getHtmlNodePosition(node, {
|
|
15149
|
-
preferOriginal: true,
|
|
15150
|
-
});
|
|
15151
|
-
const inlineContentUrl = getUrlForContentInsideHtml(node, {
|
|
15152
|
-
htmlUrl: urlInfo.url,
|
|
15153
|
-
});
|
|
15154
|
-
const debug = getHtmlNodeAttribute(node, "jsenv-debug") !== undefined;
|
|
15155
|
-
const inlineReference = urlInfo.dependencies.foundInline({
|
|
15156
|
-
type,
|
|
15157
|
-
expectedType,
|
|
15158
|
-
isOriginalPosition: isOriginal,
|
|
15159
|
-
// we remove 1 to the line because imagine the following html:
|
|
15160
|
-
// <style>body { color: red; }</style>
|
|
15161
|
-
// -> content starts same line as <style> (same for <script>)
|
|
15162
|
-
specifierLine: line - 1,
|
|
15163
|
-
specifierColumn: column,
|
|
15164
|
-
specifier: inlineContentUrl,
|
|
15165
|
-
contentType,
|
|
15166
|
-
content: inlineContent,
|
|
15167
|
-
debug,
|
|
15168
|
-
astInfo: { node },
|
|
15169
|
-
});
|
|
15048
|
+
const type = typeof value;
|
|
15049
|
+
if (type !== "object") {
|
|
15050
|
+
throw new TypeError(`an importMap must be an object, received ${value}`)
|
|
15051
|
+
}
|
|
15170
15052
|
|
|
15171
|
-
|
|
15172
|
-
|
|
15173
|
-
|
|
15174
|
-
|
|
15175
|
-
|
|
15176
|
-
|
|
15177
|
-
"jsenv-cooked-by": "jsenv:html_inline_content_analysis",
|
|
15178
|
-
});
|
|
15179
|
-
} else {
|
|
15180
|
-
setHtmlNodeText(node, inlineReference.urlInfo.content, {
|
|
15181
|
-
indentation: false, // indentation would decrease stack trace precision
|
|
15182
|
-
});
|
|
15183
|
-
setHtmlNodeAttributes(node, {
|
|
15184
|
-
"jsenv-cooked-by": "jsenv:html_inline_content_analysis",
|
|
15185
|
-
});
|
|
15186
|
-
}
|
|
15187
|
-
});
|
|
15188
|
-
});
|
|
15189
|
-
return inlineReference;
|
|
15190
|
-
};
|
|
15191
|
-
const visitTextContent = (
|
|
15192
|
-
node,
|
|
15193
|
-
{ type, subtype, expectedType, contentType },
|
|
15194
|
-
) => {
|
|
15195
|
-
const inlineContent = getHtmlNodeText(node);
|
|
15196
|
-
if (!inlineContent) {
|
|
15197
|
-
return null;
|
|
15198
|
-
}
|
|
15199
|
-
return createInlineReference(node, inlineContent, {
|
|
15200
|
-
type,
|
|
15201
|
-
subtype,
|
|
15202
|
-
expectedType,
|
|
15203
|
-
contentType,
|
|
15204
|
-
});
|
|
15205
|
-
};
|
|
15053
|
+
if (Array.isArray(value)) {
|
|
15054
|
+
throw new TypeError(
|
|
15055
|
+
`an importMap must be an object, received array ${value}`,
|
|
15056
|
+
)
|
|
15057
|
+
}
|
|
15058
|
+
};
|
|
15206
15059
|
|
|
15207
|
-
|
|
15208
|
-
|
|
15209
|
-
|
|
15210
|
-
const type = getHtmlNodeAttribute(linkNode, "type");
|
|
15211
|
-
const ref = visitHref(linkNode, {
|
|
15212
|
-
type: "link_href",
|
|
15213
|
-
subtype: rel,
|
|
15214
|
-
// https://developer.mozilla.org/en-US/docs/Web/HTML/Link_types/preload#including_a_mime_type
|
|
15215
|
-
expectedContentType: type,
|
|
15216
|
-
});
|
|
15217
|
-
if (ref) {
|
|
15218
|
-
finalizeCallbacks.push(() => {
|
|
15219
|
-
if (ref.expectedType) ; else {
|
|
15220
|
-
ref.expectedType = decideLinkExpectedType(ref, urlInfo);
|
|
15221
|
-
}
|
|
15222
|
-
});
|
|
15223
|
-
}
|
|
15224
|
-
},
|
|
15225
|
-
style: inlineContent
|
|
15226
|
-
? (styleNode) => {
|
|
15227
|
-
visitTextContent(styleNode, {
|
|
15228
|
-
type: "style",
|
|
15229
|
-
expectedType: "css",
|
|
15230
|
-
contentType: "text/css",
|
|
15231
|
-
});
|
|
15232
|
-
}
|
|
15233
|
-
: null,
|
|
15234
|
-
script: (scriptNode) => {
|
|
15235
|
-
// during build the importmap is inlined
|
|
15236
|
-
// and shoud not be considered as a dependency anymore
|
|
15237
|
-
if (
|
|
15238
|
-
getHtmlNodeAttribute(scriptNode, "jsenv-inlined-by") ===
|
|
15239
|
-
"jsenv:importmap"
|
|
15240
|
-
) {
|
|
15241
|
-
return;
|
|
15242
|
-
}
|
|
15060
|
+
const hasScheme = (string) => {
|
|
15061
|
+
return /^[a-zA-Z]{2,}:/.test(string)
|
|
15062
|
+
};
|
|
15243
15063
|
|
|
15244
|
-
|
|
15245
|
-
|
|
15246
|
-
|
|
15247
|
-
|
|
15248
|
-
|
|
15249
|
-
const externalRef = visitSrc(scriptNode, {
|
|
15250
|
-
type: "script",
|
|
15251
|
-
subtype: type,
|
|
15252
|
-
expectedType: type,
|
|
15253
|
-
});
|
|
15254
|
-
if (externalRef) {
|
|
15255
|
-
return;
|
|
15256
|
-
}
|
|
15257
|
-
}
|
|
15064
|
+
const urlToScheme = (urlString) => {
|
|
15065
|
+
const colonIndex = urlString.indexOf(":");
|
|
15066
|
+
if (colonIndex === -1) return ""
|
|
15067
|
+
return urlString.slice(0, colonIndex)
|
|
15068
|
+
};
|
|
15258
15069
|
|
|
15259
|
-
|
|
15260
|
-
|
|
15261
|
-
|
|
15262
|
-
}
|
|
15263
|
-
// If the inline script was already handled by an other plugin, ignore it
|
|
15264
|
-
// - we want to preserve inline scripts generated by html supervisor during dev
|
|
15265
|
-
// - we want to avoid cooking twice a script during build
|
|
15266
|
-
if (
|
|
15267
|
-
!inlineConvertedScript &&
|
|
15268
|
-
getHtmlNodeAttribute(scriptNode, "jsenv-injected-by") ===
|
|
15269
|
-
"jsenv:js_module_fallback"
|
|
15270
|
-
) {
|
|
15271
|
-
return;
|
|
15272
|
-
}
|
|
15070
|
+
const urlToPathname = (urlString) => {
|
|
15071
|
+
return ressourceToPathname(urlToRessource(urlString))
|
|
15072
|
+
};
|
|
15273
15073
|
|
|
15274
|
-
|
|
15275
|
-
|
|
15276
|
-
subtype,
|
|
15277
|
-
expectedType: type,
|
|
15278
|
-
contentType,
|
|
15279
|
-
});
|
|
15280
|
-
if (inlineRef) {
|
|
15281
|
-
// 1. <script type="jsx"> becomes <script>
|
|
15282
|
-
if (type === "js_classic" && extension !== ".js") {
|
|
15283
|
-
mutations.push(() => {
|
|
15284
|
-
setHtmlNodeAttributes(scriptNode, {
|
|
15285
|
-
type: undefined,
|
|
15286
|
-
});
|
|
15287
|
-
});
|
|
15288
|
-
}
|
|
15289
|
-
// 2. <script type="module/jsx"> becomes <script type="module">
|
|
15290
|
-
if (type === "js_module" && extension !== ".js") {
|
|
15291
|
-
mutations.push(() => {
|
|
15292
|
-
setHtmlNodeAttributes(scriptNode, {
|
|
15293
|
-
type: "module",
|
|
15294
|
-
});
|
|
15295
|
-
});
|
|
15296
|
-
}
|
|
15297
|
-
}
|
|
15298
|
-
},
|
|
15299
|
-
a: (aNode) => {
|
|
15300
|
-
visitHref(aNode, {
|
|
15301
|
-
type: "a_href",
|
|
15302
|
-
});
|
|
15303
|
-
},
|
|
15304
|
-
iframe: (iframeNode) => {
|
|
15305
|
-
visitSrc(iframeNode, {
|
|
15306
|
-
type: "iframe_src",
|
|
15307
|
-
});
|
|
15308
|
-
},
|
|
15309
|
-
img: (imgNode) => {
|
|
15310
|
-
visitSrc(imgNode, {
|
|
15311
|
-
type: "img_src",
|
|
15312
|
-
});
|
|
15313
|
-
visitSrcset(imgNode, {
|
|
15314
|
-
type: "img_srcset",
|
|
15315
|
-
});
|
|
15316
|
-
},
|
|
15317
|
-
source: (sourceNode) => {
|
|
15318
|
-
visitSrc(sourceNode, {
|
|
15319
|
-
type: "source_src",
|
|
15320
|
-
});
|
|
15321
|
-
visitSrcset(sourceNode, {
|
|
15322
|
-
type: "source_srcset",
|
|
15323
|
-
});
|
|
15324
|
-
},
|
|
15325
|
-
// svg <image> tag
|
|
15326
|
-
image: (imageNode) => {
|
|
15327
|
-
visitHref(imageNode, {
|
|
15328
|
-
type: "image_href",
|
|
15329
|
-
});
|
|
15330
|
-
},
|
|
15331
|
-
use: (useNode) => {
|
|
15332
|
-
visitHref(useNode, {
|
|
15333
|
-
type: "use_href",
|
|
15334
|
-
});
|
|
15335
|
-
},
|
|
15336
|
-
});
|
|
15337
|
-
finalizeCallbacks.forEach((finalizeCallback) => {
|
|
15338
|
-
finalizeCallback();
|
|
15339
|
-
});
|
|
15074
|
+
const urlToRessource = (urlString) => {
|
|
15075
|
+
const scheme = urlToScheme(urlString);
|
|
15340
15076
|
|
|
15341
|
-
if (
|
|
15342
|
-
|
|
15077
|
+
if (scheme === "file") {
|
|
15078
|
+
return urlString.slice("file://".length)
|
|
15343
15079
|
}
|
|
15344
|
-
|
|
15345
|
-
|
|
15080
|
+
|
|
15081
|
+
if (scheme === "https" || scheme === "http") {
|
|
15082
|
+
// remove origin
|
|
15083
|
+
const afterProtocol = urlString.slice(scheme.length + "://".length);
|
|
15084
|
+
const pathnameSlashIndex = afterProtocol.indexOf("/", "://".length);
|
|
15085
|
+
return afterProtocol.slice(pathnameSlashIndex)
|
|
15346
15086
|
}
|
|
15347
|
-
|
|
15348
|
-
return
|
|
15087
|
+
|
|
15088
|
+
return urlString.slice(scheme.length + 1)
|
|
15349
15089
|
};
|
|
15350
15090
|
|
|
15351
|
-
const
|
|
15352
|
-
const
|
|
15353
|
-
|
|
15354
|
-
|
|
15355
|
-
|
|
15356
|
-
const crossorigin = getHtmlNodeAttribute(node, "crossorigin") !== undefined;
|
|
15357
|
-
meta.crossorigin = crossorigin;
|
|
15358
|
-
}
|
|
15359
|
-
if (integrityCompatibleTagNames.includes(node.nodeName)) {
|
|
15360
|
-
const integrity = getHtmlNodeAttribute(node, "integrity");
|
|
15361
|
-
meta.integrity = integrity;
|
|
15362
|
-
}
|
|
15363
|
-
return meta;
|
|
15091
|
+
const ressourceToPathname = (ressource) => {
|
|
15092
|
+
const searchSeparatorIndex = ressource.indexOf("?");
|
|
15093
|
+
return searchSeparatorIndex === -1
|
|
15094
|
+
? ressource
|
|
15095
|
+
: ressource.slice(0, searchSeparatorIndex)
|
|
15364
15096
|
};
|
|
15365
15097
|
|
|
15366
|
-
const
|
|
15367
|
-
const
|
|
15368
|
-
|
|
15369
|
-
|
|
15098
|
+
const urlToOrigin = (urlString) => {
|
|
15099
|
+
const scheme = urlToScheme(urlString);
|
|
15100
|
+
|
|
15101
|
+
if (scheme === "file") {
|
|
15102
|
+
return "file://"
|
|
15370
15103
|
}
|
|
15371
|
-
|
|
15372
|
-
|
|
15104
|
+
|
|
15105
|
+
if (scheme === "http" || scheme === "https") {
|
|
15106
|
+
const secondProtocolSlashIndex = scheme.length + "://".length;
|
|
15107
|
+
const pathnameSlashIndex = urlString.indexOf("/", secondProtocolSlashIndex);
|
|
15108
|
+
|
|
15109
|
+
if (pathnameSlashIndex === -1) return urlString
|
|
15110
|
+
return urlString.slice(0, pathnameSlashIndex)
|
|
15373
15111
|
}
|
|
15374
|
-
|
|
15375
|
-
|
|
15112
|
+
|
|
15113
|
+
return urlString.slice(0, scheme.length + 1)
|
|
15114
|
+
};
|
|
15115
|
+
|
|
15116
|
+
const pathnameToParentPathname = (pathname) => {
|
|
15117
|
+
const slashLastIndex = pathname.lastIndexOf("/");
|
|
15118
|
+
if (slashLastIndex === -1) {
|
|
15119
|
+
return "/"
|
|
15376
15120
|
}
|
|
15377
|
-
|
|
15378
|
-
|
|
15379
|
-
|
|
15380
|
-
|
|
15381
|
-
|
|
15121
|
+
|
|
15122
|
+
return pathname.slice(0, slashLastIndex + 1)
|
|
15123
|
+
};
|
|
15124
|
+
|
|
15125
|
+
// could be useful: https://url.spec.whatwg.org/#url-miscellaneous
|
|
15126
|
+
|
|
15127
|
+
|
|
15128
|
+
const resolveUrl = (specifier, baseUrl) => {
|
|
15129
|
+
if (baseUrl) {
|
|
15130
|
+
if (typeof baseUrl !== "string") {
|
|
15131
|
+
throw new TypeError(writeBaseUrlMustBeAString({ baseUrl, specifier }))
|
|
15382
15132
|
}
|
|
15383
|
-
if (
|
|
15384
|
-
|
|
15385
|
-
}
|
|
15386
|
-
if (as === "script") {
|
|
15387
|
-
for (const referenceToOther of htmlUrlInfo.referenceToOthersSet) {
|
|
15388
|
-
if (referenceToOther.url !== linkReference.url) {
|
|
15389
|
-
continue;
|
|
15390
|
-
}
|
|
15391
|
-
if (referenceToOther.type !== "script") {
|
|
15392
|
-
continue;
|
|
15393
|
-
}
|
|
15394
|
-
return referenceToOther.expectedType;
|
|
15395
|
-
}
|
|
15396
|
-
return undefined;
|
|
15133
|
+
if (!hasScheme(baseUrl)) {
|
|
15134
|
+
throw new Error(writeBaseUrlMustBeAbsolute({ baseUrl, specifier }))
|
|
15397
15135
|
}
|
|
15398
15136
|
}
|
|
15399
|
-
return undefined;
|
|
15400
|
-
};
|
|
15401
15137
|
|
|
15402
|
-
|
|
15403
|
-
|
|
15404
|
-
|
|
15405
|
-
// }
|
|
15406
|
-
// return new URL(url, baseUrl).href;
|
|
15407
|
-
// };
|
|
15138
|
+
if (hasScheme(specifier)) {
|
|
15139
|
+
return specifier
|
|
15140
|
+
}
|
|
15408
15141
|
|
|
15409
|
-
|
|
15142
|
+
if (!baseUrl) {
|
|
15143
|
+
throw new Error(writeBaseUrlRequired({ baseUrl, specifier }))
|
|
15144
|
+
}
|
|
15410
15145
|
|
|
15411
|
-
|
|
15412
|
-
|
|
15413
|
-
|
|
15414
|
-
|
|
15415
|
-
transformUrlContent: {
|
|
15416
|
-
webmanifest: parseAndTransformWebmanifestUrls,
|
|
15417
|
-
},
|
|
15418
|
-
};
|
|
15419
|
-
};
|
|
15146
|
+
// scheme relative
|
|
15147
|
+
if (specifier.slice(0, 2) === "//") {
|
|
15148
|
+
return `${urlToScheme(baseUrl)}:${specifier}`
|
|
15149
|
+
}
|
|
15420
15150
|
|
|
15421
|
-
|
|
15422
|
-
|
|
15423
|
-
|
|
15424
|
-
|
|
15425
|
-
const { icons = [] } = manifest;
|
|
15426
|
-
icons.forEach((icon) => {
|
|
15427
|
-
const iconReference = urlInfo.dependencies.found({
|
|
15428
|
-
type: "webmanifest_icon_src",
|
|
15429
|
-
specifier: icon.src,
|
|
15430
|
-
});
|
|
15431
|
-
actions.push(async () => {
|
|
15432
|
-
await iconReference.readGeneratedSpecifier();
|
|
15433
|
-
icon.src = iconReference.generatedSpecifier;
|
|
15434
|
-
});
|
|
15435
|
-
});
|
|
15151
|
+
// origin relative
|
|
15152
|
+
if (specifier[0] === "/") {
|
|
15153
|
+
return `${urlToOrigin(baseUrl)}${specifier}`
|
|
15154
|
+
}
|
|
15436
15155
|
|
|
15437
|
-
|
|
15438
|
-
|
|
15156
|
+
const baseOrigin = urlToOrigin(baseUrl);
|
|
15157
|
+
const basePathname = urlToPathname(baseUrl);
|
|
15158
|
+
|
|
15159
|
+
if (specifier === ".") {
|
|
15160
|
+
const baseDirectoryPathname = pathnameToParentPathname(basePathname);
|
|
15161
|
+
return `${baseOrigin}${baseDirectoryPathname}`
|
|
15439
15162
|
}
|
|
15440
|
-
await Promise.all(actions.map((action) => action()));
|
|
15441
|
-
return JSON.stringify(manifest, null, " ");
|
|
15442
|
-
};
|
|
15443
15163
|
|
|
15444
|
-
|
|
15445
|
-
|
|
15446
|
-
|
|
15164
|
+
// pathname relative inside
|
|
15165
|
+
if (specifier.slice(0, 2) === "./") {
|
|
15166
|
+
const baseDirectoryPathname = pathnameToParentPathname(basePathname);
|
|
15167
|
+
return `${baseOrigin}${baseDirectoryPathname}${specifier.slice(2)}`
|
|
15168
|
+
}
|
|
15447
15169
|
|
|
15170
|
+
// pathname relative outside
|
|
15171
|
+
if (specifier.slice(0, 3) === "../") {
|
|
15172
|
+
let unresolvedPathname = specifier;
|
|
15173
|
+
const importerFolders = basePathname.split("/");
|
|
15174
|
+
importerFolders.pop();
|
|
15448
15175
|
|
|
15449
|
-
|
|
15450
|
-
|
|
15451
|
-
|
|
15452
|
-
|
|
15453
|
-
|
|
15454
|
-
|
|
15455
|
-
|
|
15456
|
-
|
|
15457
|
-
};
|
|
15176
|
+
while (unresolvedPathname.slice(0, 3) === "../") {
|
|
15177
|
+
unresolvedPathname = unresolvedPathname.slice(3);
|
|
15178
|
+
// when there is no folder left to resolved
|
|
15179
|
+
// we just ignore '../'
|
|
15180
|
+
if (importerFolders.length) {
|
|
15181
|
+
importerFolders.pop();
|
|
15182
|
+
}
|
|
15183
|
+
}
|
|
15458
15184
|
|
|
15459
|
-
const
|
|
15460
|
-
|
|
15461
|
-
|
|
15462
|
-
|
|
15463
|
-
});
|
|
15464
|
-
const actions = [];
|
|
15465
|
-
const magicSource = createMagicSource(urlInfo.content);
|
|
15466
|
-
for (const cssUrl of cssUrls) {
|
|
15467
|
-
const reference = urlInfo.dependencies.found({
|
|
15468
|
-
type: cssUrl.type,
|
|
15469
|
-
specifier: cssUrl.specifier,
|
|
15470
|
-
specifierStart: cssUrl.start,
|
|
15471
|
-
specifierEnd: cssUrl.end,
|
|
15472
|
-
specifierLine: cssUrl.line,
|
|
15473
|
-
specifierColumn: cssUrl.column,
|
|
15474
|
-
});
|
|
15475
|
-
actions.push(async () => {
|
|
15476
|
-
await reference.readGeneratedSpecifier();
|
|
15477
|
-
const replacement = reference.generatedSpecifier;
|
|
15478
|
-
magicSource.replace({
|
|
15479
|
-
start: cssUrl.start,
|
|
15480
|
-
end: cssUrl.end,
|
|
15481
|
-
replacement,
|
|
15482
|
-
});
|
|
15483
|
-
});
|
|
15185
|
+
const resolvedPathname = `${importerFolders.join(
|
|
15186
|
+
"/",
|
|
15187
|
+
)}/${unresolvedPathname}`;
|
|
15188
|
+
return `${baseOrigin}${resolvedPathname}`
|
|
15484
15189
|
}
|
|
15485
|
-
|
|
15486
|
-
|
|
15190
|
+
|
|
15191
|
+
// bare
|
|
15192
|
+
if (basePathname === "") {
|
|
15193
|
+
return `${baseOrigin}/${specifier}`
|
|
15487
15194
|
}
|
|
15488
|
-
|
|
15195
|
+
if (basePathname[basePathname.length] === "/") {
|
|
15196
|
+
return `${baseOrigin}${basePathname}${specifier}`
|
|
15197
|
+
}
|
|
15198
|
+
return `${baseOrigin}${pathnameToParentPathname(basePathname)}${specifier}`
|
|
15489
15199
|
};
|
|
15490
15200
|
|
|
15491
|
-
const
|
|
15492
|
-
|
|
15493
|
-
|
|
15494
|
-
|
|
15495
|
-
|
|
15496
|
-
|
|
15497
|
-
|
|
15498
|
-
|
|
15499
|
-
|
|
15500
|
-
|
|
15501
|
-
|
|
15502
|
-
|
|
15503
|
-
|
|
15504
|
-
|
|
15505
|
-
|
|
15506
|
-
|
|
15507
|
-
|
|
15508
|
-
|
|
15509
|
-
|
|
15510
|
-
|
|
15511
|
-
|
|
15201
|
+
const writeBaseUrlMustBeAString = ({
|
|
15202
|
+
baseUrl,
|
|
15203
|
+
specifier,
|
|
15204
|
+
}) => `baseUrl must be a string.
|
|
15205
|
+
--- base url ---
|
|
15206
|
+
${baseUrl}
|
|
15207
|
+
--- specifier ---
|
|
15208
|
+
${specifier}`;
|
|
15209
|
+
|
|
15210
|
+
const writeBaseUrlMustBeAbsolute = ({
|
|
15211
|
+
baseUrl,
|
|
15212
|
+
specifier,
|
|
15213
|
+
}) => `baseUrl must be absolute.
|
|
15214
|
+
--- base url ---
|
|
15215
|
+
${baseUrl}
|
|
15216
|
+
--- specifier ---
|
|
15217
|
+
${specifier}`;
|
|
15218
|
+
|
|
15219
|
+
const writeBaseUrlRequired = ({
|
|
15220
|
+
baseUrl,
|
|
15221
|
+
specifier,
|
|
15222
|
+
}) => `baseUrl required to resolve relative specifier.
|
|
15223
|
+
--- base url ---
|
|
15224
|
+
${baseUrl}
|
|
15225
|
+
--- specifier ---
|
|
15226
|
+
${specifier}`;
|
|
15227
|
+
|
|
15228
|
+
const tryUrlResolution = (string, url) => {
|
|
15229
|
+
const result = resolveUrl(string, url);
|
|
15230
|
+
return hasScheme(result) ? result : null
|
|
15512
15231
|
};
|
|
15513
15232
|
|
|
15514
|
-
const
|
|
15515
|
-
|
|
15516
|
-
|
|
15517
|
-
|
|
15518
|
-
|
|
15519
|
-
|
|
15520
|
-
|
|
15521
|
-
|
|
15522
|
-
|
|
15233
|
+
const resolveSpecifier = (specifier, importer) => {
|
|
15234
|
+
if (
|
|
15235
|
+
specifier === "." ||
|
|
15236
|
+
specifier[0] === "/" ||
|
|
15237
|
+
specifier.startsWith("./") ||
|
|
15238
|
+
specifier.startsWith("../")
|
|
15239
|
+
) {
|
|
15240
|
+
return resolveUrl(specifier, importer)
|
|
15241
|
+
}
|
|
15523
15242
|
|
|
15524
|
-
|
|
15525
|
-
|
|
15526
|
-
|
|
15527
|
-
});
|
|
15528
|
-
let { quote } = inlineReferenceInfo;
|
|
15529
|
-
if (quote === "`" && !canUseTemplateLiterals) {
|
|
15530
|
-
// if quote is "`" and template literals are not supported
|
|
15531
|
-
// we'll use a regular string (single or double quote)
|
|
15532
|
-
// when rendering the string
|
|
15533
|
-
quote = JS_QUOTES.pickBest(inlineReferenceInfo.content);
|
|
15534
|
-
}
|
|
15535
|
-
const inlineReference = urlInfo.dependencies.foundInline({
|
|
15536
|
-
type: "js_inline_content",
|
|
15537
|
-
subtype: inlineReferenceInfo.type, // "new_blob_first_arg", "new_inline_content_first_arg", "json_parse_first_arg"
|
|
15538
|
-
isOriginalPosition: urlInfo.content === urlInfo.originalContent,
|
|
15539
|
-
specifierLine: inlineReferenceInfo.line,
|
|
15540
|
-
specifierColumn: inlineReferenceInfo.column,
|
|
15541
|
-
specifier: inlineUrl,
|
|
15542
|
-
contentType: inlineReferenceInfo.contentType,
|
|
15543
|
-
content: inlineReferenceInfo.content,
|
|
15544
|
-
});
|
|
15545
|
-
const inlineUrlInfo = inlineReference.urlInfo;
|
|
15546
|
-
inlineUrlInfo.jsQuote = quote;
|
|
15547
|
-
inlineReference.escape = (value) => {
|
|
15548
|
-
return JS_QUOTES.escapeSpecialChars(value.slice(1, -1), { quote });
|
|
15549
|
-
};
|
|
15550
|
-
|
|
15551
|
-
sequentialActions.push(async () => {
|
|
15552
|
-
await inlineUrlInfo.cook();
|
|
15553
|
-
const replacement = JS_QUOTES.escapeSpecialChars(inlineUrlInfo.content, {
|
|
15554
|
-
quote,
|
|
15555
|
-
});
|
|
15556
|
-
magicSource.replace({
|
|
15557
|
-
start: inlineReferenceInfo.start,
|
|
15558
|
-
end: inlineReferenceInfo.end,
|
|
15559
|
-
replacement,
|
|
15560
|
-
});
|
|
15561
|
-
});
|
|
15562
|
-
};
|
|
15563
|
-
const onExternalReference = (externalReferenceInfo) => {
|
|
15564
|
-
if (
|
|
15565
|
-
externalReferenceInfo.subtype === "import_static" ||
|
|
15566
|
-
externalReferenceInfo.subtype === "import_dynamic"
|
|
15567
|
-
) {
|
|
15568
|
-
urlInfo.data.usesImport = true;
|
|
15569
|
-
}
|
|
15570
|
-
if (
|
|
15571
|
-
isNodeJs &&
|
|
15572
|
-
externalReferenceInfo.type === "js_url" &&
|
|
15573
|
-
externalReferenceInfo.expectedSubtype === "worker" &&
|
|
15574
|
-
externalReferenceInfo.expectedType === "js_classic" &&
|
|
15575
|
-
// TODO: it's true also if closest package.json
|
|
15576
|
-
// is type: module
|
|
15577
|
-
urlToExtension$1(
|
|
15578
|
-
new URL(externalReferenceInfo.specifier, urlInfo.url).href,
|
|
15579
|
-
) === ".mjs"
|
|
15580
|
-
) {
|
|
15581
|
-
externalReferenceInfo.expectedType = "js_module";
|
|
15582
|
-
}
|
|
15583
|
-
const reference = urlInfo.dependencies.found({
|
|
15584
|
-
type: externalReferenceInfo.type,
|
|
15585
|
-
subtype: externalReferenceInfo.subtype,
|
|
15586
|
-
expectedType: externalReferenceInfo.expectedType,
|
|
15587
|
-
expectedSubtype: externalReferenceInfo.expectedSubtype || urlInfo.subtype,
|
|
15588
|
-
specifier: externalReferenceInfo.specifier,
|
|
15589
|
-
specifierStart: externalReferenceInfo.start,
|
|
15590
|
-
specifierEnd: externalReferenceInfo.end,
|
|
15591
|
-
specifierLine: externalReferenceInfo.line,
|
|
15592
|
-
specifierColumn: externalReferenceInfo.column,
|
|
15593
|
-
data: externalReferenceInfo.data,
|
|
15594
|
-
baseUrl: {
|
|
15595
|
-
"StringLiteral": externalReferenceInfo.baseUrl,
|
|
15596
|
-
"window.location": urlInfo.url,
|
|
15597
|
-
"window.origin": urlInfo.context.rootDirectoryUrl,
|
|
15598
|
-
"import.meta.url": urlInfo.url,
|
|
15599
|
-
"context.meta.url": urlInfo.url,
|
|
15600
|
-
"document.currentScript.src": urlInfo.url,
|
|
15601
|
-
}[externalReferenceInfo.baseUrlType],
|
|
15602
|
-
importAttributes: externalReferenceInfo.importAttributes,
|
|
15603
|
-
astInfo: externalReferenceInfo.astInfo,
|
|
15604
|
-
});
|
|
15605
|
-
parallelActions.push(async () => {
|
|
15606
|
-
await reference.readGeneratedSpecifier();
|
|
15607
|
-
const replacement = reference.generatedSpecifier;
|
|
15608
|
-
magicSource.replace({
|
|
15609
|
-
start: externalReferenceInfo.start,
|
|
15610
|
-
end: externalReferenceInfo.end,
|
|
15611
|
-
replacement,
|
|
15612
|
-
});
|
|
15613
|
-
if (reference.mutation) {
|
|
15614
|
-
reference.mutation(magicSource, urlInfo);
|
|
15615
|
-
}
|
|
15616
|
-
});
|
|
15617
|
-
};
|
|
15618
|
-
const jsReferenceInfos = parseJsUrls({
|
|
15619
|
-
js: urlInfo.content,
|
|
15620
|
-
url: urlInfo.originalUrl,
|
|
15621
|
-
ast: urlInfo.contentAst,
|
|
15622
|
-
isJsModule: urlInfo.type === "js_module",
|
|
15623
|
-
isWebWorker: isWebWorkerUrlInfo(urlInfo),
|
|
15624
|
-
inlineContent,
|
|
15625
|
-
isNodeJs,
|
|
15626
|
-
});
|
|
15627
|
-
for (const jsReferenceInfo of jsReferenceInfos) {
|
|
15628
|
-
if (jsReferenceInfo.isInline) {
|
|
15629
|
-
onInlineReference(jsReferenceInfo);
|
|
15630
|
-
} else {
|
|
15631
|
-
onExternalReference(jsReferenceInfo);
|
|
15632
|
-
}
|
|
15633
|
-
}
|
|
15634
|
-
if (parallelActions.length > 0) {
|
|
15635
|
-
await Promise.all(parallelActions.map((action) => action()));
|
|
15636
|
-
}
|
|
15637
|
-
if (sequentialActions.length > 0) {
|
|
15638
|
-
await sequentialActions.reduce(async (previous, action) => {
|
|
15639
|
-
await previous;
|
|
15640
|
-
await action();
|
|
15641
|
-
}, Promise.resolve());
|
|
15642
|
-
}
|
|
15643
|
-
|
|
15644
|
-
const { content, sourcemap } = magicSource.toContentAndSourcemap();
|
|
15645
|
-
return { content, sourcemap };
|
|
15646
|
-
};
|
|
15647
|
-
|
|
15648
|
-
const jsenvPluginReferenceAnalysis = ({
|
|
15649
|
-
inlineContent = true,
|
|
15650
|
-
inlineConvertedScript = false,
|
|
15651
|
-
fetchInlineUrls = true,
|
|
15652
|
-
}) => {
|
|
15653
|
-
return [
|
|
15654
|
-
jsenvPluginDirectoryReferenceAnalysis(),
|
|
15655
|
-
jsenvPluginHtmlReferenceAnalysis({
|
|
15656
|
-
inlineContent,
|
|
15657
|
-
inlineConvertedScript,
|
|
15658
|
-
}),
|
|
15659
|
-
jsenvPluginWebmanifestReferenceAnalysis(),
|
|
15660
|
-
jsenvPluginCssReferenceAnalysis(),
|
|
15661
|
-
jsenvPluginJsReferenceAnalysis({
|
|
15662
|
-
inlineContent,
|
|
15663
|
-
}),
|
|
15664
|
-
...(inlineContent ? [jsenvPluginDataUrlsAnalysis()] : []),
|
|
15665
|
-
...(inlineContent && fetchInlineUrls
|
|
15666
|
-
? [jsenvPluginInlineContentFetcher()]
|
|
15667
|
-
: []),
|
|
15668
|
-
jsenvPluginReferenceExpectedTypes(),
|
|
15669
|
-
];
|
|
15670
|
-
};
|
|
15671
|
-
|
|
15672
|
-
const jsenvPluginInlineContentFetcher = () => {
|
|
15673
|
-
return {
|
|
15674
|
-
name: "jsenv:inline_content_fetcher",
|
|
15675
|
-
appliesDuring: "*",
|
|
15676
|
-
fetchUrlContent: async (urlInfo) => {
|
|
15677
|
-
if (!urlInfo.isInline) {
|
|
15678
|
-
return null;
|
|
15679
|
-
}
|
|
15680
|
-
// - we must use last reference because
|
|
15681
|
-
// when updating the file, first reference is the previous version
|
|
15682
|
-
// - we cannot use urlInfo.lastReference because it can be the reference created by "http_request"
|
|
15683
|
-
let lastInlineReference;
|
|
15684
|
-
for (const reference of urlInfo.referenceFromOthersSet) {
|
|
15685
|
-
if (reference.isInline) {
|
|
15686
|
-
lastInlineReference = reference;
|
|
15687
|
-
}
|
|
15688
|
-
}
|
|
15689
|
-
const { prev } = lastInlineReference;
|
|
15690
|
-
if (prev && !prev.isInline) {
|
|
15691
|
-
// got inlined, cook original url
|
|
15692
|
-
if (lastInlineReference.content === undefined) {
|
|
15693
|
-
const originalUrlInfo = prev.urlInfo;
|
|
15694
|
-
await originalUrlInfo.cook();
|
|
15695
|
-
lastInlineReference.content = originalUrlInfo.content;
|
|
15696
|
-
lastInlineReference.contentType = originalUrlInfo.contentType;
|
|
15697
|
-
}
|
|
15698
|
-
}
|
|
15699
|
-
return {
|
|
15700
|
-
originalContent: urlInfo.originalContent,
|
|
15701
|
-
content: lastInlineReference.content,
|
|
15702
|
-
contentType: lastInlineReference.contentType,
|
|
15703
|
-
};
|
|
15704
|
-
},
|
|
15705
|
-
};
|
|
15706
|
-
};
|
|
15707
|
-
|
|
15708
|
-
// duplicated from @jsenv/log to avoid the dependency
|
|
15709
|
-
const createDetailedMessage = (message, details = {}) => {
|
|
15710
|
-
let string = `${message}`;
|
|
15711
|
-
|
|
15712
|
-
Object.keys(details).forEach((key) => {
|
|
15713
|
-
const value = details[key];
|
|
15714
|
-
string += `
|
|
15715
|
-
--- ${key} ---
|
|
15716
|
-
${
|
|
15717
|
-
Array.isArray(value)
|
|
15718
|
-
? value.join(`
|
|
15719
|
-
`)
|
|
15720
|
-
: value
|
|
15721
|
-
}`;
|
|
15722
|
-
});
|
|
15723
|
-
|
|
15724
|
-
return string
|
|
15725
|
-
};
|
|
15726
|
-
|
|
15727
|
-
const assertImportMap = (value) => {
|
|
15728
|
-
if (value === null) {
|
|
15729
|
-
throw new TypeError(`an importMap must be an object, got null`)
|
|
15730
|
-
}
|
|
15731
|
-
|
|
15732
|
-
const type = typeof value;
|
|
15733
|
-
if (type !== "object") {
|
|
15734
|
-
throw new TypeError(`an importMap must be an object, received ${value}`)
|
|
15735
|
-
}
|
|
15736
|
-
|
|
15737
|
-
if (Array.isArray(value)) {
|
|
15738
|
-
throw new TypeError(
|
|
15739
|
-
`an importMap must be an object, received array ${value}`,
|
|
15740
|
-
)
|
|
15741
|
-
}
|
|
15742
|
-
};
|
|
15743
|
-
|
|
15744
|
-
const hasScheme = (string) => {
|
|
15745
|
-
return /^[a-zA-Z]{2,}:/.test(string)
|
|
15746
|
-
};
|
|
15747
|
-
|
|
15748
|
-
const urlToScheme = (urlString) => {
|
|
15749
|
-
const colonIndex = urlString.indexOf(":");
|
|
15750
|
-
if (colonIndex === -1) return ""
|
|
15751
|
-
return urlString.slice(0, colonIndex)
|
|
15752
|
-
};
|
|
15753
|
-
|
|
15754
|
-
const urlToPathname = (urlString) => {
|
|
15755
|
-
return ressourceToPathname(urlToRessource(urlString))
|
|
15756
|
-
};
|
|
15757
|
-
|
|
15758
|
-
const urlToRessource = (urlString) => {
|
|
15759
|
-
const scheme = urlToScheme(urlString);
|
|
15760
|
-
|
|
15761
|
-
if (scheme === "file") {
|
|
15762
|
-
return urlString.slice("file://".length)
|
|
15763
|
-
}
|
|
15764
|
-
|
|
15765
|
-
if (scheme === "https" || scheme === "http") {
|
|
15766
|
-
// remove origin
|
|
15767
|
-
const afterProtocol = urlString.slice(scheme.length + "://".length);
|
|
15768
|
-
const pathnameSlashIndex = afterProtocol.indexOf("/", "://".length);
|
|
15769
|
-
return afterProtocol.slice(pathnameSlashIndex)
|
|
15770
|
-
}
|
|
15771
|
-
|
|
15772
|
-
return urlString.slice(scheme.length + 1)
|
|
15773
|
-
};
|
|
15774
|
-
|
|
15775
|
-
const ressourceToPathname = (ressource) => {
|
|
15776
|
-
const searchSeparatorIndex = ressource.indexOf("?");
|
|
15777
|
-
return searchSeparatorIndex === -1
|
|
15778
|
-
? ressource
|
|
15779
|
-
: ressource.slice(0, searchSeparatorIndex)
|
|
15780
|
-
};
|
|
15781
|
-
|
|
15782
|
-
const urlToOrigin = (urlString) => {
|
|
15783
|
-
const scheme = urlToScheme(urlString);
|
|
15784
|
-
|
|
15785
|
-
if (scheme === "file") {
|
|
15786
|
-
return "file://"
|
|
15787
|
-
}
|
|
15788
|
-
|
|
15789
|
-
if (scheme === "http" || scheme === "https") {
|
|
15790
|
-
const secondProtocolSlashIndex = scheme.length + "://".length;
|
|
15791
|
-
const pathnameSlashIndex = urlString.indexOf("/", secondProtocolSlashIndex);
|
|
15792
|
-
|
|
15793
|
-
if (pathnameSlashIndex === -1) return urlString
|
|
15794
|
-
return urlString.slice(0, pathnameSlashIndex)
|
|
15795
|
-
}
|
|
15796
|
-
|
|
15797
|
-
return urlString.slice(0, scheme.length + 1)
|
|
15798
|
-
};
|
|
15799
|
-
|
|
15800
|
-
const pathnameToParentPathname = (pathname) => {
|
|
15801
|
-
const slashLastIndex = pathname.lastIndexOf("/");
|
|
15802
|
-
if (slashLastIndex === -1) {
|
|
15803
|
-
return "/"
|
|
15804
|
-
}
|
|
15805
|
-
|
|
15806
|
-
return pathname.slice(0, slashLastIndex + 1)
|
|
15807
|
-
};
|
|
15808
|
-
|
|
15809
|
-
// could be useful: https://url.spec.whatwg.org/#url-miscellaneous
|
|
15810
|
-
|
|
15811
|
-
|
|
15812
|
-
const resolveUrl = (specifier, baseUrl) => {
|
|
15813
|
-
if (baseUrl) {
|
|
15814
|
-
if (typeof baseUrl !== "string") {
|
|
15815
|
-
throw new TypeError(writeBaseUrlMustBeAString({ baseUrl, specifier }))
|
|
15816
|
-
}
|
|
15817
|
-
if (!hasScheme(baseUrl)) {
|
|
15818
|
-
throw new Error(writeBaseUrlMustBeAbsolute({ baseUrl, specifier }))
|
|
15819
|
-
}
|
|
15820
|
-
}
|
|
15821
|
-
|
|
15822
|
-
if (hasScheme(specifier)) {
|
|
15823
|
-
return specifier
|
|
15824
|
-
}
|
|
15825
|
-
|
|
15826
|
-
if (!baseUrl) {
|
|
15827
|
-
throw new Error(writeBaseUrlRequired({ baseUrl, specifier }))
|
|
15828
|
-
}
|
|
15829
|
-
|
|
15830
|
-
// scheme relative
|
|
15831
|
-
if (specifier.slice(0, 2) === "//") {
|
|
15832
|
-
return `${urlToScheme(baseUrl)}:${specifier}`
|
|
15833
|
-
}
|
|
15834
|
-
|
|
15835
|
-
// origin relative
|
|
15836
|
-
if (specifier[0] === "/") {
|
|
15837
|
-
return `${urlToOrigin(baseUrl)}${specifier}`
|
|
15838
|
-
}
|
|
15839
|
-
|
|
15840
|
-
const baseOrigin = urlToOrigin(baseUrl);
|
|
15841
|
-
const basePathname = urlToPathname(baseUrl);
|
|
15842
|
-
|
|
15843
|
-
if (specifier === ".") {
|
|
15844
|
-
const baseDirectoryPathname = pathnameToParentPathname(basePathname);
|
|
15845
|
-
return `${baseOrigin}${baseDirectoryPathname}`
|
|
15846
|
-
}
|
|
15847
|
-
|
|
15848
|
-
// pathname relative inside
|
|
15849
|
-
if (specifier.slice(0, 2) === "./") {
|
|
15850
|
-
const baseDirectoryPathname = pathnameToParentPathname(basePathname);
|
|
15851
|
-
return `${baseOrigin}${baseDirectoryPathname}${specifier.slice(2)}`
|
|
15852
|
-
}
|
|
15853
|
-
|
|
15854
|
-
// pathname relative outside
|
|
15855
|
-
if (specifier.slice(0, 3) === "../") {
|
|
15856
|
-
let unresolvedPathname = specifier;
|
|
15857
|
-
const importerFolders = basePathname.split("/");
|
|
15858
|
-
importerFolders.pop();
|
|
15859
|
-
|
|
15860
|
-
while (unresolvedPathname.slice(0, 3) === "../") {
|
|
15861
|
-
unresolvedPathname = unresolvedPathname.slice(3);
|
|
15862
|
-
// when there is no folder left to resolved
|
|
15863
|
-
// we just ignore '../'
|
|
15864
|
-
if (importerFolders.length) {
|
|
15865
|
-
importerFolders.pop();
|
|
15866
|
-
}
|
|
15867
|
-
}
|
|
15868
|
-
|
|
15869
|
-
const resolvedPathname = `${importerFolders.join(
|
|
15870
|
-
"/",
|
|
15871
|
-
)}/${unresolvedPathname}`;
|
|
15872
|
-
return `${baseOrigin}${resolvedPathname}`
|
|
15873
|
-
}
|
|
15874
|
-
|
|
15875
|
-
// bare
|
|
15876
|
-
if (basePathname === "") {
|
|
15877
|
-
return `${baseOrigin}/${specifier}`
|
|
15878
|
-
}
|
|
15879
|
-
if (basePathname[basePathname.length] === "/") {
|
|
15880
|
-
return `${baseOrigin}${basePathname}${specifier}`
|
|
15881
|
-
}
|
|
15882
|
-
return `${baseOrigin}${pathnameToParentPathname(basePathname)}${specifier}`
|
|
15883
|
-
};
|
|
15884
|
-
|
|
15885
|
-
const writeBaseUrlMustBeAString = ({
|
|
15886
|
-
baseUrl,
|
|
15887
|
-
specifier,
|
|
15888
|
-
}) => `baseUrl must be a string.
|
|
15889
|
-
--- base url ---
|
|
15890
|
-
${baseUrl}
|
|
15891
|
-
--- specifier ---
|
|
15892
|
-
${specifier}`;
|
|
15893
|
-
|
|
15894
|
-
const writeBaseUrlMustBeAbsolute = ({
|
|
15895
|
-
baseUrl,
|
|
15896
|
-
specifier,
|
|
15897
|
-
}) => `baseUrl must be absolute.
|
|
15898
|
-
--- base url ---
|
|
15899
|
-
${baseUrl}
|
|
15900
|
-
--- specifier ---
|
|
15901
|
-
${specifier}`;
|
|
15902
|
-
|
|
15903
|
-
const writeBaseUrlRequired = ({
|
|
15904
|
-
baseUrl,
|
|
15905
|
-
specifier,
|
|
15906
|
-
}) => `baseUrl required to resolve relative specifier.
|
|
15907
|
-
--- base url ---
|
|
15908
|
-
${baseUrl}
|
|
15909
|
-
--- specifier ---
|
|
15910
|
-
${specifier}`;
|
|
15911
|
-
|
|
15912
|
-
const tryUrlResolution = (string, url) => {
|
|
15913
|
-
const result = resolveUrl(string, url);
|
|
15914
|
-
return hasScheme(result) ? result : null
|
|
15915
|
-
};
|
|
15916
|
-
|
|
15917
|
-
const resolveSpecifier = (specifier, importer) => {
|
|
15918
|
-
if (
|
|
15919
|
-
specifier === "." ||
|
|
15920
|
-
specifier[0] === "/" ||
|
|
15921
|
-
specifier.startsWith("./") ||
|
|
15922
|
-
specifier.startsWith("../")
|
|
15923
|
-
) {
|
|
15924
|
-
return resolveUrl(specifier, importer)
|
|
15925
|
-
}
|
|
15926
|
-
|
|
15927
|
-
if (hasScheme(specifier)) {
|
|
15928
|
-
return specifier
|
|
15929
|
-
}
|
|
15243
|
+
if (hasScheme(specifier)) {
|
|
15244
|
+
return specifier
|
|
15245
|
+
}
|
|
15930
15246
|
|
|
15931
15247
|
return null
|
|
15932
15248
|
};
|
|
@@ -16048,561 +15364,1255 @@ const applyMappings = (
|
|
|
16048
15364
|
const afterSpecifier = specifierNormalized.slice(
|
|
16049
15365
|
specifierCandidate.length,
|
|
16050
15366
|
);
|
|
16051
|
-
const addressFinal = tryUrlResolution(afterSpecifier, address);
|
|
16052
|
-
onImportMapping({
|
|
16053
|
-
scope,
|
|
16054
|
-
from: specifierCandidate,
|
|
16055
|
-
to: address,
|
|
16056
|
-
before: specifierNormalized,
|
|
16057
|
-
after: addressFinal,
|
|
16058
|
-
});
|
|
16059
|
-
return addressFinal
|
|
15367
|
+
const addressFinal = tryUrlResolution(afterSpecifier, address);
|
|
15368
|
+
onImportMapping({
|
|
15369
|
+
scope,
|
|
15370
|
+
from: specifierCandidate,
|
|
15371
|
+
to: address,
|
|
15372
|
+
before: specifierNormalized,
|
|
15373
|
+
after: addressFinal,
|
|
15374
|
+
});
|
|
15375
|
+
return addressFinal
|
|
15376
|
+
}
|
|
15377
|
+
}
|
|
15378
|
+
|
|
15379
|
+
return null
|
|
15380
|
+
};
|
|
15381
|
+
|
|
15382
|
+
const specifierIsPrefixOf = (specifierHref, href) => {
|
|
15383
|
+
return (
|
|
15384
|
+
specifierHref[specifierHref.length - 1] === "/" &&
|
|
15385
|
+
href.startsWith(specifierHref)
|
|
15386
|
+
)
|
|
15387
|
+
};
|
|
15388
|
+
|
|
15389
|
+
// https://github.com/systemjs/systemjs/blob/89391f92dfeac33919b0223bbf834a1f4eea5750/src/common.js#L136
|
|
15390
|
+
|
|
15391
|
+
const composeTwoImportMaps = (leftImportMap, rightImportMap) => {
|
|
15392
|
+
assertImportMap(leftImportMap);
|
|
15393
|
+
assertImportMap(rightImportMap);
|
|
15394
|
+
|
|
15395
|
+
const importMap = {};
|
|
15396
|
+
|
|
15397
|
+
const leftImports = leftImportMap.imports;
|
|
15398
|
+
const rightImports = rightImportMap.imports;
|
|
15399
|
+
const leftHasImports = Boolean(leftImports);
|
|
15400
|
+
const rightHasImports = Boolean(rightImports);
|
|
15401
|
+
if (leftHasImports && rightHasImports) {
|
|
15402
|
+
importMap.imports = composeTwoMappings(leftImports, rightImports);
|
|
15403
|
+
} else if (leftHasImports) {
|
|
15404
|
+
importMap.imports = { ...leftImports };
|
|
15405
|
+
} else if (rightHasImports) {
|
|
15406
|
+
importMap.imports = { ...rightImports };
|
|
15407
|
+
}
|
|
15408
|
+
|
|
15409
|
+
const leftScopes = leftImportMap.scopes;
|
|
15410
|
+
const rightScopes = rightImportMap.scopes;
|
|
15411
|
+
const leftHasScopes = Boolean(leftScopes);
|
|
15412
|
+
const rightHasScopes = Boolean(rightScopes);
|
|
15413
|
+
if (leftHasScopes && rightHasScopes) {
|
|
15414
|
+
importMap.scopes = composeTwoScopes(
|
|
15415
|
+
leftScopes,
|
|
15416
|
+
rightScopes,
|
|
15417
|
+
importMap.imports || {},
|
|
15418
|
+
);
|
|
15419
|
+
} else if (leftHasScopes) {
|
|
15420
|
+
importMap.scopes = { ...leftScopes };
|
|
15421
|
+
} else if (rightHasScopes) {
|
|
15422
|
+
importMap.scopes = { ...rightScopes };
|
|
15423
|
+
}
|
|
15424
|
+
|
|
15425
|
+
return importMap
|
|
15426
|
+
};
|
|
15427
|
+
|
|
15428
|
+
const composeTwoMappings = (leftMappings, rightMappings) => {
|
|
15429
|
+
const mappings = {};
|
|
15430
|
+
|
|
15431
|
+
Object.keys(leftMappings).forEach((leftSpecifier) => {
|
|
15432
|
+
if (objectHasKey(rightMappings, leftSpecifier)) {
|
|
15433
|
+
// will be overidden
|
|
15434
|
+
return
|
|
15435
|
+
}
|
|
15436
|
+
const leftAddress = leftMappings[leftSpecifier];
|
|
15437
|
+
const rightSpecifier = Object.keys(rightMappings).find((rightSpecifier) => {
|
|
15438
|
+
return compareAddressAndSpecifier(leftAddress, rightSpecifier)
|
|
15439
|
+
});
|
|
15440
|
+
mappings[leftSpecifier] = rightSpecifier
|
|
15441
|
+
? rightMappings[rightSpecifier]
|
|
15442
|
+
: leftAddress;
|
|
15443
|
+
});
|
|
15444
|
+
|
|
15445
|
+
Object.keys(rightMappings).forEach((rightSpecifier) => {
|
|
15446
|
+
mappings[rightSpecifier] = rightMappings[rightSpecifier];
|
|
15447
|
+
});
|
|
15448
|
+
|
|
15449
|
+
return mappings
|
|
15450
|
+
};
|
|
15451
|
+
|
|
15452
|
+
const objectHasKey = (object, key) =>
|
|
15453
|
+
Object.prototype.hasOwnProperty.call(object, key);
|
|
15454
|
+
|
|
15455
|
+
const compareAddressAndSpecifier = (address, specifier) => {
|
|
15456
|
+
const addressUrl = resolveUrl(address, "file:///");
|
|
15457
|
+
const specifierUrl = resolveUrl(specifier, "file:///");
|
|
15458
|
+
return addressUrl === specifierUrl
|
|
15459
|
+
};
|
|
15460
|
+
|
|
15461
|
+
const composeTwoScopes = (leftScopes, rightScopes, imports) => {
|
|
15462
|
+
const scopes = {};
|
|
15463
|
+
|
|
15464
|
+
Object.keys(leftScopes).forEach((leftScopeKey) => {
|
|
15465
|
+
if (objectHasKey(rightScopes, leftScopeKey)) {
|
|
15466
|
+
// will be merged
|
|
15467
|
+
scopes[leftScopeKey] = leftScopes[leftScopeKey];
|
|
15468
|
+
return
|
|
15469
|
+
}
|
|
15470
|
+
const topLevelSpecifier = Object.keys(imports).find(
|
|
15471
|
+
(topLevelSpecifierCandidate) => {
|
|
15472
|
+
return compareAddressAndSpecifier(
|
|
15473
|
+
leftScopeKey,
|
|
15474
|
+
topLevelSpecifierCandidate,
|
|
15475
|
+
)
|
|
15476
|
+
},
|
|
15477
|
+
);
|
|
15478
|
+
if (topLevelSpecifier) {
|
|
15479
|
+
scopes[imports[topLevelSpecifier]] = leftScopes[leftScopeKey];
|
|
15480
|
+
} else {
|
|
15481
|
+
scopes[leftScopeKey] = leftScopes[leftScopeKey];
|
|
15482
|
+
}
|
|
15483
|
+
});
|
|
15484
|
+
|
|
15485
|
+
Object.keys(rightScopes).forEach((rightScopeKey) => {
|
|
15486
|
+
if (objectHasKey(scopes, rightScopeKey)) {
|
|
15487
|
+
scopes[rightScopeKey] = composeTwoMappings(
|
|
15488
|
+
scopes[rightScopeKey],
|
|
15489
|
+
rightScopes[rightScopeKey],
|
|
15490
|
+
);
|
|
15491
|
+
} else {
|
|
15492
|
+
scopes[rightScopeKey] = {
|
|
15493
|
+
...rightScopes[rightScopeKey],
|
|
15494
|
+
};
|
|
15495
|
+
}
|
|
15496
|
+
});
|
|
15497
|
+
|
|
15498
|
+
return scopes
|
|
15499
|
+
};
|
|
15500
|
+
|
|
15501
|
+
const sortImports = (imports) => {
|
|
15502
|
+
const mappingsSorted = {};
|
|
15503
|
+
|
|
15504
|
+
Object.keys(imports)
|
|
15505
|
+
.sort(compareLengthOrLocaleCompare)
|
|
15506
|
+
.forEach((name) => {
|
|
15507
|
+
mappingsSorted[name] = imports[name];
|
|
15508
|
+
});
|
|
15509
|
+
|
|
15510
|
+
return mappingsSorted
|
|
15511
|
+
};
|
|
15512
|
+
|
|
15513
|
+
const sortScopes = (scopes) => {
|
|
15514
|
+
const scopesSorted = {};
|
|
15515
|
+
|
|
15516
|
+
Object.keys(scopes)
|
|
15517
|
+
.sort(compareLengthOrLocaleCompare)
|
|
15518
|
+
.forEach((scopeSpecifier) => {
|
|
15519
|
+
scopesSorted[scopeSpecifier] = sortImports(scopes[scopeSpecifier]);
|
|
15520
|
+
});
|
|
15521
|
+
|
|
15522
|
+
return scopesSorted
|
|
15523
|
+
};
|
|
15524
|
+
|
|
15525
|
+
const compareLengthOrLocaleCompare = (a, b) => {
|
|
15526
|
+
return b.length - a.length || a.localeCompare(b)
|
|
15527
|
+
};
|
|
15528
|
+
|
|
15529
|
+
const normalizeImportMap = (importMap, baseUrl) => {
|
|
15530
|
+
assertImportMap(importMap);
|
|
15531
|
+
|
|
15532
|
+
if (!isStringOrUrl(baseUrl)) {
|
|
15533
|
+
throw new TypeError(formulateBaseUrlMustBeStringOrUrl({ baseUrl }))
|
|
15534
|
+
}
|
|
15535
|
+
|
|
15536
|
+
const { imports, scopes } = importMap;
|
|
15537
|
+
|
|
15538
|
+
return {
|
|
15539
|
+
imports: imports ? normalizeMappings(imports, baseUrl) : undefined,
|
|
15540
|
+
scopes: scopes ? normalizeScopes(scopes, baseUrl) : undefined,
|
|
15541
|
+
}
|
|
15542
|
+
};
|
|
15543
|
+
|
|
15544
|
+
const isStringOrUrl = (value) => {
|
|
15545
|
+
if (typeof value === "string") {
|
|
15546
|
+
return true
|
|
15547
|
+
}
|
|
15548
|
+
|
|
15549
|
+
if (typeof URL === "function" && value instanceof URL) {
|
|
15550
|
+
return true
|
|
15551
|
+
}
|
|
15552
|
+
|
|
15553
|
+
return false
|
|
15554
|
+
};
|
|
15555
|
+
|
|
15556
|
+
const normalizeMappings = (mappings, baseUrl) => {
|
|
15557
|
+
const mappingsNormalized = {};
|
|
15558
|
+
|
|
15559
|
+
Object.keys(mappings).forEach((specifier) => {
|
|
15560
|
+
const address = mappings[specifier];
|
|
15561
|
+
|
|
15562
|
+
if (typeof address !== "string") {
|
|
15563
|
+
console.warn(
|
|
15564
|
+
formulateAddressMustBeAString({
|
|
15565
|
+
address,
|
|
15566
|
+
specifier,
|
|
15567
|
+
}),
|
|
15568
|
+
);
|
|
15569
|
+
return
|
|
15570
|
+
}
|
|
15571
|
+
|
|
15572
|
+
const specifierResolved = resolveSpecifier(specifier, baseUrl) || specifier;
|
|
15573
|
+
|
|
15574
|
+
const addressUrl = tryUrlResolution(address, baseUrl);
|
|
15575
|
+
if (addressUrl === null) {
|
|
15576
|
+
console.warn(
|
|
15577
|
+
formulateAdressResolutionFailed({
|
|
15578
|
+
address,
|
|
15579
|
+
baseUrl,
|
|
15580
|
+
specifier,
|
|
15581
|
+
}),
|
|
15582
|
+
);
|
|
15583
|
+
return
|
|
15584
|
+
}
|
|
15585
|
+
|
|
15586
|
+
if (specifier.endsWith("/") && !addressUrl.endsWith("/")) {
|
|
15587
|
+
console.warn(
|
|
15588
|
+
formulateAddressUrlRequiresTrailingSlash({
|
|
15589
|
+
addressUrl,
|
|
15590
|
+
address,
|
|
15591
|
+
specifier,
|
|
15592
|
+
}),
|
|
15593
|
+
);
|
|
15594
|
+
return
|
|
16060
15595
|
}
|
|
16061
|
-
|
|
15596
|
+
mappingsNormalized[specifierResolved] = addressUrl;
|
|
15597
|
+
});
|
|
16062
15598
|
|
|
16063
|
-
return
|
|
15599
|
+
return sortImports(mappingsNormalized)
|
|
16064
15600
|
};
|
|
16065
15601
|
|
|
16066
|
-
const
|
|
16067
|
-
|
|
16068
|
-
|
|
16069
|
-
|
|
16070
|
-
|
|
15602
|
+
const normalizeScopes = (scopes, baseUrl) => {
|
|
15603
|
+
const scopesNormalized = {};
|
|
15604
|
+
|
|
15605
|
+
Object.keys(scopes).forEach((scopeSpecifier) => {
|
|
15606
|
+
const scopeMappings = scopes[scopeSpecifier];
|
|
15607
|
+
const scopeUrl = tryUrlResolution(scopeSpecifier, baseUrl);
|
|
15608
|
+
if (scopeUrl === null) {
|
|
15609
|
+
console.warn(
|
|
15610
|
+
formulateScopeResolutionFailed({
|
|
15611
|
+
scope: scopeSpecifier,
|
|
15612
|
+
baseUrl,
|
|
15613
|
+
}),
|
|
15614
|
+
);
|
|
15615
|
+
return
|
|
15616
|
+
}
|
|
15617
|
+
const scopeValueNormalized = normalizeMappings(scopeMappings, baseUrl);
|
|
15618
|
+
scopesNormalized[scopeUrl] = scopeValueNormalized;
|
|
15619
|
+
});
|
|
15620
|
+
|
|
15621
|
+
return sortScopes(scopesNormalized)
|
|
16071
15622
|
};
|
|
16072
15623
|
|
|
16073
|
-
|
|
15624
|
+
const formulateBaseUrlMustBeStringOrUrl = ({
|
|
15625
|
+
baseUrl,
|
|
15626
|
+
}) => `baseUrl must be a string or an url.
|
|
15627
|
+
--- base url ---
|
|
15628
|
+
${baseUrl}`;
|
|
16074
15629
|
|
|
16075
|
-
const
|
|
16076
|
-
|
|
16077
|
-
|
|
15630
|
+
const formulateAddressMustBeAString = ({
|
|
15631
|
+
specifier,
|
|
15632
|
+
address,
|
|
15633
|
+
}) => `Address must be a string.
|
|
15634
|
+
--- address ---
|
|
15635
|
+
${address}
|
|
15636
|
+
--- specifier ---
|
|
15637
|
+
${specifier}`;
|
|
16078
15638
|
|
|
16079
|
-
|
|
15639
|
+
const formulateAdressResolutionFailed = ({
|
|
15640
|
+
address,
|
|
15641
|
+
baseUrl,
|
|
15642
|
+
specifier,
|
|
15643
|
+
}) => `Address url resolution failed.
|
|
15644
|
+
--- address ---
|
|
15645
|
+
${address}
|
|
15646
|
+
--- base url ---
|
|
15647
|
+
${baseUrl}
|
|
15648
|
+
--- specifier ---
|
|
15649
|
+
${specifier}`;
|
|
16080
15650
|
|
|
16081
|
-
|
|
16082
|
-
|
|
16083
|
-
|
|
16084
|
-
|
|
16085
|
-
|
|
16086
|
-
|
|
16087
|
-
|
|
16088
|
-
|
|
16089
|
-
|
|
16090
|
-
|
|
16091
|
-
|
|
15651
|
+
const formulateAddressUrlRequiresTrailingSlash = ({
|
|
15652
|
+
addressURL,
|
|
15653
|
+
address,
|
|
15654
|
+
specifier,
|
|
15655
|
+
}) => `Address must end with /.
|
|
15656
|
+
--- address url ---
|
|
15657
|
+
${addressURL}
|
|
15658
|
+
--- address ---
|
|
15659
|
+
${address}
|
|
15660
|
+
--- specifier ---
|
|
15661
|
+
${specifier}`;
|
|
16092
15662
|
|
|
16093
|
-
|
|
16094
|
-
|
|
16095
|
-
|
|
16096
|
-
|
|
16097
|
-
|
|
16098
|
-
|
|
16099
|
-
|
|
16100
|
-
|
|
16101
|
-
|
|
16102
|
-
|
|
16103
|
-
|
|
16104
|
-
|
|
16105
|
-
|
|
16106
|
-
importMap.scopes = { ...rightScopes };
|
|
15663
|
+
const formulateScopeResolutionFailed = ({
|
|
15664
|
+
scope,
|
|
15665
|
+
baseUrl,
|
|
15666
|
+
}) => `Scope url resolution failed.
|
|
15667
|
+
--- scope ---
|
|
15668
|
+
${scope}
|
|
15669
|
+
--- base url ---
|
|
15670
|
+
${baseUrl}`;
|
|
15671
|
+
|
|
15672
|
+
const pathnameToExtension = (pathname) => {
|
|
15673
|
+
const slashLastIndex = pathname.lastIndexOf("/");
|
|
15674
|
+
if (slashLastIndex !== -1) {
|
|
15675
|
+
pathname = pathname.slice(slashLastIndex + 1);
|
|
16107
15676
|
}
|
|
16108
15677
|
|
|
16109
|
-
|
|
15678
|
+
const dotLastIndex = pathname.lastIndexOf(".");
|
|
15679
|
+
if (dotLastIndex === -1) return ""
|
|
15680
|
+
// if (dotLastIndex === pathname.length - 1) return ""
|
|
15681
|
+
return pathname.slice(dotLastIndex)
|
|
16110
15682
|
};
|
|
16111
15683
|
|
|
16112
|
-
const
|
|
16113
|
-
|
|
16114
|
-
|
|
16115
|
-
|
|
16116
|
-
|
|
16117
|
-
|
|
16118
|
-
|
|
16119
|
-
|
|
16120
|
-
|
|
16121
|
-
|
|
16122
|
-
|
|
15684
|
+
const resolveImport = ({
|
|
15685
|
+
specifier,
|
|
15686
|
+
importer,
|
|
15687
|
+
importMap,
|
|
15688
|
+
defaultExtension = false,
|
|
15689
|
+
createBareSpecifierError,
|
|
15690
|
+
onImportMapping = () => {},
|
|
15691
|
+
}) => {
|
|
15692
|
+
let url;
|
|
15693
|
+
if (importMap) {
|
|
15694
|
+
url = applyImportMap({
|
|
15695
|
+
importMap,
|
|
15696
|
+
specifier,
|
|
15697
|
+
importer,
|
|
15698
|
+
createBareSpecifierError,
|
|
15699
|
+
onImportMapping,
|
|
16123
15700
|
});
|
|
16124
|
-
|
|
16125
|
-
|
|
16126
|
-
|
|
16127
|
-
});
|
|
15701
|
+
} else {
|
|
15702
|
+
url = resolveUrl(specifier, importer);
|
|
15703
|
+
}
|
|
16128
15704
|
|
|
16129
|
-
|
|
16130
|
-
|
|
16131
|
-
}
|
|
15705
|
+
if (defaultExtension) {
|
|
15706
|
+
url = applyDefaultExtension({ url, importer, defaultExtension });
|
|
15707
|
+
}
|
|
16132
15708
|
|
|
16133
|
-
return
|
|
15709
|
+
return url
|
|
16134
15710
|
};
|
|
16135
15711
|
|
|
16136
|
-
const
|
|
16137
|
-
|
|
15712
|
+
const applyDefaultExtension = ({ url, importer, defaultExtension }) => {
|
|
15713
|
+
if (urlToPathname(url).endsWith("/")) {
|
|
15714
|
+
return url
|
|
15715
|
+
}
|
|
16138
15716
|
|
|
16139
|
-
|
|
16140
|
-
|
|
16141
|
-
|
|
16142
|
-
|
|
15717
|
+
if (typeof defaultExtension === "string") {
|
|
15718
|
+
const extension = pathnameToExtension(url);
|
|
15719
|
+
if (extension === "") {
|
|
15720
|
+
return `${url}${defaultExtension}`
|
|
15721
|
+
}
|
|
15722
|
+
return url
|
|
15723
|
+
}
|
|
15724
|
+
|
|
15725
|
+
if (defaultExtension === true) {
|
|
15726
|
+
const extension = pathnameToExtension(url);
|
|
15727
|
+
if (extension === "" && importer) {
|
|
15728
|
+
const importerPathname = urlToPathname(importer);
|
|
15729
|
+
const importerExtension = pathnameToExtension(importerPathname);
|
|
15730
|
+
return `${url}${importerExtension}`
|
|
15731
|
+
}
|
|
15732
|
+
}
|
|
15733
|
+
|
|
15734
|
+
return url
|
|
16143
15735
|
};
|
|
16144
15736
|
|
|
16145
|
-
const
|
|
16146
|
-
|
|
15737
|
+
const jsenvPluginHtmlReferenceAnalysis = ({
|
|
15738
|
+
inlineContent,
|
|
15739
|
+
inlineConvertedScript,
|
|
15740
|
+
}) => {
|
|
15741
|
+
/*
|
|
15742
|
+
* About importmap found in HTML files:
|
|
15743
|
+
* - feeds importmap files to jsenv kitchen
|
|
15744
|
+
* - use importmap to resolve import (when there is one + fallback to other resolution mecanism)
|
|
15745
|
+
* - inline importmap with [src=""]
|
|
15746
|
+
*
|
|
15747
|
+
* A correct importmap resolution should scope importmap resolution per html file.
|
|
15748
|
+
* It would be doable by adding ?html_id to each js file in order to track
|
|
15749
|
+
* the html file importing it.
|
|
15750
|
+
* Considering it happens only when all the following conditions are met:
|
|
15751
|
+
* - 2+ html files are using an importmap
|
|
15752
|
+
* - the importmap used is not the same
|
|
15753
|
+
* - the importmap contain conflicting mappings
|
|
15754
|
+
* - these html files are both executed during the same scenario (dev, test, build)
|
|
15755
|
+
* And that it would be ugly to see ?html_id all over the place
|
|
15756
|
+
* -> The importmap resolution implemented here takes a shortcut and does the following:
|
|
15757
|
+
* - All importmap found are merged into a single one that is applied to every import specifiers
|
|
15758
|
+
*/
|
|
15759
|
+
|
|
15760
|
+
let globalImportmap = null;
|
|
15761
|
+
const importmaps = {};
|
|
15762
|
+
let importmapLoadingCount = 0;
|
|
15763
|
+
const allImportmapLoadedCallbackSet = new Set();
|
|
15764
|
+
const startLoadingImportmap = (htmlUrlInfo) => {
|
|
15765
|
+
importmapLoadingCount++;
|
|
15766
|
+
return (importmapUrlInfo) => {
|
|
15767
|
+
const htmlUrl = htmlUrlInfo.url;
|
|
15768
|
+
if (importmapUrlInfo) {
|
|
15769
|
+
// importmap was found in this HTML file and is known
|
|
15770
|
+
const importmap = JSON.parse(importmapUrlInfo.content);
|
|
15771
|
+
importmaps[htmlUrl] = normalizeImportMap(importmap, htmlUrl);
|
|
15772
|
+
} else {
|
|
15773
|
+
// no importmap in this HTML file
|
|
15774
|
+
importmaps[htmlUrl] = null;
|
|
15775
|
+
}
|
|
15776
|
+
globalImportmap = Object.keys(importmaps).reduce((previous, url) => {
|
|
15777
|
+
const importmap = importmaps[url];
|
|
15778
|
+
if (!previous) {
|
|
15779
|
+
return importmap;
|
|
15780
|
+
}
|
|
15781
|
+
if (!importmap) {
|
|
15782
|
+
return previous;
|
|
15783
|
+
}
|
|
15784
|
+
return composeTwoImportMaps(previous, importmap);
|
|
15785
|
+
}, null);
|
|
16147
15786
|
|
|
16148
|
-
|
|
16149
|
-
|
|
16150
|
-
|
|
16151
|
-
|
|
16152
|
-
|
|
16153
|
-
|
|
16154
|
-
|
|
16155
|
-
|
|
16156
|
-
|
|
16157
|
-
|
|
16158
|
-
|
|
16159
|
-
|
|
15787
|
+
importmapLoadingCount--;
|
|
15788
|
+
if (importmapLoadingCount === 0) {
|
|
15789
|
+
allImportmapLoadedCallbackSet.forEach((callback) => {
|
|
15790
|
+
callback();
|
|
15791
|
+
});
|
|
15792
|
+
allImportmapLoadedCallbackSet.clear();
|
|
15793
|
+
}
|
|
15794
|
+
};
|
|
15795
|
+
};
|
|
15796
|
+
|
|
15797
|
+
return {
|
|
15798
|
+
name: "jsenv:html_reference_analysis",
|
|
15799
|
+
appliesDuring: "*",
|
|
15800
|
+
resolveReference: {
|
|
15801
|
+
js_import: (reference) => {
|
|
15802
|
+
if (!globalImportmap) {
|
|
15803
|
+
return null;
|
|
15804
|
+
}
|
|
15805
|
+
try {
|
|
15806
|
+
let fromMapping = false;
|
|
15807
|
+
const result = resolveImport({
|
|
15808
|
+
specifier: reference.specifier,
|
|
15809
|
+
importer: reference.ownerUrlInfo.url,
|
|
15810
|
+
importMap: globalImportmap,
|
|
15811
|
+
onImportMapping: () => {
|
|
15812
|
+
fromMapping = true;
|
|
15813
|
+
},
|
|
15814
|
+
});
|
|
15815
|
+
if (fromMapping) {
|
|
15816
|
+
return result;
|
|
15817
|
+
}
|
|
15818
|
+
return null;
|
|
15819
|
+
} catch (e) {
|
|
15820
|
+
if (e.message.includes("bare specifier")) {
|
|
15821
|
+
// in theory we should throw to be compliant with web behaviour
|
|
15822
|
+
// but for now it's simpler to return null
|
|
15823
|
+
// and let a chance to other plugins to handle the bare specifier
|
|
15824
|
+
// (node esm resolution)
|
|
15825
|
+
// and we want importmap to be prio over node esm so we cannot put this plugin after
|
|
15826
|
+
return null;
|
|
15827
|
+
}
|
|
15828
|
+
throw e;
|
|
15829
|
+
}
|
|
16160
15830
|
},
|
|
16161
|
-
|
|
16162
|
-
|
|
16163
|
-
|
|
16164
|
-
|
|
16165
|
-
|
|
16166
|
-
|
|
16167
|
-
|
|
15831
|
+
},
|
|
15832
|
+
transformUrlContent: {
|
|
15833
|
+
js_module: async () => {
|
|
15834
|
+
// wait for importmap if any
|
|
15835
|
+
// so that resolveReference can happen with importmap
|
|
15836
|
+
if (importmapLoadingCount) {
|
|
15837
|
+
await new Promise((resolve) => {
|
|
15838
|
+
allImportmapLoadedCallbackSet.add(resolve);
|
|
15839
|
+
});
|
|
15840
|
+
}
|
|
15841
|
+
},
|
|
15842
|
+
html: async (urlInfo) => {
|
|
15843
|
+
let importmapFound = false;
|
|
15844
|
+
const importmapLoaded = startLoadingImportmap(urlInfo);
|
|
16168
15845
|
|
|
16169
|
-
|
|
16170
|
-
|
|
16171
|
-
scopes[rightScopeKey] = composeTwoMappings(
|
|
16172
|
-
scopes[rightScopeKey],
|
|
16173
|
-
rightScopes[rightScopeKey],
|
|
16174
|
-
);
|
|
16175
|
-
} else {
|
|
16176
|
-
scopes[rightScopeKey] = {
|
|
16177
|
-
...rightScopes[rightScopeKey],
|
|
16178
|
-
};
|
|
16179
|
-
}
|
|
16180
|
-
});
|
|
15846
|
+
const content = urlInfo.content;
|
|
15847
|
+
const htmlAst = parseHtmlString(content);
|
|
16181
15848
|
|
|
16182
|
-
|
|
16183
|
-
|
|
15849
|
+
const mutations = [];
|
|
15850
|
+
const actions = [];
|
|
15851
|
+
const finalizeCallbacks = [];
|
|
16184
15852
|
|
|
16185
|
-
const
|
|
16186
|
-
|
|
15853
|
+
const createExternalReference = (
|
|
15854
|
+
node,
|
|
15855
|
+
attributeName,
|
|
15856
|
+
attributeValue,
|
|
15857
|
+
{ type, subtype, expectedType, ...rest },
|
|
15858
|
+
) => {
|
|
15859
|
+
let position;
|
|
15860
|
+
if (getHtmlNodeAttribute(node, "jsenv-cooked-by")) {
|
|
15861
|
+
// when generated from inline content,
|
|
15862
|
+
// line, column is not "src" nor "inlined-from-src" but "original-position"
|
|
15863
|
+
position = getHtmlNodePosition(node);
|
|
15864
|
+
} else {
|
|
15865
|
+
position = getHtmlNodeAttributePosition(node, attributeName);
|
|
15866
|
+
}
|
|
15867
|
+
const {
|
|
15868
|
+
line,
|
|
15869
|
+
column,
|
|
15870
|
+
// originalLine, originalColumn
|
|
15871
|
+
} = position;
|
|
15872
|
+
const debug = getHtmlNodeAttribute(node, "jsenv-debug") !== undefined;
|
|
15873
|
+
|
|
15874
|
+
const { crossorigin, integrity } = readFetchMetas(node);
|
|
15875
|
+
const isResourceHint = [
|
|
15876
|
+
"preconnect",
|
|
15877
|
+
"dns-prefetch",
|
|
15878
|
+
"prefetch",
|
|
15879
|
+
"preload",
|
|
15880
|
+
"modulepreload",
|
|
15881
|
+
].includes(subtype);
|
|
15882
|
+
let attributeLocation = node.sourceCodeLocation.attrs[attributeName];
|
|
15883
|
+
if (
|
|
15884
|
+
!attributeLocation &&
|
|
15885
|
+
attributeName === "href" &&
|
|
15886
|
+
(node.tagName === "use" || node.tagName === "image")
|
|
15887
|
+
) {
|
|
15888
|
+
attributeLocation = node.sourceCodeLocation.attrs["xlink:href"];
|
|
15889
|
+
}
|
|
15890
|
+
const attributeStart = attributeLocation.startOffset;
|
|
15891
|
+
const attributeValueStart = urlInfo.content.indexOf(
|
|
15892
|
+
attributeValue,
|
|
15893
|
+
attributeStart + `${attributeName}=`.length,
|
|
15894
|
+
);
|
|
15895
|
+
const attributeValueEnd = attributeValueStart + attributeValue.length;
|
|
15896
|
+
const reference = urlInfo.dependencies.found({
|
|
15897
|
+
type,
|
|
15898
|
+
subtype,
|
|
15899
|
+
expectedType,
|
|
15900
|
+
specifier: attributeValue,
|
|
15901
|
+
specifierLine: line,
|
|
15902
|
+
specifierColumn: column,
|
|
15903
|
+
specifierStart: attributeValueStart,
|
|
15904
|
+
specifierEnd: attributeValueEnd,
|
|
15905
|
+
isResourceHint,
|
|
15906
|
+
isWeak: isResourceHint,
|
|
15907
|
+
crossorigin,
|
|
15908
|
+
integrity,
|
|
15909
|
+
debug,
|
|
15910
|
+
astInfo: { node, attributeName },
|
|
15911
|
+
...rest,
|
|
15912
|
+
});
|
|
15913
|
+
actions.push(async () => {
|
|
15914
|
+
await reference.readGeneratedSpecifier();
|
|
15915
|
+
mutations.push(() => {
|
|
15916
|
+
setHtmlNodeAttributes(node, {
|
|
15917
|
+
[attributeName]: reference.generatedSpecifier,
|
|
15918
|
+
});
|
|
15919
|
+
});
|
|
15920
|
+
});
|
|
15921
|
+
return reference;
|
|
15922
|
+
};
|
|
15923
|
+
const visitHref = (node, referenceProps) => {
|
|
15924
|
+
const href = getHtmlNodeAttribute(node, "href");
|
|
15925
|
+
if (href) {
|
|
15926
|
+
return createExternalReference(node, "href", href, referenceProps);
|
|
15927
|
+
}
|
|
15928
|
+
return null;
|
|
15929
|
+
};
|
|
15930
|
+
const visitSrc = (node, referenceProps) => {
|
|
15931
|
+
const src = getHtmlNodeAttribute(node, "src");
|
|
15932
|
+
if (src) {
|
|
15933
|
+
return createExternalReference(node, "src", src, referenceProps);
|
|
15934
|
+
}
|
|
15935
|
+
return null;
|
|
15936
|
+
};
|
|
15937
|
+
const visitSrcset = (node, referenceProps) => {
|
|
15938
|
+
const srcset = getHtmlNodeAttribute(node, "srcset");
|
|
15939
|
+
if (srcset) {
|
|
15940
|
+
const srcCandidates = parseSrcSet(srcset);
|
|
15941
|
+
return srcCandidates.map((srcCandidate) => {
|
|
15942
|
+
return createExternalReference(
|
|
15943
|
+
node,
|
|
15944
|
+
"srcset",
|
|
15945
|
+
srcCandidate.specifier,
|
|
15946
|
+
referenceProps,
|
|
15947
|
+
);
|
|
15948
|
+
});
|
|
15949
|
+
}
|
|
15950
|
+
return null;
|
|
15951
|
+
};
|
|
16187
15952
|
|
|
16188
|
-
|
|
16189
|
-
|
|
16190
|
-
|
|
16191
|
-
|
|
16192
|
-
|
|
15953
|
+
const createInlineReference = (
|
|
15954
|
+
node,
|
|
15955
|
+
inlineContent,
|
|
15956
|
+
{ type, expectedType, contentType },
|
|
15957
|
+
) => {
|
|
15958
|
+
const hotAccept =
|
|
15959
|
+
getHtmlNodeAttribute(node, "hot-accept") !== undefined;
|
|
15960
|
+
const { line, column, isOriginal } = getHtmlNodePosition(node, {
|
|
15961
|
+
preferOriginal: true,
|
|
15962
|
+
});
|
|
15963
|
+
const inlineContentUrl = getUrlForContentInsideHtml(node, {
|
|
15964
|
+
htmlUrl: urlInfo.url,
|
|
15965
|
+
});
|
|
15966
|
+
const debug = getHtmlNodeAttribute(node, "jsenv-debug") !== undefined;
|
|
15967
|
+
const inlineReference = urlInfo.dependencies.foundInline({
|
|
15968
|
+
type,
|
|
15969
|
+
expectedType,
|
|
15970
|
+
isOriginalPosition: isOriginal,
|
|
15971
|
+
// we remove 1 to the line because imagine the following html:
|
|
15972
|
+
// <style>body { color: red; }</style>
|
|
15973
|
+
// -> content starts same line as <style> (same for <script>)
|
|
15974
|
+
specifierLine: line - 1,
|
|
15975
|
+
specifierColumn: column,
|
|
15976
|
+
specifier: inlineContentUrl,
|
|
15977
|
+
contentType,
|
|
15978
|
+
content: inlineContent,
|
|
15979
|
+
debug,
|
|
15980
|
+
astInfo: { node },
|
|
15981
|
+
});
|
|
16193
15982
|
|
|
16194
|
-
|
|
16195
|
-
|
|
15983
|
+
actions.push(async () => {
|
|
15984
|
+
await inlineReference.urlInfo.cook();
|
|
15985
|
+
mutations.push(() => {
|
|
15986
|
+
if (hotAccept) {
|
|
15987
|
+
removeHtmlNodeText(node);
|
|
15988
|
+
setHtmlNodeAttributes(node, {
|
|
15989
|
+
"jsenv-cooked-by": "jsenv:html_inline_content_analysis",
|
|
15990
|
+
});
|
|
15991
|
+
} else {
|
|
15992
|
+
setHtmlNodeText(node, inlineReference.urlInfo.content, {
|
|
15993
|
+
indentation: false, // indentation would decrease stack trace precision
|
|
15994
|
+
});
|
|
15995
|
+
setHtmlNodeAttributes(node, {
|
|
15996
|
+
"jsenv-cooked-by": "jsenv:html_inline_content_analysis",
|
|
15997
|
+
});
|
|
15998
|
+
}
|
|
15999
|
+
});
|
|
16000
|
+
});
|
|
16001
|
+
return inlineReference;
|
|
16002
|
+
};
|
|
16003
|
+
const visitTextContent = (
|
|
16004
|
+
node,
|
|
16005
|
+
{ type, subtype, expectedType, contentType },
|
|
16006
|
+
) => {
|
|
16007
|
+
const inlineContent = getHtmlNodeText(node);
|
|
16008
|
+
if (!inlineContent) {
|
|
16009
|
+
return null;
|
|
16010
|
+
}
|
|
16011
|
+
return createInlineReference(node, inlineContent, {
|
|
16012
|
+
type,
|
|
16013
|
+
subtype,
|
|
16014
|
+
expectedType,
|
|
16015
|
+
contentType,
|
|
16016
|
+
});
|
|
16017
|
+
};
|
|
16196
16018
|
|
|
16197
|
-
|
|
16198
|
-
|
|
16019
|
+
visitHtmlNodes(htmlAst, {
|
|
16020
|
+
link: (linkNode) => {
|
|
16021
|
+
const rel = getHtmlNodeAttribute(linkNode, "rel");
|
|
16022
|
+
const type = getHtmlNodeAttribute(linkNode, "type");
|
|
16023
|
+
const ref = visitHref(linkNode, {
|
|
16024
|
+
type: "link_href",
|
|
16025
|
+
subtype: rel,
|
|
16026
|
+
// https://developer.mozilla.org/en-US/docs/Web/HTML/Link_types/preload#including_a_mime_type
|
|
16027
|
+
expectedContentType: type,
|
|
16028
|
+
});
|
|
16029
|
+
if (ref) {
|
|
16030
|
+
finalizeCallbacks.push(() => {
|
|
16031
|
+
if (ref.expectedType) ; else {
|
|
16032
|
+
ref.expectedType = decideLinkExpectedType(ref, urlInfo);
|
|
16033
|
+
}
|
|
16034
|
+
});
|
|
16035
|
+
}
|
|
16036
|
+
},
|
|
16037
|
+
style: inlineContent
|
|
16038
|
+
? (styleNode) => {
|
|
16039
|
+
visitTextContent(styleNode, {
|
|
16040
|
+
type: "style",
|
|
16041
|
+
expectedType: "css",
|
|
16042
|
+
contentType: "text/css",
|
|
16043
|
+
});
|
|
16044
|
+
}
|
|
16045
|
+
: null,
|
|
16046
|
+
script: (scriptNode) => {
|
|
16047
|
+
const { type, subtype, contentType, extension } =
|
|
16048
|
+
analyzeScriptNode(scriptNode);
|
|
16049
|
+
if (type === "text") {
|
|
16050
|
+
// ignore <script type="whatever">foobar</script>
|
|
16051
|
+
// per HTML spec https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script#attr-type
|
|
16052
|
+
return;
|
|
16053
|
+
}
|
|
16054
|
+
if (type === "importmap") {
|
|
16055
|
+
importmapFound = true;
|
|
16056
|
+
|
|
16057
|
+
const src = getHtmlNodeAttribute(scriptNode, "src");
|
|
16058
|
+
if (src) {
|
|
16059
|
+
// Browser would throw on remote importmap
|
|
16060
|
+
// and won't sent a request to the server for it
|
|
16061
|
+
// We must precook the importmap to know its content and inline it into the HTML
|
|
16062
|
+
const importmapReference = createExternalReference(
|
|
16063
|
+
scriptNode,
|
|
16064
|
+
"src",
|
|
16065
|
+
src,
|
|
16066
|
+
{
|
|
16067
|
+
type: "script",
|
|
16068
|
+
subtype: "importmap",
|
|
16069
|
+
expectedType: "importmap",
|
|
16070
|
+
},
|
|
16071
|
+
);
|
|
16072
|
+
const { line, column, isOriginal } = getHtmlNodePosition(
|
|
16073
|
+
scriptNode,
|
|
16074
|
+
{
|
|
16075
|
+
preferOriginal: true,
|
|
16076
|
+
},
|
|
16077
|
+
);
|
|
16078
|
+
const importmapInlineUrl = getUrlForContentInsideHtml(
|
|
16079
|
+
scriptNode,
|
|
16080
|
+
{
|
|
16081
|
+
htmlUrl: urlInfo.url,
|
|
16082
|
+
},
|
|
16083
|
+
);
|
|
16084
|
+
const importmapReferenceInlined = importmapReference.inline({
|
|
16085
|
+
line: line - 1,
|
|
16086
|
+
column,
|
|
16087
|
+
isOriginal,
|
|
16088
|
+
specifier: importmapInlineUrl,
|
|
16089
|
+
contentType: "application/importmap+json",
|
|
16090
|
+
});
|
|
16091
|
+
const importmapInlineUrlInfo =
|
|
16092
|
+
importmapReferenceInlined.urlInfo;
|
|
16093
|
+
actions.push(async () => {
|
|
16094
|
+
await importmapInlineUrlInfo.cook();
|
|
16095
|
+
importmapLoaded(importmapInlineUrlInfo);
|
|
16096
|
+
mutations.push(() => {
|
|
16097
|
+
setHtmlNodeText(
|
|
16098
|
+
scriptNode,
|
|
16099
|
+
importmapInlineUrlInfo.content,
|
|
16100
|
+
{
|
|
16101
|
+
indentation: "auto",
|
|
16102
|
+
},
|
|
16103
|
+
);
|
|
16104
|
+
setHtmlNodeAttributes(scriptNode, {
|
|
16105
|
+
"src": undefined,
|
|
16106
|
+
"jsenv-inlined-by": "jsenv:html_reference_analysis",
|
|
16107
|
+
"inlined-from-src": src,
|
|
16108
|
+
});
|
|
16109
|
+
});
|
|
16110
|
+
});
|
|
16111
|
+
} else {
|
|
16112
|
+
const htmlNodeText = getHtmlNodeText(scriptNode);
|
|
16113
|
+
if (htmlNodeText) {
|
|
16114
|
+
const importmapReference = createInlineReference(
|
|
16115
|
+
scriptNode,
|
|
16116
|
+
htmlNodeText,
|
|
16117
|
+
{
|
|
16118
|
+
type: "script",
|
|
16119
|
+
expectedType: "importmap",
|
|
16120
|
+
contentType: "application/importmap+json",
|
|
16121
|
+
},
|
|
16122
|
+
);
|
|
16123
|
+
const inlineImportmapUrlInfo = importmapReference.urlInfo;
|
|
16124
|
+
actions.push(async () => {
|
|
16125
|
+
await inlineImportmapUrlInfo.cook();
|
|
16126
|
+
importmapLoaded(inlineImportmapUrlInfo);
|
|
16127
|
+
mutations.push(() => {
|
|
16128
|
+
setHtmlNodeText(
|
|
16129
|
+
scriptNode,
|
|
16130
|
+
inlineImportmapUrlInfo.content,
|
|
16131
|
+
{
|
|
16132
|
+
indentation: "auto",
|
|
16133
|
+
},
|
|
16134
|
+
);
|
|
16135
|
+
setHtmlNodeAttributes(scriptNode, {
|
|
16136
|
+
"jsenv-cooked-by": "jsenv:html_reference_analysis",
|
|
16137
|
+
});
|
|
16138
|
+
});
|
|
16139
|
+
});
|
|
16140
|
+
}
|
|
16141
|
+
}
|
|
16142
|
+
// once this plugin knows the importmap, it will use it
|
|
16143
|
+
// to map imports. These import specifiers will be normalized
|
|
16144
|
+
// by "formatReference" making the importmap presence useless.
|
|
16145
|
+
// In dev/test we keep importmap into the HTML to see it even if useless
|
|
16146
|
+
// Duing build we get rid of it
|
|
16147
|
+
if (urlInfo.context.build) {
|
|
16148
|
+
mutations.push(() => {
|
|
16149
|
+
removeHtmlNode(scriptNode);
|
|
16150
|
+
});
|
|
16151
|
+
}
|
|
16152
|
+
return;
|
|
16153
|
+
}
|
|
16154
|
+
const externalRef = visitSrc(scriptNode, {
|
|
16155
|
+
type: "script",
|
|
16156
|
+
subtype: type,
|
|
16157
|
+
expectedType: type,
|
|
16158
|
+
});
|
|
16159
|
+
if (externalRef) {
|
|
16160
|
+
return;
|
|
16161
|
+
}
|
|
16199
16162
|
|
|
16200
|
-
|
|
16201
|
-
|
|
16202
|
-
|
|
16203
|
-
|
|
16204
|
-
|
|
16163
|
+
// now visit the content, if any
|
|
16164
|
+
if (!inlineContent) {
|
|
16165
|
+
return;
|
|
16166
|
+
}
|
|
16167
|
+
// If the inline script was already handled by an other plugin, ignore it
|
|
16168
|
+
// - we want to preserve inline scripts generated by html supervisor during dev
|
|
16169
|
+
// - we want to avoid cooking twice a script during build
|
|
16170
|
+
if (
|
|
16171
|
+
!inlineConvertedScript &&
|
|
16172
|
+
getHtmlNodeAttribute(scriptNode, "jsenv-injected-by") ===
|
|
16173
|
+
"jsenv:js_module_fallback"
|
|
16174
|
+
) {
|
|
16175
|
+
return;
|
|
16176
|
+
}
|
|
16205
16177
|
|
|
16206
|
-
|
|
16207
|
-
|
|
16178
|
+
const inlineRef = visitTextContent(scriptNode, {
|
|
16179
|
+
type: "script",
|
|
16180
|
+
subtype,
|
|
16181
|
+
expectedType: type,
|
|
16182
|
+
contentType,
|
|
16183
|
+
});
|
|
16184
|
+
if (inlineRef) {
|
|
16185
|
+
// 1. <script type="jsx"> becomes <script>
|
|
16186
|
+
if (type === "js_classic" && extension !== ".js") {
|
|
16187
|
+
mutations.push(() => {
|
|
16188
|
+
setHtmlNodeAttributes(scriptNode, {
|
|
16189
|
+
type: undefined,
|
|
16190
|
+
});
|
|
16191
|
+
});
|
|
16192
|
+
}
|
|
16193
|
+
// 2. <script type="module/jsx"> becomes <script type="module">
|
|
16194
|
+
if (type === "js_module" && extension !== ".js") {
|
|
16195
|
+
mutations.push(() => {
|
|
16196
|
+
setHtmlNodeAttributes(scriptNode, {
|
|
16197
|
+
type: "module",
|
|
16198
|
+
});
|
|
16199
|
+
});
|
|
16200
|
+
}
|
|
16201
|
+
}
|
|
16202
|
+
},
|
|
16203
|
+
a: (aNode) => {
|
|
16204
|
+
visitHref(aNode, {
|
|
16205
|
+
type: "a_href",
|
|
16206
|
+
});
|
|
16207
|
+
},
|
|
16208
|
+
iframe: (iframeNode) => {
|
|
16209
|
+
visitSrc(iframeNode, {
|
|
16210
|
+
type: "iframe_src",
|
|
16211
|
+
});
|
|
16212
|
+
},
|
|
16213
|
+
img: (imgNode) => {
|
|
16214
|
+
visitSrc(imgNode, {
|
|
16215
|
+
type: "img_src",
|
|
16216
|
+
});
|
|
16217
|
+
visitSrcset(imgNode, {
|
|
16218
|
+
type: "img_srcset",
|
|
16219
|
+
});
|
|
16220
|
+
},
|
|
16221
|
+
source: (sourceNode) => {
|
|
16222
|
+
visitSrc(sourceNode, {
|
|
16223
|
+
type: "source_src",
|
|
16224
|
+
});
|
|
16225
|
+
visitSrcset(sourceNode, {
|
|
16226
|
+
type: "source_srcset",
|
|
16227
|
+
});
|
|
16228
|
+
},
|
|
16229
|
+
// svg <image> tag
|
|
16230
|
+
image: (imageNode) => {
|
|
16231
|
+
visitHref(imageNode, {
|
|
16232
|
+
type: "image_href",
|
|
16233
|
+
});
|
|
16234
|
+
},
|
|
16235
|
+
use: (useNode) => {
|
|
16236
|
+
visitHref(useNode, {
|
|
16237
|
+
type: "use_href",
|
|
16238
|
+
});
|
|
16239
|
+
},
|
|
16240
|
+
});
|
|
16241
|
+
if (!importmapFound) {
|
|
16242
|
+
importmapLoaded();
|
|
16243
|
+
}
|
|
16244
|
+
finalizeCallbacks.forEach((finalizeCallback) => {
|
|
16245
|
+
finalizeCallback();
|
|
16246
|
+
});
|
|
16208
16247
|
|
|
16209
|
-
|
|
16210
|
-
|
|
16248
|
+
if (actions.length > 0) {
|
|
16249
|
+
await Promise.all(actions.map((action) => action()));
|
|
16250
|
+
actions.length = 0;
|
|
16251
|
+
}
|
|
16252
|
+
if (mutations.length === 0) {
|
|
16253
|
+
return null;
|
|
16254
|
+
}
|
|
16255
|
+
mutations.forEach((mutation) => mutation());
|
|
16256
|
+
mutations.length = 0;
|
|
16257
|
+
return stringifyHtmlAst(htmlAst);
|
|
16258
|
+
},
|
|
16259
|
+
},
|
|
16260
|
+
};
|
|
16211
16261
|
};
|
|
16212
16262
|
|
|
16213
|
-
const
|
|
16214
|
-
|
|
16215
|
-
|
|
16216
|
-
|
|
16217
|
-
|
|
16263
|
+
const crossOriginCompatibleTagNames = ["script", "link", "img", "source"];
|
|
16264
|
+
const integrityCompatibleTagNames = ["script", "link", "img", "source"];
|
|
16265
|
+
const readFetchMetas = (node) => {
|
|
16266
|
+
const meta = {};
|
|
16267
|
+
if (crossOriginCompatibleTagNames.includes(node.nodeName)) {
|
|
16268
|
+
const crossorigin = getHtmlNodeAttribute(node, "crossorigin") !== undefined;
|
|
16269
|
+
meta.crossorigin = crossorigin;
|
|
16218
16270
|
}
|
|
16219
|
-
|
|
16220
|
-
|
|
16221
|
-
|
|
16222
|
-
return {
|
|
16223
|
-
imports: imports ? normalizeMappings(imports, baseUrl) : undefined,
|
|
16224
|
-
scopes: scopes ? normalizeScopes(scopes, baseUrl) : undefined,
|
|
16271
|
+
if (integrityCompatibleTagNames.includes(node.nodeName)) {
|
|
16272
|
+
const integrity = getHtmlNodeAttribute(node, "integrity");
|
|
16273
|
+
meta.integrity = integrity;
|
|
16225
16274
|
}
|
|
16275
|
+
return meta;
|
|
16226
16276
|
};
|
|
16227
16277
|
|
|
16228
|
-
const
|
|
16229
|
-
|
|
16230
|
-
|
|
16231
|
-
|
|
16232
|
-
|
|
16233
|
-
if (typeof URL === "function" && value instanceof URL) {
|
|
16234
|
-
return true
|
|
16278
|
+
const decideLinkExpectedType = (linkReference, htmlUrlInfo) => {
|
|
16279
|
+
const rel = getHtmlNodeAttribute(linkReference.astInfo.node, "rel");
|
|
16280
|
+
if (rel === "webmanifest") {
|
|
16281
|
+
return "webmanifest";
|
|
16235
16282
|
}
|
|
16236
|
-
|
|
16237
|
-
|
|
16238
|
-
}
|
|
16239
|
-
|
|
16240
|
-
|
|
16241
|
-
|
|
16242
|
-
|
|
16243
|
-
|
|
16244
|
-
const
|
|
16245
|
-
|
|
16246
|
-
|
|
16247
|
-
console.warn(
|
|
16248
|
-
formulateAddressMustBeAString({
|
|
16249
|
-
address,
|
|
16250
|
-
specifier,
|
|
16251
|
-
}),
|
|
16252
|
-
);
|
|
16253
|
-
return
|
|
16254
|
-
}
|
|
16255
|
-
|
|
16256
|
-
const specifierResolved = resolveSpecifier(specifier, baseUrl) || specifier;
|
|
16257
|
-
|
|
16258
|
-
const addressUrl = tryUrlResolution(address, baseUrl);
|
|
16259
|
-
if (addressUrl === null) {
|
|
16260
|
-
console.warn(
|
|
16261
|
-
formulateAdressResolutionFailed({
|
|
16262
|
-
address,
|
|
16263
|
-
baseUrl,
|
|
16264
|
-
specifier,
|
|
16265
|
-
}),
|
|
16266
|
-
);
|
|
16267
|
-
return
|
|
16283
|
+
if (rel === "modulepreload") {
|
|
16284
|
+
return "js_module";
|
|
16285
|
+
}
|
|
16286
|
+
if (rel === "stylesheet") {
|
|
16287
|
+
return "css";
|
|
16288
|
+
}
|
|
16289
|
+
if (rel === "preload") {
|
|
16290
|
+
// https://developer.mozilla.org/en-US/docs/Web/HTML/Link_types/preload#what_types_of_content_can_be_preloaded
|
|
16291
|
+
const as = getHtmlNodeAttribute(linkReference.astInfo.node, "as");
|
|
16292
|
+
if (as === "document") {
|
|
16293
|
+
return "html";
|
|
16268
16294
|
}
|
|
16269
|
-
|
|
16270
|
-
|
|
16271
|
-
console.warn(
|
|
16272
|
-
formulateAddressUrlRequiresTrailingSlash({
|
|
16273
|
-
addressUrl,
|
|
16274
|
-
address,
|
|
16275
|
-
specifier,
|
|
16276
|
-
}),
|
|
16277
|
-
);
|
|
16278
|
-
return
|
|
16295
|
+
if (as === "style") {
|
|
16296
|
+
return "css";
|
|
16279
16297
|
}
|
|
16280
|
-
|
|
16281
|
-
|
|
16282
|
-
|
|
16283
|
-
|
|
16298
|
+
if (as === "script") {
|
|
16299
|
+
for (const referenceToOther of htmlUrlInfo.referenceToOthersSet) {
|
|
16300
|
+
if (referenceToOther.url !== linkReference.url) {
|
|
16301
|
+
continue;
|
|
16302
|
+
}
|
|
16303
|
+
if (referenceToOther.type !== "script") {
|
|
16304
|
+
continue;
|
|
16305
|
+
}
|
|
16306
|
+
return referenceToOther.expectedType;
|
|
16307
|
+
}
|
|
16308
|
+
return undefined;
|
|
16309
|
+
}
|
|
16310
|
+
}
|
|
16311
|
+
return undefined;
|
|
16284
16312
|
};
|
|
16285
16313
|
|
|
16286
|
-
const
|
|
16287
|
-
|
|
16314
|
+
// const applyWebUrlResolution = (url, baseUrl) => {
|
|
16315
|
+
// if (url[0] === "/") {
|
|
16316
|
+
// return new URL(url.slice(1), baseUrl).href;
|
|
16317
|
+
// }
|
|
16318
|
+
// return new URL(url, baseUrl).href;
|
|
16319
|
+
// };
|
|
16288
16320
|
|
|
16289
|
-
|
|
16290
|
-
const scopeMappings = scopes[scopeSpecifier];
|
|
16291
|
-
const scopeUrl = tryUrlResolution(scopeSpecifier, baseUrl);
|
|
16292
|
-
if (scopeUrl === null) {
|
|
16293
|
-
console.warn(
|
|
16294
|
-
formulateScopeResolutionFailed({
|
|
16295
|
-
scope: scopeSpecifier,
|
|
16296
|
-
baseUrl,
|
|
16297
|
-
}),
|
|
16298
|
-
);
|
|
16299
|
-
return
|
|
16300
|
-
}
|
|
16301
|
-
const scopeValueNormalized = normalizeMappings(scopeMappings, baseUrl);
|
|
16302
|
-
scopesNormalized[scopeUrl] = scopeValueNormalized;
|
|
16303
|
-
});
|
|
16321
|
+
// css: parseAndTransformCssUrls,
|
|
16304
16322
|
|
|
16305
|
-
|
|
16323
|
+
const jsenvPluginWebmanifestReferenceAnalysis = () => {
|
|
16324
|
+
return {
|
|
16325
|
+
name: "jsenv:webmanifest_reference_analysis",
|
|
16326
|
+
appliesDuring: "*",
|
|
16327
|
+
transformUrlContent: {
|
|
16328
|
+
webmanifest: parseAndTransformWebmanifestUrls,
|
|
16329
|
+
},
|
|
16330
|
+
};
|
|
16306
16331
|
};
|
|
16307
16332
|
|
|
16308
|
-
const
|
|
16309
|
-
|
|
16310
|
-
|
|
16311
|
-
|
|
16312
|
-
|
|
16313
|
-
|
|
16314
|
-
const
|
|
16315
|
-
|
|
16316
|
-
|
|
16317
|
-
})
|
|
16318
|
-
|
|
16319
|
-
|
|
16320
|
-
|
|
16321
|
-
|
|
16322
|
-
|
|
16323
|
-
const formulateAdressResolutionFailed = ({
|
|
16324
|
-
address,
|
|
16325
|
-
baseUrl,
|
|
16326
|
-
specifier,
|
|
16327
|
-
}) => `Address url resolution failed.
|
|
16328
|
-
--- address ---
|
|
16329
|
-
${address}
|
|
16330
|
-
--- base url ---
|
|
16331
|
-
${baseUrl}
|
|
16332
|
-
--- specifier ---
|
|
16333
|
-
${specifier}`;
|
|
16333
|
+
const parseAndTransformWebmanifestUrls = async (urlInfo) => {
|
|
16334
|
+
const content = urlInfo.content;
|
|
16335
|
+
const manifest = JSON.parse(content);
|
|
16336
|
+
const actions = [];
|
|
16337
|
+
const { icons = [] } = manifest;
|
|
16338
|
+
icons.forEach((icon) => {
|
|
16339
|
+
const iconReference = urlInfo.dependencies.found({
|
|
16340
|
+
type: "webmanifest_icon_src",
|
|
16341
|
+
specifier: icon.src,
|
|
16342
|
+
});
|
|
16343
|
+
actions.push(async () => {
|
|
16344
|
+
await iconReference.readGeneratedSpecifier();
|
|
16345
|
+
icon.src = iconReference.generatedSpecifier;
|
|
16346
|
+
});
|
|
16347
|
+
});
|
|
16334
16348
|
|
|
16335
|
-
|
|
16336
|
-
|
|
16337
|
-
|
|
16338
|
-
|
|
16339
|
-
|
|
16340
|
-
|
|
16341
|
-
${addressURL}
|
|
16342
|
-
--- address ---
|
|
16343
|
-
${address}
|
|
16344
|
-
--- specifier ---
|
|
16345
|
-
${specifier}`;
|
|
16349
|
+
if (actions.length === 0) {
|
|
16350
|
+
return null;
|
|
16351
|
+
}
|
|
16352
|
+
await Promise.all(actions.map((action) => action()));
|
|
16353
|
+
return JSON.stringify(manifest, null, " ");
|
|
16354
|
+
};
|
|
16346
16355
|
|
|
16347
|
-
|
|
16348
|
-
|
|
16349
|
-
|
|
16350
|
-
}) => `Scope url resolution failed.
|
|
16351
|
-
--- scope ---
|
|
16352
|
-
${scope}
|
|
16353
|
-
--- base url ---
|
|
16354
|
-
${baseUrl}`;
|
|
16356
|
+
/*
|
|
16357
|
+
* https://github.com/parcel-bundler/parcel/blob/v2/packages/transformers/css/src/CSSTransformer.js
|
|
16358
|
+
*/
|
|
16355
16359
|
|
|
16356
|
-
const pathnameToExtension = (pathname) => {
|
|
16357
|
-
const slashLastIndex = pathname.lastIndexOf("/");
|
|
16358
|
-
if (slashLastIndex !== -1) {
|
|
16359
|
-
pathname = pathname.slice(slashLastIndex + 1);
|
|
16360
|
-
}
|
|
16361
16360
|
|
|
16362
|
-
|
|
16363
|
-
|
|
16364
|
-
|
|
16365
|
-
|
|
16361
|
+
const jsenvPluginCssReferenceAnalysis = () => {
|
|
16362
|
+
return {
|
|
16363
|
+
name: "jsenv:css_reference_analysis",
|
|
16364
|
+
appliesDuring: "*",
|
|
16365
|
+
transformUrlContent: {
|
|
16366
|
+
css: parseAndTransformCssUrls,
|
|
16367
|
+
},
|
|
16368
|
+
};
|
|
16366
16369
|
};
|
|
16367
16370
|
|
|
16368
|
-
const
|
|
16369
|
-
|
|
16370
|
-
|
|
16371
|
-
|
|
16372
|
-
|
|
16373
|
-
|
|
16374
|
-
|
|
16375
|
-
|
|
16376
|
-
|
|
16377
|
-
|
|
16378
|
-
|
|
16379
|
-
|
|
16380
|
-
|
|
16381
|
-
|
|
16382
|
-
|
|
16383
|
-
|
|
16371
|
+
const parseAndTransformCssUrls = async (urlInfo) => {
|
|
16372
|
+
const cssUrls = await parseCssUrls({
|
|
16373
|
+
css: urlInfo.content,
|
|
16374
|
+
url: urlInfo.originalUrl,
|
|
16375
|
+
});
|
|
16376
|
+
const actions = [];
|
|
16377
|
+
const magicSource = createMagicSource(urlInfo.content);
|
|
16378
|
+
for (const cssUrl of cssUrls) {
|
|
16379
|
+
const reference = urlInfo.dependencies.found({
|
|
16380
|
+
type: cssUrl.type,
|
|
16381
|
+
specifier: cssUrl.specifier,
|
|
16382
|
+
specifierStart: cssUrl.start,
|
|
16383
|
+
specifierEnd: cssUrl.end,
|
|
16384
|
+
specifierLine: cssUrl.line,
|
|
16385
|
+
specifierColumn: cssUrl.column,
|
|
16386
|
+
});
|
|
16387
|
+
actions.push(async () => {
|
|
16388
|
+
await reference.readGeneratedSpecifier();
|
|
16389
|
+
const replacement = reference.generatedSpecifier;
|
|
16390
|
+
magicSource.replace({
|
|
16391
|
+
start: cssUrl.start,
|
|
16392
|
+
end: cssUrl.end,
|
|
16393
|
+
replacement,
|
|
16394
|
+
});
|
|
16384
16395
|
});
|
|
16385
|
-
} else {
|
|
16386
|
-
url = resolveUrl(specifier, importer);
|
|
16387
16396
|
}
|
|
16388
|
-
|
|
16389
|
-
|
|
16390
|
-
url = applyDefaultExtension({ url, importer, defaultExtension });
|
|
16397
|
+
if (actions.length > 0) {
|
|
16398
|
+
await Promise.all(actions.map((action) => action()));
|
|
16391
16399
|
}
|
|
16400
|
+
return magicSource.toContentAndSourcemap();
|
|
16401
|
+
};
|
|
16392
16402
|
|
|
16393
|
-
|
|
16403
|
+
const jsenvPluginJsReferenceAnalysis = ({ inlineContent }) => {
|
|
16404
|
+
return [
|
|
16405
|
+
{
|
|
16406
|
+
name: "jsenv:js_reference_analysis",
|
|
16407
|
+
appliesDuring: "*",
|
|
16408
|
+
transformUrlContent: {
|
|
16409
|
+
js_classic: (urlInfo) =>
|
|
16410
|
+
parseAndTransformJsReferences(urlInfo, {
|
|
16411
|
+
inlineContent,
|
|
16412
|
+
canUseTemplateLiterals:
|
|
16413
|
+
urlInfo.context.isSupportedOnCurrentClients("template_literals"),
|
|
16414
|
+
}),
|
|
16415
|
+
js_module: (urlInfo) =>
|
|
16416
|
+
parseAndTransformJsReferences(urlInfo, {
|
|
16417
|
+
inlineContent,
|
|
16418
|
+
canUseTemplateLiterals:
|
|
16419
|
+
urlInfo.context.isSupportedOnCurrentClients("template_literals"),
|
|
16420
|
+
}),
|
|
16421
|
+
},
|
|
16422
|
+
},
|
|
16423
|
+
];
|
|
16394
16424
|
};
|
|
16395
16425
|
|
|
16396
|
-
const
|
|
16397
|
-
|
|
16398
|
-
|
|
16399
|
-
|
|
16426
|
+
const parseAndTransformJsReferences = async (
|
|
16427
|
+
urlInfo,
|
|
16428
|
+
{ inlineContent, canUseTemplateLiterals },
|
|
16429
|
+
) => {
|
|
16430
|
+
const magicSource = createMagicSource(urlInfo.content);
|
|
16431
|
+
const parallelActions = [];
|
|
16432
|
+
const sequentialActions = [];
|
|
16433
|
+
const isNodeJs =
|
|
16434
|
+
Object.keys(urlInfo.context.runtimeCompat).toString() === "node";
|
|
16400
16435
|
|
|
16401
|
-
|
|
16402
|
-
const
|
|
16403
|
-
|
|
16404
|
-
|
|
16436
|
+
const onInlineReference = (inlineReferenceInfo) => {
|
|
16437
|
+
const inlineUrl = getUrlForContentInsideJs(inlineReferenceInfo, {
|
|
16438
|
+
url: urlInfo.url,
|
|
16439
|
+
});
|
|
16440
|
+
let { quote } = inlineReferenceInfo;
|
|
16441
|
+
if (quote === "`" && !canUseTemplateLiterals) {
|
|
16442
|
+
// if quote is "`" and template literals are not supported
|
|
16443
|
+
// we'll use a regular string (single or double quote)
|
|
16444
|
+
// when rendering the string
|
|
16445
|
+
quote = JS_QUOTES.pickBest(inlineReferenceInfo.content);
|
|
16405
16446
|
}
|
|
16406
|
-
|
|
16407
|
-
|
|
16447
|
+
const inlineReference = urlInfo.dependencies.foundInline({
|
|
16448
|
+
type: "js_inline_content",
|
|
16449
|
+
subtype: inlineReferenceInfo.type, // "new_blob_first_arg", "new_inline_content_first_arg", "json_parse_first_arg"
|
|
16450
|
+
isOriginalPosition: urlInfo.content === urlInfo.originalContent,
|
|
16451
|
+
specifierLine: inlineReferenceInfo.line,
|
|
16452
|
+
specifierColumn: inlineReferenceInfo.column,
|
|
16453
|
+
specifier: inlineUrl,
|
|
16454
|
+
contentType: inlineReferenceInfo.contentType,
|
|
16455
|
+
content: inlineReferenceInfo.content,
|
|
16456
|
+
});
|
|
16457
|
+
const inlineUrlInfo = inlineReference.urlInfo;
|
|
16458
|
+
inlineUrlInfo.jsQuote = quote;
|
|
16459
|
+
inlineReference.escape = (value) => {
|
|
16460
|
+
return JS_QUOTES.escapeSpecialChars(value.slice(1, -1), { quote });
|
|
16461
|
+
};
|
|
16408
16462
|
|
|
16409
|
-
|
|
16410
|
-
|
|
16411
|
-
|
|
16412
|
-
|
|
16413
|
-
|
|
16414
|
-
|
|
16463
|
+
sequentialActions.push(async () => {
|
|
16464
|
+
await inlineUrlInfo.cook();
|
|
16465
|
+
const replacement = JS_QUOTES.escapeSpecialChars(inlineUrlInfo.content, {
|
|
16466
|
+
quote,
|
|
16467
|
+
});
|
|
16468
|
+
magicSource.replace({
|
|
16469
|
+
start: inlineReferenceInfo.start,
|
|
16470
|
+
end: inlineReferenceInfo.end,
|
|
16471
|
+
replacement,
|
|
16472
|
+
});
|
|
16473
|
+
});
|
|
16474
|
+
};
|
|
16475
|
+
const onExternalReference = (externalReferenceInfo) => {
|
|
16476
|
+
if (
|
|
16477
|
+
externalReferenceInfo.subtype === "import_static" ||
|
|
16478
|
+
externalReferenceInfo.subtype === "import_dynamic"
|
|
16479
|
+
) {
|
|
16480
|
+
urlInfo.data.usesImport = true;
|
|
16481
|
+
}
|
|
16482
|
+
if (
|
|
16483
|
+
isNodeJs &&
|
|
16484
|
+
externalReferenceInfo.type === "js_url" &&
|
|
16485
|
+
externalReferenceInfo.expectedSubtype === "worker" &&
|
|
16486
|
+
externalReferenceInfo.expectedType === "js_classic" &&
|
|
16487
|
+
// TODO: it's true also if closest package.json
|
|
16488
|
+
// is type: module
|
|
16489
|
+
urlToExtension$1(
|
|
16490
|
+
new URL(externalReferenceInfo.specifier, urlInfo.url).href,
|
|
16491
|
+
) === ".mjs"
|
|
16492
|
+
) {
|
|
16493
|
+
externalReferenceInfo.expectedType = "js_module";
|
|
16494
|
+
}
|
|
16495
|
+
const reference = urlInfo.dependencies.found({
|
|
16496
|
+
type: externalReferenceInfo.type,
|
|
16497
|
+
subtype: externalReferenceInfo.subtype,
|
|
16498
|
+
expectedType: externalReferenceInfo.expectedType,
|
|
16499
|
+
expectedSubtype: externalReferenceInfo.expectedSubtype || urlInfo.subtype,
|
|
16500
|
+
specifier: externalReferenceInfo.specifier,
|
|
16501
|
+
specifierStart: externalReferenceInfo.start,
|
|
16502
|
+
specifierEnd: externalReferenceInfo.end,
|
|
16503
|
+
specifierLine: externalReferenceInfo.line,
|
|
16504
|
+
specifierColumn: externalReferenceInfo.column,
|
|
16505
|
+
data: externalReferenceInfo.data,
|
|
16506
|
+
baseUrl: {
|
|
16507
|
+
"StringLiteral": externalReferenceInfo.baseUrl,
|
|
16508
|
+
"window.location": urlInfo.url,
|
|
16509
|
+
"window.origin": urlInfo.context.rootDirectoryUrl,
|
|
16510
|
+
"import.meta.url": urlInfo.url,
|
|
16511
|
+
"context.meta.url": urlInfo.url,
|
|
16512
|
+
"document.currentScript.src": urlInfo.url,
|
|
16513
|
+
}[externalReferenceInfo.baseUrlType],
|
|
16514
|
+
importAttributes: externalReferenceInfo.importAttributes,
|
|
16515
|
+
astInfo: externalReferenceInfo.astInfo,
|
|
16516
|
+
});
|
|
16517
|
+
parallelActions.push(async () => {
|
|
16518
|
+
await reference.readGeneratedSpecifier();
|
|
16519
|
+
const replacement = reference.generatedSpecifier;
|
|
16520
|
+
magicSource.replace({
|
|
16521
|
+
start: externalReferenceInfo.start,
|
|
16522
|
+
end: externalReferenceInfo.end,
|
|
16523
|
+
replacement,
|
|
16524
|
+
});
|
|
16525
|
+
if (reference.mutation) {
|
|
16526
|
+
reference.mutation(magicSource, urlInfo);
|
|
16527
|
+
}
|
|
16528
|
+
});
|
|
16529
|
+
};
|
|
16530
|
+
const jsReferenceInfos = parseJsUrls({
|
|
16531
|
+
js: urlInfo.content,
|
|
16532
|
+
url: urlInfo.originalUrl,
|
|
16533
|
+
ast: urlInfo.contentAst,
|
|
16534
|
+
isJsModule: urlInfo.type === "js_module",
|
|
16535
|
+
isWebWorker: isWebWorkerUrlInfo(urlInfo),
|
|
16536
|
+
inlineContent,
|
|
16537
|
+
isNodeJs,
|
|
16538
|
+
});
|
|
16539
|
+
for (const jsReferenceInfo of jsReferenceInfos) {
|
|
16540
|
+
if (jsReferenceInfo.isInline) {
|
|
16541
|
+
onInlineReference(jsReferenceInfo);
|
|
16542
|
+
} else {
|
|
16543
|
+
onExternalReference(jsReferenceInfo);
|
|
16415
16544
|
}
|
|
16416
16545
|
}
|
|
16546
|
+
if (parallelActions.length > 0) {
|
|
16547
|
+
await Promise.all(parallelActions.map((action) => action()));
|
|
16548
|
+
}
|
|
16549
|
+
if (sequentialActions.length > 0) {
|
|
16550
|
+
await sequentialActions.reduce(async (previous, action) => {
|
|
16551
|
+
await previous;
|
|
16552
|
+
await action();
|
|
16553
|
+
}, Promise.resolve());
|
|
16554
|
+
}
|
|
16417
16555
|
|
|
16418
|
-
|
|
16556
|
+
const { content, sourcemap } = magicSource.toContentAndSourcemap();
|
|
16557
|
+
return { content, sourcemap };
|
|
16419
16558
|
};
|
|
16420
16559
|
|
|
16421
|
-
|
|
16422
|
-
|
|
16423
|
-
|
|
16424
|
-
|
|
16425
|
-
|
|
16426
|
-
|
|
16427
|
-
|
|
16428
|
-
|
|
16429
|
-
|
|
16430
|
-
|
|
16431
|
-
|
|
16432
|
-
|
|
16433
|
-
|
|
16434
|
-
|
|
16435
|
-
|
|
16436
|
-
|
|
16437
|
-
|
|
16438
|
-
|
|
16439
|
-
|
|
16440
|
-
|
|
16441
|
-
|
|
16442
|
-
|
|
16443
|
-
|
|
16444
|
-
const onHtmlImportmapParsed = (importmap, htmlUrl) => {
|
|
16445
|
-
importmaps[htmlUrl] = importmap
|
|
16446
|
-
? normalizeImportMap(importmap, htmlUrl)
|
|
16447
|
-
: null;
|
|
16448
|
-
finalImportmap = Object.keys(importmaps).reduce((previous, url) => {
|
|
16449
|
-
const importmap = importmaps[url];
|
|
16450
|
-
if (!previous) {
|
|
16451
|
-
return importmap;
|
|
16452
|
-
}
|
|
16453
|
-
if (!importmap) {
|
|
16454
|
-
return previous;
|
|
16455
|
-
}
|
|
16456
|
-
return composeTwoImportMaps(previous, importmap);
|
|
16457
|
-
}, null);
|
|
16458
|
-
};
|
|
16560
|
+
const jsenvPluginReferenceAnalysis = ({
|
|
16561
|
+
inlineContent = true,
|
|
16562
|
+
inlineConvertedScript = false,
|
|
16563
|
+
fetchInlineUrls = true,
|
|
16564
|
+
}) => {
|
|
16565
|
+
return [
|
|
16566
|
+
jsenvPluginDirectoryReferenceAnalysis(),
|
|
16567
|
+
jsenvPluginHtmlReferenceAnalysis({
|
|
16568
|
+
inlineContent,
|
|
16569
|
+
inlineConvertedScript,
|
|
16570
|
+
}),
|
|
16571
|
+
jsenvPluginWebmanifestReferenceAnalysis(),
|
|
16572
|
+
jsenvPluginCssReferenceAnalysis(),
|
|
16573
|
+
jsenvPluginJsReferenceAnalysis({
|
|
16574
|
+
inlineContent,
|
|
16575
|
+
}),
|
|
16576
|
+
...(inlineContent ? [jsenvPluginDataUrlsAnalysis()] : []),
|
|
16577
|
+
...(inlineContent && fetchInlineUrls
|
|
16578
|
+
? [jsenvPluginInlineContentFetcher()]
|
|
16579
|
+
: []),
|
|
16580
|
+
jsenvPluginReferenceExpectedTypes(),
|
|
16581
|
+
];
|
|
16582
|
+
};
|
|
16459
16583
|
|
|
16584
|
+
const jsenvPluginInlineContentFetcher = () => {
|
|
16460
16585
|
return {
|
|
16461
|
-
name: "jsenv:
|
|
16586
|
+
name: "jsenv:inline_content_fetcher",
|
|
16462
16587
|
appliesDuring: "*",
|
|
16463
|
-
|
|
16464
|
-
|
|
16465
|
-
|
|
16466
|
-
|
|
16467
|
-
|
|
16468
|
-
|
|
16469
|
-
|
|
16470
|
-
|
|
16471
|
-
|
|
16472
|
-
|
|
16473
|
-
|
|
16474
|
-
onImportMapping: () => {
|
|
16475
|
-
fromMapping = true;
|
|
16476
|
-
},
|
|
16477
|
-
});
|
|
16478
|
-
if (fromMapping) {
|
|
16479
|
-
return result;
|
|
16480
|
-
}
|
|
16481
|
-
return null;
|
|
16482
|
-
} catch (e) {
|
|
16483
|
-
if (e.message.includes("bare specifier")) {
|
|
16484
|
-
// in theory we should throw to be compliant with web behaviour
|
|
16485
|
-
// but for now it's simpler to return null
|
|
16486
|
-
// and let a chance to other plugins to handle the bare specifier
|
|
16487
|
-
// (node esm resolution)
|
|
16488
|
-
// and we want importmap to be prio over node esm so we cannot put this plugin after
|
|
16489
|
-
return null;
|
|
16490
|
-
}
|
|
16491
|
-
throw e;
|
|
16492
|
-
}
|
|
16493
|
-
},
|
|
16494
|
-
},
|
|
16495
|
-
transformUrlContent: {
|
|
16496
|
-
html: async (htmlUrlInfo) => {
|
|
16497
|
-
const htmlAst = parseHtmlString(htmlUrlInfo.content);
|
|
16498
|
-
const importmap = findHtmlNode(htmlAst, (node) => {
|
|
16499
|
-
if (node.nodeName !== "script") {
|
|
16500
|
-
return false;
|
|
16501
|
-
}
|
|
16502
|
-
const type = getHtmlNodeAttribute(node, "type");
|
|
16503
|
-
if (type === undefined || type !== "importmap") {
|
|
16504
|
-
return false;
|
|
16505
|
-
}
|
|
16506
|
-
return true;
|
|
16507
|
-
});
|
|
16508
|
-
if (!importmap) {
|
|
16509
|
-
onHtmlImportmapParsed(null, htmlUrlInfo.url);
|
|
16510
|
-
return null;
|
|
16511
|
-
}
|
|
16512
|
-
const handleInlineImportmap = async (importmap, htmlNodeText) => {
|
|
16513
|
-
const { line, column, isOriginal } = getHtmlNodePosition(importmap, {
|
|
16514
|
-
preferOriginal: true,
|
|
16515
|
-
});
|
|
16516
|
-
const inlineImportmapUrl = getUrlForContentInsideHtml(importmap, {
|
|
16517
|
-
htmlUrl: htmlUrlInfo.url,
|
|
16518
|
-
});
|
|
16519
|
-
const inlineImportmapReference = htmlUrlInfo.dependencies.foundInline(
|
|
16520
|
-
{
|
|
16521
|
-
type: "script",
|
|
16522
|
-
isOriginalPosition: isOriginal,
|
|
16523
|
-
specifierLine: line - 1,
|
|
16524
|
-
specifierColumn: column,
|
|
16525
|
-
specifier: inlineImportmapUrl,
|
|
16526
|
-
contentType: "application/importmap+json",
|
|
16527
|
-
content: htmlNodeText,
|
|
16528
|
-
},
|
|
16529
|
-
);
|
|
16530
|
-
const inlineImportmapUrlInfo = inlineImportmapReference.urlInfo;
|
|
16531
|
-
await inlineImportmapUrlInfo.cook();
|
|
16532
|
-
setHtmlNodeText(importmap, inlineImportmapUrlInfo.content, {
|
|
16533
|
-
indentation: "auto",
|
|
16534
|
-
});
|
|
16535
|
-
setHtmlNodeAttributes(importmap, {
|
|
16536
|
-
"jsenv-cooked-by": "jsenv:importmap",
|
|
16537
|
-
});
|
|
16538
|
-
onHtmlImportmapParsed(
|
|
16539
|
-
JSON.parse(inlineImportmapUrlInfo.content),
|
|
16540
|
-
htmlUrlInfo.url,
|
|
16541
|
-
);
|
|
16542
|
-
};
|
|
16543
|
-
const handleImportmapWithSrc = async (importmap, src) => {
|
|
16544
|
-
// Browser would throw on remote importmap
|
|
16545
|
-
// and won't sent a request to the server for it
|
|
16546
|
-
// We must precook the importmap to know its content and inline it into the HTML
|
|
16547
|
-
// In this situation the ref to the importmap was already discovered
|
|
16548
|
-
// when parsing the HTML
|
|
16549
|
-
let importmapReference = null;
|
|
16550
|
-
for (const referenceToOther of htmlUrlInfo.referenceToOthersSet) {
|
|
16551
|
-
if (referenceToOther.generatedSpecifier === src) {
|
|
16552
|
-
importmapReference = referenceToOther;
|
|
16553
|
-
break;
|
|
16554
|
-
}
|
|
16555
|
-
}
|
|
16556
|
-
const { line, column, isOriginal } = getHtmlNodePosition(importmap, {
|
|
16557
|
-
preferOriginal: true,
|
|
16558
|
-
});
|
|
16559
|
-
const importmapInlineUrl = getUrlForContentInsideHtml(importmap, {
|
|
16560
|
-
htmlUrl: htmlUrlInfo.url,
|
|
16561
|
-
});
|
|
16562
|
-
const importmapReferenceInlined = importmapReference.inline({
|
|
16563
|
-
line: line - 1,
|
|
16564
|
-
column,
|
|
16565
|
-
isOriginal,
|
|
16566
|
-
specifier: importmapInlineUrl,
|
|
16567
|
-
contentType: "application/importmap+json",
|
|
16568
|
-
});
|
|
16569
|
-
const importmapInlineUrlInfo = importmapReferenceInlined.urlInfo;
|
|
16570
|
-
await importmapInlineUrlInfo.cook();
|
|
16571
|
-
onHtmlImportmapParsed(
|
|
16572
|
-
JSON.parse(importmapInlineUrlInfo.content),
|
|
16573
|
-
htmlUrlInfo.url,
|
|
16574
|
-
);
|
|
16575
|
-
setHtmlNodeText(importmap, importmapInlineUrlInfo.content, {
|
|
16576
|
-
indentation: "auto",
|
|
16577
|
-
});
|
|
16578
|
-
setHtmlNodeAttributes(importmap, {
|
|
16579
|
-
"src": undefined,
|
|
16580
|
-
"jsenv-inlined-by": "jsenv:importmap",
|
|
16581
|
-
"inlined-from-src": src,
|
|
16582
|
-
});
|
|
16583
|
-
};
|
|
16584
|
-
|
|
16585
|
-
const src = getHtmlNodeAttribute(importmap, "src");
|
|
16586
|
-
if (src) {
|
|
16587
|
-
await handleImportmapWithSrc(importmap, src);
|
|
16588
|
-
} else {
|
|
16589
|
-
const htmlNodeText = getHtmlNodeText(importmap);
|
|
16590
|
-
if (htmlNodeText) {
|
|
16591
|
-
await handleInlineImportmap(importmap, htmlNodeText);
|
|
16592
|
-
}
|
|
16588
|
+
fetchUrlContent: async (urlInfo) => {
|
|
16589
|
+
if (!urlInfo.isInline) {
|
|
16590
|
+
return null;
|
|
16591
|
+
}
|
|
16592
|
+
// - we must use last reference because
|
|
16593
|
+
// when updating the file, first reference is the previous version
|
|
16594
|
+
// - we cannot use urlInfo.lastReference because it can be the reference created by "http_request"
|
|
16595
|
+
let lastInlineReference;
|
|
16596
|
+
for (const reference of urlInfo.referenceFromOthersSet) {
|
|
16597
|
+
if (reference.isInline) {
|
|
16598
|
+
lastInlineReference = reference;
|
|
16593
16599
|
}
|
|
16594
|
-
|
|
16595
|
-
|
|
16596
|
-
|
|
16597
|
-
//
|
|
16598
|
-
|
|
16599
|
-
|
|
16600
|
-
|
|
16600
|
+
}
|
|
16601
|
+
const { prev } = lastInlineReference;
|
|
16602
|
+
if (prev && !prev.isInline) {
|
|
16603
|
+
// got inlined, cook original url
|
|
16604
|
+
if (lastInlineReference.content === undefined) {
|
|
16605
|
+
const originalUrlInfo = prev.urlInfo;
|
|
16606
|
+
await originalUrlInfo.cook();
|
|
16607
|
+
lastInlineReference.content = originalUrlInfo.content;
|
|
16608
|
+
lastInlineReference.contentType = originalUrlInfo.contentType;
|
|
16601
16609
|
}
|
|
16602
|
-
|
|
16603
|
-
|
|
16604
|
-
|
|
16605
|
-
|
|
16610
|
+
}
|
|
16611
|
+
return {
|
|
16612
|
+
originalContent: urlInfo.originalContent,
|
|
16613
|
+
content: lastInlineReference.content,
|
|
16614
|
+
contentType: lastInlineReference.contentType,
|
|
16615
|
+
};
|
|
16606
16616
|
},
|
|
16607
16617
|
};
|
|
16608
16618
|
};
|
|
@@ -19478,14 +19488,22 @@ const jsenvPluginAutoreloadServer = ({
|
|
|
19478
19488
|
return iterateMemoized(firstUrlInfo, []);
|
|
19479
19489
|
};
|
|
19480
19490
|
|
|
19481
|
-
|
|
19491
|
+
let propagationResult = propagateUpdate(firstUrlInfo);
|
|
19482
19492
|
const seen = new Set();
|
|
19483
19493
|
const invalidateImporters = (urlInfo) => {
|
|
19484
19494
|
// to indicate this urlInfo should be modified
|
|
19485
19495
|
for (const referenceFromOther of urlInfo.referenceFromOthersSet) {
|
|
19486
19496
|
const urlInfoReferencingThisOne = referenceFromOther.ownerUrlInfo;
|
|
19487
|
-
const { hotAcceptDependencies = [] } =
|
|
19497
|
+
const { hotDecline, hotAcceptDependencies = [] } =
|
|
19488
19498
|
urlInfoReferencingThisOne.data;
|
|
19499
|
+
if (hotDecline) {
|
|
19500
|
+
propagationResult = {
|
|
19501
|
+
declined: true,
|
|
19502
|
+
reason: `file declines hot reload`,
|
|
19503
|
+
declinedBy: formatUrlForClient(urlInfoReferencingThisOne.url),
|
|
19504
|
+
};
|
|
19505
|
+
return;
|
|
19506
|
+
}
|
|
19489
19507
|
if (hotAcceptDependencies.includes(urlInfo.url)) {
|
|
19490
19508
|
continue;
|
|
19491
19509
|
}
|
|
@@ -19764,7 +19782,7 @@ const jsenvPluginRibbon = ({
|
|
|
19764
19782
|
null,
|
|
19765
19783
|
" ",
|
|
19766
19784
|
);
|
|
19767
|
-
|
|
19785
|
+
injectHtmlNodeAsEarlyAsPossible(
|
|
19768
19786
|
htmlAst,
|
|
19769
19787
|
createHtmlNode({
|
|
19770
19788
|
tagName: "script",
|
|
@@ -19829,7 +19847,6 @@ const getCorePlugins = ({
|
|
|
19829
19847
|
jsenvPluginReferenceAnalysis(referenceAnalysis),
|
|
19830
19848
|
...(injections ? [jsenvPluginInjections(injections)] : []),
|
|
19831
19849
|
jsenvPluginTranspilation(transpilation),
|
|
19832
|
-
jsenvPluginImportmap(),
|
|
19833
19850
|
...(inlining ? [jsenvPluginInlining()] : []),
|
|
19834
19851
|
...(supervisor ? [jsenvPluginSupervisor(supervisor)] : []), // after inline as it needs inline script to be cooked
|
|
19835
19852
|
|
|
@@ -22279,7 +22296,7 @@ const createFileService = ({
|
|
|
22279
22296
|
associations: watchAssociations,
|
|
22280
22297
|
});
|
|
22281
22298
|
urlInfoCreated.isWatched = watch;
|
|
22282
|
-
//
|
|
22299
|
+
// when an url depends on many others, we check all these (like package.json)
|
|
22283
22300
|
urlInfoCreated.isValid = () => {
|
|
22284
22301
|
if (!urlInfoCreated.url.startsWith("file:")) {
|
|
22285
22302
|
return false;
|