@jsenv/core 38.2.10 → 38.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dist/jsenv_core.js +1592 -1494
- package/package.json +14 -14
- package/src/dev/file_service.js +1 -1
- package/src/kitchen/kitchen.js +1 -1
- package/src/kitchen/url_graph/references.js +2 -2
- package/src/kitchen/url_graph/url_graph.js +15 -4
- package/src/plugins/autoreload/jsenv_plugin_autoreload_server.js +133 -65
- package/src/plugins/autoreload/jsenv_plugin_hot_search_param.js +15 -6
- package/src/plugins/plugins.js +0 -2
- package/src/plugins/protocol_file/jsenv_plugin_protocol_file.js +12 -4
- package/src/plugins/reference_analysis/directory/jsenv_plugin_directory_reference_analysis.js +3 -0
- package/src/plugins/reference_analysis/html/jsenv_plugin_html_reference_analysis.js +493 -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";
|
|
@@ -7355,7 +7355,11 @@ const serveDirectory = (
|
|
|
7355
7355
|
const directoryContentArray = readdirSync(new URL(url));
|
|
7356
7356
|
const responseProducers = {
|
|
7357
7357
|
"application/json": () => {
|
|
7358
|
-
const directoryContentJson = JSON.stringify(
|
|
7358
|
+
const directoryContentJson = JSON.stringify(
|
|
7359
|
+
directoryContentArray,
|
|
7360
|
+
null,
|
|
7361
|
+
" ",
|
|
7362
|
+
);
|
|
7359
7363
|
return {
|
|
7360
7364
|
status: 200,
|
|
7361
7365
|
headers: {
|
|
@@ -9343,6 +9347,7 @@ const babelPluginCompatMap = {
|
|
|
9343
9347
|
samsung: "9",
|
|
9344
9348
|
electron: "3",
|
|
9345
9349
|
},
|
|
9350
|
+
"proposal-decorators": {},
|
|
9346
9351
|
"transform-parameters": {
|
|
9347
9352
|
chrome: "49",
|
|
9348
9353
|
opera: "36",
|
|
@@ -9739,6 +9744,14 @@ const getBaseBabelPluginStructure = ({
|
|
|
9739
9744
|
babelPluginStructure["proposal-unicode-property-regex"] =
|
|
9740
9745
|
requireBabelPlugin("@babel/plugin-proposal-unicode-property-regex");
|
|
9741
9746
|
}
|
|
9747
|
+
// if (isBabelPluginNeeded("proposal-decorators") && content.includes("@")) {
|
|
9748
|
+
// babelPluginStructure["proposal-decorators"] = [
|
|
9749
|
+
// requireBabelPlugin("@babel/plugin-proposal-decorators"),
|
|
9750
|
+
// {
|
|
9751
|
+
// version: "2023-05",
|
|
9752
|
+
// },
|
|
9753
|
+
// ];
|
|
9754
|
+
// }
|
|
9742
9755
|
if (isBabelPluginNeeded("transform-async-to-promises")) {
|
|
9743
9756
|
babelPluginStructure["transform-async-to-promises"] = [
|
|
9744
9757
|
requireBabelPlugin("babel-plugin-transform-async-to-promises"),
|
|
@@ -11801,12 +11814,12 @@ const createReference = ({
|
|
|
11801
11814
|
ownerUrlInfo.context.finalizeReference(reference);
|
|
11802
11815
|
};
|
|
11803
11816
|
|
|
11804
|
-
// "
|
|
11817
|
+
// "formatReference" can be async BUT this is an exception
|
|
11805
11818
|
// for most cases it will be sync. We want to favor the sync signature to keep things simpler
|
|
11806
11819
|
// The only case where it needs to be async is when
|
|
11807
11820
|
// the specifier is a `data:*` url
|
|
11808
11821
|
// in this case we'll wait for the promise returned by
|
|
11809
|
-
// "
|
|
11822
|
+
// "formatReference"
|
|
11810
11823
|
reference.readGeneratedSpecifier = () => {
|
|
11811
11824
|
if (reference.generatedSpecifier.then) {
|
|
11812
11825
|
return reference.generatedSpecifier.then((value) => {
|
|
@@ -12311,6 +12324,7 @@ const createUrlInfo = (url, context) => {
|
|
|
12311
12324
|
context,
|
|
12312
12325
|
error: null,
|
|
12313
12326
|
modifiedTimestamp: 0,
|
|
12327
|
+
descendantModifiedTimestamp: 0,
|
|
12314
12328
|
dereferencedTimestamp: 0,
|
|
12315
12329
|
originalContentEtag: null,
|
|
12316
12330
|
contentEtag: null,
|
|
@@ -12384,6 +12398,9 @@ const createUrlInfo = (url, context) => {
|
|
|
12384
12398
|
continue;
|
|
12385
12399
|
}
|
|
12386
12400
|
if (ref.gotInlined()) {
|
|
12401
|
+
if (ref.ownerUrlInfo.isUsed()) {
|
|
12402
|
+
return true;
|
|
12403
|
+
}
|
|
12387
12404
|
// the url info was inlined, an other reference is required
|
|
12388
12405
|
// to consider the non-inlined urlInfo as used
|
|
12389
12406
|
continue;
|
|
@@ -12483,7 +12500,7 @@ const createUrlInfo = (url, context) => {
|
|
|
12483
12500
|
};
|
|
12484
12501
|
urlInfo.onModified = ({ modifiedTimestamp = Date.now() } = {}) => {
|
|
12485
12502
|
const visitedSet = new Set();
|
|
12486
|
-
const
|
|
12503
|
+
const considerModified = (urlInfo) => {
|
|
12487
12504
|
if (visitedSet.has(urlInfo)) {
|
|
12488
12505
|
return;
|
|
12489
12506
|
}
|
|
@@ -12493,14 +12510,21 @@ const createUrlInfo = (url, context) => {
|
|
|
12493
12510
|
for (const referenceToOther of urlInfo.referenceToOthersSet) {
|
|
12494
12511
|
const referencedUrlInfo = referenceToOther.urlInfo;
|
|
12495
12512
|
if (referencedUrlInfo.isInline) {
|
|
12496
|
-
|
|
12513
|
+
considerModified(referencedUrlInfo);
|
|
12514
|
+
}
|
|
12515
|
+
}
|
|
12516
|
+
for (const referenceFromOther of urlInfo.referenceFromOthersSet) {
|
|
12517
|
+
if (referenceFromOther.gotInlined()) {
|
|
12518
|
+
const urlInfoReferencingThisOne = referenceFromOther.ownerUrlInfo;
|
|
12519
|
+
considerModified(urlInfoReferencingThisOne);
|
|
12497
12520
|
}
|
|
12498
12521
|
}
|
|
12499
12522
|
for (const searchParamVariant of urlInfo.searchParamVariantSet) {
|
|
12500
|
-
|
|
12523
|
+
considerModified(searchParamVariant);
|
|
12501
12524
|
}
|
|
12502
12525
|
};
|
|
12503
|
-
|
|
12526
|
+
considerModified(urlInfo);
|
|
12527
|
+
visitedSet.clear();
|
|
12504
12528
|
};
|
|
12505
12529
|
urlInfo.onDereferenced = (lastReferenceFromOther) => {
|
|
12506
12530
|
urlInfo.dereferencedTimestamp = Date.now();
|
|
@@ -14378,7 +14402,7 @@ ${ANSI.color(normalizedReturnValue, ANSI.YELLOW)}
|
|
|
14378
14402
|
// the HTML in itself it still valid
|
|
14379
14403
|
// keep the syntax error and continue with the HTML
|
|
14380
14404
|
const errorInfo =
|
|
14381
|
-
e.code === "PARSE_ERROR"
|
|
14405
|
+
e.code === "PARSE_ERROR" && e.cause
|
|
14382
14406
|
? `${e.cause.reasonCode}\n${e.traceMessage}`
|
|
14383
14407
|
: e.stack;
|
|
14384
14408
|
logger.error(
|
|
@@ -14885,6 +14909,9 @@ const jsenvPluginDirectoryReferenceAnalysis = () => {
|
|
|
14885
14909
|
urlInfo.url,
|
|
14886
14910
|
urlInfo.context.rootDirectoryUrl,
|
|
14887
14911
|
);
|
|
14912
|
+
if (urlInfo.contentType !== "application/json") {
|
|
14913
|
+
return null;
|
|
14914
|
+
}
|
|
14888
14915
|
const entryNames = JSON.parse(urlInfo.content);
|
|
14889
14916
|
const newEntryNames = [];
|
|
14890
14917
|
for (const entryName of entryNames) {
|
|
@@ -14994,1598 +15021,1586 @@ const base64ToString = (base64String) =>
|
|
|
14994
15021
|
Buffer.from(base64String, "base64").toString("utf8");
|
|
14995
15022
|
const dataToBase64 = (data) => Buffer.from(data).toString("base64");
|
|
14996
15023
|
|
|
14997
|
-
|
|
14998
|
-
|
|
14999
|
-
|
|
15000
|
-
}) => {
|
|
15001
|
-
return {
|
|
15002
|
-
name: "jsenv:html_reference_analysis",
|
|
15003
|
-
appliesDuring: "*",
|
|
15004
|
-
transformUrlContent: {
|
|
15005
|
-
html: (urlInfo) =>
|
|
15006
|
-
parseAndTransformHtmlReferences(urlInfo, {
|
|
15007
|
-
inlineContent,
|
|
15008
|
-
inlineConvertedScript,
|
|
15009
|
-
}),
|
|
15010
|
-
},
|
|
15011
|
-
};
|
|
15012
|
-
};
|
|
15024
|
+
// duplicated from @jsenv/log to avoid the dependency
|
|
15025
|
+
const createDetailedMessage = (message, details = {}) => {
|
|
15026
|
+
let string = `${message}`;
|
|
15013
15027
|
|
|
15014
|
-
|
|
15015
|
-
|
|
15016
|
-
|
|
15017
|
-
|
|
15018
|
-
|
|
15019
|
-
|
|
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
|
+
});
|
|
15020
15039
|
|
|
15021
|
-
|
|
15022
|
-
|
|
15023
|
-
const finalizeCallbacks = [];
|
|
15040
|
+
return string
|
|
15041
|
+
};
|
|
15024
15042
|
|
|
15025
|
-
|
|
15026
|
-
|
|
15027
|
-
|
|
15028
|
-
|
|
15029
|
-
{ type, subtype, expectedType, ...rest },
|
|
15030
|
-
) => {
|
|
15031
|
-
let position;
|
|
15032
|
-
if (getHtmlNodeAttribute(node, "jsenv-cooked-by")) {
|
|
15033
|
-
// when generated from inline content,
|
|
15034
|
-
// line, column is not "src" nor "inlined-from-src" but "original-position"
|
|
15035
|
-
position = getHtmlNodePosition(node);
|
|
15036
|
-
} else {
|
|
15037
|
-
position = getHtmlNodeAttributePosition(node, attributeName);
|
|
15038
|
-
}
|
|
15039
|
-
const {
|
|
15040
|
-
line,
|
|
15041
|
-
column,
|
|
15042
|
-
// originalLine, originalColumn
|
|
15043
|
-
} = position;
|
|
15044
|
-
const debug = getHtmlNodeAttribute(node, "jsenv-debug") !== undefined;
|
|
15045
|
-
|
|
15046
|
-
const { crossorigin, integrity } = readFetchMetas(node);
|
|
15047
|
-
const isResourceHint = [
|
|
15048
|
-
"preconnect",
|
|
15049
|
-
"dns-prefetch",
|
|
15050
|
-
"prefetch",
|
|
15051
|
-
"preload",
|
|
15052
|
-
"modulepreload",
|
|
15053
|
-
].includes(subtype);
|
|
15054
|
-
let attributeLocation = node.sourceCodeLocation.attrs[attributeName];
|
|
15055
|
-
if (
|
|
15056
|
-
!attributeLocation &&
|
|
15057
|
-
attributeName === "href" &&
|
|
15058
|
-
(node.tagName === "use" || node.tagName === "image")
|
|
15059
|
-
) {
|
|
15060
|
-
attributeLocation = node.sourceCodeLocation.attrs["xlink:href"];
|
|
15061
|
-
}
|
|
15062
|
-
const attributeStart = attributeLocation.startOffset;
|
|
15063
|
-
const attributeValueStart = urlInfo.content.indexOf(
|
|
15064
|
-
attributeValue,
|
|
15065
|
-
attributeStart + `${attributeName}=`.length,
|
|
15066
|
-
);
|
|
15067
|
-
const attributeValueEnd = attributeValueStart + attributeValue.length;
|
|
15068
|
-
const reference = urlInfo.dependencies.found({
|
|
15069
|
-
type,
|
|
15070
|
-
subtype,
|
|
15071
|
-
expectedType,
|
|
15072
|
-
specifier: attributeValue,
|
|
15073
|
-
specifierLine: line,
|
|
15074
|
-
specifierColumn: column,
|
|
15075
|
-
specifierStart: attributeValueStart,
|
|
15076
|
-
specifierEnd: attributeValueEnd,
|
|
15077
|
-
isResourceHint,
|
|
15078
|
-
isWeak: isResourceHint,
|
|
15079
|
-
crossorigin,
|
|
15080
|
-
integrity,
|
|
15081
|
-
debug,
|
|
15082
|
-
astInfo: { node, attributeName },
|
|
15083
|
-
...rest,
|
|
15084
|
-
});
|
|
15085
|
-
actions.push(async () => {
|
|
15086
|
-
await reference.readGeneratedSpecifier();
|
|
15087
|
-
mutations.push(() => {
|
|
15088
|
-
setHtmlNodeAttributes(node, {
|
|
15089
|
-
[attributeName]: reference.generatedSpecifier,
|
|
15090
|
-
});
|
|
15091
|
-
});
|
|
15092
|
-
});
|
|
15093
|
-
return reference;
|
|
15094
|
-
};
|
|
15095
|
-
const visitHref = (node, referenceProps) => {
|
|
15096
|
-
const href = getHtmlNodeAttribute(node, "href");
|
|
15097
|
-
if (href) {
|
|
15098
|
-
return createExternalReference(node, "href", href, referenceProps);
|
|
15099
|
-
}
|
|
15100
|
-
return null;
|
|
15101
|
-
};
|
|
15102
|
-
const visitSrc = (node, referenceProps) => {
|
|
15103
|
-
const src = getHtmlNodeAttribute(node, "src");
|
|
15104
|
-
if (src) {
|
|
15105
|
-
return createExternalReference(node, "src", src, referenceProps);
|
|
15106
|
-
}
|
|
15107
|
-
return null;
|
|
15108
|
-
};
|
|
15109
|
-
const visitSrcset = (node, referenceProps) => {
|
|
15110
|
-
const srcset = getHtmlNodeAttribute(node, "srcset");
|
|
15111
|
-
if (srcset) {
|
|
15112
|
-
const srcCandidates = parseSrcSet(srcset);
|
|
15113
|
-
return srcCandidates.map((srcCandidate) => {
|
|
15114
|
-
return createExternalReference(
|
|
15115
|
-
node,
|
|
15116
|
-
"srcset",
|
|
15117
|
-
srcCandidate.specifier,
|
|
15118
|
-
referenceProps,
|
|
15119
|
-
);
|
|
15120
|
-
});
|
|
15121
|
-
}
|
|
15122
|
-
return null;
|
|
15123
|
-
};
|
|
15043
|
+
const assertImportMap = (value) => {
|
|
15044
|
+
if (value === null) {
|
|
15045
|
+
throw new TypeError(`an importMap must be an object, got null`)
|
|
15046
|
+
}
|
|
15124
15047
|
|
|
15125
|
-
const
|
|
15126
|
-
|
|
15127
|
-
|
|
15128
|
-
|
|
15129
|
-
) => {
|
|
15130
|
-
const hotAccept = getHtmlNodeAttribute(node, "hot-accept") !== undefined;
|
|
15131
|
-
const { line, column, isOriginal } = getHtmlNodePosition(node, {
|
|
15132
|
-
preferOriginal: true,
|
|
15133
|
-
});
|
|
15134
|
-
const inlineContentUrl = getUrlForContentInsideHtml(node, {
|
|
15135
|
-
htmlUrl: urlInfo.url,
|
|
15136
|
-
});
|
|
15137
|
-
const debug = getHtmlNodeAttribute(node, "jsenv-debug") !== undefined;
|
|
15138
|
-
const inlineReference = urlInfo.dependencies.foundInline({
|
|
15139
|
-
type,
|
|
15140
|
-
expectedType,
|
|
15141
|
-
isOriginalPosition: isOriginal,
|
|
15142
|
-
// we remove 1 to the line because imagine the following html:
|
|
15143
|
-
// <style>body { color: red; }</style>
|
|
15144
|
-
// -> content starts same line as <style> (same for <script>)
|
|
15145
|
-
specifierLine: line - 1,
|
|
15146
|
-
specifierColumn: column,
|
|
15147
|
-
specifier: inlineContentUrl,
|
|
15148
|
-
contentType,
|
|
15149
|
-
content: inlineContent,
|
|
15150
|
-
debug,
|
|
15151
|
-
astInfo: { node },
|
|
15152
|
-
});
|
|
15048
|
+
const type = typeof value;
|
|
15049
|
+
if (type !== "object") {
|
|
15050
|
+
throw new TypeError(`an importMap must be an object, received ${value}`)
|
|
15051
|
+
}
|
|
15153
15052
|
|
|
15154
|
-
|
|
15155
|
-
|
|
15156
|
-
|
|
15157
|
-
|
|
15158
|
-
|
|
15159
|
-
|
|
15160
|
-
"jsenv-cooked-by": "jsenv:html_inline_content_analysis",
|
|
15161
|
-
});
|
|
15162
|
-
} else {
|
|
15163
|
-
setHtmlNodeText(node, inlineReference.urlInfo.content, {
|
|
15164
|
-
indentation: false, // indentation would decrease stack trace precision
|
|
15165
|
-
});
|
|
15166
|
-
setHtmlNodeAttributes(node, {
|
|
15167
|
-
"jsenv-cooked-by": "jsenv:html_inline_content_analysis",
|
|
15168
|
-
});
|
|
15169
|
-
}
|
|
15170
|
-
});
|
|
15171
|
-
});
|
|
15172
|
-
return inlineReference;
|
|
15173
|
-
};
|
|
15174
|
-
const visitTextContent = (
|
|
15175
|
-
node,
|
|
15176
|
-
{ type, subtype, expectedType, contentType },
|
|
15177
|
-
) => {
|
|
15178
|
-
const inlineContent = getHtmlNodeText(node);
|
|
15179
|
-
if (!inlineContent) {
|
|
15180
|
-
return null;
|
|
15181
|
-
}
|
|
15182
|
-
return createInlineReference(node, inlineContent, {
|
|
15183
|
-
type,
|
|
15184
|
-
subtype,
|
|
15185
|
-
expectedType,
|
|
15186
|
-
contentType,
|
|
15187
|
-
});
|
|
15188
|
-
};
|
|
15053
|
+
if (Array.isArray(value)) {
|
|
15054
|
+
throw new TypeError(
|
|
15055
|
+
`an importMap must be an object, received array ${value}`,
|
|
15056
|
+
)
|
|
15057
|
+
}
|
|
15058
|
+
};
|
|
15189
15059
|
|
|
15190
|
-
|
|
15191
|
-
|
|
15192
|
-
|
|
15193
|
-
const type = getHtmlNodeAttribute(linkNode, "type");
|
|
15194
|
-
const ref = visitHref(linkNode, {
|
|
15195
|
-
type: "link_href",
|
|
15196
|
-
subtype: rel,
|
|
15197
|
-
// https://developer.mozilla.org/en-US/docs/Web/HTML/Link_types/preload#including_a_mime_type
|
|
15198
|
-
expectedContentType: type,
|
|
15199
|
-
});
|
|
15200
|
-
if (ref) {
|
|
15201
|
-
finalizeCallbacks.push(() => {
|
|
15202
|
-
if (ref.expectedType) ; else {
|
|
15203
|
-
ref.expectedType = decideLinkExpectedType(ref, urlInfo);
|
|
15204
|
-
}
|
|
15205
|
-
});
|
|
15206
|
-
}
|
|
15207
|
-
},
|
|
15208
|
-
style: inlineContent
|
|
15209
|
-
? (styleNode) => {
|
|
15210
|
-
visitTextContent(styleNode, {
|
|
15211
|
-
type: "style",
|
|
15212
|
-
expectedType: "css",
|
|
15213
|
-
contentType: "text/css",
|
|
15214
|
-
});
|
|
15215
|
-
}
|
|
15216
|
-
: null,
|
|
15217
|
-
script: (scriptNode) => {
|
|
15218
|
-
// during build the importmap is inlined
|
|
15219
|
-
// and shoud not be considered as a dependency anymore
|
|
15220
|
-
if (
|
|
15221
|
-
getHtmlNodeAttribute(scriptNode, "jsenv-inlined-by") ===
|
|
15222
|
-
"jsenv:importmap"
|
|
15223
|
-
) {
|
|
15224
|
-
return;
|
|
15225
|
-
}
|
|
15060
|
+
const hasScheme = (string) => {
|
|
15061
|
+
return /^[a-zA-Z]{2,}:/.test(string)
|
|
15062
|
+
};
|
|
15226
15063
|
|
|
15227
|
-
|
|
15228
|
-
|
|
15229
|
-
|
|
15230
|
-
|
|
15231
|
-
|
|
15232
|
-
const externalRef = visitSrc(scriptNode, {
|
|
15233
|
-
type: "script",
|
|
15234
|
-
subtype: type,
|
|
15235
|
-
expectedType: type,
|
|
15236
|
-
});
|
|
15237
|
-
if (externalRef) {
|
|
15238
|
-
return;
|
|
15239
|
-
}
|
|
15240
|
-
}
|
|
15064
|
+
const urlToScheme = (urlString) => {
|
|
15065
|
+
const colonIndex = urlString.indexOf(":");
|
|
15066
|
+
if (colonIndex === -1) return ""
|
|
15067
|
+
return urlString.slice(0, colonIndex)
|
|
15068
|
+
};
|
|
15241
15069
|
|
|
15242
|
-
|
|
15243
|
-
|
|
15244
|
-
|
|
15245
|
-
}
|
|
15246
|
-
// If the inline script was already handled by an other plugin, ignore it
|
|
15247
|
-
// - we want to preserve inline scripts generated by html supervisor during dev
|
|
15248
|
-
// - we want to avoid cooking twice a script during build
|
|
15249
|
-
if (
|
|
15250
|
-
!inlineConvertedScript &&
|
|
15251
|
-
getHtmlNodeAttribute(scriptNode, "jsenv-injected-by") ===
|
|
15252
|
-
"jsenv:js_module_fallback"
|
|
15253
|
-
) {
|
|
15254
|
-
return;
|
|
15255
|
-
}
|
|
15070
|
+
const urlToPathname = (urlString) => {
|
|
15071
|
+
return ressourceToPathname(urlToRessource(urlString))
|
|
15072
|
+
};
|
|
15256
15073
|
|
|
15257
|
-
|
|
15258
|
-
|
|
15259
|
-
subtype,
|
|
15260
|
-
expectedType: type,
|
|
15261
|
-
contentType,
|
|
15262
|
-
});
|
|
15263
|
-
if (inlineRef) {
|
|
15264
|
-
// 1. <script type="jsx"> becomes <script>
|
|
15265
|
-
if (type === "js_classic" && extension !== ".js") {
|
|
15266
|
-
mutations.push(() => {
|
|
15267
|
-
setHtmlNodeAttributes(scriptNode, {
|
|
15268
|
-
type: undefined,
|
|
15269
|
-
});
|
|
15270
|
-
});
|
|
15271
|
-
}
|
|
15272
|
-
// 2. <script type="module/jsx"> becomes <script type="module">
|
|
15273
|
-
if (type === "js_module" && extension !== ".js") {
|
|
15274
|
-
mutations.push(() => {
|
|
15275
|
-
setHtmlNodeAttributes(scriptNode, {
|
|
15276
|
-
type: "module",
|
|
15277
|
-
});
|
|
15278
|
-
});
|
|
15279
|
-
}
|
|
15280
|
-
}
|
|
15281
|
-
},
|
|
15282
|
-
a: (aNode) => {
|
|
15283
|
-
visitHref(aNode, {
|
|
15284
|
-
type: "a_href",
|
|
15285
|
-
});
|
|
15286
|
-
},
|
|
15287
|
-
iframe: (iframeNode) => {
|
|
15288
|
-
visitSrc(iframeNode, {
|
|
15289
|
-
type: "iframe_src",
|
|
15290
|
-
});
|
|
15291
|
-
},
|
|
15292
|
-
img: (imgNode) => {
|
|
15293
|
-
visitSrc(imgNode, {
|
|
15294
|
-
type: "img_src",
|
|
15295
|
-
});
|
|
15296
|
-
visitSrcset(imgNode, {
|
|
15297
|
-
type: "img_srcset",
|
|
15298
|
-
});
|
|
15299
|
-
},
|
|
15300
|
-
source: (sourceNode) => {
|
|
15301
|
-
visitSrc(sourceNode, {
|
|
15302
|
-
type: "source_src",
|
|
15303
|
-
});
|
|
15304
|
-
visitSrcset(sourceNode, {
|
|
15305
|
-
type: "source_srcset",
|
|
15306
|
-
});
|
|
15307
|
-
},
|
|
15308
|
-
// svg <image> tag
|
|
15309
|
-
image: (imageNode) => {
|
|
15310
|
-
visitHref(imageNode, {
|
|
15311
|
-
type: "image_href",
|
|
15312
|
-
});
|
|
15313
|
-
},
|
|
15314
|
-
use: (useNode) => {
|
|
15315
|
-
visitHref(useNode, {
|
|
15316
|
-
type: "use_href",
|
|
15317
|
-
});
|
|
15318
|
-
},
|
|
15319
|
-
});
|
|
15320
|
-
finalizeCallbacks.forEach((finalizeCallback) => {
|
|
15321
|
-
finalizeCallback();
|
|
15322
|
-
});
|
|
15074
|
+
const urlToRessource = (urlString) => {
|
|
15075
|
+
const scheme = urlToScheme(urlString);
|
|
15323
15076
|
|
|
15324
|
-
if (
|
|
15325
|
-
|
|
15077
|
+
if (scheme === "file") {
|
|
15078
|
+
return urlString.slice("file://".length)
|
|
15326
15079
|
}
|
|
15327
|
-
|
|
15328
|
-
|
|
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)
|
|
15329
15086
|
}
|
|
15330
|
-
|
|
15331
|
-
return
|
|
15087
|
+
|
|
15088
|
+
return urlString.slice(scheme.length + 1)
|
|
15332
15089
|
};
|
|
15333
15090
|
|
|
15334
|
-
const
|
|
15335
|
-
const
|
|
15336
|
-
|
|
15337
|
-
|
|
15338
|
-
|
|
15339
|
-
|
|
15340
|
-
|
|
15091
|
+
const ressourceToPathname = (ressource) => {
|
|
15092
|
+
const searchSeparatorIndex = ressource.indexOf("?");
|
|
15093
|
+
return searchSeparatorIndex === -1
|
|
15094
|
+
? ressource
|
|
15095
|
+
: ressource.slice(0, searchSeparatorIndex)
|
|
15096
|
+
};
|
|
15097
|
+
|
|
15098
|
+
const urlToOrigin = (urlString) => {
|
|
15099
|
+
const scheme = urlToScheme(urlString);
|
|
15100
|
+
|
|
15101
|
+
if (scheme === "file") {
|
|
15102
|
+
return "file://"
|
|
15341
15103
|
}
|
|
15342
|
-
|
|
15343
|
-
|
|
15344
|
-
|
|
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)
|
|
15345
15111
|
}
|
|
15346
|
-
|
|
15112
|
+
|
|
15113
|
+
return urlString.slice(0, scheme.length + 1)
|
|
15347
15114
|
};
|
|
15348
15115
|
|
|
15349
|
-
const
|
|
15350
|
-
const
|
|
15351
|
-
if (
|
|
15352
|
-
return "
|
|
15116
|
+
const pathnameToParentPathname = (pathname) => {
|
|
15117
|
+
const slashLastIndex = pathname.lastIndexOf("/");
|
|
15118
|
+
if (slashLastIndex === -1) {
|
|
15119
|
+
return "/"
|
|
15353
15120
|
}
|
|
15354
|
-
|
|
15355
|
-
|
|
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 }))
|
|
15132
|
+
}
|
|
15133
|
+
if (!hasScheme(baseUrl)) {
|
|
15134
|
+
throw new Error(writeBaseUrlMustBeAbsolute({ baseUrl, specifier }))
|
|
15135
|
+
}
|
|
15356
15136
|
}
|
|
15357
|
-
|
|
15358
|
-
|
|
15137
|
+
|
|
15138
|
+
if (hasScheme(specifier)) {
|
|
15139
|
+
return specifier
|
|
15359
15140
|
}
|
|
15360
|
-
|
|
15361
|
-
|
|
15362
|
-
|
|
15363
|
-
if (as === "document") {
|
|
15364
|
-
return "html";
|
|
15365
|
-
}
|
|
15366
|
-
if (as === "style") {
|
|
15367
|
-
return "css";
|
|
15368
|
-
}
|
|
15369
|
-
if (as === "script") {
|
|
15370
|
-
for (const referenceToOther of htmlUrlInfo.referenceToOthersSet) {
|
|
15371
|
-
if (referenceToOther.url !== linkReference.url) {
|
|
15372
|
-
continue;
|
|
15373
|
-
}
|
|
15374
|
-
if (referenceToOther.type !== "script") {
|
|
15375
|
-
continue;
|
|
15376
|
-
}
|
|
15377
|
-
return referenceToOther.expectedType;
|
|
15378
|
-
}
|
|
15379
|
-
return undefined;
|
|
15380
|
-
}
|
|
15141
|
+
|
|
15142
|
+
if (!baseUrl) {
|
|
15143
|
+
throw new Error(writeBaseUrlRequired({ baseUrl, specifier }))
|
|
15381
15144
|
}
|
|
15382
|
-
return undefined;
|
|
15383
|
-
};
|
|
15384
15145
|
|
|
15385
|
-
//
|
|
15386
|
-
|
|
15387
|
-
|
|
15388
|
-
|
|
15389
|
-
// return new URL(url, baseUrl).href;
|
|
15390
|
-
// };
|
|
15146
|
+
// scheme relative
|
|
15147
|
+
if (specifier.slice(0, 2) === "//") {
|
|
15148
|
+
return `${urlToScheme(baseUrl)}:${specifier}`
|
|
15149
|
+
}
|
|
15391
15150
|
|
|
15392
|
-
//
|
|
15151
|
+
// origin relative
|
|
15152
|
+
if (specifier[0] === "/") {
|
|
15153
|
+
return `${urlToOrigin(baseUrl)}${specifier}`
|
|
15154
|
+
}
|
|
15393
15155
|
|
|
15394
|
-
const
|
|
15395
|
-
|
|
15396
|
-
name: "jsenv:webmanifest_reference_analysis",
|
|
15397
|
-
appliesDuring: "*",
|
|
15398
|
-
transformUrlContent: {
|
|
15399
|
-
webmanifest: parseAndTransformWebmanifestUrls,
|
|
15400
|
-
},
|
|
15401
|
-
};
|
|
15402
|
-
};
|
|
15156
|
+
const baseOrigin = urlToOrigin(baseUrl);
|
|
15157
|
+
const basePathname = urlToPathname(baseUrl);
|
|
15403
15158
|
|
|
15404
|
-
|
|
15405
|
-
|
|
15406
|
-
|
|
15407
|
-
|
|
15408
|
-
const { icons = [] } = manifest;
|
|
15409
|
-
icons.forEach((icon) => {
|
|
15410
|
-
const iconReference = urlInfo.dependencies.found({
|
|
15411
|
-
type: "webmanifest_icon_src",
|
|
15412
|
-
specifier: icon.src,
|
|
15413
|
-
});
|
|
15414
|
-
actions.push(async () => {
|
|
15415
|
-
await iconReference.readGeneratedSpecifier();
|
|
15416
|
-
icon.src = iconReference.generatedSpecifier;
|
|
15417
|
-
});
|
|
15418
|
-
});
|
|
15159
|
+
if (specifier === ".") {
|
|
15160
|
+
const baseDirectoryPathname = pathnameToParentPathname(basePathname);
|
|
15161
|
+
return `${baseOrigin}${baseDirectoryPathname}`
|
|
15162
|
+
}
|
|
15419
15163
|
|
|
15420
|
-
|
|
15421
|
-
|
|
15164
|
+
// pathname relative inside
|
|
15165
|
+
if (specifier.slice(0, 2) === "./") {
|
|
15166
|
+
const baseDirectoryPathname = pathnameToParentPathname(basePathname);
|
|
15167
|
+
return `${baseOrigin}${baseDirectoryPathname}${specifier.slice(2)}`
|
|
15422
15168
|
}
|
|
15423
|
-
await Promise.all(actions.map((action) => action()));
|
|
15424
|
-
return JSON.stringify(manifest, null, " ");
|
|
15425
|
-
};
|
|
15426
15169
|
|
|
15427
|
-
|
|
15428
|
-
|
|
15429
|
-
|
|
15170
|
+
// pathname relative outside
|
|
15171
|
+
if (specifier.slice(0, 3) === "../") {
|
|
15172
|
+
let unresolvedPathname = specifier;
|
|
15173
|
+
const importerFolders = basePathname.split("/");
|
|
15174
|
+
importerFolders.pop();
|
|
15430
15175
|
|
|
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
|
+
}
|
|
15431
15184
|
|
|
15432
|
-
const
|
|
15433
|
-
|
|
15434
|
-
|
|
15435
|
-
|
|
15436
|
-
|
|
15437
|
-
css: parseAndTransformCssUrls,
|
|
15438
|
-
},
|
|
15439
|
-
};
|
|
15440
|
-
};
|
|
15185
|
+
const resolvedPathname = `${importerFolders.join(
|
|
15186
|
+
"/",
|
|
15187
|
+
)}/${unresolvedPathname}`;
|
|
15188
|
+
return `${baseOrigin}${resolvedPathname}`
|
|
15189
|
+
}
|
|
15441
15190
|
|
|
15442
|
-
|
|
15443
|
-
|
|
15444
|
-
|
|
15445
|
-
url: urlInfo.originalUrl,
|
|
15446
|
-
});
|
|
15447
|
-
const actions = [];
|
|
15448
|
-
const magicSource = createMagicSource(urlInfo.content);
|
|
15449
|
-
for (const cssUrl of cssUrls) {
|
|
15450
|
-
const reference = urlInfo.dependencies.found({
|
|
15451
|
-
type: cssUrl.type,
|
|
15452
|
-
specifier: cssUrl.specifier,
|
|
15453
|
-
specifierStart: cssUrl.start,
|
|
15454
|
-
specifierEnd: cssUrl.end,
|
|
15455
|
-
specifierLine: cssUrl.line,
|
|
15456
|
-
specifierColumn: cssUrl.column,
|
|
15457
|
-
});
|
|
15458
|
-
actions.push(async () => {
|
|
15459
|
-
await reference.readGeneratedSpecifier();
|
|
15460
|
-
const replacement = reference.generatedSpecifier;
|
|
15461
|
-
magicSource.replace({
|
|
15462
|
-
start: cssUrl.start,
|
|
15463
|
-
end: cssUrl.end,
|
|
15464
|
-
replacement,
|
|
15465
|
-
});
|
|
15466
|
-
});
|
|
15191
|
+
// bare
|
|
15192
|
+
if (basePathname === "") {
|
|
15193
|
+
return `${baseOrigin}/${specifier}`
|
|
15467
15194
|
}
|
|
15468
|
-
if (
|
|
15469
|
-
|
|
15195
|
+
if (basePathname[basePathname.length] === "/") {
|
|
15196
|
+
return `${baseOrigin}${basePathname}${specifier}`
|
|
15470
15197
|
}
|
|
15471
|
-
return
|
|
15198
|
+
return `${baseOrigin}${pathnameToParentPathname(basePathname)}${specifier}`
|
|
15472
15199
|
};
|
|
15473
15200
|
|
|
15474
|
-
const
|
|
15475
|
-
|
|
15476
|
-
|
|
15477
|
-
|
|
15478
|
-
|
|
15479
|
-
|
|
15480
|
-
|
|
15481
|
-
|
|
15482
|
-
|
|
15483
|
-
|
|
15484
|
-
|
|
15485
|
-
|
|
15486
|
-
|
|
15487
|
-
|
|
15488
|
-
|
|
15489
|
-
|
|
15490
|
-
|
|
15491
|
-
|
|
15492
|
-
|
|
15493
|
-
|
|
15494
|
-
|
|
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
|
|
15495
15231
|
};
|
|
15496
15232
|
|
|
15497
|
-
const
|
|
15498
|
-
|
|
15499
|
-
|
|
15500
|
-
|
|
15501
|
-
|
|
15502
|
-
|
|
15503
|
-
|
|
15504
|
-
|
|
15505
|
-
|
|
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
|
+
}
|
|
15506
15242
|
|
|
15507
|
-
|
|
15508
|
-
|
|
15509
|
-
|
|
15510
|
-
});
|
|
15511
|
-
let { quote } = inlineReferenceInfo;
|
|
15512
|
-
if (quote === "`" && !canUseTemplateLiterals) {
|
|
15513
|
-
// if quote is "`" and template literals are not supported
|
|
15514
|
-
// we'll use a regular string (single or double quote)
|
|
15515
|
-
// when rendering the string
|
|
15516
|
-
quote = JS_QUOTES.pickBest(inlineReferenceInfo.content);
|
|
15517
|
-
}
|
|
15518
|
-
const inlineReference = urlInfo.dependencies.foundInline({
|
|
15519
|
-
type: "js_inline_content",
|
|
15520
|
-
subtype: inlineReferenceInfo.type, // "new_blob_first_arg", "new_inline_content_first_arg", "json_parse_first_arg"
|
|
15521
|
-
isOriginalPosition: urlInfo.content === urlInfo.originalContent,
|
|
15522
|
-
specifierLine: inlineReferenceInfo.line,
|
|
15523
|
-
specifierColumn: inlineReferenceInfo.column,
|
|
15524
|
-
specifier: inlineUrl,
|
|
15525
|
-
contentType: inlineReferenceInfo.contentType,
|
|
15526
|
-
content: inlineReferenceInfo.content,
|
|
15527
|
-
});
|
|
15528
|
-
const inlineUrlInfo = inlineReference.urlInfo;
|
|
15529
|
-
inlineUrlInfo.jsQuote = quote;
|
|
15530
|
-
inlineReference.escape = (value) => {
|
|
15531
|
-
return JS_QUOTES.escapeSpecialChars(value.slice(1, -1), { quote });
|
|
15532
|
-
};
|
|
15243
|
+
if (hasScheme(specifier)) {
|
|
15244
|
+
return specifier
|
|
15245
|
+
}
|
|
15533
15246
|
|
|
15534
|
-
|
|
15535
|
-
|
|
15536
|
-
|
|
15537
|
-
|
|
15538
|
-
|
|
15539
|
-
|
|
15540
|
-
|
|
15541
|
-
|
|
15542
|
-
|
|
15543
|
-
|
|
15544
|
-
|
|
15545
|
-
|
|
15546
|
-
|
|
15547
|
-
|
|
15548
|
-
|
|
15549
|
-
|
|
15550
|
-
|
|
15551
|
-
|
|
15552
|
-
|
|
15553
|
-
|
|
15554
|
-
|
|
15555
|
-
|
|
15556
|
-
|
|
15557
|
-
|
|
15558
|
-
|
|
15559
|
-
|
|
15560
|
-
|
|
15561
|
-
|
|
15562
|
-
|
|
15563
|
-
|
|
15564
|
-
|
|
15247
|
+
return null
|
|
15248
|
+
};
|
|
15249
|
+
|
|
15250
|
+
const applyImportMap = ({
|
|
15251
|
+
importMap,
|
|
15252
|
+
specifier,
|
|
15253
|
+
importer,
|
|
15254
|
+
createBareSpecifierError = ({ specifier, importer }) => {
|
|
15255
|
+
return new Error(
|
|
15256
|
+
createDetailedMessage(`Unmapped bare specifier.`, {
|
|
15257
|
+
specifier,
|
|
15258
|
+
importer,
|
|
15259
|
+
}),
|
|
15260
|
+
)
|
|
15261
|
+
},
|
|
15262
|
+
onImportMapping = () => {},
|
|
15263
|
+
}) => {
|
|
15264
|
+
assertImportMap(importMap);
|
|
15265
|
+
if (typeof specifier !== "string") {
|
|
15266
|
+
throw new TypeError(
|
|
15267
|
+
createDetailedMessage("specifier must be a string.", {
|
|
15268
|
+
specifier,
|
|
15269
|
+
importer,
|
|
15270
|
+
}),
|
|
15271
|
+
)
|
|
15272
|
+
}
|
|
15273
|
+
if (importer) {
|
|
15274
|
+
if (typeof importer !== "string") {
|
|
15275
|
+
throw new TypeError(
|
|
15276
|
+
createDetailedMessage("importer must be a string.", {
|
|
15277
|
+
importer,
|
|
15278
|
+
specifier,
|
|
15279
|
+
}),
|
|
15280
|
+
)
|
|
15565
15281
|
}
|
|
15566
|
-
|
|
15567
|
-
|
|
15568
|
-
|
|
15569
|
-
|
|
15570
|
-
|
|
15571
|
-
|
|
15572
|
-
|
|
15573
|
-
specifierEnd: externalReferenceInfo.end,
|
|
15574
|
-
specifierLine: externalReferenceInfo.line,
|
|
15575
|
-
specifierColumn: externalReferenceInfo.column,
|
|
15576
|
-
data: externalReferenceInfo.data,
|
|
15577
|
-
baseUrl: {
|
|
15578
|
-
"StringLiteral": externalReferenceInfo.baseUrl,
|
|
15579
|
-
"window.location": urlInfo.url,
|
|
15580
|
-
"window.origin": urlInfo.context.rootDirectoryUrl,
|
|
15581
|
-
"import.meta.url": urlInfo.url,
|
|
15582
|
-
"context.meta.url": urlInfo.url,
|
|
15583
|
-
"document.currentScript.src": urlInfo.url,
|
|
15584
|
-
}[externalReferenceInfo.baseUrlType],
|
|
15585
|
-
importAttributes: externalReferenceInfo.importAttributes,
|
|
15586
|
-
astInfo: externalReferenceInfo.astInfo,
|
|
15587
|
-
});
|
|
15588
|
-
parallelActions.push(async () => {
|
|
15589
|
-
await reference.readGeneratedSpecifier();
|
|
15590
|
-
const replacement = reference.generatedSpecifier;
|
|
15591
|
-
magicSource.replace({
|
|
15592
|
-
start: externalReferenceInfo.start,
|
|
15593
|
-
end: externalReferenceInfo.end,
|
|
15594
|
-
replacement,
|
|
15595
|
-
});
|
|
15596
|
-
if (reference.mutation) {
|
|
15597
|
-
reference.mutation(magicSource, urlInfo);
|
|
15598
|
-
}
|
|
15599
|
-
});
|
|
15600
|
-
};
|
|
15601
|
-
const jsReferenceInfos = parseJsUrls({
|
|
15602
|
-
js: urlInfo.content,
|
|
15603
|
-
url: urlInfo.originalUrl,
|
|
15604
|
-
ast: urlInfo.contentAst,
|
|
15605
|
-
isJsModule: urlInfo.type === "js_module",
|
|
15606
|
-
isWebWorker: isWebWorkerUrlInfo(urlInfo),
|
|
15607
|
-
inlineContent,
|
|
15608
|
-
isNodeJs,
|
|
15609
|
-
});
|
|
15610
|
-
for (const jsReferenceInfo of jsReferenceInfos) {
|
|
15611
|
-
if (jsReferenceInfo.isInline) {
|
|
15612
|
-
onInlineReference(jsReferenceInfo);
|
|
15613
|
-
} else {
|
|
15614
|
-
onExternalReference(jsReferenceInfo);
|
|
15282
|
+
if (!hasScheme(importer)) {
|
|
15283
|
+
throw new Error(
|
|
15284
|
+
createDetailedMessage(`importer must be an absolute url.`, {
|
|
15285
|
+
importer,
|
|
15286
|
+
specifier,
|
|
15287
|
+
}),
|
|
15288
|
+
)
|
|
15615
15289
|
}
|
|
15616
15290
|
}
|
|
15617
|
-
if (parallelActions.length > 0) {
|
|
15618
|
-
await Promise.all(parallelActions.map((action) => action()));
|
|
15619
|
-
}
|
|
15620
|
-
if (sequentialActions.length > 0) {
|
|
15621
|
-
await sequentialActions.reduce(async (previous, action) => {
|
|
15622
|
-
await previous;
|
|
15623
|
-
await action();
|
|
15624
|
-
}, Promise.resolve());
|
|
15625
|
-
}
|
|
15626
|
-
|
|
15627
|
-
const { content, sourcemap } = magicSource.toContentAndSourcemap();
|
|
15628
|
-
return { content, sourcemap };
|
|
15629
|
-
};
|
|
15630
15291
|
|
|
15631
|
-
const
|
|
15632
|
-
|
|
15633
|
-
inlineConvertedScript = false,
|
|
15634
|
-
fetchInlineUrls = true,
|
|
15635
|
-
}) => {
|
|
15636
|
-
return [
|
|
15637
|
-
jsenvPluginDirectoryReferenceAnalysis(),
|
|
15638
|
-
jsenvPluginHtmlReferenceAnalysis({
|
|
15639
|
-
inlineContent,
|
|
15640
|
-
inlineConvertedScript,
|
|
15641
|
-
}),
|
|
15642
|
-
jsenvPluginWebmanifestReferenceAnalysis(),
|
|
15643
|
-
jsenvPluginCssReferenceAnalysis(),
|
|
15644
|
-
jsenvPluginJsReferenceAnalysis({
|
|
15645
|
-
inlineContent,
|
|
15646
|
-
}),
|
|
15647
|
-
...(inlineContent ? [jsenvPluginDataUrlsAnalysis()] : []),
|
|
15648
|
-
...(inlineContent && fetchInlineUrls
|
|
15649
|
-
? [jsenvPluginInlineContentFetcher()]
|
|
15650
|
-
: []),
|
|
15651
|
-
jsenvPluginReferenceExpectedTypes(),
|
|
15652
|
-
];
|
|
15653
|
-
};
|
|
15292
|
+
const specifierUrl = resolveSpecifier(specifier, importer);
|
|
15293
|
+
const specifierNormalized = specifierUrl || specifier;
|
|
15654
15294
|
|
|
15655
|
-
const
|
|
15656
|
-
|
|
15657
|
-
|
|
15658
|
-
|
|
15659
|
-
|
|
15660
|
-
|
|
15661
|
-
|
|
15662
|
-
|
|
15663
|
-
|
|
15664
|
-
|
|
15665
|
-
|
|
15666
|
-
|
|
15667
|
-
|
|
15668
|
-
|
|
15669
|
-
|
|
15670
|
-
|
|
15671
|
-
|
|
15672
|
-
|
|
15673
|
-
if (
|
|
15674
|
-
|
|
15675
|
-
if (lastInlineReference.content === undefined) {
|
|
15676
|
-
const originalUrlInfo = prev.urlInfo;
|
|
15677
|
-
await originalUrlInfo.cook();
|
|
15678
|
-
lastInlineReference.content = originalUrlInfo.content;
|
|
15679
|
-
lastInlineReference.contentType = originalUrlInfo.contentType;
|
|
15680
|
-
}
|
|
15295
|
+
const { scopes } = importMap;
|
|
15296
|
+
if (scopes && importer) {
|
|
15297
|
+
const scopeSpecifierMatching = Object.keys(scopes).find(
|
|
15298
|
+
(scopeSpecifier) => {
|
|
15299
|
+
return (
|
|
15300
|
+
scopeSpecifier === importer ||
|
|
15301
|
+
specifierIsPrefixOf(scopeSpecifier, importer)
|
|
15302
|
+
)
|
|
15303
|
+
},
|
|
15304
|
+
);
|
|
15305
|
+
if (scopeSpecifierMatching) {
|
|
15306
|
+
const scopeMappings = scopes[scopeSpecifierMatching];
|
|
15307
|
+
const mappingFromScopes = applyMappings(
|
|
15308
|
+
scopeMappings,
|
|
15309
|
+
specifierNormalized,
|
|
15310
|
+
scopeSpecifierMatching,
|
|
15311
|
+
onImportMapping,
|
|
15312
|
+
);
|
|
15313
|
+
if (mappingFromScopes !== null) {
|
|
15314
|
+
return mappingFromScopes
|
|
15681
15315
|
}
|
|
15682
|
-
|
|
15683
|
-
|
|
15684
|
-
content: lastInlineReference.content,
|
|
15685
|
-
contentType: lastInlineReference.contentType,
|
|
15686
|
-
};
|
|
15687
|
-
},
|
|
15688
|
-
};
|
|
15689
|
-
};
|
|
15316
|
+
}
|
|
15317
|
+
}
|
|
15690
15318
|
|
|
15691
|
-
|
|
15692
|
-
|
|
15693
|
-
|
|
15319
|
+
const { imports } = importMap;
|
|
15320
|
+
if (imports) {
|
|
15321
|
+
const mappingFromImports = applyMappings(
|
|
15322
|
+
imports,
|
|
15323
|
+
specifierNormalized,
|
|
15324
|
+
undefined,
|
|
15325
|
+
onImportMapping,
|
|
15326
|
+
);
|
|
15327
|
+
if (mappingFromImports !== null) {
|
|
15328
|
+
return mappingFromImports
|
|
15329
|
+
}
|
|
15330
|
+
}
|
|
15694
15331
|
|
|
15695
|
-
|
|
15696
|
-
|
|
15697
|
-
|
|
15698
|
-
--- ${key} ---
|
|
15699
|
-
${
|
|
15700
|
-
Array.isArray(value)
|
|
15701
|
-
? value.join(`
|
|
15702
|
-
`)
|
|
15703
|
-
: value
|
|
15704
|
-
}`;
|
|
15705
|
-
});
|
|
15332
|
+
if (specifierUrl) {
|
|
15333
|
+
return specifierUrl
|
|
15334
|
+
}
|
|
15706
15335
|
|
|
15707
|
-
|
|
15336
|
+
throw createBareSpecifierError({ specifier, importer })
|
|
15708
15337
|
};
|
|
15709
15338
|
|
|
15710
|
-
const
|
|
15711
|
-
|
|
15712
|
-
|
|
15713
|
-
|
|
15339
|
+
const applyMappings = (
|
|
15340
|
+
mappings,
|
|
15341
|
+
specifierNormalized,
|
|
15342
|
+
scope,
|
|
15343
|
+
onImportMapping,
|
|
15344
|
+
) => {
|
|
15345
|
+
const specifierCandidates = Object.keys(mappings);
|
|
15714
15346
|
|
|
15715
|
-
|
|
15716
|
-
|
|
15717
|
-
|
|
15347
|
+
let i = 0;
|
|
15348
|
+
while (i < specifierCandidates.length) {
|
|
15349
|
+
const specifierCandidate = specifierCandidates[i];
|
|
15350
|
+
i++;
|
|
15351
|
+
if (specifierCandidate === specifierNormalized) {
|
|
15352
|
+
const address = mappings[specifierCandidate];
|
|
15353
|
+
onImportMapping({
|
|
15354
|
+
scope,
|
|
15355
|
+
from: specifierCandidate,
|
|
15356
|
+
to: address,
|
|
15357
|
+
before: specifierNormalized,
|
|
15358
|
+
after: address,
|
|
15359
|
+
});
|
|
15360
|
+
return address
|
|
15361
|
+
}
|
|
15362
|
+
if (specifierIsPrefixOf(specifierCandidate, specifierNormalized)) {
|
|
15363
|
+
const address = mappings[specifierCandidate];
|
|
15364
|
+
const afterSpecifier = specifierNormalized.slice(
|
|
15365
|
+
specifierCandidate.length,
|
|
15366
|
+
);
|
|
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
|
+
}
|
|
15718
15377
|
}
|
|
15719
15378
|
|
|
15720
|
-
|
|
15721
|
-
throw new TypeError(
|
|
15722
|
-
`an importMap must be an object, received array ${value}`,
|
|
15723
|
-
)
|
|
15724
|
-
}
|
|
15379
|
+
return null
|
|
15725
15380
|
};
|
|
15726
15381
|
|
|
15727
|
-
const
|
|
15728
|
-
return
|
|
15382
|
+
const specifierIsPrefixOf = (specifierHref, href) => {
|
|
15383
|
+
return (
|
|
15384
|
+
specifierHref[specifierHref.length - 1] === "/" &&
|
|
15385
|
+
href.startsWith(specifierHref)
|
|
15386
|
+
)
|
|
15729
15387
|
};
|
|
15730
15388
|
|
|
15731
|
-
|
|
15732
|
-
const colonIndex = urlString.indexOf(":");
|
|
15733
|
-
if (colonIndex === -1) return ""
|
|
15734
|
-
return urlString.slice(0, colonIndex)
|
|
15735
|
-
};
|
|
15389
|
+
// https://github.com/systemjs/systemjs/blob/89391f92dfeac33919b0223bbf834a1f4eea5750/src/common.js#L136
|
|
15736
15390
|
|
|
15737
|
-
const
|
|
15738
|
-
|
|
15739
|
-
|
|
15391
|
+
const composeTwoImportMaps = (leftImportMap, rightImportMap) => {
|
|
15392
|
+
assertImportMap(leftImportMap);
|
|
15393
|
+
assertImportMap(rightImportMap);
|
|
15740
15394
|
|
|
15741
|
-
const
|
|
15742
|
-
const scheme = urlToScheme(urlString);
|
|
15395
|
+
const importMap = {};
|
|
15743
15396
|
|
|
15744
|
-
|
|
15745
|
-
|
|
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 };
|
|
15746
15407
|
}
|
|
15747
15408
|
|
|
15748
|
-
|
|
15749
|
-
|
|
15750
|
-
|
|
15751
|
-
|
|
15752
|
-
|
|
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 };
|
|
15753
15423
|
}
|
|
15754
15424
|
|
|
15755
|
-
return
|
|
15756
|
-
};
|
|
15757
|
-
|
|
15758
|
-
const ressourceToPathname = (ressource) => {
|
|
15759
|
-
const searchSeparatorIndex = ressource.indexOf("?");
|
|
15760
|
-
return searchSeparatorIndex === -1
|
|
15761
|
-
? ressource
|
|
15762
|
-
: ressource.slice(0, searchSeparatorIndex)
|
|
15425
|
+
return importMap
|
|
15763
15426
|
};
|
|
15764
15427
|
|
|
15765
|
-
const
|
|
15766
|
-
const
|
|
15767
|
-
|
|
15768
|
-
if (scheme === "file") {
|
|
15769
|
-
return "file://"
|
|
15770
|
-
}
|
|
15428
|
+
const composeTwoMappings = (leftMappings, rightMappings) => {
|
|
15429
|
+
const mappings = {};
|
|
15771
15430
|
|
|
15772
|
-
|
|
15773
|
-
|
|
15774
|
-
|
|
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
|
+
});
|
|
15775
15444
|
|
|
15776
|
-
|
|
15777
|
-
|
|
15778
|
-
}
|
|
15445
|
+
Object.keys(rightMappings).forEach((rightSpecifier) => {
|
|
15446
|
+
mappings[rightSpecifier] = rightMappings[rightSpecifier];
|
|
15447
|
+
});
|
|
15779
15448
|
|
|
15780
|
-
return
|
|
15449
|
+
return mappings
|
|
15781
15450
|
};
|
|
15782
15451
|
|
|
15783
|
-
const
|
|
15784
|
-
|
|
15785
|
-
if (slashLastIndex === -1) {
|
|
15786
|
-
return "/"
|
|
15787
|
-
}
|
|
15452
|
+
const objectHasKey = (object, key) =>
|
|
15453
|
+
Object.prototype.hasOwnProperty.call(object, key);
|
|
15788
15454
|
|
|
15789
|
-
|
|
15455
|
+
const compareAddressAndSpecifier = (address, specifier) => {
|
|
15456
|
+
const addressUrl = resolveUrl(address, "file:///");
|
|
15457
|
+
const specifierUrl = resolveUrl(specifier, "file:///");
|
|
15458
|
+
return addressUrl === specifierUrl
|
|
15790
15459
|
};
|
|
15791
15460
|
|
|
15792
|
-
|
|
15793
|
-
|
|
15461
|
+
const composeTwoScopes = (leftScopes, rightScopes, imports) => {
|
|
15462
|
+
const scopes = {};
|
|
15794
15463
|
|
|
15795
|
-
|
|
15796
|
-
|
|
15797
|
-
|
|
15798
|
-
|
|
15464
|
+
Object.keys(leftScopes).forEach((leftScopeKey) => {
|
|
15465
|
+
if (objectHasKey(rightScopes, leftScopeKey)) {
|
|
15466
|
+
// will be merged
|
|
15467
|
+
scopes[leftScopeKey] = leftScopes[leftScopeKey];
|
|
15468
|
+
return
|
|
15799
15469
|
}
|
|
15800
|
-
|
|
15801
|
-
|
|
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];
|
|
15802
15482
|
}
|
|
15803
|
-
}
|
|
15804
|
-
|
|
15805
|
-
if (hasScheme(specifier)) {
|
|
15806
|
-
return specifier
|
|
15807
|
-
}
|
|
15808
|
-
|
|
15809
|
-
if (!baseUrl) {
|
|
15810
|
-
throw new Error(writeBaseUrlRequired({ baseUrl, specifier }))
|
|
15811
|
-
}
|
|
15483
|
+
});
|
|
15812
15484
|
|
|
15813
|
-
|
|
15814
|
-
|
|
15815
|
-
|
|
15816
|
-
|
|
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
|
+
});
|
|
15817
15497
|
|
|
15818
|
-
|
|
15819
|
-
|
|
15820
|
-
return `${urlToOrigin(baseUrl)}${specifier}`
|
|
15821
|
-
}
|
|
15498
|
+
return scopes
|
|
15499
|
+
};
|
|
15822
15500
|
|
|
15823
|
-
|
|
15824
|
-
const
|
|
15501
|
+
const sortImports = (imports) => {
|
|
15502
|
+
const mappingsSorted = {};
|
|
15825
15503
|
|
|
15826
|
-
|
|
15827
|
-
|
|
15828
|
-
|
|
15829
|
-
|
|
15504
|
+
Object.keys(imports)
|
|
15505
|
+
.sort(compareLengthOrLocaleCompare)
|
|
15506
|
+
.forEach((name) => {
|
|
15507
|
+
mappingsSorted[name] = imports[name];
|
|
15508
|
+
});
|
|
15830
15509
|
|
|
15831
|
-
|
|
15832
|
-
|
|
15833
|
-
const baseDirectoryPathname = pathnameToParentPathname(basePathname);
|
|
15834
|
-
return `${baseOrigin}${baseDirectoryPathname}${specifier.slice(2)}`
|
|
15835
|
-
}
|
|
15510
|
+
return mappingsSorted
|
|
15511
|
+
};
|
|
15836
15512
|
|
|
15837
|
-
|
|
15838
|
-
|
|
15839
|
-
let unresolvedPathname = specifier;
|
|
15840
|
-
const importerFolders = basePathname.split("/");
|
|
15841
|
-
importerFolders.pop();
|
|
15513
|
+
const sortScopes = (scopes) => {
|
|
15514
|
+
const scopesSorted = {};
|
|
15842
15515
|
|
|
15843
|
-
|
|
15844
|
-
|
|
15845
|
-
|
|
15846
|
-
|
|
15847
|
-
|
|
15848
|
-
importerFolders.pop();
|
|
15849
|
-
}
|
|
15850
|
-
}
|
|
15516
|
+
Object.keys(scopes)
|
|
15517
|
+
.sort(compareLengthOrLocaleCompare)
|
|
15518
|
+
.forEach((scopeSpecifier) => {
|
|
15519
|
+
scopesSorted[scopeSpecifier] = sortImports(scopes[scopeSpecifier]);
|
|
15520
|
+
});
|
|
15851
15521
|
|
|
15852
|
-
|
|
15853
|
-
|
|
15854
|
-
)}/${unresolvedPathname}`;
|
|
15855
|
-
return `${baseOrigin}${resolvedPathname}`
|
|
15856
|
-
}
|
|
15522
|
+
return scopesSorted
|
|
15523
|
+
};
|
|
15857
15524
|
|
|
15858
|
-
|
|
15859
|
-
|
|
15860
|
-
return `${baseOrigin}/${specifier}`
|
|
15861
|
-
}
|
|
15862
|
-
if (basePathname[basePathname.length] === "/") {
|
|
15863
|
-
return `${baseOrigin}${basePathname}${specifier}`
|
|
15864
|
-
}
|
|
15865
|
-
return `${baseOrigin}${pathnameToParentPathname(basePathname)}${specifier}`
|
|
15525
|
+
const compareLengthOrLocaleCompare = (a, b) => {
|
|
15526
|
+
return b.length - a.length || a.localeCompare(b)
|
|
15866
15527
|
};
|
|
15867
15528
|
|
|
15868
|
-
const
|
|
15869
|
-
|
|
15870
|
-
specifier,
|
|
15871
|
-
}) => `baseUrl must be a string.
|
|
15872
|
-
--- base url ---
|
|
15873
|
-
${baseUrl}
|
|
15874
|
-
--- specifier ---
|
|
15875
|
-
${specifier}`;
|
|
15529
|
+
const normalizeImportMap = (importMap, baseUrl) => {
|
|
15530
|
+
assertImportMap(importMap);
|
|
15876
15531
|
|
|
15877
|
-
|
|
15878
|
-
|
|
15879
|
-
|
|
15880
|
-
}) => `baseUrl must be absolute.
|
|
15881
|
-
--- base url ---
|
|
15882
|
-
${baseUrl}
|
|
15883
|
-
--- specifier ---
|
|
15884
|
-
${specifier}`;
|
|
15532
|
+
if (!isStringOrUrl(baseUrl)) {
|
|
15533
|
+
throw new TypeError(formulateBaseUrlMustBeStringOrUrl({ baseUrl }))
|
|
15534
|
+
}
|
|
15885
15535
|
|
|
15886
|
-
const
|
|
15887
|
-
baseUrl,
|
|
15888
|
-
specifier,
|
|
15889
|
-
}) => `baseUrl required to resolve relative specifier.
|
|
15890
|
-
--- base url ---
|
|
15891
|
-
${baseUrl}
|
|
15892
|
-
--- specifier ---
|
|
15893
|
-
${specifier}`;
|
|
15536
|
+
const { imports, scopes } = importMap;
|
|
15894
15537
|
|
|
15895
|
-
|
|
15896
|
-
|
|
15897
|
-
|
|
15538
|
+
return {
|
|
15539
|
+
imports: imports ? normalizeMappings(imports, baseUrl) : undefined,
|
|
15540
|
+
scopes: scopes ? normalizeScopes(scopes, baseUrl) : undefined,
|
|
15541
|
+
}
|
|
15898
15542
|
};
|
|
15899
15543
|
|
|
15900
|
-
const
|
|
15901
|
-
if (
|
|
15902
|
-
|
|
15903
|
-
specifier[0] === "/" ||
|
|
15904
|
-
specifier.startsWith("./") ||
|
|
15905
|
-
specifier.startsWith("../")
|
|
15906
|
-
) {
|
|
15907
|
-
return resolveUrl(specifier, importer)
|
|
15544
|
+
const isStringOrUrl = (value) => {
|
|
15545
|
+
if (typeof value === "string") {
|
|
15546
|
+
return true
|
|
15908
15547
|
}
|
|
15909
15548
|
|
|
15910
|
-
if (
|
|
15911
|
-
return
|
|
15549
|
+
if (typeof URL === "function" && value instanceof URL) {
|
|
15550
|
+
return true
|
|
15912
15551
|
}
|
|
15913
15552
|
|
|
15914
|
-
return
|
|
15553
|
+
return false
|
|
15915
15554
|
};
|
|
15916
15555
|
|
|
15917
|
-
const
|
|
15918
|
-
|
|
15919
|
-
|
|
15920
|
-
|
|
15921
|
-
|
|
15922
|
-
|
|
15923
|
-
|
|
15924
|
-
|
|
15925
|
-
|
|
15926
|
-
|
|
15927
|
-
)
|
|
15928
|
-
},
|
|
15929
|
-
onImportMapping = () => {},
|
|
15930
|
-
}) => {
|
|
15931
|
-
assertImportMap(importMap);
|
|
15932
|
-
if (typeof specifier !== "string") {
|
|
15933
|
-
throw new TypeError(
|
|
15934
|
-
createDetailedMessage("specifier must be a string.", {
|
|
15935
|
-
specifier,
|
|
15936
|
-
importer,
|
|
15937
|
-
}),
|
|
15938
|
-
)
|
|
15939
|
-
}
|
|
15940
|
-
if (importer) {
|
|
15941
|
-
if (typeof importer !== "string") {
|
|
15942
|
-
throw new TypeError(
|
|
15943
|
-
createDetailedMessage("importer must be a string.", {
|
|
15944
|
-
importer,
|
|
15945
|
-
specifier,
|
|
15946
|
-
}),
|
|
15947
|
-
)
|
|
15948
|
-
}
|
|
15949
|
-
if (!hasScheme(importer)) {
|
|
15950
|
-
throw new Error(
|
|
15951
|
-
createDetailedMessage(`importer must be an absolute url.`, {
|
|
15952
|
-
importer,
|
|
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,
|
|
15953
15566
|
specifier,
|
|
15954
15567
|
}),
|
|
15955
|
-
)
|
|
15568
|
+
);
|
|
15569
|
+
return
|
|
15956
15570
|
}
|
|
15957
|
-
}
|
|
15958
15571
|
|
|
15959
|
-
|
|
15960
|
-
const specifierNormalized = specifierUrl || specifier;
|
|
15572
|
+
const specifierResolved = resolveSpecifier(specifier, baseUrl) || specifier;
|
|
15961
15573
|
|
|
15962
|
-
|
|
15963
|
-
|
|
15964
|
-
|
|
15965
|
-
|
|
15966
|
-
|
|
15967
|
-
|
|
15968
|
-
|
|
15969
|
-
)
|
|
15970
|
-
},
|
|
15971
|
-
);
|
|
15972
|
-
if (scopeSpecifierMatching) {
|
|
15973
|
-
const scopeMappings = scopes[scopeSpecifierMatching];
|
|
15974
|
-
const mappingFromScopes = applyMappings(
|
|
15975
|
-
scopeMappings,
|
|
15976
|
-
specifierNormalized,
|
|
15977
|
-
scopeSpecifierMatching,
|
|
15978
|
-
onImportMapping,
|
|
15574
|
+
const addressUrl = tryUrlResolution(address, baseUrl);
|
|
15575
|
+
if (addressUrl === null) {
|
|
15576
|
+
console.warn(
|
|
15577
|
+
formulateAdressResolutionFailed({
|
|
15578
|
+
address,
|
|
15579
|
+
baseUrl,
|
|
15580
|
+
specifier,
|
|
15581
|
+
}),
|
|
15979
15582
|
);
|
|
15980
|
-
|
|
15981
|
-
return mappingFromScopes
|
|
15982
|
-
}
|
|
15583
|
+
return
|
|
15983
15584
|
}
|
|
15984
|
-
}
|
|
15985
15585
|
|
|
15986
|
-
|
|
15987
|
-
|
|
15988
|
-
|
|
15989
|
-
|
|
15990
|
-
|
|
15991
|
-
|
|
15992
|
-
|
|
15993
|
-
|
|
15994
|
-
|
|
15995
|
-
return mappingFromImports
|
|
15586
|
+
if (specifier.endsWith("/") && !addressUrl.endsWith("/")) {
|
|
15587
|
+
console.warn(
|
|
15588
|
+
formulateAddressUrlRequiresTrailingSlash({
|
|
15589
|
+
addressUrl,
|
|
15590
|
+
address,
|
|
15591
|
+
specifier,
|
|
15592
|
+
}),
|
|
15593
|
+
);
|
|
15594
|
+
return
|
|
15996
15595
|
}
|
|
15997
|
-
|
|
15998
|
-
|
|
15999
|
-
if (specifierUrl) {
|
|
16000
|
-
return specifierUrl
|
|
16001
|
-
}
|
|
15596
|
+
mappingsNormalized[specifierResolved] = addressUrl;
|
|
15597
|
+
});
|
|
16002
15598
|
|
|
16003
|
-
|
|
15599
|
+
return sortImports(mappingsNormalized)
|
|
16004
15600
|
};
|
|
16005
15601
|
|
|
16006
|
-
const
|
|
16007
|
-
|
|
16008
|
-
specifierNormalized,
|
|
16009
|
-
scope,
|
|
16010
|
-
onImportMapping,
|
|
16011
|
-
) => {
|
|
16012
|
-
const specifierCandidates = Object.keys(mappings);
|
|
15602
|
+
const normalizeScopes = (scopes, baseUrl) => {
|
|
15603
|
+
const scopesNormalized = {};
|
|
16013
15604
|
|
|
16014
|
-
|
|
16015
|
-
|
|
16016
|
-
const
|
|
16017
|
-
|
|
16018
|
-
|
|
16019
|
-
|
|
16020
|
-
|
|
16021
|
-
|
|
16022
|
-
|
|
16023
|
-
to: address,
|
|
16024
|
-
before: specifierNormalized,
|
|
16025
|
-
after: address,
|
|
16026
|
-
});
|
|
16027
|
-
return address
|
|
16028
|
-
}
|
|
16029
|
-
if (specifierIsPrefixOf(specifierCandidate, specifierNormalized)) {
|
|
16030
|
-
const address = mappings[specifierCandidate];
|
|
16031
|
-
const afterSpecifier = specifierNormalized.slice(
|
|
16032
|
-
specifierCandidate.length,
|
|
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
|
+
}),
|
|
16033
15614
|
);
|
|
16034
|
-
|
|
16035
|
-
onImportMapping({
|
|
16036
|
-
scope,
|
|
16037
|
-
from: specifierCandidate,
|
|
16038
|
-
to: address,
|
|
16039
|
-
before: specifierNormalized,
|
|
16040
|
-
after: addressFinal,
|
|
16041
|
-
});
|
|
16042
|
-
return addressFinal
|
|
15615
|
+
return
|
|
16043
15616
|
}
|
|
16044
|
-
|
|
15617
|
+
const scopeValueNormalized = normalizeMappings(scopeMappings, baseUrl);
|
|
15618
|
+
scopesNormalized[scopeUrl] = scopeValueNormalized;
|
|
15619
|
+
});
|
|
16045
15620
|
|
|
16046
|
-
return
|
|
15621
|
+
return sortScopes(scopesNormalized)
|
|
16047
15622
|
};
|
|
16048
15623
|
|
|
16049
|
-
const
|
|
16050
|
-
|
|
16051
|
-
|
|
16052
|
-
|
|
16053
|
-
|
|
16054
|
-
|
|
15624
|
+
const formulateBaseUrlMustBeStringOrUrl = ({
|
|
15625
|
+
baseUrl,
|
|
15626
|
+
}) => `baseUrl must be a string or an url.
|
|
15627
|
+
--- base url ---
|
|
15628
|
+
${baseUrl}`;
|
|
15629
|
+
|
|
15630
|
+
const formulateAddressMustBeAString = ({
|
|
15631
|
+
specifier,
|
|
15632
|
+
address,
|
|
15633
|
+
}) => `Address must be a string.
|
|
15634
|
+
--- address ---
|
|
15635
|
+
${address}
|
|
15636
|
+
--- specifier ---
|
|
15637
|
+
${specifier}`;
|
|
15638
|
+
|
|
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}`;
|
|
15650
|
+
|
|
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}`;
|
|
16055
15662
|
|
|
16056
|
-
|
|
15663
|
+
const formulateScopeResolutionFailed = ({
|
|
15664
|
+
scope,
|
|
15665
|
+
baseUrl,
|
|
15666
|
+
}) => `Scope url resolution failed.
|
|
15667
|
+
--- scope ---
|
|
15668
|
+
${scope}
|
|
15669
|
+
--- base url ---
|
|
15670
|
+
${baseUrl}`;
|
|
16057
15671
|
|
|
16058
|
-
const
|
|
16059
|
-
|
|
16060
|
-
|
|
15672
|
+
const pathnameToExtension = (pathname) => {
|
|
15673
|
+
const slashLastIndex = pathname.lastIndexOf("/");
|
|
15674
|
+
if (slashLastIndex !== -1) {
|
|
15675
|
+
pathname = pathname.slice(slashLastIndex + 1);
|
|
15676
|
+
}
|
|
16061
15677
|
|
|
16062
|
-
const
|
|
15678
|
+
const dotLastIndex = pathname.lastIndexOf(".");
|
|
15679
|
+
if (dotLastIndex === -1) return ""
|
|
15680
|
+
// if (dotLastIndex === pathname.length - 1) return ""
|
|
15681
|
+
return pathname.slice(dotLastIndex)
|
|
15682
|
+
};
|
|
16063
15683
|
|
|
16064
|
-
|
|
16065
|
-
|
|
16066
|
-
|
|
16067
|
-
|
|
16068
|
-
|
|
16069
|
-
|
|
16070
|
-
|
|
16071
|
-
|
|
16072
|
-
|
|
16073
|
-
|
|
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,
|
|
15700
|
+
});
|
|
15701
|
+
} else {
|
|
15702
|
+
url = resolveUrl(specifier, importer);
|
|
16074
15703
|
}
|
|
16075
15704
|
|
|
16076
|
-
|
|
16077
|
-
|
|
16078
|
-
const leftHasScopes = Boolean(leftScopes);
|
|
16079
|
-
const rightHasScopes = Boolean(rightScopes);
|
|
16080
|
-
if (leftHasScopes && rightHasScopes) {
|
|
16081
|
-
importMap.scopes = composeTwoScopes(
|
|
16082
|
-
leftScopes,
|
|
16083
|
-
rightScopes,
|
|
16084
|
-
importMap.imports || {},
|
|
16085
|
-
);
|
|
16086
|
-
} else if (leftHasScopes) {
|
|
16087
|
-
importMap.scopes = { ...leftScopes };
|
|
16088
|
-
} else if (rightHasScopes) {
|
|
16089
|
-
importMap.scopes = { ...rightScopes };
|
|
15705
|
+
if (defaultExtension) {
|
|
15706
|
+
url = applyDefaultExtension({ url, importer, defaultExtension });
|
|
16090
15707
|
}
|
|
16091
15708
|
|
|
16092
|
-
return
|
|
15709
|
+
return url
|
|
16093
15710
|
};
|
|
16094
15711
|
|
|
16095
|
-
const
|
|
16096
|
-
|
|
15712
|
+
const applyDefaultExtension = ({ url, importer, defaultExtension }) => {
|
|
15713
|
+
if (urlToPathname(url).endsWith("/")) {
|
|
15714
|
+
return url
|
|
15715
|
+
}
|
|
16097
15716
|
|
|
16098
|
-
|
|
16099
|
-
|
|
16100
|
-
|
|
16101
|
-
return
|
|
15717
|
+
if (typeof defaultExtension === "string") {
|
|
15718
|
+
const extension = pathnameToExtension(url);
|
|
15719
|
+
if (extension === "") {
|
|
15720
|
+
return `${url}${defaultExtension}`
|
|
16102
15721
|
}
|
|
16103
|
-
|
|
16104
|
-
|
|
16105
|
-
return compareAddressAndSpecifier(leftAddress, rightSpecifier)
|
|
16106
|
-
});
|
|
16107
|
-
mappings[leftSpecifier] = rightSpecifier
|
|
16108
|
-
? rightMappings[rightSpecifier]
|
|
16109
|
-
: leftAddress;
|
|
16110
|
-
});
|
|
16111
|
-
|
|
16112
|
-
Object.keys(rightMappings).forEach((rightSpecifier) => {
|
|
16113
|
-
mappings[rightSpecifier] = rightMappings[rightSpecifier];
|
|
16114
|
-
});
|
|
16115
|
-
|
|
16116
|
-
return mappings
|
|
16117
|
-
};
|
|
15722
|
+
return url
|
|
15723
|
+
}
|
|
16118
15724
|
|
|
16119
|
-
|
|
16120
|
-
|
|
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
|
+
}
|
|
16121
15733
|
|
|
16122
|
-
|
|
16123
|
-
const addressUrl = resolveUrl(address, "file:///");
|
|
16124
|
-
const specifierUrl = resolveUrl(specifier, "file:///");
|
|
16125
|
-
return addressUrl === specifierUrl
|
|
15734
|
+
return url
|
|
16126
15735
|
};
|
|
16127
15736
|
|
|
16128
|
-
const
|
|
16129
|
-
|
|
16130
|
-
|
|
16131
|
-
|
|
16132
|
-
|
|
16133
|
-
|
|
16134
|
-
|
|
16135
|
-
|
|
16136
|
-
|
|
16137
|
-
|
|
16138
|
-
|
|
16139
|
-
|
|
16140
|
-
|
|
16141
|
-
|
|
16142
|
-
|
|
16143
|
-
|
|
16144
|
-
|
|
16145
|
-
|
|
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
|
+
const onImportmapParsed = (htmlUrl, importmap) => {
|
|
15763
|
+
if (importmap) {
|
|
15764
|
+
importmaps[htmlUrl] = normalizeImportMap(importmap, htmlUrl);
|
|
16147
15765
|
} else {
|
|
16148
|
-
|
|
15766
|
+
importmaps[htmlUrl] = null;
|
|
16149
15767
|
}
|
|
16150
|
-
|
|
15768
|
+
globalImportmap = Object.keys(importmaps).reduce((previous, url) => {
|
|
15769
|
+
const importmap = importmaps[url];
|
|
15770
|
+
if (!previous) {
|
|
15771
|
+
return importmap;
|
|
15772
|
+
}
|
|
15773
|
+
if (!importmap) {
|
|
15774
|
+
return previous;
|
|
15775
|
+
}
|
|
15776
|
+
return composeTwoImportMaps(previous, importmap);
|
|
15777
|
+
}, null);
|
|
15778
|
+
};
|
|
16151
15779
|
|
|
16152
|
-
|
|
16153
|
-
|
|
16154
|
-
|
|
16155
|
-
|
|
16156
|
-
|
|
16157
|
-
|
|
16158
|
-
|
|
16159
|
-
|
|
16160
|
-
|
|
16161
|
-
|
|
16162
|
-
|
|
16163
|
-
|
|
15780
|
+
return {
|
|
15781
|
+
name: "jsenv:html_reference_analysis",
|
|
15782
|
+
appliesDuring: "*",
|
|
15783
|
+
resolveReference: {
|
|
15784
|
+
js_import: (reference) => {
|
|
15785
|
+
if (!globalImportmap) {
|
|
15786
|
+
return null;
|
|
15787
|
+
}
|
|
15788
|
+
try {
|
|
15789
|
+
let fromMapping = false;
|
|
15790
|
+
const result = resolveImport({
|
|
15791
|
+
specifier: reference.specifier,
|
|
15792
|
+
importer: reference.ownerUrlInfo.url,
|
|
15793
|
+
importMap: globalImportmap,
|
|
15794
|
+
onImportMapping: () => {
|
|
15795
|
+
fromMapping = true;
|
|
15796
|
+
},
|
|
15797
|
+
});
|
|
15798
|
+
if (fromMapping) {
|
|
15799
|
+
return result;
|
|
15800
|
+
}
|
|
15801
|
+
return null;
|
|
15802
|
+
} catch (e) {
|
|
15803
|
+
if (e.message.includes("bare specifier")) {
|
|
15804
|
+
// in theory we should throw to be compliant with web behaviour
|
|
15805
|
+
// but for now it's simpler to return null
|
|
15806
|
+
// and let a chance to other plugins to handle the bare specifier
|
|
15807
|
+
// (node esm resolution)
|
|
15808
|
+
// and we want importmap to be prio over node esm so we cannot put this plugin after
|
|
15809
|
+
return null;
|
|
15810
|
+
}
|
|
15811
|
+
throw e;
|
|
15812
|
+
}
|
|
15813
|
+
},
|
|
15814
|
+
},
|
|
15815
|
+
transformUrlContent: {
|
|
15816
|
+
html: async (urlInfo) => {
|
|
15817
|
+
let importmapFound = false;
|
|
15818
|
+
let importmapParsedCallbackSet = new Set();
|
|
15819
|
+
const onImportmapReady = (importmap) => {
|
|
15820
|
+
onImportmapParsed(urlInfo.url, importmap);
|
|
15821
|
+
importmapParsedCallbackSet.forEach((callback) => {
|
|
15822
|
+
callback();
|
|
15823
|
+
});
|
|
15824
|
+
importmapParsedCallbackSet.clear();
|
|
15825
|
+
};
|
|
16164
15826
|
|
|
16165
|
-
|
|
16166
|
-
|
|
15827
|
+
const content = urlInfo.content;
|
|
15828
|
+
const htmlAst = parseHtmlString(content);
|
|
16167
15829
|
|
|
16168
|
-
const
|
|
16169
|
-
|
|
15830
|
+
const mutations = [];
|
|
15831
|
+
const actions = [];
|
|
15832
|
+
const finalizeCallbacks = [];
|
|
16170
15833
|
|
|
16171
|
-
|
|
16172
|
-
|
|
16173
|
-
|
|
16174
|
-
|
|
16175
|
-
|
|
15834
|
+
const createExternalReference = (
|
|
15835
|
+
node,
|
|
15836
|
+
attributeName,
|
|
15837
|
+
attributeValue,
|
|
15838
|
+
{ type, subtype, expectedType, ...rest },
|
|
15839
|
+
) => {
|
|
15840
|
+
let position;
|
|
15841
|
+
if (getHtmlNodeAttribute(node, "jsenv-cooked-by")) {
|
|
15842
|
+
// when generated from inline content,
|
|
15843
|
+
// line, column is not "src" nor "inlined-from-src" but "original-position"
|
|
15844
|
+
position = getHtmlNodePosition(node);
|
|
15845
|
+
} else {
|
|
15846
|
+
position = getHtmlNodeAttributePosition(node, attributeName);
|
|
15847
|
+
}
|
|
15848
|
+
const {
|
|
15849
|
+
line,
|
|
15850
|
+
column,
|
|
15851
|
+
// originalLine, originalColumn
|
|
15852
|
+
} = position;
|
|
15853
|
+
const debug = getHtmlNodeAttribute(node, "jsenv-debug") !== undefined;
|
|
15854
|
+
|
|
15855
|
+
const { crossorigin, integrity } = readFetchMetas(node);
|
|
15856
|
+
const isResourceHint = [
|
|
15857
|
+
"preconnect",
|
|
15858
|
+
"dns-prefetch",
|
|
15859
|
+
"prefetch",
|
|
15860
|
+
"preload",
|
|
15861
|
+
"modulepreload",
|
|
15862
|
+
].includes(subtype);
|
|
15863
|
+
let attributeLocation = node.sourceCodeLocation.attrs[attributeName];
|
|
15864
|
+
if (
|
|
15865
|
+
!attributeLocation &&
|
|
15866
|
+
attributeName === "href" &&
|
|
15867
|
+
(node.tagName === "use" || node.tagName === "image")
|
|
15868
|
+
) {
|
|
15869
|
+
attributeLocation = node.sourceCodeLocation.attrs["xlink:href"];
|
|
15870
|
+
}
|
|
15871
|
+
const attributeStart = attributeLocation.startOffset;
|
|
15872
|
+
const attributeValueStart = urlInfo.content.indexOf(
|
|
15873
|
+
attributeValue,
|
|
15874
|
+
attributeStart + `${attributeName}=`.length,
|
|
15875
|
+
);
|
|
15876
|
+
const attributeValueEnd = attributeValueStart + attributeValue.length;
|
|
15877
|
+
const reference = urlInfo.dependencies.found({
|
|
15878
|
+
type,
|
|
15879
|
+
subtype,
|
|
15880
|
+
expectedType,
|
|
15881
|
+
specifier: attributeValue,
|
|
15882
|
+
specifierLine: line,
|
|
15883
|
+
specifierColumn: column,
|
|
15884
|
+
specifierStart: attributeValueStart,
|
|
15885
|
+
specifierEnd: attributeValueEnd,
|
|
15886
|
+
isResourceHint,
|
|
15887
|
+
isWeak: isResourceHint,
|
|
15888
|
+
crossorigin,
|
|
15889
|
+
integrity,
|
|
15890
|
+
debug,
|
|
15891
|
+
astInfo: { node, attributeName },
|
|
15892
|
+
...rest,
|
|
15893
|
+
});
|
|
15894
|
+
actions.push(async () => {
|
|
15895
|
+
await reference.readGeneratedSpecifier();
|
|
15896
|
+
mutations.push(() => {
|
|
15897
|
+
setHtmlNodeAttributes(node, {
|
|
15898
|
+
[attributeName]: reference.generatedSpecifier,
|
|
15899
|
+
});
|
|
15900
|
+
});
|
|
15901
|
+
});
|
|
15902
|
+
return reference;
|
|
15903
|
+
};
|
|
15904
|
+
const visitHref = (node, referenceProps) => {
|
|
15905
|
+
const href = getHtmlNodeAttribute(node, "href");
|
|
15906
|
+
if (href) {
|
|
15907
|
+
return createExternalReference(node, "href", href, referenceProps);
|
|
15908
|
+
}
|
|
15909
|
+
return null;
|
|
15910
|
+
};
|
|
15911
|
+
const visitSrc = (node, referenceProps) => {
|
|
15912
|
+
const src = getHtmlNodeAttribute(node, "src");
|
|
15913
|
+
if (src) {
|
|
15914
|
+
return createExternalReference(node, "src", src, referenceProps);
|
|
15915
|
+
}
|
|
15916
|
+
return null;
|
|
15917
|
+
};
|
|
15918
|
+
const visitSrcset = (node, referenceProps) => {
|
|
15919
|
+
const srcset = getHtmlNodeAttribute(node, "srcset");
|
|
15920
|
+
if (srcset) {
|
|
15921
|
+
const srcCandidates = parseSrcSet(srcset);
|
|
15922
|
+
return srcCandidates.map((srcCandidate) => {
|
|
15923
|
+
return createExternalReference(
|
|
15924
|
+
node,
|
|
15925
|
+
"srcset",
|
|
15926
|
+
srcCandidate.specifier,
|
|
15927
|
+
referenceProps,
|
|
15928
|
+
);
|
|
15929
|
+
});
|
|
15930
|
+
}
|
|
15931
|
+
return null;
|
|
15932
|
+
};
|
|
15933
|
+
|
|
15934
|
+
const createInlineReference = (
|
|
15935
|
+
node,
|
|
15936
|
+
inlineContent,
|
|
15937
|
+
{ type, expectedType, contentType },
|
|
15938
|
+
) => {
|
|
15939
|
+
const hotAccept =
|
|
15940
|
+
getHtmlNodeAttribute(node, "hot-accept") !== undefined;
|
|
15941
|
+
const { line, column, isOriginal } = getHtmlNodePosition(node, {
|
|
15942
|
+
preferOriginal: true,
|
|
15943
|
+
});
|
|
15944
|
+
const inlineContentUrl = getUrlForContentInsideHtml(node, {
|
|
15945
|
+
htmlUrl: urlInfo.url,
|
|
15946
|
+
});
|
|
15947
|
+
const debug = getHtmlNodeAttribute(node, "jsenv-debug") !== undefined;
|
|
15948
|
+
const inlineReference = urlInfo.dependencies.foundInline({
|
|
15949
|
+
type,
|
|
15950
|
+
expectedType,
|
|
15951
|
+
isOriginalPosition: isOriginal,
|
|
15952
|
+
// we remove 1 to the line because imagine the following html:
|
|
15953
|
+
// <style>body { color: red; }</style>
|
|
15954
|
+
// -> content starts same line as <style> (same for <script>)
|
|
15955
|
+
specifierLine: line - 1,
|
|
15956
|
+
specifierColumn: column,
|
|
15957
|
+
specifier: inlineContentUrl,
|
|
15958
|
+
contentType,
|
|
15959
|
+
content: inlineContent,
|
|
15960
|
+
debug,
|
|
15961
|
+
astInfo: { node },
|
|
15962
|
+
});
|
|
16176
15963
|
|
|
16177
|
-
|
|
16178
|
-
|
|
15964
|
+
actions.push(async () => {
|
|
15965
|
+
if (expectedType === "js_module" && importmapFound) {
|
|
15966
|
+
await new Promise((resolve) => {
|
|
15967
|
+
importmapParsedCallbackSet.add(resolve);
|
|
15968
|
+
});
|
|
15969
|
+
}
|
|
15970
|
+
await inlineReference.urlInfo.cook();
|
|
15971
|
+
mutations.push(() => {
|
|
15972
|
+
if (hotAccept) {
|
|
15973
|
+
removeHtmlNodeText(node);
|
|
15974
|
+
setHtmlNodeAttributes(node, {
|
|
15975
|
+
"jsenv-cooked-by": "jsenv:html_inline_content_analysis",
|
|
15976
|
+
});
|
|
15977
|
+
} else {
|
|
15978
|
+
setHtmlNodeText(node, inlineReference.urlInfo.content, {
|
|
15979
|
+
indentation: false, // indentation would decrease stack trace precision
|
|
15980
|
+
});
|
|
15981
|
+
setHtmlNodeAttributes(node, {
|
|
15982
|
+
"jsenv-cooked-by": "jsenv:html_inline_content_analysis",
|
|
15983
|
+
});
|
|
15984
|
+
}
|
|
15985
|
+
});
|
|
15986
|
+
});
|
|
15987
|
+
return inlineReference;
|
|
15988
|
+
};
|
|
15989
|
+
const visitTextContent = (
|
|
15990
|
+
node,
|
|
15991
|
+
{ type, subtype, expectedType, contentType },
|
|
15992
|
+
) => {
|
|
15993
|
+
const inlineContent = getHtmlNodeText(node);
|
|
15994
|
+
if (!inlineContent) {
|
|
15995
|
+
return null;
|
|
15996
|
+
}
|
|
15997
|
+
return createInlineReference(node, inlineContent, {
|
|
15998
|
+
type,
|
|
15999
|
+
subtype,
|
|
16000
|
+
expectedType,
|
|
16001
|
+
contentType,
|
|
16002
|
+
});
|
|
16003
|
+
};
|
|
16179
16004
|
|
|
16180
|
-
|
|
16181
|
-
|
|
16005
|
+
visitHtmlNodes(htmlAst, {
|
|
16006
|
+
link: (linkNode) => {
|
|
16007
|
+
const rel = getHtmlNodeAttribute(linkNode, "rel");
|
|
16008
|
+
const type = getHtmlNodeAttribute(linkNode, "type");
|
|
16009
|
+
const ref = visitHref(linkNode, {
|
|
16010
|
+
type: "link_href",
|
|
16011
|
+
subtype: rel,
|
|
16012
|
+
// https://developer.mozilla.org/en-US/docs/Web/HTML/Link_types/preload#including_a_mime_type
|
|
16013
|
+
expectedContentType: type,
|
|
16014
|
+
});
|
|
16015
|
+
if (ref) {
|
|
16016
|
+
finalizeCallbacks.push(() => {
|
|
16017
|
+
if (ref.expectedType) ; else {
|
|
16018
|
+
ref.expectedType = decideLinkExpectedType(ref, urlInfo);
|
|
16019
|
+
}
|
|
16020
|
+
});
|
|
16021
|
+
}
|
|
16022
|
+
},
|
|
16023
|
+
style: inlineContent
|
|
16024
|
+
? (styleNode) => {
|
|
16025
|
+
visitTextContent(styleNode, {
|
|
16026
|
+
type: "style",
|
|
16027
|
+
expectedType: "css",
|
|
16028
|
+
contentType: "text/css",
|
|
16029
|
+
});
|
|
16030
|
+
}
|
|
16031
|
+
: null,
|
|
16032
|
+
script: (scriptNode) => {
|
|
16033
|
+
const { type, subtype, contentType, extension } =
|
|
16034
|
+
analyzeScriptNode(scriptNode);
|
|
16035
|
+
if (type === "text") {
|
|
16036
|
+
// ignore <script type="whatever">foobar</script>
|
|
16037
|
+
// per HTML spec https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script#attr-type
|
|
16038
|
+
return;
|
|
16039
|
+
}
|
|
16040
|
+
if (type === "importmap") {
|
|
16041
|
+
importmapFound = true;
|
|
16042
|
+
|
|
16043
|
+
const src = getHtmlNodeAttribute(scriptNode, "src");
|
|
16044
|
+
if (src) {
|
|
16045
|
+
// Browser would throw on remote importmap
|
|
16046
|
+
// and won't sent a request to the server for it
|
|
16047
|
+
// We must precook the importmap to know its content and inline it into the HTML
|
|
16048
|
+
const importmapReference = createExternalReference(
|
|
16049
|
+
scriptNode,
|
|
16050
|
+
"src",
|
|
16051
|
+
src,
|
|
16052
|
+
{
|
|
16053
|
+
type: "script",
|
|
16054
|
+
subtype: "importmap",
|
|
16055
|
+
expectedType: "importmap",
|
|
16056
|
+
},
|
|
16057
|
+
);
|
|
16058
|
+
const { line, column, isOriginal } = getHtmlNodePosition(
|
|
16059
|
+
scriptNode,
|
|
16060
|
+
{
|
|
16061
|
+
preferOriginal: true,
|
|
16062
|
+
},
|
|
16063
|
+
);
|
|
16064
|
+
const importmapInlineUrl = getUrlForContentInsideHtml(
|
|
16065
|
+
scriptNode,
|
|
16066
|
+
{
|
|
16067
|
+
htmlUrl: urlInfo.url,
|
|
16068
|
+
},
|
|
16069
|
+
);
|
|
16070
|
+
const importmapReferenceInlined = importmapReference.inline({
|
|
16071
|
+
line: line - 1,
|
|
16072
|
+
column,
|
|
16073
|
+
isOriginal,
|
|
16074
|
+
specifier: importmapInlineUrl,
|
|
16075
|
+
contentType: "application/importmap+json",
|
|
16076
|
+
});
|
|
16077
|
+
const importmapInlineUrlInfo =
|
|
16078
|
+
importmapReferenceInlined.urlInfo;
|
|
16079
|
+
actions.push(async () => {
|
|
16080
|
+
await importmapInlineUrlInfo.cook();
|
|
16081
|
+
onImportmapReady(JSON.parse(importmapInlineUrlInfo.content));
|
|
16082
|
+
mutations.push(() => {
|
|
16083
|
+
setHtmlNodeText(
|
|
16084
|
+
scriptNode,
|
|
16085
|
+
importmapInlineUrlInfo.content,
|
|
16086
|
+
{
|
|
16087
|
+
indentation: "auto",
|
|
16088
|
+
},
|
|
16089
|
+
);
|
|
16090
|
+
setHtmlNodeAttributes(scriptNode, {
|
|
16091
|
+
"src": undefined,
|
|
16092
|
+
"jsenv-inlined-by": "jsenv:html_reference_analysis",
|
|
16093
|
+
"inlined-from-src": src,
|
|
16094
|
+
});
|
|
16095
|
+
});
|
|
16096
|
+
});
|
|
16097
|
+
} else {
|
|
16098
|
+
const htmlNodeText = getHtmlNodeText(scriptNode);
|
|
16099
|
+
if (htmlNodeText) {
|
|
16100
|
+
const importmapReference = createInlineReference(
|
|
16101
|
+
scriptNode,
|
|
16102
|
+
htmlNodeText,
|
|
16103
|
+
{
|
|
16104
|
+
type: "script",
|
|
16105
|
+
expectedType: "importmap",
|
|
16106
|
+
contentType: "application/importmap+json",
|
|
16107
|
+
},
|
|
16108
|
+
);
|
|
16109
|
+
const inlineImportmapUrlInfo = importmapReference.urlInfo;
|
|
16110
|
+
actions.push(async () => {
|
|
16111
|
+
await inlineImportmapUrlInfo.cook();
|
|
16112
|
+
onImportmapReady(
|
|
16113
|
+
JSON.parse(inlineImportmapUrlInfo.content),
|
|
16114
|
+
);
|
|
16115
|
+
mutations.push(() => {
|
|
16116
|
+
setHtmlNodeText(
|
|
16117
|
+
scriptNode,
|
|
16118
|
+
inlineImportmapUrlInfo.content,
|
|
16119
|
+
{
|
|
16120
|
+
indentation: "auto",
|
|
16121
|
+
},
|
|
16122
|
+
);
|
|
16123
|
+
setHtmlNodeAttributes(scriptNode, {
|
|
16124
|
+
"jsenv-cooked-by": "jsenv:html_reference_analysis",
|
|
16125
|
+
});
|
|
16126
|
+
});
|
|
16127
|
+
});
|
|
16128
|
+
}
|
|
16129
|
+
}
|
|
16130
|
+
// once this plugin knows the importmap, it will use it
|
|
16131
|
+
// to map imports. These import specifiers will be normalized
|
|
16132
|
+
// by "formatReference" making the importmap presence useless.
|
|
16133
|
+
// In dev/test we keep importmap into the HTML to see it even if useless
|
|
16134
|
+
// Duing build we get rid of it
|
|
16135
|
+
if (urlInfo.context.build) {
|
|
16136
|
+
mutations.push(() => {
|
|
16137
|
+
removeHtmlNode(scriptNode);
|
|
16138
|
+
});
|
|
16139
|
+
}
|
|
16140
|
+
return;
|
|
16141
|
+
}
|
|
16142
|
+
const externalRef = visitSrc(scriptNode, {
|
|
16143
|
+
type: "script",
|
|
16144
|
+
subtype: type,
|
|
16145
|
+
expectedType: type,
|
|
16146
|
+
});
|
|
16147
|
+
if (externalRef) {
|
|
16148
|
+
return;
|
|
16149
|
+
}
|
|
16182
16150
|
|
|
16183
|
-
|
|
16184
|
-
|
|
16185
|
-
|
|
16186
|
-
|
|
16187
|
-
|
|
16151
|
+
// now visit the content, if any
|
|
16152
|
+
if (!inlineContent) {
|
|
16153
|
+
return;
|
|
16154
|
+
}
|
|
16155
|
+
// If the inline script was already handled by an other plugin, ignore it
|
|
16156
|
+
// - we want to preserve inline scripts generated by html supervisor during dev
|
|
16157
|
+
// - we want to avoid cooking twice a script during build
|
|
16158
|
+
if (
|
|
16159
|
+
!inlineConvertedScript &&
|
|
16160
|
+
getHtmlNodeAttribute(scriptNode, "jsenv-injected-by") ===
|
|
16161
|
+
"jsenv:js_module_fallback"
|
|
16162
|
+
) {
|
|
16163
|
+
return;
|
|
16164
|
+
}
|
|
16188
16165
|
|
|
16189
|
-
|
|
16190
|
-
|
|
16166
|
+
const inlineRef = visitTextContent(scriptNode, {
|
|
16167
|
+
type: "script",
|
|
16168
|
+
subtype,
|
|
16169
|
+
expectedType: type,
|
|
16170
|
+
contentType,
|
|
16171
|
+
});
|
|
16172
|
+
if (inlineRef) {
|
|
16173
|
+
// 1. <script type="jsx"> becomes <script>
|
|
16174
|
+
if (type === "js_classic" && extension !== ".js") {
|
|
16175
|
+
mutations.push(() => {
|
|
16176
|
+
setHtmlNodeAttributes(scriptNode, {
|
|
16177
|
+
type: undefined,
|
|
16178
|
+
});
|
|
16179
|
+
});
|
|
16180
|
+
}
|
|
16181
|
+
// 2. <script type="module/jsx"> becomes <script type="module">
|
|
16182
|
+
if (type === "js_module" && extension !== ".js") {
|
|
16183
|
+
mutations.push(() => {
|
|
16184
|
+
setHtmlNodeAttributes(scriptNode, {
|
|
16185
|
+
type: "module",
|
|
16186
|
+
});
|
|
16187
|
+
});
|
|
16188
|
+
}
|
|
16189
|
+
}
|
|
16190
|
+
},
|
|
16191
|
+
a: (aNode) => {
|
|
16192
|
+
visitHref(aNode, {
|
|
16193
|
+
type: "a_href",
|
|
16194
|
+
});
|
|
16195
|
+
},
|
|
16196
|
+
iframe: (iframeNode) => {
|
|
16197
|
+
visitSrc(iframeNode, {
|
|
16198
|
+
type: "iframe_src",
|
|
16199
|
+
});
|
|
16200
|
+
},
|
|
16201
|
+
img: (imgNode) => {
|
|
16202
|
+
visitSrc(imgNode, {
|
|
16203
|
+
type: "img_src",
|
|
16204
|
+
});
|
|
16205
|
+
visitSrcset(imgNode, {
|
|
16206
|
+
type: "img_srcset",
|
|
16207
|
+
});
|
|
16208
|
+
},
|
|
16209
|
+
source: (sourceNode) => {
|
|
16210
|
+
visitSrc(sourceNode, {
|
|
16211
|
+
type: "source_src",
|
|
16212
|
+
});
|
|
16213
|
+
visitSrcset(sourceNode, {
|
|
16214
|
+
type: "source_srcset",
|
|
16215
|
+
});
|
|
16216
|
+
},
|
|
16217
|
+
// svg <image> tag
|
|
16218
|
+
image: (imageNode) => {
|
|
16219
|
+
visitHref(imageNode, {
|
|
16220
|
+
type: "image_href",
|
|
16221
|
+
});
|
|
16222
|
+
},
|
|
16223
|
+
use: (useNode) => {
|
|
16224
|
+
visitHref(useNode, {
|
|
16225
|
+
type: "use_href",
|
|
16226
|
+
});
|
|
16227
|
+
},
|
|
16228
|
+
});
|
|
16229
|
+
if (!importmapFound) {
|
|
16230
|
+
onImportmapReady();
|
|
16231
|
+
}
|
|
16232
|
+
finalizeCallbacks.forEach((finalizeCallback) => {
|
|
16233
|
+
finalizeCallback();
|
|
16234
|
+
});
|
|
16191
16235
|
|
|
16192
|
-
|
|
16193
|
-
|
|
16236
|
+
if (actions.length > 0) {
|
|
16237
|
+
await Promise.all(actions.map((action) => action()));
|
|
16238
|
+
actions.length = 0;
|
|
16239
|
+
}
|
|
16240
|
+
if (mutations.length === 0) {
|
|
16241
|
+
return null;
|
|
16242
|
+
}
|
|
16243
|
+
mutations.forEach((mutation) => mutation());
|
|
16244
|
+
mutations.length = 0;
|
|
16245
|
+
return stringifyHtmlAst(htmlAst);
|
|
16246
|
+
},
|
|
16247
|
+
},
|
|
16248
|
+
};
|
|
16194
16249
|
};
|
|
16195
16250
|
|
|
16196
|
-
const
|
|
16197
|
-
|
|
16198
|
-
|
|
16199
|
-
|
|
16200
|
-
|
|
16251
|
+
const crossOriginCompatibleTagNames = ["script", "link", "img", "source"];
|
|
16252
|
+
const integrityCompatibleTagNames = ["script", "link", "img", "source"];
|
|
16253
|
+
const readFetchMetas = (node) => {
|
|
16254
|
+
const meta = {};
|
|
16255
|
+
if (crossOriginCompatibleTagNames.includes(node.nodeName)) {
|
|
16256
|
+
const crossorigin = getHtmlNodeAttribute(node, "crossorigin") !== undefined;
|
|
16257
|
+
meta.crossorigin = crossorigin;
|
|
16201
16258
|
}
|
|
16202
|
-
|
|
16203
|
-
|
|
16204
|
-
|
|
16205
|
-
return {
|
|
16206
|
-
imports: imports ? normalizeMappings(imports, baseUrl) : undefined,
|
|
16207
|
-
scopes: scopes ? normalizeScopes(scopes, baseUrl) : undefined,
|
|
16259
|
+
if (integrityCompatibleTagNames.includes(node.nodeName)) {
|
|
16260
|
+
const integrity = getHtmlNodeAttribute(node, "integrity");
|
|
16261
|
+
meta.integrity = integrity;
|
|
16208
16262
|
}
|
|
16263
|
+
return meta;
|
|
16209
16264
|
};
|
|
16210
16265
|
|
|
16211
|
-
const
|
|
16212
|
-
|
|
16213
|
-
|
|
16266
|
+
const decideLinkExpectedType = (linkReference, htmlUrlInfo) => {
|
|
16267
|
+
const rel = getHtmlNodeAttribute(linkReference.astInfo.node, "rel");
|
|
16268
|
+
if (rel === "webmanifest") {
|
|
16269
|
+
return "webmanifest";
|
|
16214
16270
|
}
|
|
16215
|
-
|
|
16216
|
-
|
|
16217
|
-
return true
|
|
16271
|
+
if (rel === "modulepreload") {
|
|
16272
|
+
return "js_module";
|
|
16218
16273
|
}
|
|
16219
|
-
|
|
16220
|
-
|
|
16221
|
-
}
|
|
16222
|
-
|
|
16223
|
-
|
|
16224
|
-
|
|
16225
|
-
|
|
16226
|
-
|
|
16227
|
-
const address = mappings[specifier];
|
|
16228
|
-
|
|
16229
|
-
if (typeof address !== "string") {
|
|
16230
|
-
console.warn(
|
|
16231
|
-
formulateAddressMustBeAString({
|
|
16232
|
-
address,
|
|
16233
|
-
specifier,
|
|
16234
|
-
}),
|
|
16235
|
-
);
|
|
16236
|
-
return
|
|
16237
|
-
}
|
|
16238
|
-
|
|
16239
|
-
const specifierResolved = resolveSpecifier(specifier, baseUrl) || specifier;
|
|
16240
|
-
|
|
16241
|
-
const addressUrl = tryUrlResolution(address, baseUrl);
|
|
16242
|
-
if (addressUrl === null) {
|
|
16243
|
-
console.warn(
|
|
16244
|
-
formulateAdressResolutionFailed({
|
|
16245
|
-
address,
|
|
16246
|
-
baseUrl,
|
|
16247
|
-
specifier,
|
|
16248
|
-
}),
|
|
16249
|
-
);
|
|
16250
|
-
return
|
|
16274
|
+
if (rel === "stylesheet") {
|
|
16275
|
+
return "css";
|
|
16276
|
+
}
|
|
16277
|
+
if (rel === "preload") {
|
|
16278
|
+
// https://developer.mozilla.org/en-US/docs/Web/HTML/Link_types/preload#what_types_of_content_can_be_preloaded
|
|
16279
|
+
const as = getHtmlNodeAttribute(linkReference.astInfo.node, "as");
|
|
16280
|
+
if (as === "document") {
|
|
16281
|
+
return "html";
|
|
16251
16282
|
}
|
|
16252
|
-
|
|
16253
|
-
|
|
16254
|
-
console.warn(
|
|
16255
|
-
formulateAddressUrlRequiresTrailingSlash({
|
|
16256
|
-
addressUrl,
|
|
16257
|
-
address,
|
|
16258
|
-
specifier,
|
|
16259
|
-
}),
|
|
16260
|
-
);
|
|
16261
|
-
return
|
|
16283
|
+
if (as === "style") {
|
|
16284
|
+
return "css";
|
|
16262
16285
|
}
|
|
16263
|
-
|
|
16264
|
-
|
|
16265
|
-
|
|
16266
|
-
|
|
16267
|
-
}
|
|
16268
|
-
|
|
16269
|
-
|
|
16270
|
-
|
|
16271
|
-
|
|
16272
|
-
|
|
16273
|
-
|
|
16274
|
-
const scopeUrl = tryUrlResolution(scopeSpecifier, baseUrl);
|
|
16275
|
-
if (scopeUrl === null) {
|
|
16276
|
-
console.warn(
|
|
16277
|
-
formulateScopeResolutionFailed({
|
|
16278
|
-
scope: scopeSpecifier,
|
|
16279
|
-
baseUrl,
|
|
16280
|
-
}),
|
|
16281
|
-
);
|
|
16282
|
-
return
|
|
16286
|
+
if (as === "script") {
|
|
16287
|
+
for (const referenceToOther of htmlUrlInfo.referenceToOthersSet) {
|
|
16288
|
+
if (referenceToOther.url !== linkReference.url) {
|
|
16289
|
+
continue;
|
|
16290
|
+
}
|
|
16291
|
+
if (referenceToOther.type !== "script") {
|
|
16292
|
+
continue;
|
|
16293
|
+
}
|
|
16294
|
+
return referenceToOther.expectedType;
|
|
16295
|
+
}
|
|
16296
|
+
return undefined;
|
|
16283
16297
|
}
|
|
16284
|
-
|
|
16285
|
-
|
|
16286
|
-
});
|
|
16287
|
-
|
|
16288
|
-
return sortScopes(scopesNormalized)
|
|
16298
|
+
}
|
|
16299
|
+
return undefined;
|
|
16289
16300
|
};
|
|
16290
16301
|
|
|
16291
|
-
const
|
|
16292
|
-
|
|
16293
|
-
|
|
16294
|
-
|
|
16295
|
-
|
|
16296
|
-
|
|
16297
|
-
const formulateAddressMustBeAString = ({
|
|
16298
|
-
specifier,
|
|
16299
|
-
address,
|
|
16300
|
-
}) => `Address must be a string.
|
|
16301
|
-
--- address ---
|
|
16302
|
-
${address}
|
|
16303
|
-
--- specifier ---
|
|
16304
|
-
${specifier}`;
|
|
16302
|
+
// const applyWebUrlResolution = (url, baseUrl) => {
|
|
16303
|
+
// if (url[0] === "/") {
|
|
16304
|
+
// return new URL(url.slice(1), baseUrl).href;
|
|
16305
|
+
// }
|
|
16306
|
+
// return new URL(url, baseUrl).href;
|
|
16307
|
+
// };
|
|
16305
16308
|
|
|
16306
|
-
|
|
16307
|
-
address,
|
|
16308
|
-
baseUrl,
|
|
16309
|
-
specifier,
|
|
16310
|
-
}) => `Address url resolution failed.
|
|
16311
|
-
--- address ---
|
|
16312
|
-
${address}
|
|
16313
|
-
--- base url ---
|
|
16314
|
-
${baseUrl}
|
|
16315
|
-
--- specifier ---
|
|
16316
|
-
${specifier}`;
|
|
16309
|
+
// css: parseAndTransformCssUrls,
|
|
16317
16310
|
|
|
16318
|
-
const
|
|
16319
|
-
|
|
16320
|
-
|
|
16321
|
-
|
|
16322
|
-
|
|
16323
|
-
|
|
16324
|
-
|
|
16325
|
-
|
|
16326
|
-
|
|
16327
|
-
--- specifier ---
|
|
16328
|
-
${specifier}`;
|
|
16311
|
+
const jsenvPluginWebmanifestReferenceAnalysis = () => {
|
|
16312
|
+
return {
|
|
16313
|
+
name: "jsenv:webmanifest_reference_analysis",
|
|
16314
|
+
appliesDuring: "*",
|
|
16315
|
+
transformUrlContent: {
|
|
16316
|
+
webmanifest: parseAndTransformWebmanifestUrls,
|
|
16317
|
+
},
|
|
16318
|
+
};
|
|
16319
|
+
};
|
|
16329
16320
|
|
|
16330
|
-
const
|
|
16331
|
-
|
|
16332
|
-
|
|
16333
|
-
|
|
16334
|
-
|
|
16335
|
-
|
|
16336
|
-
|
|
16337
|
-
|
|
16321
|
+
const parseAndTransformWebmanifestUrls = async (urlInfo) => {
|
|
16322
|
+
const content = urlInfo.content;
|
|
16323
|
+
const manifest = JSON.parse(content);
|
|
16324
|
+
const actions = [];
|
|
16325
|
+
const { icons = [] } = manifest;
|
|
16326
|
+
icons.forEach((icon) => {
|
|
16327
|
+
const iconReference = urlInfo.dependencies.found({
|
|
16328
|
+
type: "webmanifest_icon_src",
|
|
16329
|
+
specifier: icon.src,
|
|
16330
|
+
});
|
|
16331
|
+
actions.push(async () => {
|
|
16332
|
+
await iconReference.readGeneratedSpecifier();
|
|
16333
|
+
icon.src = iconReference.generatedSpecifier;
|
|
16334
|
+
});
|
|
16335
|
+
});
|
|
16338
16336
|
|
|
16339
|
-
|
|
16340
|
-
|
|
16341
|
-
if (slashLastIndex !== -1) {
|
|
16342
|
-
pathname = pathname.slice(slashLastIndex + 1);
|
|
16337
|
+
if (actions.length === 0) {
|
|
16338
|
+
return null;
|
|
16343
16339
|
}
|
|
16340
|
+
await Promise.all(actions.map((action) => action()));
|
|
16341
|
+
return JSON.stringify(manifest, null, " ");
|
|
16342
|
+
};
|
|
16344
16343
|
|
|
16345
|
-
|
|
16346
|
-
|
|
16347
|
-
|
|
16348
|
-
|
|
16344
|
+
/*
|
|
16345
|
+
* https://github.com/parcel-bundler/parcel/blob/v2/packages/transformers/css/src/CSSTransformer.js
|
|
16346
|
+
*/
|
|
16347
|
+
|
|
16348
|
+
|
|
16349
|
+
const jsenvPluginCssReferenceAnalysis = () => {
|
|
16350
|
+
return {
|
|
16351
|
+
name: "jsenv:css_reference_analysis",
|
|
16352
|
+
appliesDuring: "*",
|
|
16353
|
+
transformUrlContent: {
|
|
16354
|
+
css: parseAndTransformCssUrls,
|
|
16355
|
+
},
|
|
16356
|
+
};
|
|
16349
16357
|
};
|
|
16350
16358
|
|
|
16351
|
-
const
|
|
16352
|
-
|
|
16353
|
-
|
|
16354
|
-
|
|
16355
|
-
|
|
16356
|
-
|
|
16357
|
-
|
|
16358
|
-
|
|
16359
|
-
|
|
16360
|
-
|
|
16361
|
-
|
|
16362
|
-
|
|
16363
|
-
|
|
16364
|
-
|
|
16365
|
-
|
|
16366
|
-
|
|
16359
|
+
const parseAndTransformCssUrls = async (urlInfo) => {
|
|
16360
|
+
const cssUrls = await parseCssUrls({
|
|
16361
|
+
css: urlInfo.content,
|
|
16362
|
+
url: urlInfo.originalUrl,
|
|
16363
|
+
});
|
|
16364
|
+
const actions = [];
|
|
16365
|
+
const magicSource = createMagicSource(urlInfo.content);
|
|
16366
|
+
for (const cssUrl of cssUrls) {
|
|
16367
|
+
const reference = urlInfo.dependencies.found({
|
|
16368
|
+
type: cssUrl.type,
|
|
16369
|
+
specifier: cssUrl.specifier,
|
|
16370
|
+
specifierStart: cssUrl.start,
|
|
16371
|
+
specifierEnd: cssUrl.end,
|
|
16372
|
+
specifierLine: cssUrl.line,
|
|
16373
|
+
specifierColumn: cssUrl.column,
|
|
16374
|
+
});
|
|
16375
|
+
actions.push(async () => {
|
|
16376
|
+
await reference.readGeneratedSpecifier();
|
|
16377
|
+
const replacement = reference.generatedSpecifier;
|
|
16378
|
+
magicSource.replace({
|
|
16379
|
+
start: cssUrl.start,
|
|
16380
|
+
end: cssUrl.end,
|
|
16381
|
+
replacement,
|
|
16382
|
+
});
|
|
16367
16383
|
});
|
|
16368
|
-
} else {
|
|
16369
|
-
url = resolveUrl(specifier, importer);
|
|
16370
16384
|
}
|
|
16371
|
-
|
|
16372
|
-
|
|
16373
|
-
url = applyDefaultExtension({ url, importer, defaultExtension });
|
|
16385
|
+
if (actions.length > 0) {
|
|
16386
|
+
await Promise.all(actions.map((action) => action()));
|
|
16374
16387
|
}
|
|
16388
|
+
return magicSource.toContentAndSourcemap();
|
|
16389
|
+
};
|
|
16375
16390
|
|
|
16376
|
-
|
|
16391
|
+
const jsenvPluginJsReferenceAnalysis = ({ inlineContent }) => {
|
|
16392
|
+
return [
|
|
16393
|
+
{
|
|
16394
|
+
name: "jsenv:js_reference_analysis",
|
|
16395
|
+
appliesDuring: "*",
|
|
16396
|
+
transformUrlContent: {
|
|
16397
|
+
js_classic: (urlInfo) =>
|
|
16398
|
+
parseAndTransformJsReferences(urlInfo, {
|
|
16399
|
+
inlineContent,
|
|
16400
|
+
canUseTemplateLiterals:
|
|
16401
|
+
urlInfo.context.isSupportedOnCurrentClients("template_literals"),
|
|
16402
|
+
}),
|
|
16403
|
+
js_module: (urlInfo) =>
|
|
16404
|
+
parseAndTransformJsReferences(urlInfo, {
|
|
16405
|
+
inlineContent,
|
|
16406
|
+
canUseTemplateLiterals:
|
|
16407
|
+
urlInfo.context.isSupportedOnCurrentClients("template_literals"),
|
|
16408
|
+
}),
|
|
16409
|
+
},
|
|
16410
|
+
},
|
|
16411
|
+
];
|
|
16377
16412
|
};
|
|
16378
16413
|
|
|
16379
|
-
const
|
|
16380
|
-
|
|
16381
|
-
|
|
16382
|
-
|
|
16414
|
+
const parseAndTransformJsReferences = async (
|
|
16415
|
+
urlInfo,
|
|
16416
|
+
{ inlineContent, canUseTemplateLiterals },
|
|
16417
|
+
) => {
|
|
16418
|
+
const magicSource = createMagicSource(urlInfo.content);
|
|
16419
|
+
const parallelActions = [];
|
|
16420
|
+
const sequentialActions = [];
|
|
16421
|
+
const isNodeJs =
|
|
16422
|
+
Object.keys(urlInfo.context.runtimeCompat).toString() === "node";
|
|
16383
16423
|
|
|
16384
|
-
|
|
16385
|
-
const
|
|
16386
|
-
|
|
16387
|
-
|
|
16424
|
+
const onInlineReference = (inlineReferenceInfo) => {
|
|
16425
|
+
const inlineUrl = getUrlForContentInsideJs(inlineReferenceInfo, {
|
|
16426
|
+
url: urlInfo.url,
|
|
16427
|
+
});
|
|
16428
|
+
let { quote } = inlineReferenceInfo;
|
|
16429
|
+
if (quote === "`" && !canUseTemplateLiterals) {
|
|
16430
|
+
// if quote is "`" and template literals are not supported
|
|
16431
|
+
// we'll use a regular string (single or double quote)
|
|
16432
|
+
// when rendering the string
|
|
16433
|
+
quote = JS_QUOTES.pickBest(inlineReferenceInfo.content);
|
|
16434
|
+
}
|
|
16435
|
+
const inlineReference = urlInfo.dependencies.foundInline({
|
|
16436
|
+
type: "js_inline_content",
|
|
16437
|
+
subtype: inlineReferenceInfo.type, // "new_blob_first_arg", "new_inline_content_first_arg", "json_parse_first_arg"
|
|
16438
|
+
isOriginalPosition: urlInfo.content === urlInfo.originalContent,
|
|
16439
|
+
specifierLine: inlineReferenceInfo.line,
|
|
16440
|
+
specifierColumn: inlineReferenceInfo.column,
|
|
16441
|
+
specifier: inlineUrl,
|
|
16442
|
+
contentType: inlineReferenceInfo.contentType,
|
|
16443
|
+
content: inlineReferenceInfo.content,
|
|
16444
|
+
});
|
|
16445
|
+
const inlineUrlInfo = inlineReference.urlInfo;
|
|
16446
|
+
inlineUrlInfo.jsQuote = quote;
|
|
16447
|
+
inlineReference.escape = (value) => {
|
|
16448
|
+
return JS_QUOTES.escapeSpecialChars(value.slice(1, -1), { quote });
|
|
16449
|
+
};
|
|
16450
|
+
|
|
16451
|
+
sequentialActions.push(async () => {
|
|
16452
|
+
await inlineUrlInfo.cook();
|
|
16453
|
+
const replacement = JS_QUOTES.escapeSpecialChars(inlineUrlInfo.content, {
|
|
16454
|
+
quote,
|
|
16455
|
+
});
|
|
16456
|
+
magicSource.replace({
|
|
16457
|
+
start: inlineReferenceInfo.start,
|
|
16458
|
+
end: inlineReferenceInfo.end,
|
|
16459
|
+
replacement,
|
|
16460
|
+
});
|
|
16461
|
+
});
|
|
16462
|
+
};
|
|
16463
|
+
const onExternalReference = (externalReferenceInfo) => {
|
|
16464
|
+
if (
|
|
16465
|
+
externalReferenceInfo.subtype === "import_static" ||
|
|
16466
|
+
externalReferenceInfo.subtype === "import_dynamic"
|
|
16467
|
+
) {
|
|
16468
|
+
urlInfo.data.usesImport = true;
|
|
16469
|
+
}
|
|
16470
|
+
if (
|
|
16471
|
+
isNodeJs &&
|
|
16472
|
+
externalReferenceInfo.type === "js_url" &&
|
|
16473
|
+
externalReferenceInfo.expectedSubtype === "worker" &&
|
|
16474
|
+
externalReferenceInfo.expectedType === "js_classic" &&
|
|
16475
|
+
// TODO: it's true also if closest package.json
|
|
16476
|
+
// is type: module
|
|
16477
|
+
urlToExtension$1(
|
|
16478
|
+
new URL(externalReferenceInfo.specifier, urlInfo.url).href,
|
|
16479
|
+
) === ".mjs"
|
|
16480
|
+
) {
|
|
16481
|
+
externalReferenceInfo.expectedType = "js_module";
|
|
16482
|
+
}
|
|
16483
|
+
const reference = urlInfo.dependencies.found({
|
|
16484
|
+
type: externalReferenceInfo.type,
|
|
16485
|
+
subtype: externalReferenceInfo.subtype,
|
|
16486
|
+
expectedType: externalReferenceInfo.expectedType,
|
|
16487
|
+
expectedSubtype: externalReferenceInfo.expectedSubtype || urlInfo.subtype,
|
|
16488
|
+
specifier: externalReferenceInfo.specifier,
|
|
16489
|
+
specifierStart: externalReferenceInfo.start,
|
|
16490
|
+
specifierEnd: externalReferenceInfo.end,
|
|
16491
|
+
specifierLine: externalReferenceInfo.line,
|
|
16492
|
+
specifierColumn: externalReferenceInfo.column,
|
|
16493
|
+
data: externalReferenceInfo.data,
|
|
16494
|
+
baseUrl: {
|
|
16495
|
+
"StringLiteral": externalReferenceInfo.baseUrl,
|
|
16496
|
+
"window.location": urlInfo.url,
|
|
16497
|
+
"window.origin": urlInfo.context.rootDirectoryUrl,
|
|
16498
|
+
"import.meta.url": urlInfo.url,
|
|
16499
|
+
"context.meta.url": urlInfo.url,
|
|
16500
|
+
"document.currentScript.src": urlInfo.url,
|
|
16501
|
+
}[externalReferenceInfo.baseUrlType],
|
|
16502
|
+
importAttributes: externalReferenceInfo.importAttributes,
|
|
16503
|
+
astInfo: externalReferenceInfo.astInfo,
|
|
16504
|
+
});
|
|
16505
|
+
parallelActions.push(async () => {
|
|
16506
|
+
await reference.readGeneratedSpecifier();
|
|
16507
|
+
const replacement = reference.generatedSpecifier;
|
|
16508
|
+
magicSource.replace({
|
|
16509
|
+
start: externalReferenceInfo.start,
|
|
16510
|
+
end: externalReferenceInfo.end,
|
|
16511
|
+
replacement,
|
|
16512
|
+
});
|
|
16513
|
+
if (reference.mutation) {
|
|
16514
|
+
reference.mutation(magicSource, urlInfo);
|
|
16515
|
+
}
|
|
16516
|
+
});
|
|
16517
|
+
};
|
|
16518
|
+
const jsReferenceInfos = parseJsUrls({
|
|
16519
|
+
js: urlInfo.content,
|
|
16520
|
+
url: urlInfo.originalUrl,
|
|
16521
|
+
ast: urlInfo.contentAst,
|
|
16522
|
+
isJsModule: urlInfo.type === "js_module",
|
|
16523
|
+
isWebWorker: isWebWorkerUrlInfo(urlInfo),
|
|
16524
|
+
inlineContent,
|
|
16525
|
+
isNodeJs,
|
|
16526
|
+
});
|
|
16527
|
+
for (const jsReferenceInfo of jsReferenceInfos) {
|
|
16528
|
+
if (jsReferenceInfo.isInline) {
|
|
16529
|
+
onInlineReference(jsReferenceInfo);
|
|
16530
|
+
} else {
|
|
16531
|
+
onExternalReference(jsReferenceInfo);
|
|
16388
16532
|
}
|
|
16389
|
-
return url
|
|
16390
16533
|
}
|
|
16391
|
-
|
|
16392
|
-
|
|
16393
|
-
|
|
16394
|
-
|
|
16395
|
-
|
|
16396
|
-
|
|
16397
|
-
|
|
16398
|
-
}
|
|
16534
|
+
if (parallelActions.length > 0) {
|
|
16535
|
+
await Promise.all(parallelActions.map((action) => action()));
|
|
16536
|
+
}
|
|
16537
|
+
if (sequentialActions.length > 0) {
|
|
16538
|
+
await sequentialActions.reduce(async (previous, action) => {
|
|
16539
|
+
await previous;
|
|
16540
|
+
await action();
|
|
16541
|
+
}, Promise.resolve());
|
|
16399
16542
|
}
|
|
16400
16543
|
|
|
16401
|
-
|
|
16544
|
+
const { content, sourcemap } = magicSource.toContentAndSourcemap();
|
|
16545
|
+
return { content, sourcemap };
|
|
16402
16546
|
};
|
|
16403
16547
|
|
|
16404
|
-
|
|
16405
|
-
|
|
16406
|
-
|
|
16407
|
-
|
|
16408
|
-
|
|
16409
|
-
|
|
16410
|
-
|
|
16411
|
-
|
|
16412
|
-
|
|
16413
|
-
|
|
16414
|
-
|
|
16415
|
-
|
|
16416
|
-
|
|
16417
|
-
|
|
16418
|
-
|
|
16419
|
-
|
|
16420
|
-
|
|
16421
|
-
|
|
16422
|
-
|
|
16423
|
-
|
|
16424
|
-
|
|
16425
|
-
|
|
16426
|
-
|
|
16427
|
-
const onHtmlImportmapParsed = (importmap, htmlUrl) => {
|
|
16428
|
-
importmaps[htmlUrl] = importmap
|
|
16429
|
-
? normalizeImportMap(importmap, htmlUrl)
|
|
16430
|
-
: null;
|
|
16431
|
-
finalImportmap = Object.keys(importmaps).reduce((previous, url) => {
|
|
16432
|
-
const importmap = importmaps[url];
|
|
16433
|
-
if (!previous) {
|
|
16434
|
-
return importmap;
|
|
16435
|
-
}
|
|
16436
|
-
if (!importmap) {
|
|
16437
|
-
return previous;
|
|
16438
|
-
}
|
|
16439
|
-
return composeTwoImportMaps(previous, importmap);
|
|
16440
|
-
}, null);
|
|
16441
|
-
};
|
|
16548
|
+
const jsenvPluginReferenceAnalysis = ({
|
|
16549
|
+
inlineContent = true,
|
|
16550
|
+
inlineConvertedScript = false,
|
|
16551
|
+
fetchInlineUrls = true,
|
|
16552
|
+
}) => {
|
|
16553
|
+
return [
|
|
16554
|
+
jsenvPluginDirectoryReferenceAnalysis(),
|
|
16555
|
+
jsenvPluginHtmlReferenceAnalysis({
|
|
16556
|
+
inlineContent,
|
|
16557
|
+
inlineConvertedScript,
|
|
16558
|
+
}),
|
|
16559
|
+
jsenvPluginWebmanifestReferenceAnalysis(),
|
|
16560
|
+
jsenvPluginCssReferenceAnalysis(),
|
|
16561
|
+
jsenvPluginJsReferenceAnalysis({
|
|
16562
|
+
inlineContent,
|
|
16563
|
+
}),
|
|
16564
|
+
...(inlineContent ? [jsenvPluginDataUrlsAnalysis()] : []),
|
|
16565
|
+
...(inlineContent && fetchInlineUrls
|
|
16566
|
+
? [jsenvPluginInlineContentFetcher()]
|
|
16567
|
+
: []),
|
|
16568
|
+
jsenvPluginReferenceExpectedTypes(),
|
|
16569
|
+
];
|
|
16570
|
+
};
|
|
16442
16571
|
|
|
16572
|
+
const jsenvPluginInlineContentFetcher = () => {
|
|
16443
16573
|
return {
|
|
16444
|
-
name: "jsenv:
|
|
16574
|
+
name: "jsenv:inline_content_fetcher",
|
|
16445
16575
|
appliesDuring: "*",
|
|
16446
|
-
|
|
16447
|
-
|
|
16448
|
-
|
|
16449
|
-
|
|
16450
|
-
|
|
16451
|
-
|
|
16452
|
-
|
|
16453
|
-
|
|
16454
|
-
|
|
16455
|
-
|
|
16456
|
-
|
|
16457
|
-
onImportMapping: () => {
|
|
16458
|
-
fromMapping = true;
|
|
16459
|
-
},
|
|
16460
|
-
});
|
|
16461
|
-
if (fromMapping) {
|
|
16462
|
-
return result;
|
|
16463
|
-
}
|
|
16464
|
-
return null;
|
|
16465
|
-
} catch (e) {
|
|
16466
|
-
if (e.message.includes("bare specifier")) {
|
|
16467
|
-
// in theory we should throw to be compliant with web behaviour
|
|
16468
|
-
// but for now it's simpler to return null
|
|
16469
|
-
// and let a chance to other plugins to handle the bare specifier
|
|
16470
|
-
// (node esm resolution)
|
|
16471
|
-
// and we want importmap to be prio over node esm so we cannot put this plugin after
|
|
16472
|
-
return null;
|
|
16473
|
-
}
|
|
16474
|
-
throw e;
|
|
16475
|
-
}
|
|
16476
|
-
},
|
|
16477
|
-
},
|
|
16478
|
-
transformUrlContent: {
|
|
16479
|
-
html: async (htmlUrlInfo) => {
|
|
16480
|
-
const htmlAst = parseHtmlString(htmlUrlInfo.content);
|
|
16481
|
-
const importmap = findHtmlNode(htmlAst, (node) => {
|
|
16482
|
-
if (node.nodeName !== "script") {
|
|
16483
|
-
return false;
|
|
16484
|
-
}
|
|
16485
|
-
const type = getHtmlNodeAttribute(node, "type");
|
|
16486
|
-
if (type === undefined || type !== "importmap") {
|
|
16487
|
-
return false;
|
|
16488
|
-
}
|
|
16489
|
-
return true;
|
|
16490
|
-
});
|
|
16491
|
-
if (!importmap) {
|
|
16492
|
-
onHtmlImportmapParsed(null, htmlUrlInfo.url);
|
|
16493
|
-
return null;
|
|
16494
|
-
}
|
|
16495
|
-
const handleInlineImportmap = async (importmap, htmlNodeText) => {
|
|
16496
|
-
const { line, column, isOriginal } = getHtmlNodePosition(importmap, {
|
|
16497
|
-
preferOriginal: true,
|
|
16498
|
-
});
|
|
16499
|
-
const inlineImportmapUrl = getUrlForContentInsideHtml(importmap, {
|
|
16500
|
-
htmlUrl: htmlUrlInfo.url,
|
|
16501
|
-
});
|
|
16502
|
-
const inlineImportmapReference = htmlUrlInfo.dependencies.foundInline(
|
|
16503
|
-
{
|
|
16504
|
-
type: "script",
|
|
16505
|
-
isOriginalPosition: isOriginal,
|
|
16506
|
-
specifierLine: line - 1,
|
|
16507
|
-
specifierColumn: column,
|
|
16508
|
-
specifier: inlineImportmapUrl,
|
|
16509
|
-
contentType: "application/importmap+json",
|
|
16510
|
-
content: htmlNodeText,
|
|
16511
|
-
},
|
|
16512
|
-
);
|
|
16513
|
-
const inlineImportmapUrlInfo = inlineImportmapReference.urlInfo;
|
|
16514
|
-
await inlineImportmapUrlInfo.cook();
|
|
16515
|
-
setHtmlNodeText(importmap, inlineImportmapUrlInfo.content, {
|
|
16516
|
-
indentation: "auto",
|
|
16517
|
-
});
|
|
16518
|
-
setHtmlNodeAttributes(importmap, {
|
|
16519
|
-
"jsenv-cooked-by": "jsenv:importmap",
|
|
16520
|
-
});
|
|
16521
|
-
onHtmlImportmapParsed(
|
|
16522
|
-
JSON.parse(inlineImportmapUrlInfo.content),
|
|
16523
|
-
htmlUrlInfo.url,
|
|
16524
|
-
);
|
|
16525
|
-
};
|
|
16526
|
-
const handleImportmapWithSrc = async (importmap, src) => {
|
|
16527
|
-
// Browser would throw on remote importmap
|
|
16528
|
-
// and won't sent a request to the server for it
|
|
16529
|
-
// We must precook the importmap to know its content and inline it into the HTML
|
|
16530
|
-
// In this situation the ref to the importmap was already discovered
|
|
16531
|
-
// when parsing the HTML
|
|
16532
|
-
let importmapReference = null;
|
|
16533
|
-
for (const referenceToOther of htmlUrlInfo.referenceToOthersSet) {
|
|
16534
|
-
if (referenceToOther.generatedSpecifier === src) {
|
|
16535
|
-
importmapReference = referenceToOther;
|
|
16536
|
-
break;
|
|
16537
|
-
}
|
|
16538
|
-
}
|
|
16539
|
-
const { line, column, isOriginal } = getHtmlNodePosition(importmap, {
|
|
16540
|
-
preferOriginal: true,
|
|
16541
|
-
});
|
|
16542
|
-
const importmapInlineUrl = getUrlForContentInsideHtml(importmap, {
|
|
16543
|
-
htmlUrl: htmlUrlInfo.url,
|
|
16544
|
-
});
|
|
16545
|
-
const importmapReferenceInlined = importmapReference.inline({
|
|
16546
|
-
line: line - 1,
|
|
16547
|
-
column,
|
|
16548
|
-
isOriginal,
|
|
16549
|
-
specifier: importmapInlineUrl,
|
|
16550
|
-
contentType: "application/importmap+json",
|
|
16551
|
-
});
|
|
16552
|
-
const importmapInlineUrlInfo = importmapReferenceInlined.urlInfo;
|
|
16553
|
-
await importmapInlineUrlInfo.cook();
|
|
16554
|
-
onHtmlImportmapParsed(
|
|
16555
|
-
JSON.parse(importmapInlineUrlInfo.content),
|
|
16556
|
-
htmlUrlInfo.url,
|
|
16557
|
-
);
|
|
16558
|
-
setHtmlNodeText(importmap, importmapInlineUrlInfo.content, {
|
|
16559
|
-
indentation: "auto",
|
|
16560
|
-
});
|
|
16561
|
-
setHtmlNodeAttributes(importmap, {
|
|
16562
|
-
"src": undefined,
|
|
16563
|
-
"jsenv-inlined-by": "jsenv:importmap",
|
|
16564
|
-
"inlined-from-src": src,
|
|
16565
|
-
});
|
|
16566
|
-
};
|
|
16567
|
-
|
|
16568
|
-
const src = getHtmlNodeAttribute(importmap, "src");
|
|
16569
|
-
if (src) {
|
|
16570
|
-
await handleImportmapWithSrc(importmap, src);
|
|
16571
|
-
} else {
|
|
16572
|
-
const htmlNodeText = getHtmlNodeText(importmap);
|
|
16573
|
-
if (htmlNodeText) {
|
|
16574
|
-
await handleInlineImportmap(importmap, htmlNodeText);
|
|
16575
|
-
}
|
|
16576
|
+
fetchUrlContent: async (urlInfo) => {
|
|
16577
|
+
if (!urlInfo.isInline) {
|
|
16578
|
+
return null;
|
|
16579
|
+
}
|
|
16580
|
+
// - we must use last reference because
|
|
16581
|
+
// when updating the file, first reference is the previous version
|
|
16582
|
+
// - we cannot use urlInfo.lastReference because it can be the reference created by "http_request"
|
|
16583
|
+
let lastInlineReference;
|
|
16584
|
+
for (const reference of urlInfo.referenceFromOthersSet) {
|
|
16585
|
+
if (reference.isInline) {
|
|
16586
|
+
lastInlineReference = reference;
|
|
16576
16587
|
}
|
|
16577
|
-
|
|
16578
|
-
|
|
16579
|
-
|
|
16580
|
-
//
|
|
16581
|
-
|
|
16582
|
-
|
|
16583
|
-
|
|
16588
|
+
}
|
|
16589
|
+
const { prev } = lastInlineReference;
|
|
16590
|
+
if (prev && !prev.isInline) {
|
|
16591
|
+
// got inlined, cook original url
|
|
16592
|
+
if (lastInlineReference.content === undefined) {
|
|
16593
|
+
const originalUrlInfo = prev.urlInfo;
|
|
16594
|
+
await originalUrlInfo.cook();
|
|
16595
|
+
lastInlineReference.content = originalUrlInfo.content;
|
|
16596
|
+
lastInlineReference.contentType = originalUrlInfo.contentType;
|
|
16584
16597
|
}
|
|
16585
|
-
|
|
16586
|
-
|
|
16587
|
-
|
|
16588
|
-
|
|
16598
|
+
}
|
|
16599
|
+
return {
|
|
16600
|
+
originalContent: urlInfo.originalContent,
|
|
16601
|
+
content: lastInlineReference.content,
|
|
16602
|
+
contentType: lastInlineReference.contentType,
|
|
16603
|
+
};
|
|
16589
16604
|
},
|
|
16590
16605
|
};
|
|
16591
16606
|
};
|
|
@@ -18050,6 +18065,7 @@ const jsenvPluginProtocolFile = ({
|
|
|
18050
18065
|
reference.leadsToADirectory = stat && stat.isDirectory();
|
|
18051
18066
|
if (reference.leadsToADirectory) {
|
|
18052
18067
|
const directoryAllowed =
|
|
18068
|
+
reference.type === "http_request" ||
|
|
18053
18069
|
reference.type === "filesystem" ||
|
|
18054
18070
|
(typeof directoryReferenceAllowed === "function" &&
|
|
18055
18071
|
directoryReferenceAllowed(reference)) ||
|
|
@@ -18115,7 +18131,6 @@ const jsenvPluginProtocolFile = ({
|
|
|
18115
18131
|
}
|
|
18116
18132
|
const urlObject = new URL(urlInfo.url);
|
|
18117
18133
|
if (urlInfo.firstReference.leadsToADirectory) {
|
|
18118
|
-
const directoryEntries = readdirSync(urlObject);
|
|
18119
18134
|
if (!urlInfo.filenameHint) {
|
|
18120
18135
|
if (urlInfo.firstReference.type === "filesystem") {
|
|
18121
18136
|
urlInfo.filenameHint = `${
|
|
@@ -18125,10 +18140,17 @@ const jsenvPluginProtocolFile = ({
|
|
|
18125
18140
|
urlInfo.filenameHint = `${urlToFilename$1(urlInfo.url)}/`;
|
|
18126
18141
|
}
|
|
18127
18142
|
}
|
|
18143
|
+
const { headers, body } = serveDirectory(urlObject.href, {
|
|
18144
|
+
headers: urlInfo.context.request
|
|
18145
|
+
? urlInfo.context.request.headers
|
|
18146
|
+
: {},
|
|
18147
|
+
rootDirectoryUrl: urlInfo.context.rootDirectoryUrl,
|
|
18148
|
+
});
|
|
18128
18149
|
return {
|
|
18129
18150
|
type: "directory",
|
|
18130
|
-
contentType: "
|
|
18131
|
-
|
|
18151
|
+
contentType: headers["content-type"],
|
|
18152
|
+
contentLength: headers["content-length"],
|
|
18153
|
+
content: body,
|
|
18132
18154
|
};
|
|
18133
18155
|
}
|
|
18134
18156
|
if (
|
|
@@ -19254,8 +19276,16 @@ const jsenvPluginHotSearchParam = () => {
|
|
|
19254
19276
|
// At this stage the parent is using ?hot and we are going to decide if
|
|
19255
19277
|
// we propagate the search param to child.
|
|
19256
19278
|
const referencedUrlInfo = reference.urlInfo;
|
|
19257
|
-
const {
|
|
19258
|
-
|
|
19279
|
+
const {
|
|
19280
|
+
modifiedTimestamp,
|
|
19281
|
+
descendantModifiedTimestamp,
|
|
19282
|
+
dereferencedTimestamp,
|
|
19283
|
+
} = referencedUrlInfo;
|
|
19284
|
+
if (
|
|
19285
|
+
!modifiedTimestamp &&
|
|
19286
|
+
!descendantModifiedTimestamp &&
|
|
19287
|
+
!dereferencedTimestamp
|
|
19288
|
+
) {
|
|
19259
19289
|
return null;
|
|
19260
19290
|
}
|
|
19261
19291
|
// The goal is to send an url that will bypass client (the browser) cache
|
|
@@ -19268,10 +19298,11 @@ const jsenvPluginHotSearchParam = () => {
|
|
|
19268
19298
|
// We use the latest timestamp to ensure it's fresh
|
|
19269
19299
|
// The dereferencedTimestamp is needed because when a js module is re-referenced
|
|
19270
19300
|
// browser must re-execute it, even if the code is not modified
|
|
19271
|
-
const latestTimestamp =
|
|
19272
|
-
|
|
19273
|
-
|
|
19274
|
-
|
|
19301
|
+
const latestTimestamp = Math.max(
|
|
19302
|
+
modifiedTimestamp,
|
|
19303
|
+
descendantModifiedTimestamp,
|
|
19304
|
+
dereferencedTimestamp,
|
|
19305
|
+
);
|
|
19275
19306
|
return {
|
|
19276
19307
|
hot: latestTimestamp,
|
|
19277
19308
|
};
|
|
@@ -19333,89 +19364,157 @@ const jsenvPluginAutoreloadServer = ({
|
|
|
19333
19364
|
}
|
|
19334
19365
|
return url;
|
|
19335
19366
|
};
|
|
19336
|
-
const
|
|
19337
|
-
const
|
|
19338
|
-
|
|
19339
|
-
|
|
19340
|
-
|
|
19341
|
-
|
|
19342
|
-
|
|
19343
|
-
|
|
19344
|
-
|
|
19345
|
-
|
|
19346
|
-
|
|
19347
|
-
|
|
19348
|
-
|
|
19367
|
+
const update = (firstUrlInfo) => {
|
|
19368
|
+
const boundaries = new Set();
|
|
19369
|
+
const instructions = [];
|
|
19370
|
+
const propagateUpdate = (firstUrlInfo) => {
|
|
19371
|
+
const iterate = (urlInfo, chain) => {
|
|
19372
|
+
if (urlInfo.data.hotAcceptSelf) {
|
|
19373
|
+
boundaries.add(urlInfo);
|
|
19374
|
+
instructions.push({
|
|
19375
|
+
type: urlInfo.type,
|
|
19376
|
+
boundary: formatUrlForClient(urlInfo.url),
|
|
19377
|
+
acceptedBy: formatUrlForClient(urlInfo.url),
|
|
19378
|
+
});
|
|
19379
|
+
return {
|
|
19380
|
+
accepted: true,
|
|
19381
|
+
reason:
|
|
19382
|
+
urlInfo === firstUrlInfo
|
|
19383
|
+
? `file accepts hot reload`
|
|
19384
|
+
: `a dependent file accepts hot reload`,
|
|
19385
|
+
};
|
|
19386
|
+
}
|
|
19387
|
+
if (urlInfo.data.hotDecline) {
|
|
19388
|
+
return {
|
|
19389
|
+
declined: true,
|
|
19390
|
+
reason: `file declines hot reload`,
|
|
19391
|
+
declinedBy: formatUrlForClient(urlInfo.url),
|
|
19392
|
+
};
|
|
19393
|
+
}
|
|
19394
|
+
let instructionCountBefore = instructions.length;
|
|
19395
|
+
for (const referenceFromOther of urlInfo.referenceFromOthersSet) {
|
|
19396
|
+
if (
|
|
19397
|
+
referenceFromOther.isImplicit &&
|
|
19398
|
+
referenceFromOther.isWeak
|
|
19399
|
+
) {
|
|
19400
|
+
if (!referenceFromOther.original) {
|
|
19401
|
+
continue;
|
|
19402
|
+
}
|
|
19403
|
+
if (referenceFromOther.original.isWeak) {
|
|
19404
|
+
continue;
|
|
19405
|
+
}
|
|
19406
|
+
}
|
|
19407
|
+
const urlInfoReferencingThisOne =
|
|
19408
|
+
referenceFromOther.ownerUrlInfo;
|
|
19409
|
+
if (urlInfoReferencingThisOne.data.hotDecline) {
|
|
19410
|
+
return {
|
|
19411
|
+
declined: true,
|
|
19412
|
+
reason: `a dependent file declines hot reload`,
|
|
19413
|
+
declinedBy: formatUrlForClient(
|
|
19414
|
+
urlInfoReferencingThisOne.url,
|
|
19415
|
+
),
|
|
19416
|
+
};
|
|
19417
|
+
}
|
|
19418
|
+
const { hotAcceptDependencies = [] } =
|
|
19419
|
+
urlInfoReferencingThisOne.data;
|
|
19420
|
+
if (hotAcceptDependencies.includes(urlInfo.url)) {
|
|
19421
|
+
boundaries.add(urlInfoReferencingThisOne);
|
|
19422
|
+
instructions.push({
|
|
19423
|
+
type: urlInfoReferencingThisOne.type,
|
|
19424
|
+
boundary: formatUrlForClient(urlInfoReferencingThisOne.url),
|
|
19349
19425
|
acceptedBy: formatUrlForClient(urlInfo.url),
|
|
19350
|
-
}
|
|
19351
|
-
],
|
|
19352
|
-
};
|
|
19353
|
-
}
|
|
19354
|
-
const instructions = [];
|
|
19355
|
-
for (const referenceFromOther of urlInfo.referenceFromOthersSet) {
|
|
19356
|
-
if (referenceFromOther.isImplicit && referenceFromOther.isWeak) {
|
|
19357
|
-
if (!referenceFromOther.original) {
|
|
19426
|
+
});
|
|
19358
19427
|
continue;
|
|
19359
19428
|
}
|
|
19360
|
-
if (
|
|
19429
|
+
if (chain.includes(urlInfoReferencingThisOne.url)) {
|
|
19430
|
+
return {
|
|
19431
|
+
declined: true,
|
|
19432
|
+
reason: "dead end",
|
|
19433
|
+
declinedBy: formatUrlForClient(
|
|
19434
|
+
urlInfoReferencingThisOne.url,
|
|
19435
|
+
),
|
|
19436
|
+
};
|
|
19437
|
+
}
|
|
19438
|
+
const dependentPropagationResult = iterateMemoized(
|
|
19439
|
+
urlInfoReferencingThisOne,
|
|
19440
|
+
[...chain, urlInfoReferencingThisOne.url],
|
|
19441
|
+
);
|
|
19442
|
+
if (dependentPropagationResult.accepted) {
|
|
19361
19443
|
continue;
|
|
19362
19444
|
}
|
|
19445
|
+
if (
|
|
19446
|
+
// declined explicitely by an other file, it must decline the whole update
|
|
19447
|
+
dependentPropagationResult.declinedBy
|
|
19448
|
+
) {
|
|
19449
|
+
return dependentPropagationResult;
|
|
19450
|
+
}
|
|
19451
|
+
// declined by absence of boundary, we can keep searching
|
|
19363
19452
|
}
|
|
19364
|
-
|
|
19365
|
-
if (urlInfoReferencingThisOne.data.hotDecline) {
|
|
19453
|
+
if (instructionCountBefore === instructions.length) {
|
|
19366
19454
|
return {
|
|
19367
19455
|
declined: true,
|
|
19368
|
-
reason: `
|
|
19369
|
-
declinedBy: urlInfoReferencingThisOne.url,
|
|
19456
|
+
reason: `there is no file accepting hot reload while propagating update`,
|
|
19370
19457
|
};
|
|
19371
19458
|
}
|
|
19372
|
-
|
|
19373
|
-
|
|
19374
|
-
|
|
19375
|
-
|
|
19376
|
-
|
|
19377
|
-
|
|
19378
|
-
|
|
19379
|
-
|
|
19380
|
-
|
|
19459
|
+
return {
|
|
19460
|
+
accepted: true,
|
|
19461
|
+
reason: `${instructions.length} dependent file(s) accepts hot reload`,
|
|
19462
|
+
};
|
|
19463
|
+
};
|
|
19464
|
+
|
|
19465
|
+
const map = new Map();
|
|
19466
|
+
const iterateMemoized = (urlInfo, chain) => {
|
|
19467
|
+
const resultFromCache = map.get(urlInfo.url);
|
|
19468
|
+
if (resultFromCache) {
|
|
19469
|
+
return resultFromCache;
|
|
19381
19470
|
}
|
|
19382
|
-
|
|
19383
|
-
|
|
19471
|
+
const result = iterate(urlInfo, chain);
|
|
19472
|
+
map.set(urlInfo.url, result);
|
|
19473
|
+
return result;
|
|
19474
|
+
};
|
|
19475
|
+
map.clear();
|
|
19476
|
+
return iterateMemoized(firstUrlInfo, []);
|
|
19477
|
+
};
|
|
19478
|
+
|
|
19479
|
+
let propagationResult = propagateUpdate(firstUrlInfo);
|
|
19480
|
+
const seen = new Set();
|
|
19481
|
+
const invalidateImporters = (urlInfo) => {
|
|
19482
|
+
// to indicate this urlInfo should be modified
|
|
19483
|
+
for (const referenceFromOther of urlInfo.referenceFromOthersSet) {
|
|
19484
|
+
const urlInfoReferencingThisOne = referenceFromOther.ownerUrlInfo;
|
|
19485
|
+
const { hotDecline, hotAcceptDependencies = [] } =
|
|
19486
|
+
urlInfoReferencingThisOne.data;
|
|
19487
|
+
if (hotDecline) {
|
|
19488
|
+
propagationResult = {
|
|
19384
19489
|
declined: true,
|
|
19385
|
-
reason:
|
|
19490
|
+
reason: `file declines hot reload`,
|
|
19386
19491
|
declinedBy: formatUrlForClient(urlInfoReferencingThisOne.url),
|
|
19387
19492
|
};
|
|
19493
|
+
return;
|
|
19388
19494
|
}
|
|
19389
|
-
|
|
19390
|
-
urlInfoReferencingThisOne,
|
|
19391
|
-
[...seen, urlInfoReferencingThisOne.url],
|
|
19392
|
-
);
|
|
19393
|
-
if (dependentPropagationResult.accepted) {
|
|
19394
|
-
instructions.push(...dependentPropagationResult.instructions);
|
|
19495
|
+
if (hotAcceptDependencies.includes(urlInfo.url)) {
|
|
19395
19496
|
continue;
|
|
19396
19497
|
}
|
|
19397
|
-
if (
|
|
19398
|
-
|
|
19399
|
-
dependentPropagationResult.declinedBy
|
|
19400
|
-
) {
|
|
19401
|
-
return dependentPropagationResult;
|
|
19498
|
+
if (seen.has(urlInfoReferencingThisOne)) {
|
|
19499
|
+
continue;
|
|
19402
19500
|
}
|
|
19403
|
-
|
|
19404
|
-
|
|
19405
|
-
|
|
19406
|
-
|
|
19407
|
-
|
|
19408
|
-
|
|
19409
|
-
|
|
19501
|
+
seen.add(urlInfoReferencingThisOne);
|
|
19502
|
+
// see https://github.com/vitejs/vite/blob/ab5bb40942c7023046fa6f6d0b49cabc105b6073/packages/vite/src/node/server/moduleGraph.ts#L205C5-L207C6
|
|
19503
|
+
if (boundaries.has(urlInfoReferencingThisOne)) {
|
|
19504
|
+
return;
|
|
19505
|
+
}
|
|
19506
|
+
urlInfoReferencingThisOne.descendantModifiedTimestamp =
|
|
19507
|
+
Date.now();
|
|
19508
|
+
invalidateImporters(urlInfoReferencingThisOne);
|
|
19410
19509
|
}
|
|
19411
|
-
return {
|
|
19412
|
-
accepted: true,
|
|
19413
|
-
reason: `${instructions.length} dependent file(s) accepts hot reload`,
|
|
19414
|
-
instructions,
|
|
19415
|
-
};
|
|
19416
19510
|
};
|
|
19417
|
-
|
|
19418
|
-
|
|
19511
|
+
invalidateImporters(firstUrlInfo);
|
|
19512
|
+
boundaries.clear();
|
|
19513
|
+
seen.clear();
|
|
19514
|
+
return {
|
|
19515
|
+
...propagationResult,
|
|
19516
|
+
instructions,
|
|
19517
|
+
};
|
|
19419
19518
|
};
|
|
19420
19519
|
|
|
19421
19520
|
// We are delaying the moment we tell client how to reload because:
|
|
@@ -19449,7 +19548,7 @@ const jsenvPluginAutoreloadServer = ({
|
|
|
19449
19548
|
if (!changedUrlInfo.isUsed()) {
|
|
19450
19549
|
continue;
|
|
19451
19550
|
}
|
|
19452
|
-
const hotUpdate =
|
|
19551
|
+
const hotUpdate = update(changedUrlInfo);
|
|
19453
19552
|
const relativeUrl = formatUrlForClient(changedUrlInfo.url);
|
|
19454
19553
|
if (hotUpdate.declined) {
|
|
19455
19554
|
reloadMessage = {
|
|
@@ -19486,7 +19585,7 @@ const jsenvPluginAutoreloadServer = ({
|
|
|
19486
19585
|
if (!ownerUrlInfo.isUsed()) {
|
|
19487
19586
|
continue;
|
|
19488
19587
|
}
|
|
19489
|
-
const ownerHotUpdate =
|
|
19588
|
+
const ownerHotUpdate = update(ownerUrlInfo);
|
|
19490
19589
|
const cause = `${formatUrlForClient(
|
|
19491
19590
|
prunedUrlInfo.url,
|
|
19492
19591
|
)} is no longer referenced`;
|
|
@@ -19671,7 +19770,7 @@ const jsenvPluginRibbon = ({
|
|
|
19671
19770
|
null,
|
|
19672
19771
|
" ",
|
|
19673
19772
|
);
|
|
19674
|
-
|
|
19773
|
+
injectHtmlNodeAsEarlyAsPossible(
|
|
19675
19774
|
htmlAst,
|
|
19676
19775
|
createHtmlNode({
|
|
19677
19776
|
tagName: "script",
|
|
@@ -19736,7 +19835,6 @@ const getCorePlugins = ({
|
|
|
19736
19835
|
jsenvPluginReferenceAnalysis(referenceAnalysis),
|
|
19737
19836
|
...(injections ? [jsenvPluginInjections(injections)] : []),
|
|
19738
19837
|
jsenvPluginTranspilation(transpilation),
|
|
19739
|
-
jsenvPluginImportmap(),
|
|
19740
19838
|
...(inlining ? [jsenvPluginInlining()] : []),
|
|
19741
19839
|
...(supervisor ? [jsenvPluginSupervisor(supervisor)] : []), // after inline as it needs inline script to be cooked
|
|
19742
19840
|
|
|
@@ -22186,7 +22284,7 @@ const createFileService = ({
|
|
|
22186
22284
|
associations: watchAssociations,
|
|
22187
22285
|
});
|
|
22188
22286
|
urlInfoCreated.isWatched = watch;
|
|
22189
|
-
//
|
|
22287
|
+
// when an url depends on many others, we check all these (like package.json)
|
|
22190
22288
|
urlInfoCreated.isValid = () => {
|
|
22191
22289
|
if (!urlInfoCreated.url.startsWith("file:")) {
|
|
22192
22290
|
return false;
|