@jsenv/core 35.0.5 → 36.0.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 -1
- package/dist/js/inline_content.js +5 -4
- package/dist/jsenv_core.js +1128 -1497
- package/package.json +8 -8
- package/src/build/build.js +45 -39
- package/src/dev/file_service.js +7 -17
- package/src/dev/start_dev_server.js +12 -7
- package/src/kitchen/kitchen.js +38 -19
- package/src/kitchen/url_graph.js +1 -1
- package/src/plugins/autoreload/jsenv_plugin_hmr.js +2 -2
- package/src/plugins/file_urls/jsenv_plugin_file_urls.js +4 -4
- package/src/plugins/http_urls/jsenv_plugin_http_urls.js +1 -1
- package/src/plugins/importmap/jsenv_plugin_importmap.js +1 -1
- package/src/plugins/inlining/jsenv_plugin_inlining.js +1 -1
- package/src/plugins/inlining/jsenv_plugin_inlining_as_data_url.js +13 -2
- package/src/plugins/plugin_controller.js +19 -10
- package/src/plugins/plugins.js +21 -25
- package/src/plugins/{url_analysis/css/css_urls.js → reference_analysis/css/jsenv_plugin_css_reference_analysis.js} +11 -1
- package/src/plugins/{inline_content_analysis/jsenv_plugin_data_urls.js → reference_analysis/data_urls/jsenv_plugin_data_urls_analysis.js} +19 -19
- package/src/plugins/reference_analysis/directory/jsenv_plugin_directory_reference_analysis.js +51 -0
- package/src/plugins/reference_analysis/html/jsenv_plugin_html_reference_analysis.js +429 -0
- package/src/plugins/reference_analysis/inline_content.js +7 -0
- package/src/plugins/reference_analysis/js/jsenv_plugin_js_reference_analysis.js +161 -0
- package/src/plugins/reference_analysis/jsenv_plugin_reference_analysis.js +120 -0
- package/src/plugins/{url_analysis → reference_analysis}/jsenv_plugin_reference_expected_types.js +19 -12
- package/src/plugins/{url_analysis/webmanifest/webmanifest_urls.js → reference_analysis/webmanifest/jsenv_plugin_webmanifest_reference_analysis.js} +13 -1
- package/src/plugins/resolution_node_esm/jsenv_plugin_node_esm_resolution.js +74 -0
- package/src/plugins/{url_resolution → resolution_node_esm}/node_esm_resolver.js +8 -0
- package/src/plugins/resolution_web/jsenv_plugin_web_resolution.js +45 -0
- package/src/plugins/transpilation/as_js_module/jsenv_plugin_as_js_module.js +1 -1
- package/src/plugins/transpilation/import_assertions/jsenv_plugin_import_assertions.js +4 -6
- package/src/plugins/transpilation/js_module_fallback/jsenv_plugin_js_module_conversion.js +1 -1
- package/src/plugins/transpilation/js_module_fallback/jsenv_plugin_js_module_fallback_inside_html.js +1 -1
- package/src/plugins/transpilation/js_module_fallback/jsenv_plugin_js_module_fallback_on_workers.js +1 -1
- package/src/plugins/url_type_from_reference.js +13 -0
- package/src/plugins/{url_version/jsenv_plugin_url_version.js → version_search_param/jsenv_plugin_version_search_param.js} +4 -4
- package/dist/html/explorer.html +0 -559
- package/dist/other/jsenv.png +0 -0
- package/src/plugins/explorer/client/explorer.html +0 -608
- package/src/plugins/explorer/client/jsenv.png +0 -0
- package/src/plugins/explorer/jsenv_plugin_explorer.js +0 -86
- package/src/plugins/inline_content_analysis/client/inline_content.js +0 -6
- package/src/plugins/inline_content_analysis/jsenv_plugin_html_inline_content_analysis.js +0 -206
- package/src/plugins/inline_content_analysis/jsenv_plugin_inline_content_analysis.js +0 -34
- package/src/plugins/inline_content_analysis/jsenv_plugin_js_inline_content_analysis.js +0 -314
- package/src/plugins/url_analysis/html/html_urls.js +0 -313
- package/src/plugins/url_analysis/js/js_urls.js +0 -65
- package/src/plugins/url_analysis/jsenv_plugin_url_analysis.js +0 -116
- package/src/plugins/url_resolution/jsenv_plugin_url_resolution.js +0 -140
package/dist/jsenv_core.js
CHANGED
|
@@ -14,7 +14,7 @@ import { Readable, Stream, Writable } from "node:stream";
|
|
|
14
14
|
import { Http2ServerResponse } from "node:http2";
|
|
15
15
|
import { lookup } from "node:dns";
|
|
16
16
|
import { SOURCEMAP, generateSourcemapFileUrl, composeTwoSourcemaps, generateSourcemapDataUrl, createMagicSource, getOriginalPosition } from "@jsenv/sourcemap";
|
|
17
|
-
import { parseHtmlString,
|
|
17
|
+
import { parseHtmlString, visitHtmlNodes, getHtmlNodeAttribute, analyzeScriptNode, stringifyHtmlAst, parseSrcSet, getHtmlNodeText, setHtmlNodeAttributes, getHtmlNodePosition, getHtmlNodeAttributePosition, removeHtmlNodeText, setHtmlNodeText, parseCssUrls, parseJsUrls, applyBabelPlugins, injectHtmlNodeAsEarlyAsPossible, createHtmlNode, findHtmlNode, removeHtmlNode, injectJsImport, analyzeLinkNode, injectHtmlNode, insertHtmlNodeAfter } from "@jsenv/ast";
|
|
18
18
|
import { createRequire } from "node:module";
|
|
19
19
|
import babelParser from "@babel/parser";
|
|
20
20
|
|
|
@@ -139,6 +139,10 @@ const generateInlineContentUrl = ({
|
|
|
139
139
|
};
|
|
140
140
|
|
|
141
141
|
// consider switching to https://babeljs.io/docs/en/babel-code-frame
|
|
142
|
+
// https://github.com/postcss/postcss/blob/fd30d3df5abc0954a0ec642a3cdc644ab2aacf9c/lib/css-syntax-error.js#L43
|
|
143
|
+
// https://github.com/postcss/postcss/blob/fd30d3df5abc0954a0ec642a3cdc644ab2aacf9c/lib/terminal-highlight.js#L50
|
|
144
|
+
// https://github.com/babel/babel/blob/eea156b2cb8deecfcf82d52aa1b71ba4995c7d68/packages/babel-code-frame/src/index.js#L1
|
|
145
|
+
|
|
142
146
|
const stringifyUrlSite = ({
|
|
143
147
|
url,
|
|
144
148
|
line,
|
|
@@ -791,6 +795,7 @@ const getPermissionOrComputeDefault = (action, subject, permissions) => {
|
|
|
791
795
|
* - stats object documentation on Node.js
|
|
792
796
|
* https://nodejs.org/docs/latest-v13.x/api/fs.html#fs_class_fs_stats
|
|
793
797
|
*/
|
|
798
|
+
|
|
794
799
|
const isWindows$3 = process.platform === "win32";
|
|
795
800
|
const readEntryStat = async (source, {
|
|
796
801
|
nullIfNotFound = false,
|
|
@@ -861,6 +866,7 @@ const readStat = (sourcePath, {
|
|
|
861
866
|
* - eTag documentation on MDN
|
|
862
867
|
* https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag
|
|
863
868
|
*/
|
|
869
|
+
|
|
864
870
|
const ETAG_FOR_EMPTY_CONTENT$1 = '"0-2jmj7l5rSw0yVb/vlWAYkK/YBwk"';
|
|
865
871
|
const bufferToEtag$1 = buffer => {
|
|
866
872
|
if (!Buffer.isBuffer(buffer)) {
|
|
@@ -1023,6 +1029,7 @@ const removeNoop = () => {};
|
|
|
1023
1029
|
/*
|
|
1024
1030
|
* https://github.com/whatwg/dom/issues/920
|
|
1025
1031
|
*/
|
|
1032
|
+
|
|
1026
1033
|
const Abort = {
|
|
1027
1034
|
isAbortError: error => {
|
|
1028
1035
|
return error && error.name === "AbortError";
|
|
@@ -1414,6 +1421,7 @@ const asFlatAssociations = associations => {
|
|
|
1414
1421
|
* https://github.com/kaelzhang/node-ignore
|
|
1415
1422
|
*/
|
|
1416
1423
|
|
|
1424
|
+
|
|
1417
1425
|
/** @module jsenv_url_meta **/
|
|
1418
1426
|
/**
|
|
1419
1427
|
* An object representing the result of applying a pattern to an url
|
|
@@ -1881,80 +1889,6 @@ const comparePathnames = (leftPathame, rightPathname) => {
|
|
|
1881
1889
|
return 0;
|
|
1882
1890
|
};
|
|
1883
1891
|
|
|
1884
|
-
const collectFiles = async ({
|
|
1885
|
-
signal = new AbortController().signal,
|
|
1886
|
-
directoryUrl,
|
|
1887
|
-
associations,
|
|
1888
|
-
predicate
|
|
1889
|
-
}) => {
|
|
1890
|
-
const rootDirectoryUrl = assertAndNormalizeDirectoryUrl(directoryUrl);
|
|
1891
|
-
if (typeof predicate !== "function") {
|
|
1892
|
-
throw new TypeError(`predicate must be a function, got ${predicate}`);
|
|
1893
|
-
}
|
|
1894
|
-
associations = URL_META.resolveAssociations(associations, rootDirectoryUrl);
|
|
1895
|
-
const collectOperation = Abort.startOperation();
|
|
1896
|
-
collectOperation.addAbortSignal(signal);
|
|
1897
|
-
const matchingFileResultArray = [];
|
|
1898
|
-
const visitDirectory = async directoryUrl => {
|
|
1899
|
-
collectOperation.throwIfAborted();
|
|
1900
|
-
const directoryItems = await readDirectory(directoryUrl);
|
|
1901
|
-
await Promise.all(directoryItems.map(async directoryItem => {
|
|
1902
|
-
const directoryChildNodeUrl = `${directoryUrl}${directoryItem}`;
|
|
1903
|
-
collectOperation.throwIfAborted();
|
|
1904
|
-
const directoryChildNodeStats = await readEntryStat(directoryChildNodeUrl, {
|
|
1905
|
-
// we ignore symlink because recursively traversed
|
|
1906
|
-
// so symlinked file will be discovered.
|
|
1907
|
-
// Moreover if they lead outside of directoryPath it can become a problem
|
|
1908
|
-
// like infinite recursion of whatever.
|
|
1909
|
-
// that we could handle using an object of pathname already seen but it will be useless
|
|
1910
|
-
// because directoryPath is recursively traversed
|
|
1911
|
-
followLink: false
|
|
1912
|
-
});
|
|
1913
|
-
if (directoryChildNodeStats.isDirectory()) {
|
|
1914
|
-
const subDirectoryUrl = `${directoryChildNodeUrl}/`;
|
|
1915
|
-
if (!URL_META.urlChildMayMatch({
|
|
1916
|
-
url: subDirectoryUrl,
|
|
1917
|
-
associations,
|
|
1918
|
-
predicate
|
|
1919
|
-
})) {
|
|
1920
|
-
return;
|
|
1921
|
-
}
|
|
1922
|
-
await visitDirectory(subDirectoryUrl);
|
|
1923
|
-
return;
|
|
1924
|
-
}
|
|
1925
|
-
if (directoryChildNodeStats.isFile()) {
|
|
1926
|
-
const meta = URL_META.applyAssociations({
|
|
1927
|
-
url: directoryChildNodeUrl,
|
|
1928
|
-
associations
|
|
1929
|
-
});
|
|
1930
|
-
if (!predicate(meta)) return;
|
|
1931
|
-
const relativeUrl = urlToRelativeUrl(directoryChildNodeUrl, rootDirectoryUrl);
|
|
1932
|
-
matchingFileResultArray.push({
|
|
1933
|
-
url: new URL(relativeUrl, rootDirectoryUrl).href,
|
|
1934
|
-
relativeUrl: decodeURIComponent(relativeUrl),
|
|
1935
|
-
meta,
|
|
1936
|
-
fileStats: directoryChildNodeStats
|
|
1937
|
-
});
|
|
1938
|
-
return;
|
|
1939
|
-
}
|
|
1940
|
-
}));
|
|
1941
|
-
};
|
|
1942
|
-
try {
|
|
1943
|
-
await visitDirectory(rootDirectoryUrl);
|
|
1944
|
-
|
|
1945
|
-
// When we operate on thoose files later it feels more natural
|
|
1946
|
-
// to perform operation in the same order they appear in the filesystem.
|
|
1947
|
-
// It also allow to get a predictable return value.
|
|
1948
|
-
// For that reason we sort matchingFileResultArray
|
|
1949
|
-
matchingFileResultArray.sort((leftFile, rightFile) => {
|
|
1950
|
-
return comparePathnames(leftFile.relativeUrl, rightFile.relativeUrl);
|
|
1951
|
-
});
|
|
1952
|
-
return matchingFileResultArray;
|
|
1953
|
-
} finally {
|
|
1954
|
-
await collectOperation.end();
|
|
1955
|
-
}
|
|
1956
|
-
};
|
|
1957
|
-
|
|
1958
1892
|
// https://nodejs.org/dist/latest-v13.x/docs/api/fs.html#fs_fspromises_mkdir_path_options
|
|
1959
1893
|
const {
|
|
1960
1894
|
mkdir
|
|
@@ -3011,6 +2945,7 @@ function isUnicodeSupported() {
|
|
|
3011
2945
|
}
|
|
3012
2946
|
|
|
3013
2947
|
// see also https://github.com/sindresorhus/figures
|
|
2948
|
+
|
|
3014
2949
|
const canUseUnicode = isUnicodeSupported();
|
|
3015
2950
|
const COMMAND_RAW = canUseUnicode ? `❯` : `>`;
|
|
3016
2951
|
const OK_RAW = canUseUnicode ? `✔` : `√`;
|
|
@@ -3428,6 +3363,7 @@ const spyStreamOutput = stream => {
|
|
|
3428
3363
|
/*
|
|
3429
3364
|
* see also https://github.com/vadimdemedes/ink
|
|
3430
3365
|
*/
|
|
3366
|
+
|
|
3431
3367
|
const createLog = ({
|
|
3432
3368
|
stream = process.stdout,
|
|
3433
3369
|
newLine = "after"
|
|
@@ -4022,6 +3958,7 @@ const listenEvent = (objectWithEventEmitter, eventName, callback, {
|
|
|
4022
3958
|
https://stackoverflow.com/a/42019773/2634179
|
|
4023
3959
|
|
|
4024
3960
|
*/
|
|
3961
|
+
|
|
4025
3962
|
const createPolyglotServer = async ({
|
|
4026
3963
|
http2 = false,
|
|
4027
3964
|
http1Allowed = true,
|
|
@@ -4481,6 +4418,7 @@ const normalizeHeaderValue = headerValue => {
|
|
|
4481
4418
|
https://developer.mozilla.org/en-US/docs/Web/API/Headers
|
|
4482
4419
|
https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch
|
|
4483
4420
|
*/
|
|
4421
|
+
|
|
4484
4422
|
const headersFromObject = headersObject => {
|
|
4485
4423
|
const headers = {};
|
|
4486
4424
|
Object.keys(headersObject).forEach(headerName => {
|
|
@@ -6769,6 +6707,7 @@ const serveDirectory = (url, {
|
|
|
6769
6707
|
* { status: 200, body: "Hello world" }.
|
|
6770
6708
|
* It is meant to be used inside "requestToResponse"
|
|
6771
6709
|
*/
|
|
6710
|
+
|
|
6772
6711
|
const fetchFileSystem = async (filesystemUrl, {
|
|
6773
6712
|
// signal,
|
|
6774
6713
|
method = "GET",
|
|
@@ -7856,7 +7795,7 @@ const createUrlInfo = url => {
|
|
|
7856
7795
|
dependents: new Set(),
|
|
7857
7796
|
implicitUrls: new Set(),
|
|
7858
7797
|
type: undefined,
|
|
7859
|
-
// "html", "css", "js_classic", "js_module", "importmap", "json", "webmanifest", ...
|
|
7798
|
+
// "html", "css", "js_classic", "js_module", "importmap", "sourcemap", "json", "webmanifest", ...
|
|
7860
7799
|
subtype: undefined,
|
|
7861
7800
|
// "worker", "service_worker", "shared_worker" for js, otherwise undefined
|
|
7862
7801
|
typeHint: undefined,
|
|
@@ -7891,7 +7830,7 @@ const createUrlInfo = url => {
|
|
|
7891
7830
|
|
|
7892
7831
|
const HOOK_NAMES = ["init", "serve",
|
|
7893
7832
|
// is called only during dev/tests
|
|
7894
|
-
"
|
|
7833
|
+
"resolveReference", "redirectReference", "transformReferenceSearchParams", "formatReference", "fetchUrlContent", "transformUrlContent", "finalizeUrlContent", "bundle",
|
|
7895
7834
|
// is called only during build
|
|
7896
7835
|
"optimizeUrlContent",
|
|
7897
7836
|
// is called only during build
|
|
@@ -7905,8 +7844,19 @@ const createPluginController = kitchenContext => {
|
|
|
7905
7844
|
// also it should increase perf as there is less work to do
|
|
7906
7845
|
const hookGroups = {};
|
|
7907
7846
|
const addPlugin = (plugin, {
|
|
7908
|
-
position = "
|
|
7847
|
+
position = "end"
|
|
7909
7848
|
}) => {
|
|
7849
|
+
if (Array.isArray(plugin)) {
|
|
7850
|
+
if (position === "start") {
|
|
7851
|
+
plugin = plugin.slice().reverse();
|
|
7852
|
+
}
|
|
7853
|
+
plugin.forEach(plugin => {
|
|
7854
|
+
addPlugin(plugin, {
|
|
7855
|
+
position
|
|
7856
|
+
});
|
|
7857
|
+
});
|
|
7858
|
+
return;
|
|
7859
|
+
}
|
|
7910
7860
|
if (plugin === null || typeof plugin !== "object") {
|
|
7911
7861
|
throw new TypeError(`plugin must be objects, got ${plugin}`);
|
|
7912
7862
|
}
|
|
@@ -7938,9 +7888,9 @@ const createPluginController = kitchenContext => {
|
|
|
7938
7888
|
value: hookValue
|
|
7939
7889
|
};
|
|
7940
7890
|
if (position === "start") {
|
|
7941
|
-
group.push(hook);
|
|
7942
|
-
} else {
|
|
7943
7891
|
group.unshift(hook);
|
|
7892
|
+
} else {
|
|
7893
|
+
group.push(hook);
|
|
7944
7894
|
}
|
|
7945
7895
|
}
|
|
7946
7896
|
});
|
|
@@ -7993,12 +7943,12 @@ const createPluginController = kitchenContext => {
|
|
|
7993
7943
|
};
|
|
7994
7944
|
const pushPlugin = plugin => {
|
|
7995
7945
|
addPlugin(plugin, {
|
|
7996
|
-
position: "
|
|
7946
|
+
position: "end"
|
|
7997
7947
|
});
|
|
7998
7948
|
};
|
|
7999
7949
|
const unshiftPlugin = plugin => {
|
|
8000
7950
|
addPlugin(plugin, {
|
|
8001
|
-
position: "
|
|
7951
|
+
position: "start"
|
|
8002
7952
|
});
|
|
8003
7953
|
};
|
|
8004
7954
|
let lastPluginUsed = null;
|
|
@@ -8155,7 +8105,7 @@ const assertAndNormalizeReturnValue = (hookName, returnValue) => {
|
|
|
8155
8105
|
};
|
|
8156
8106
|
const returnValueAssertions = [{
|
|
8157
8107
|
name: "url_assertion",
|
|
8158
|
-
appliesTo: ["
|
|
8108
|
+
appliesTo: ["resolveReference", "redirectReference"],
|
|
8159
8109
|
assertion: valueReturned => {
|
|
8160
8110
|
if (valueReturned instanceof URL) {
|
|
8161
8111
|
return valueReturned.href;
|
|
@@ -9151,6 +9101,7 @@ const createKitchen = ({
|
|
|
9151
9101
|
signal,
|
|
9152
9102
|
logLevel,
|
|
9153
9103
|
rootDirectoryUrl,
|
|
9104
|
+
mainFilePath,
|
|
9154
9105
|
urlGraph,
|
|
9155
9106
|
dev = false,
|
|
9156
9107
|
build = false,
|
|
@@ -9175,6 +9126,7 @@ const createKitchen = ({
|
|
|
9175
9126
|
signal,
|
|
9176
9127
|
logger,
|
|
9177
9128
|
rootDirectoryUrl,
|
|
9129
|
+
mainFilePath,
|
|
9178
9130
|
urlGraph,
|
|
9179
9131
|
dev,
|
|
9180
9132
|
build,
|
|
@@ -9192,16 +9144,34 @@ const createKitchen = ({
|
|
|
9192
9144
|
outDirectoryUrl
|
|
9193
9145
|
};
|
|
9194
9146
|
const pluginController = createPluginController(kitchenContext);
|
|
9195
|
-
|
|
9196
|
-
|
|
9197
|
-
|
|
9198
|
-
|
|
9199
|
-
|
|
9200
|
-
|
|
9201
|
-
|
|
9202
|
-
|
|
9203
|
-
|
|
9204
|
-
|
|
9147
|
+
plugins.forEach(pluginEntry => {
|
|
9148
|
+
pluginController.pushPlugin(pluginEntry);
|
|
9149
|
+
});
|
|
9150
|
+
|
|
9151
|
+
/*
|
|
9152
|
+
* - "http_request"
|
|
9153
|
+
* - "entry_point"
|
|
9154
|
+
* - "link_href"
|
|
9155
|
+
* - "style"
|
|
9156
|
+
* - "script"
|
|
9157
|
+
* - "a_href"
|
|
9158
|
+
* - "iframe_src
|
|
9159
|
+
* - "img_src"
|
|
9160
|
+
* - "img_srcset"
|
|
9161
|
+
* - "source_src"
|
|
9162
|
+
* - "source_srcset"
|
|
9163
|
+
* - "image_href"
|
|
9164
|
+
* - "use_href"
|
|
9165
|
+
* - "css_@import"
|
|
9166
|
+
* - "css_url"
|
|
9167
|
+
* - "js_import"
|
|
9168
|
+
* - "js_import_script"
|
|
9169
|
+
* - "js_url"
|
|
9170
|
+
* - "js_inline_content"
|
|
9171
|
+
* - "sourcemap_comment"
|
|
9172
|
+
* - "webmanifest_icon_src"
|
|
9173
|
+
* - "package_json"
|
|
9174
|
+
* */
|
|
9205
9175
|
const createReference = ({
|
|
9206
9176
|
data = {},
|
|
9207
9177
|
node,
|
|
@@ -9306,14 +9276,14 @@ const createKitchen = ({
|
|
|
9306
9276
|
resolveReference: (reference, context = referenceContext) => resolveReference(reference, context)
|
|
9307
9277
|
};
|
|
9308
9278
|
try {
|
|
9309
|
-
let
|
|
9310
|
-
if (!
|
|
9279
|
+
let url = pluginController.callHooksUntil("resolveReference", reference, referenceContext);
|
|
9280
|
+
if (!url) {
|
|
9311
9281
|
throw new Error(`NO_RESOLVE`);
|
|
9312
9282
|
}
|
|
9313
|
-
if (
|
|
9283
|
+
if (url.includes("?debug")) {
|
|
9314
9284
|
reference.debug = true;
|
|
9315
9285
|
}
|
|
9316
|
-
|
|
9286
|
+
url = normalizeUrl(url);
|
|
9317
9287
|
let referencedUrlObject;
|
|
9318
9288
|
let searchParams;
|
|
9319
9289
|
const onReferenceUrlChange = referenceUrl => {
|
|
@@ -9322,14 +9292,14 @@ const createKitchen = ({
|
|
|
9322
9292
|
reference.url = referenceUrl;
|
|
9323
9293
|
reference.searchParams = searchParams;
|
|
9324
9294
|
};
|
|
9325
|
-
onReferenceUrlChange(
|
|
9295
|
+
onReferenceUrlChange(url);
|
|
9326
9296
|
if (reference.debug) {
|
|
9327
9297
|
logger.debug(`url resolved by "${pluginController.getLastPluginUsed().name}"
|
|
9328
9298
|
${ANSI.color(reference.specifier, ANSI.GREY)} ->
|
|
9329
9299
|
${ANSI.color(reference.url, ANSI.YELLOW)}
|
|
9330
9300
|
`);
|
|
9331
9301
|
}
|
|
9332
|
-
pluginController.callHooks("
|
|
9302
|
+
pluginController.callHooks("redirectReference", reference, referenceContext, (returnValue, plugin) => {
|
|
9333
9303
|
const normalizedReturnValue = normalizeUrl(returnValue);
|
|
9334
9304
|
if (normalizedReturnValue === reference.url) {
|
|
9335
9305
|
return;
|
|
@@ -9356,13 +9326,13 @@ ${ANSI.color(normalizedReturnValue, ANSI.YELLOW)}
|
|
|
9356
9326
|
// - convey information (?hmr)
|
|
9357
9327
|
// But do not represent an other resource, it is considered as
|
|
9358
9328
|
// the same resource under the hood
|
|
9359
|
-
pluginController.callHooks("
|
|
9329
|
+
pluginController.callHooks("transformReferenceSearchParams", reference, referenceContext, returnValue => {
|
|
9360
9330
|
Object.keys(returnValue).forEach(key => {
|
|
9361
9331
|
searchParams.set(key, returnValue[key]);
|
|
9362
9332
|
});
|
|
9363
9333
|
reference.generatedUrl = normalizeUrl(referencedUrlObject.href);
|
|
9364
9334
|
});
|
|
9365
|
-
const returnValue = pluginController.callHooksUntil("
|
|
9335
|
+
const returnValue = pluginController.callHooksUntil("formatReference", reference, referenceContext);
|
|
9366
9336
|
reference.generatedSpecifier = returnValue || reference.generatedUrl;
|
|
9367
9337
|
reference.generatedSpecifier = urlSpecifierEncoding.encode(reference);
|
|
9368
9338
|
return [reference, urlInfo];
|
|
@@ -10259,7 +10229,7 @@ const createRepartitionMessage = ({
|
|
|
10259
10229
|
};
|
|
10260
10230
|
|
|
10261
10231
|
const jsenvPluginReferenceExpectedTypes = () => {
|
|
10262
|
-
const
|
|
10232
|
+
const redirectJsReference = reference => {
|
|
10263
10233
|
const urlObject = new URL(reference.url);
|
|
10264
10234
|
const {
|
|
10265
10235
|
searchParams
|
|
@@ -10269,16 +10239,23 @@ const jsenvPluginReferenceExpectedTypes = () => {
|
|
|
10269
10239
|
}
|
|
10270
10240
|
if (searchParams.has("js_classic")) {
|
|
10271
10241
|
reference.expectedType = "js_classic";
|
|
10272
|
-
} else if (searchParams.has("
|
|
10242
|
+
} else if (searchParams.has("js_module")) {
|
|
10243
|
+
reference.expectedType = "js_module";
|
|
10244
|
+
}
|
|
10245
|
+
// we need to keep these checks here because during versioning:
|
|
10246
|
+
// - only reference anlysis plugin is executed
|
|
10247
|
+
// -> plugin about js transpilation don't apply and can't set expectedType: 'js_classic'
|
|
10248
|
+
// - query params like ?js_module_fallback are still there
|
|
10249
|
+
// - without this check build would throw as reference could expect js module and find js classic
|
|
10250
|
+
else if (searchParams.has("js_module_fallback") || searchParams.has("as_js_classic")) {
|
|
10273
10251
|
reference.expectedType = "js_classic";
|
|
10274
10252
|
} else if (searchParams.has("as_js_module")) {
|
|
10275
10253
|
reference.expectedType = "js_module";
|
|
10276
|
-
}
|
|
10277
|
-
|
|
10278
|
-
|
|
10279
|
-
|
|
10280
|
-
|
|
10281
|
-
// new URL('./file.js?js_classic', import.meta.url)
|
|
10254
|
+
}
|
|
10255
|
+
// by default, js referenced by new URL is considered as "js_module"
|
|
10256
|
+
// in case this is not desired code must use "?js_classic" like
|
|
10257
|
+
// new URL('./file.js?js_classic', import.meta.url)
|
|
10258
|
+
else if (reference.type === "js_url" && reference.expectedType === undefined && CONTENT_TYPE.fromUrlExtension(reference.url) === "text/javascript") {
|
|
10282
10259
|
reference.expectedType = "js_module";
|
|
10283
10260
|
}
|
|
10284
10261
|
if (searchParams.has("worker")) {
|
|
@@ -10293,40 +10270,175 @@ const jsenvPluginReferenceExpectedTypes = () => {
|
|
|
10293
10270
|
return {
|
|
10294
10271
|
name: "jsenv:reference_expected_types",
|
|
10295
10272
|
appliesDuring: "*",
|
|
10296
|
-
|
|
10297
|
-
script:
|
|
10298
|
-
js_url:
|
|
10299
|
-
js_import:
|
|
10273
|
+
redirectReference: {
|
|
10274
|
+
script: redirectJsReference,
|
|
10275
|
+
js_url: redirectJsReference,
|
|
10276
|
+
js_import: redirectJsReference
|
|
10277
|
+
}
|
|
10278
|
+
};
|
|
10279
|
+
};
|
|
10280
|
+
|
|
10281
|
+
const jsenvPluginDirectoryReferenceAnalysis = () => {
|
|
10282
|
+
return {
|
|
10283
|
+
name: "jsenv:directory_reference_analysis",
|
|
10284
|
+
transformUrlContent: {
|
|
10285
|
+
directory: (urlInfo, context) => {
|
|
10286
|
+
const originalDirectoryReference = findOriginalDirectoryReference(urlInfo, context);
|
|
10287
|
+
const directoryRelativeUrl = urlToRelativeUrl(urlInfo.url, context.rootDirectoryUrl);
|
|
10288
|
+
JSON.parse(urlInfo.content).forEach(directoryEntryName => {
|
|
10289
|
+
context.referenceUtils.found({
|
|
10290
|
+
type: "filesystem",
|
|
10291
|
+
subtype: "directory_entry",
|
|
10292
|
+
specifier: directoryEntryName,
|
|
10293
|
+
trace: {
|
|
10294
|
+
message: `"${directoryRelativeUrl}${directoryEntryName}" entry in directory referenced by ${originalDirectoryReference.trace.message}`
|
|
10295
|
+
}
|
|
10296
|
+
});
|
|
10297
|
+
});
|
|
10298
|
+
}
|
|
10299
|
+
}
|
|
10300
|
+
};
|
|
10301
|
+
};
|
|
10302
|
+
const findOriginalDirectoryReference = (urlInfo, context) => {
|
|
10303
|
+
const findNonFileSystemAncestor = urlInfo => {
|
|
10304
|
+
for (const dependentUrl of urlInfo.dependents) {
|
|
10305
|
+
const dependentUrlInfo = context.urlGraph.getUrlInfo(dependentUrl);
|
|
10306
|
+
if (dependentUrlInfo.type !== "directory") {
|
|
10307
|
+
return [dependentUrlInfo, urlInfo];
|
|
10308
|
+
}
|
|
10309
|
+
const found = findNonFileSystemAncestor(dependentUrlInfo);
|
|
10310
|
+
if (found) {
|
|
10311
|
+
return found;
|
|
10312
|
+
}
|
|
10313
|
+
}
|
|
10314
|
+
return [];
|
|
10315
|
+
};
|
|
10316
|
+
const [ancestor, child] = findNonFileSystemAncestor(urlInfo);
|
|
10317
|
+
if (!ancestor) {
|
|
10318
|
+
return null;
|
|
10319
|
+
}
|
|
10320
|
+
const ref = ancestor.references.find(ref => ref.url === child.url);
|
|
10321
|
+
return ref;
|
|
10322
|
+
};
|
|
10323
|
+
|
|
10324
|
+
const jsenvPluginDataUrlsAnalysis = () => {
|
|
10325
|
+
return {
|
|
10326
|
+
name: "jsenv:data_urls_analysis",
|
|
10327
|
+
appliesDuring: "*",
|
|
10328
|
+
resolveReference: reference => {
|
|
10329
|
+
if (!reference.specifier.startsWith("data:")) {
|
|
10330
|
+
return null;
|
|
10331
|
+
}
|
|
10332
|
+
return reference.specifier;
|
|
10333
|
+
},
|
|
10334
|
+
formatReference: (reference, context) => {
|
|
10335
|
+
if (!reference.generatedUrl.startsWith("data:")) {
|
|
10336
|
+
return null;
|
|
10337
|
+
}
|
|
10338
|
+
if (reference.type === "sourcemap_comment") {
|
|
10339
|
+
return null;
|
|
10340
|
+
}
|
|
10341
|
+
return (async () => {
|
|
10342
|
+
const urlInfo = context.urlGraph.getUrlInfo(reference.url);
|
|
10343
|
+
await context.cook(urlInfo, {
|
|
10344
|
+
reference
|
|
10345
|
+
});
|
|
10346
|
+
if (urlInfo.originalContent === urlInfo.content) {
|
|
10347
|
+
return reference.generatedUrl;
|
|
10348
|
+
}
|
|
10349
|
+
const specifier = DATA_URL.stringify({
|
|
10350
|
+
contentType: urlInfo.contentType,
|
|
10351
|
+
base64Flag: urlInfo.data.base64Flag,
|
|
10352
|
+
data: urlInfo.data.base64Flag ? dataToBase64(urlInfo.content) : String(urlInfo.content)
|
|
10353
|
+
});
|
|
10354
|
+
return specifier;
|
|
10355
|
+
})();
|
|
10356
|
+
},
|
|
10357
|
+
fetchUrlContent: urlInfo => {
|
|
10358
|
+
if (!urlInfo.url.startsWith("data:")) {
|
|
10359
|
+
return null;
|
|
10360
|
+
}
|
|
10361
|
+
const {
|
|
10362
|
+
contentType,
|
|
10363
|
+
base64Flag,
|
|
10364
|
+
data: urlData
|
|
10365
|
+
} = DATA_URL.parse(urlInfo.url);
|
|
10366
|
+
urlInfo.data.base64Flag = base64Flag;
|
|
10367
|
+
return {
|
|
10368
|
+
content: contentFromUrlData({
|
|
10369
|
+
contentType,
|
|
10370
|
+
base64Flag,
|
|
10371
|
+
urlData
|
|
10372
|
+
}),
|
|
10373
|
+
contentType
|
|
10374
|
+
};
|
|
10300
10375
|
}
|
|
10301
10376
|
};
|
|
10302
10377
|
};
|
|
10378
|
+
const contentFromUrlData = ({
|
|
10379
|
+
contentType,
|
|
10380
|
+
base64Flag,
|
|
10381
|
+
urlData
|
|
10382
|
+
}) => {
|
|
10383
|
+
if (CONTENT_TYPE.isTextual(contentType)) {
|
|
10384
|
+
if (base64Flag) {
|
|
10385
|
+
return base64ToString(urlData);
|
|
10386
|
+
}
|
|
10387
|
+
return urlData;
|
|
10388
|
+
}
|
|
10389
|
+
if (base64Flag) {
|
|
10390
|
+
return base64ToBuffer(urlData);
|
|
10391
|
+
}
|
|
10392
|
+
return Buffer.from(urlData);
|
|
10393
|
+
};
|
|
10394
|
+
const base64ToBuffer = base64String => Buffer.from(base64String, "base64");
|
|
10395
|
+
const base64ToString = base64String => Buffer.from(base64String, "base64").toString("utf8");
|
|
10396
|
+
const dataToBase64 = data => Buffer.from(data).toString("base64");
|
|
10303
10397
|
|
|
10304
|
-
const
|
|
10398
|
+
const jsenvPluginHtmlReferenceAnalysis = ({
|
|
10399
|
+
inlineContent,
|
|
10400
|
+
inlineConvertedScript
|
|
10401
|
+
}) => {
|
|
10402
|
+
return {
|
|
10403
|
+
name: "jsenv:html_reference_analysis",
|
|
10404
|
+
appliesDuring: "*",
|
|
10405
|
+
transformUrlContent: {
|
|
10406
|
+
html: (urlInfo, context) => parseAndTransformHtmlReferences(urlInfo, context, {
|
|
10407
|
+
inlineContent,
|
|
10408
|
+
inlineConvertedScript
|
|
10409
|
+
})
|
|
10410
|
+
}
|
|
10411
|
+
};
|
|
10412
|
+
};
|
|
10413
|
+
const parseAndTransformHtmlReferences = async (urlInfo, context, {
|
|
10414
|
+
inlineContent,
|
|
10415
|
+
inlineConvertedScript
|
|
10416
|
+
}) => {
|
|
10305
10417
|
const url = urlInfo.originalUrl;
|
|
10306
10418
|
const content = urlInfo.content;
|
|
10307
|
-
const htmlAst = parseHtmlString(content
|
|
10308
|
-
storeOriginalPositions: context.dev
|
|
10309
|
-
});
|
|
10310
|
-
const mentions = visitHtmlUrls({
|
|
10311
|
-
url,
|
|
10312
|
-
htmlAst
|
|
10313
|
-
});
|
|
10419
|
+
const htmlAst = parseHtmlString(content);
|
|
10314
10420
|
const mutations = [];
|
|
10315
10421
|
const actions = [];
|
|
10316
|
-
|
|
10422
|
+
const finalizeCallbacks = [];
|
|
10423
|
+
const createExternalReference = (node, attributeName, attributeValue, {
|
|
10424
|
+
type,
|
|
10425
|
+
subtype,
|
|
10426
|
+
expectedType
|
|
10427
|
+
}) => {
|
|
10428
|
+
let position;
|
|
10429
|
+
if (getHtmlNodeAttribute(node, "jsenv-cooked-by")) {
|
|
10430
|
+
// when generated from inline content,
|
|
10431
|
+
// line, column is not "src" nor "inlined-from-src" but "original-position"
|
|
10432
|
+
position = getHtmlNodePosition(node);
|
|
10433
|
+
} else {
|
|
10434
|
+
position = getHtmlNodeAttributePosition(node, attributeName);
|
|
10435
|
+
}
|
|
10317
10436
|
const {
|
|
10318
|
-
type,
|
|
10319
|
-
subtype,
|
|
10320
|
-
expectedType,
|
|
10321
10437
|
line,
|
|
10322
|
-
column
|
|
10323
|
-
originalLine,
|
|
10324
|
-
|
|
10325
|
-
|
|
10326
|
-
attributeName,
|
|
10327
|
-
debug,
|
|
10328
|
-
specifier
|
|
10329
|
-
} = mention;
|
|
10438
|
+
column
|
|
10439
|
+
// originalLine, originalColumn
|
|
10440
|
+
} = position;
|
|
10441
|
+
const debug = getHtmlNodeAttribute(node, "jsenv-debug") !== undefined;
|
|
10330
10442
|
const {
|
|
10331
10443
|
crossorigin,
|
|
10332
10444
|
integrity
|
|
@@ -10336,9 +10448,7 @@ const parseAndTransformHtmlUrls = async (urlInfo, context) => {
|
|
|
10336
10448
|
type,
|
|
10337
10449
|
subtype,
|
|
10338
10450
|
expectedType,
|
|
10339
|
-
|
|
10340
|
-
originalColumn,
|
|
10341
|
-
specifier,
|
|
10451
|
+
specifier: attributeValue,
|
|
10342
10452
|
specifierLine: line,
|
|
10343
10453
|
specifierColumn: column,
|
|
10344
10454
|
isResourceHint,
|
|
@@ -10354,221 +10464,283 @@ const parseAndTransformHtmlUrls = async (urlInfo, context) => {
|
|
|
10354
10464
|
});
|
|
10355
10465
|
});
|
|
10356
10466
|
});
|
|
10357
|
-
}
|
|
10358
|
-
|
|
10359
|
-
|
|
10360
|
-
|
|
10361
|
-
|
|
10467
|
+
};
|
|
10468
|
+
const visitHref = (node, referenceProps) => {
|
|
10469
|
+
const href = getHtmlNodeAttribute(node, "href");
|
|
10470
|
+
if (href) {
|
|
10471
|
+
return createExternalReference(node, "href", href, referenceProps);
|
|
10472
|
+
}
|
|
10473
|
+
const inlinedFromHref = getHtmlNodeAttribute(node, "inlined-from-href");
|
|
10474
|
+
if (inlinedFromHref) {
|
|
10475
|
+
return createExternalReference(node, "inlined-from-href", new URL(inlinedFromHref, url).href, referenceProps);
|
|
10476
|
+
}
|
|
10362
10477
|
return null;
|
|
10363
|
-
}
|
|
10364
|
-
|
|
10365
|
-
|
|
10366
|
-
|
|
10367
|
-
|
|
10368
|
-
|
|
10369
|
-
const
|
|
10370
|
-
|
|
10371
|
-
|
|
10372
|
-
|
|
10373
|
-
|
|
10374
|
-
}
|
|
10375
|
-
|
|
10376
|
-
const
|
|
10377
|
-
|
|
10378
|
-
|
|
10379
|
-
|
|
10380
|
-
|
|
10381
|
-
|
|
10382
|
-
|
|
10383
|
-
|
|
10384
|
-
}
|
|
10385
|
-
const
|
|
10386
|
-
|
|
10387
|
-
const addMention = ({
|
|
10478
|
+
};
|
|
10479
|
+
const visitSrc = (node, referenceProps) => {
|
|
10480
|
+
const src = getHtmlNodeAttribute(node, "src");
|
|
10481
|
+
if (src) {
|
|
10482
|
+
return createExternalReference(node, "src", src, referenceProps);
|
|
10483
|
+
}
|
|
10484
|
+
const inlinedFromSrc = getHtmlNodeAttribute(node, "inlined-from-src");
|
|
10485
|
+
if (inlinedFromSrc) {
|
|
10486
|
+
return createExternalReference(node, "inlined-from-src", new URL(inlinedFromSrc, url).href, referenceProps);
|
|
10487
|
+
}
|
|
10488
|
+
return null;
|
|
10489
|
+
};
|
|
10490
|
+
const visitSrcset = (node, referenceProps) => {
|
|
10491
|
+
const srcset = getHtmlNodeAttribute(node, "srcset");
|
|
10492
|
+
if (srcset) {
|
|
10493
|
+
const srcCandidates = parseSrcSet(srcset);
|
|
10494
|
+
return srcCandidates.map(srcCandidate => {
|
|
10495
|
+
return createExternalReference(node, "srcset", srcCandidate.specifier, referenceProps);
|
|
10496
|
+
});
|
|
10497
|
+
}
|
|
10498
|
+
return null;
|
|
10499
|
+
};
|
|
10500
|
+
const createInlineReference = (node, inlineContent, {
|
|
10501
|
+
extension,
|
|
10388
10502
|
type,
|
|
10389
|
-
subtype,
|
|
10390
10503
|
expectedType,
|
|
10391
|
-
|
|
10392
|
-
attributeName,
|
|
10393
|
-
specifier
|
|
10504
|
+
contentType
|
|
10394
10505
|
}) => {
|
|
10395
|
-
|
|
10396
|
-
if (getHtmlNodeAttribute(node, "jsenv-cooked-by")) {
|
|
10397
|
-
// when generated from inline content,
|
|
10398
|
-
// line, column is not "src" nor "inlined-from-src" but "original-position"
|
|
10399
|
-
position = getHtmlNodePosition(node);
|
|
10400
|
-
} else {
|
|
10401
|
-
position = getHtmlNodeAttributePosition(node, attributeName);
|
|
10402
|
-
}
|
|
10506
|
+
const hotAccept = getHtmlNodeAttribute(node, "hot-accept") !== undefined;
|
|
10403
10507
|
const {
|
|
10404
10508
|
line,
|
|
10405
|
-
column
|
|
10406
|
-
|
|
10407
|
-
|
|
10408
|
-
|
|
10409
|
-
|
|
10410
|
-
|
|
10411
|
-
|
|
10412
|
-
|
|
10509
|
+
column,
|
|
10510
|
+
lineEnd,
|
|
10511
|
+
columnEnd,
|
|
10512
|
+
isOriginal
|
|
10513
|
+
} = getHtmlNodePosition(node, {
|
|
10514
|
+
preferOriginal: true
|
|
10515
|
+
});
|
|
10516
|
+
const inlineContentUrl = generateInlineContentUrl({
|
|
10517
|
+
url: urlInfo.url,
|
|
10518
|
+
extension,
|
|
10413
10519
|
line,
|
|
10414
10520
|
column,
|
|
10415
|
-
|
|
10416
|
-
|
|
10521
|
+
lineEnd,
|
|
10522
|
+
columnEnd
|
|
10523
|
+
});
|
|
10524
|
+
const debug = getHtmlNodeAttribute(node, "jsenv-debug") !== undefined;
|
|
10525
|
+
const [inlineReference, inlineUrlInfo] = context.referenceUtils.foundInline({
|
|
10417
10526
|
node,
|
|
10418
|
-
|
|
10527
|
+
type,
|
|
10528
|
+
expectedType,
|
|
10529
|
+
isOriginalPosition: isOriginal,
|
|
10530
|
+
// we remove 1 to the line because imagine the following html:
|
|
10531
|
+
// <style>body { color: red; }</style>
|
|
10532
|
+
// -> content starts same line as <style> (same for <script>)
|
|
10533
|
+
specifierLine: line - 1,
|
|
10534
|
+
specifierColumn: column,
|
|
10535
|
+
specifier: inlineContentUrl,
|
|
10536
|
+
contentType,
|
|
10537
|
+
content: inlineContent,
|
|
10419
10538
|
debug
|
|
10420
|
-
};
|
|
10421
|
-
|
|
10422
|
-
|
|
10423
|
-
|
|
10424
|
-
|
|
10425
|
-
|
|
10426
|
-
attributeName,
|
|
10427
|
-
...rest
|
|
10428
|
-
}) => {
|
|
10429
|
-
const value = getHtmlNodeAttribute(node, attributeName);
|
|
10430
|
-
if (value) {
|
|
10431
|
-
if (getHtmlNodeAttribute(node, "jsenv-inlined-by") === "jsenv:importmap") {
|
|
10432
|
-
// during build the importmap is inlined
|
|
10433
|
-
// and shoud not be considered as a dependency anymore
|
|
10434
|
-
return null;
|
|
10435
|
-
}
|
|
10436
|
-
return addMention({
|
|
10437
|
-
...rest,
|
|
10438
|
-
node,
|
|
10439
|
-
attributeName,
|
|
10440
|
-
specifier: attributeName === "inlined-from-src" || attributeName === "inlined-from-href" ? new URL(value, url).href : value
|
|
10441
|
-
});
|
|
10442
|
-
}
|
|
10443
|
-
if (attributeName === "src") {
|
|
10444
|
-
return visitAttributeAsUrlSpecifier({
|
|
10445
|
-
...rest,
|
|
10446
|
-
node,
|
|
10447
|
-
attributeName: "inlined-from-src"
|
|
10539
|
+
});
|
|
10540
|
+
actions.push(async () => {
|
|
10541
|
+
await cookInlineContent({
|
|
10542
|
+
context,
|
|
10543
|
+
inlineContentUrlInfo: inlineUrlInfo,
|
|
10544
|
+
inlineContentReference: inlineReference
|
|
10448
10545
|
});
|
|
10449
|
-
|
|
10450
|
-
|
|
10451
|
-
|
|
10452
|
-
|
|
10453
|
-
|
|
10454
|
-
|
|
10546
|
+
mutations.push(() => {
|
|
10547
|
+
if (hotAccept) {
|
|
10548
|
+
removeHtmlNodeText(node);
|
|
10549
|
+
setHtmlNodeAttributes(node, {
|
|
10550
|
+
"jsenv-cooked-by": "jsenv:html_inline_content_analysis"
|
|
10551
|
+
});
|
|
10552
|
+
} else {
|
|
10553
|
+
setHtmlNodeText(node, inlineUrlInfo.content, {
|
|
10554
|
+
indentation: false // indentation would decrease stack trace precision
|
|
10555
|
+
});
|
|
10556
|
+
|
|
10557
|
+
setHtmlNodeAttributes(node, {
|
|
10558
|
+
"jsenv-cooked-by": "jsenv:html_inline_content_analysis"
|
|
10559
|
+
});
|
|
10560
|
+
}
|
|
10455
10561
|
});
|
|
10456
|
-
}
|
|
10457
|
-
return
|
|
10562
|
+
});
|
|
10563
|
+
return inlineReference;
|
|
10458
10564
|
};
|
|
10459
|
-
const
|
|
10565
|
+
const visitTextContent = (node, {
|
|
10566
|
+
extension,
|
|
10460
10567
|
type,
|
|
10461
|
-
|
|
10568
|
+
expectedType,
|
|
10569
|
+
contentType
|
|
10462
10570
|
}) => {
|
|
10463
|
-
const
|
|
10464
|
-
if (
|
|
10465
|
-
|
|
10466
|
-
srcCandidates.forEach(srcCandidate => {
|
|
10467
|
-
addMention({
|
|
10468
|
-
type,
|
|
10469
|
-
node,
|
|
10470
|
-
attributeName: "srcset",
|
|
10471
|
-
specifier: srcCandidate.specifier
|
|
10472
|
-
});
|
|
10473
|
-
});
|
|
10571
|
+
const inlineContent = getHtmlNodeText(node);
|
|
10572
|
+
if (!inlineContent) {
|
|
10573
|
+
return null;
|
|
10474
10574
|
}
|
|
10575
|
+
return createInlineReference(node, inlineContent, {
|
|
10576
|
+
extension,
|
|
10577
|
+
type,
|
|
10578
|
+
expectedType,
|
|
10579
|
+
contentType
|
|
10580
|
+
});
|
|
10475
10581
|
};
|
|
10476
10582
|
visitHtmlNodes(htmlAst, {
|
|
10477
|
-
link:
|
|
10478
|
-
const rel = getHtmlNodeAttribute(
|
|
10479
|
-
const type = getHtmlNodeAttribute(
|
|
10480
|
-
const
|
|
10583
|
+
link: linkNode => {
|
|
10584
|
+
const rel = getHtmlNodeAttribute(linkNode, "rel");
|
|
10585
|
+
const type = getHtmlNodeAttribute(linkNode, "type");
|
|
10586
|
+
const ref = visitHref(linkNode, {
|
|
10481
10587
|
type: "link_href",
|
|
10482
10588
|
subtype: rel,
|
|
10483
|
-
node,
|
|
10484
|
-
attributeName: "href",
|
|
10485
10589
|
// https://developer.mozilla.org/en-US/docs/Web/HTML/Link_types/preload#including_a_mime_type
|
|
10486
10590
|
expectedContentType: type
|
|
10487
10591
|
});
|
|
10488
|
-
if (
|
|
10592
|
+
if (ref) {
|
|
10489
10593
|
finalizeCallbacks.push(() => {
|
|
10490
|
-
|
|
10594
|
+
ref.expectedType = decideLinkExpectedType(ref, context);
|
|
10491
10595
|
});
|
|
10492
10596
|
}
|
|
10493
10597
|
},
|
|
10494
|
-
|
|
10495
|
-
|
|
10598
|
+
style: inlineContent ? styleNode => {
|
|
10599
|
+
visitTextContent(styleNode, {
|
|
10600
|
+
extension: ".css",
|
|
10601
|
+
type: "style",
|
|
10602
|
+
expectedType: "css",
|
|
10603
|
+
contentType: "text/css"
|
|
10604
|
+
});
|
|
10605
|
+
} : null,
|
|
10606
|
+
script: scriptNode => {
|
|
10607
|
+
// during build the importmap is inlined
|
|
10608
|
+
// and shoud not be considered as a dependency anymore
|
|
10609
|
+
if (getHtmlNodeAttribute(scriptNode, "jsenv-inlined-by") === "jsenv:importmap") {
|
|
10610
|
+
return;
|
|
10611
|
+
}
|
|
10496
10612
|
const {
|
|
10497
|
-
type
|
|
10498
|
-
|
|
10499
|
-
|
|
10500
|
-
|
|
10501
|
-
|
|
10502
|
-
|
|
10613
|
+
type,
|
|
10614
|
+
contentType,
|
|
10615
|
+
extension
|
|
10616
|
+
} = analyzeScriptNode(scriptNode);
|
|
10617
|
+
// ignore <script type="whatever">foobar</script>
|
|
10618
|
+
// per HTML spec https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script#attr-type
|
|
10619
|
+
if (type !== "text") {
|
|
10620
|
+
const externalRef = visitSrc(scriptNode, {
|
|
10621
|
+
type: "script",
|
|
10622
|
+
subtype: type,
|
|
10623
|
+
expectedType: type
|
|
10624
|
+
});
|
|
10625
|
+
if (externalRef) {
|
|
10626
|
+
return;
|
|
10627
|
+
}
|
|
10628
|
+
}
|
|
10629
|
+
|
|
10630
|
+
// now visit the content, if any
|
|
10631
|
+
if (!inlineContent) {
|
|
10503
10632
|
return;
|
|
10504
10633
|
}
|
|
10505
|
-
|
|
10634
|
+
// If the inline script was already handled by an other plugin, ignore it
|
|
10635
|
+
// - we want to preserve inline scripts generated by html supervisor during dev
|
|
10636
|
+
// - we want to avoid cooking twice a script during build
|
|
10637
|
+
if (!inlineConvertedScript && getHtmlNodeAttribute(scriptNode, "jsenv-injected-by") === "jsenv:js_module_fallback") {
|
|
10638
|
+
return;
|
|
10639
|
+
}
|
|
10640
|
+
const inlineRef = visitTextContent(scriptNode, {
|
|
10641
|
+
extension: extension || CONTENT_TYPE.asFileExtension(contentType),
|
|
10506
10642
|
type: "script",
|
|
10507
|
-
subtype: type,
|
|
10508
10643
|
expectedType: type,
|
|
10509
|
-
|
|
10510
|
-
attributeName: "src"
|
|
10644
|
+
contentType
|
|
10511
10645
|
});
|
|
10646
|
+
if (inlineRef && extension) {
|
|
10647
|
+
// 1. <script type="jsx"> becomes <script>
|
|
10648
|
+
// 2. <script type="module/jsx"> becomes <script type="module">
|
|
10649
|
+
mutations.push(() => {
|
|
10650
|
+
setHtmlNodeAttributes(scriptNode, {
|
|
10651
|
+
type: type === "js_module" ? "module" : undefined
|
|
10652
|
+
});
|
|
10653
|
+
});
|
|
10654
|
+
}
|
|
10512
10655
|
},
|
|
10513
|
-
a:
|
|
10514
|
-
|
|
10515
|
-
type: "a_href"
|
|
10516
|
-
node,
|
|
10517
|
-
attributeName: "href"
|
|
10656
|
+
a: aNode => {
|
|
10657
|
+
visitHref(aNode, {
|
|
10658
|
+
type: "a_href"
|
|
10518
10659
|
});
|
|
10519
10660
|
},
|
|
10520
|
-
iframe:
|
|
10521
|
-
|
|
10522
|
-
type: "iframe_src"
|
|
10523
|
-
node,
|
|
10524
|
-
attributeName: "src"
|
|
10661
|
+
iframe: iframeNode => {
|
|
10662
|
+
visitSrc(iframeNode, {
|
|
10663
|
+
type: "iframe_src"
|
|
10525
10664
|
});
|
|
10526
10665
|
},
|
|
10527
|
-
img:
|
|
10528
|
-
|
|
10529
|
-
type: "img_src"
|
|
10530
|
-
node,
|
|
10531
|
-
attributeName: "src"
|
|
10666
|
+
img: imgNode => {
|
|
10667
|
+
visitSrc(imgNode, {
|
|
10668
|
+
type: "img_src"
|
|
10532
10669
|
});
|
|
10533
|
-
visitSrcset({
|
|
10534
|
-
type: "img_srcset"
|
|
10535
|
-
node
|
|
10670
|
+
visitSrcset(imgNode, {
|
|
10671
|
+
type: "img_srcset"
|
|
10536
10672
|
});
|
|
10537
10673
|
},
|
|
10538
|
-
source:
|
|
10539
|
-
|
|
10540
|
-
type: "source_src"
|
|
10541
|
-
node,
|
|
10542
|
-
attributeName: "src"
|
|
10674
|
+
source: sourceNode => {
|
|
10675
|
+
visitSrc(sourceNode, {
|
|
10676
|
+
type: "source_src"
|
|
10543
10677
|
});
|
|
10544
|
-
visitSrcset({
|
|
10545
|
-
type: "source_srcset"
|
|
10546
|
-
node
|
|
10678
|
+
visitSrcset(sourceNode, {
|
|
10679
|
+
type: "source_srcset"
|
|
10547
10680
|
});
|
|
10548
10681
|
},
|
|
10549
10682
|
// svg <image> tag
|
|
10550
|
-
image:
|
|
10551
|
-
|
|
10552
|
-
type: "image_href"
|
|
10553
|
-
node,
|
|
10554
|
-
attributeName: "href"
|
|
10683
|
+
image: imageNode => {
|
|
10684
|
+
visitHref(imageNode, {
|
|
10685
|
+
type: "image_href"
|
|
10555
10686
|
});
|
|
10556
10687
|
},
|
|
10557
|
-
use:
|
|
10558
|
-
|
|
10559
|
-
type: "use_href"
|
|
10560
|
-
node,
|
|
10561
|
-
attributeName: "href"
|
|
10688
|
+
use: useNode => {
|
|
10689
|
+
visitHref(useNode, {
|
|
10690
|
+
type: "use_href"
|
|
10562
10691
|
});
|
|
10563
10692
|
}
|
|
10564
10693
|
});
|
|
10565
10694
|
finalizeCallbacks.forEach(finalizeCallback => {
|
|
10566
10695
|
finalizeCallback();
|
|
10567
10696
|
});
|
|
10568
|
-
|
|
10697
|
+
if (actions.length > 0) {
|
|
10698
|
+
await Promise.all(actions.map(action => action()));
|
|
10699
|
+
}
|
|
10700
|
+
if (mutations.length === 0) {
|
|
10701
|
+
return null;
|
|
10702
|
+
}
|
|
10703
|
+
mutations.forEach(mutation => mutation());
|
|
10704
|
+
return stringifyHtmlAst(htmlAst);
|
|
10705
|
+
};
|
|
10706
|
+
const cookInlineContent = async ({
|
|
10707
|
+
context,
|
|
10708
|
+
inlineContentUrlInfo,
|
|
10709
|
+
inlineContentReference
|
|
10710
|
+
}) => {
|
|
10711
|
+
try {
|
|
10712
|
+
await context.cook(inlineContentUrlInfo, {
|
|
10713
|
+
reference: inlineContentReference
|
|
10714
|
+
});
|
|
10715
|
+
} catch (e) {
|
|
10716
|
+
if (e.code === "PARSE_ERROR") {
|
|
10717
|
+
// When something like <style> or <script> contains syntax error
|
|
10718
|
+
// the HTML in itself it still valid
|
|
10719
|
+
// keep the syntax error and continue with the HTML
|
|
10720
|
+
const messageStart = inlineContentUrlInfo.type === "css" ? `Syntax error on css declared inside <style>` : `Syntax error on js declared inside <script>`;
|
|
10721
|
+
context.logger.error(`${messageStart}: ${e.cause.reasonCode}
|
|
10722
|
+
${e.traceMessage}`);
|
|
10723
|
+
} else {
|
|
10724
|
+
throw e;
|
|
10725
|
+
}
|
|
10726
|
+
}
|
|
10727
|
+
};
|
|
10728
|
+
const crossOriginCompatibleTagNames = ["script", "link", "img", "source"];
|
|
10729
|
+
const integrityCompatibleTagNames = ["script", "link", "img", "source"];
|
|
10730
|
+
const readFetchMetas = node => {
|
|
10731
|
+
const meta = {};
|
|
10732
|
+
if (crossOriginCompatibleTagNames.includes(node.nodeName)) {
|
|
10733
|
+
const crossorigin = getHtmlNodeAttribute(node, "crossorigin") !== undefined;
|
|
10734
|
+
meta.crossorigin = crossorigin;
|
|
10735
|
+
}
|
|
10736
|
+
if (integrityCompatibleTagNames.includes(node.nodeName)) {
|
|
10737
|
+
const integrity = getHtmlNodeAttribute(node, "integrity");
|
|
10738
|
+
meta.integrity = integrity;
|
|
10739
|
+
}
|
|
10740
|
+
return meta;
|
|
10569
10741
|
};
|
|
10570
|
-
const decideLinkExpectedType = (
|
|
10571
|
-
const rel = getHtmlNodeAttribute(
|
|
10742
|
+
const decideLinkExpectedType = (linkReference, context) => {
|
|
10743
|
+
const rel = getHtmlNodeAttribute(linkReference.node, "rel");
|
|
10572
10744
|
if (rel === "webmanifest") {
|
|
10573
10745
|
return "webmanifest";
|
|
10574
10746
|
}
|
|
@@ -10580,7 +10752,7 @@ const decideLinkExpectedType = (linkMention, mentions) => {
|
|
|
10580
10752
|
}
|
|
10581
10753
|
if (rel === "preload") {
|
|
10582
10754
|
// https://developer.mozilla.org/en-US/docs/Web/HTML/Link_types/preload#what_types_of_content_can_be_preloaded
|
|
10583
|
-
const as = getHtmlNodeAttribute(
|
|
10755
|
+
const as = getHtmlNodeAttribute(linkReference.node, "as");
|
|
10584
10756
|
if (as === "document") {
|
|
10585
10757
|
return "html";
|
|
10586
10758
|
}
|
|
@@ -10588,7 +10760,7 @@ const decideLinkExpectedType = (linkMention, mentions) => {
|
|
|
10588
10760
|
return "css";
|
|
10589
10761
|
}
|
|
10590
10762
|
if (as === "script") {
|
|
10591
|
-
const firstScriptOnThisUrl =
|
|
10763
|
+
const firstScriptOnThisUrl = context.referenceUtils.find(refCandidate => refCandidate.url === linkReference.url && refCandidate.type === "script");
|
|
10592
10764
|
if (firstScriptOnThisUrl) {
|
|
10593
10765
|
return firstScriptOnThisUrl.expectedType;
|
|
10594
10766
|
}
|
|
@@ -10598,9 +10770,53 @@ const decideLinkExpectedType = (linkMention, mentions) => {
|
|
|
10598
10770
|
return undefined;
|
|
10599
10771
|
};
|
|
10600
10772
|
|
|
10773
|
+
// css: parseAndTransformCssUrls,
|
|
10774
|
+
|
|
10775
|
+
const jsenvPluginWebmanifestReferenceAnalysis = () => {
|
|
10776
|
+
return {
|
|
10777
|
+
name: "jsenv:webmanifest_reference_analysis",
|
|
10778
|
+
appliesDuring: "*",
|
|
10779
|
+
transformUrlContent: {
|
|
10780
|
+
webmanifest: parseAndTransformWebmanifestUrls
|
|
10781
|
+
}
|
|
10782
|
+
};
|
|
10783
|
+
};
|
|
10784
|
+
const parseAndTransformWebmanifestUrls = async (urlInfo, context) => {
|
|
10785
|
+
const content = urlInfo.content;
|
|
10786
|
+
const manifest = JSON.parse(content);
|
|
10787
|
+
const actions = [];
|
|
10788
|
+
const {
|
|
10789
|
+
icons = []
|
|
10790
|
+
} = manifest;
|
|
10791
|
+
icons.forEach(icon => {
|
|
10792
|
+
const [reference] = context.referenceUtils.found({
|
|
10793
|
+
type: "webmanifest_icon_src",
|
|
10794
|
+
specifier: icon.src
|
|
10795
|
+
});
|
|
10796
|
+
actions.push(async () => {
|
|
10797
|
+
icon.src = await context.referenceUtils.readGeneratedSpecifier(reference);
|
|
10798
|
+
});
|
|
10799
|
+
});
|
|
10800
|
+
if (actions.length === 0) {
|
|
10801
|
+
return null;
|
|
10802
|
+
}
|
|
10803
|
+
await Promise.all(actions.map(action => action()));
|
|
10804
|
+
return JSON.stringify(manifest, null, " ");
|
|
10805
|
+
};
|
|
10806
|
+
|
|
10601
10807
|
/*
|
|
10602
10808
|
* https://github.com/parcel-bundler/parcel/blob/v2/packages/transformers/css/src/CSSTransformer.js
|
|
10603
10809
|
*/
|
|
10810
|
+
|
|
10811
|
+
const jsenvPluginCssReferenceAnalysis = () => {
|
|
10812
|
+
return {
|
|
10813
|
+
name: "jsenv:css_reference_analysis",
|
|
10814
|
+
appliesDuring: "*",
|
|
10815
|
+
transformUrlContent: {
|
|
10816
|
+
css: parseAndTransformCssUrls
|
|
10817
|
+
}
|
|
10818
|
+
};
|
|
10819
|
+
};
|
|
10604
10820
|
const parseAndTransformCssUrls = async (urlInfo, context) => {
|
|
10605
10821
|
const cssUrls = await parseCssUrls({
|
|
10606
10822
|
css: urlInfo.content,
|
|
@@ -10632,121 +10848,315 @@ const parseAndTransformCssUrls = async (urlInfo, context) => {
|
|
|
10632
10848
|
return magicSource.toContentAndSourcemap();
|
|
10633
10849
|
};
|
|
10634
10850
|
|
|
10635
|
-
const
|
|
10636
|
-
|
|
10637
|
-
|
|
10638
|
-
|
|
10639
|
-
|
|
10640
|
-
|
|
10641
|
-
});
|
|
10642
|
-
const actions = [];
|
|
10643
|
-
const magicSource = createMagicSource(urlInfo.content);
|
|
10644
|
-
for (const jsMention of jsMentions) {
|
|
10645
|
-
if (jsMention.subtype === "import_static" || jsMention.subtype === "import_dynamic") {
|
|
10646
|
-
urlInfo.data.usesImport = true;
|
|
10851
|
+
const isEscaped = (i, string) => {
|
|
10852
|
+
let backslashBeforeCount = 0;
|
|
10853
|
+
while (i--) {
|
|
10854
|
+
const previousChar = string[i];
|
|
10855
|
+
if (previousChar === "\\") {
|
|
10856
|
+
backslashBeforeCount++;
|
|
10647
10857
|
}
|
|
10648
|
-
|
|
10649
|
-
node: jsMention.node,
|
|
10650
|
-
type: jsMention.type,
|
|
10651
|
-
subtype: jsMention.subtype,
|
|
10652
|
-
expectedType: jsMention.expectedType,
|
|
10653
|
-
expectedSubtype: jsMention.expectedSubtype || urlInfo.subtype,
|
|
10654
|
-
specifier: jsMention.specifier,
|
|
10655
|
-
specifierStart: jsMention.start,
|
|
10656
|
-
specifierEnd: jsMention.end,
|
|
10657
|
-
specifierLine: jsMention.line,
|
|
10658
|
-
specifierColumn: jsMention.column,
|
|
10659
|
-
data: jsMention.data,
|
|
10660
|
-
baseUrl: {
|
|
10661
|
-
"StringLiteral": jsMention.baseUrl,
|
|
10662
|
-
"window.location": urlInfo.url,
|
|
10663
|
-
"window.origin": context.rootDirectoryUrl,
|
|
10664
|
-
"import.meta.url": urlInfo.url,
|
|
10665
|
-
"context.meta.url": urlInfo.url,
|
|
10666
|
-
"document.currentScript.src": urlInfo.url
|
|
10667
|
-
}[jsMention.baseUrlType],
|
|
10668
|
-
assert: jsMention.assert,
|
|
10669
|
-
assertNode: jsMention.assertNode,
|
|
10670
|
-
typePropertyNode: jsMention.typePropertyNode
|
|
10671
|
-
});
|
|
10672
|
-
actions.push(async () => {
|
|
10673
|
-
const replacement = await context.referenceUtils.readGeneratedSpecifier(reference);
|
|
10674
|
-
magicSource.replace({
|
|
10675
|
-
start: jsMention.start,
|
|
10676
|
-
end: jsMention.end,
|
|
10677
|
-
replacement
|
|
10678
|
-
});
|
|
10679
|
-
if (reference.mutation) {
|
|
10680
|
-
reference.mutation(magicSource);
|
|
10681
|
-
}
|
|
10682
|
-
});
|
|
10683
|
-
}
|
|
10684
|
-
if (actions.length > 0) {
|
|
10685
|
-
await Promise.all(actions.map(action => action()));
|
|
10686
|
-
}
|
|
10687
|
-
const {
|
|
10688
|
-
content,
|
|
10689
|
-
sourcemap
|
|
10690
|
-
} = magicSource.toContentAndSourcemap();
|
|
10691
|
-
return {
|
|
10692
|
-
content,
|
|
10693
|
-
sourcemap
|
|
10694
|
-
};
|
|
10695
|
-
};
|
|
10696
|
-
|
|
10697
|
-
const parseAndTransformWebmanifestUrls = async (urlInfo, context) => {
|
|
10698
|
-
const content = urlInfo.content;
|
|
10699
|
-
const manifest = JSON.parse(content);
|
|
10700
|
-
const actions = [];
|
|
10701
|
-
const {
|
|
10702
|
-
icons = []
|
|
10703
|
-
} = manifest;
|
|
10704
|
-
icons.forEach(icon => {
|
|
10705
|
-
const [reference] = context.referenceUtils.found({
|
|
10706
|
-
type: "webmanifest_icon_src",
|
|
10707
|
-
specifier: icon.src
|
|
10708
|
-
});
|
|
10709
|
-
actions.push(async () => {
|
|
10710
|
-
icon.src = await context.referenceUtils.readGeneratedSpecifier(reference);
|
|
10711
|
-
});
|
|
10712
|
-
});
|
|
10713
|
-
if (actions.length === 0) {
|
|
10714
|
-
return null;
|
|
10858
|
+
break;
|
|
10715
10859
|
}
|
|
10716
|
-
|
|
10717
|
-
return
|
|
10860
|
+
const isEven = backslashBeforeCount % 2 === 0;
|
|
10861
|
+
return !isEven;
|
|
10718
10862
|
};
|
|
10719
10863
|
|
|
10720
|
-
const
|
|
10721
|
-
|
|
10722
|
-
|
|
10723
|
-
|
|
10724
|
-
}) => {
|
|
10725
|
-
|
|
10726
|
-
|
|
10727
|
-
|
|
10728
|
-
|
|
10729
|
-
|
|
10730
|
-
|
|
10731
|
-
|
|
10732
|
-
|
|
10733
|
-
|
|
10734
|
-
|
|
10735
|
-
|
|
10736
|
-
|
|
10737
|
-
|
|
10738
|
-
|
|
10739
|
-
|
|
10740
|
-
|
|
10741
|
-
|
|
10742
|
-
|
|
10743
|
-
|
|
10744
|
-
|
|
10745
|
-
|
|
10746
|
-
|
|
10747
|
-
|
|
10748
|
-
|
|
10749
|
-
|
|
10864
|
+
const JS_QUOTES = {
|
|
10865
|
+
pickBest: (string, {
|
|
10866
|
+
canUseTemplateString,
|
|
10867
|
+
defaultQuote = DOUBLE
|
|
10868
|
+
} = {}) => {
|
|
10869
|
+
// check default first, once tested do no re-test it
|
|
10870
|
+
if (!string.includes(defaultQuote)) {
|
|
10871
|
+
return defaultQuote;
|
|
10872
|
+
}
|
|
10873
|
+
if (defaultQuote !== DOUBLE && !string.includes(DOUBLE)) {
|
|
10874
|
+
return DOUBLE;
|
|
10875
|
+
}
|
|
10876
|
+
if (defaultQuote !== SINGLE && !string.includes(SINGLE)) {
|
|
10877
|
+
return SINGLE;
|
|
10878
|
+
}
|
|
10879
|
+
if (canUseTemplateString && defaultQuote !== BACKTICK && !string.includes(BACKTICK)) {
|
|
10880
|
+
return BACKTICK;
|
|
10881
|
+
}
|
|
10882
|
+
return defaultQuote;
|
|
10883
|
+
},
|
|
10884
|
+
escapeSpecialChars: (string, {
|
|
10885
|
+
quote = "pickBest",
|
|
10886
|
+
canUseTemplateString,
|
|
10887
|
+
defaultQuote,
|
|
10888
|
+
allowEscapeForVersioning = false
|
|
10889
|
+
}) => {
|
|
10890
|
+
quote = quote === "pickBest" ? JS_QUOTES.pickBest(string, {
|
|
10891
|
+
canUseTemplateString,
|
|
10892
|
+
defaultQuote
|
|
10893
|
+
}) : quote;
|
|
10894
|
+
const replacements = JS_QUOTE_REPLACEMENTS[quote];
|
|
10895
|
+
let result = "";
|
|
10896
|
+
let last = 0;
|
|
10897
|
+
let i = 0;
|
|
10898
|
+
while (i < string.length) {
|
|
10899
|
+
const char = string[i];
|
|
10900
|
+
i++;
|
|
10901
|
+
if (isEscaped(i - 1, string)) continue;
|
|
10902
|
+
const replacement = replacements[char];
|
|
10903
|
+
if (replacement) {
|
|
10904
|
+
if (allowEscapeForVersioning && char === quote && string.slice(i, i + 6) === "+__v__") {
|
|
10905
|
+
let isVersioningConcatenation = false;
|
|
10906
|
+
let j = i + 6; // start after the +
|
|
10907
|
+
while (j < string.length) {
|
|
10908
|
+
const lookAheadChar = string[j];
|
|
10909
|
+
j++;
|
|
10910
|
+
if (lookAheadChar === "+" && string[j] === quote && !isEscaped(j - 1, string)) {
|
|
10911
|
+
isVersioningConcatenation = true;
|
|
10912
|
+
break;
|
|
10913
|
+
}
|
|
10914
|
+
}
|
|
10915
|
+
if (isVersioningConcatenation) {
|
|
10916
|
+
// it's a concatenation
|
|
10917
|
+
// skip until the end of concatenation (the second +)
|
|
10918
|
+
// and resume from there
|
|
10919
|
+
i = j + 1;
|
|
10920
|
+
continue;
|
|
10921
|
+
}
|
|
10922
|
+
}
|
|
10923
|
+
if (last === i - 1) {
|
|
10924
|
+
result += replacement;
|
|
10925
|
+
} else {
|
|
10926
|
+
result += `${string.slice(last, i - 1)}${replacement}`;
|
|
10927
|
+
}
|
|
10928
|
+
last = i;
|
|
10929
|
+
}
|
|
10930
|
+
}
|
|
10931
|
+
if (last !== string.length) {
|
|
10932
|
+
result += string.slice(last);
|
|
10933
|
+
}
|
|
10934
|
+
return `${quote}${result}${quote}`;
|
|
10935
|
+
}
|
|
10936
|
+
};
|
|
10937
|
+
const DOUBLE = `"`;
|
|
10938
|
+
const SINGLE = `'`;
|
|
10939
|
+
const BACKTICK = "`";
|
|
10940
|
+
const lineEndingEscapes = {
|
|
10941
|
+
"\n": "\\n",
|
|
10942
|
+
"\r": "\\r",
|
|
10943
|
+
"\u2028": "\\u2028",
|
|
10944
|
+
"\u2029": "\\u2029"
|
|
10945
|
+
};
|
|
10946
|
+
const JS_QUOTE_REPLACEMENTS = {
|
|
10947
|
+
[DOUBLE]: {
|
|
10948
|
+
'"': '\\"',
|
|
10949
|
+
...lineEndingEscapes
|
|
10950
|
+
},
|
|
10951
|
+
[SINGLE]: {
|
|
10952
|
+
"'": "\\'",
|
|
10953
|
+
...lineEndingEscapes
|
|
10954
|
+
},
|
|
10955
|
+
[BACKTICK]: {
|
|
10956
|
+
"`": "\\`",
|
|
10957
|
+
"$": "\\$"
|
|
10958
|
+
}
|
|
10959
|
+
};
|
|
10960
|
+
|
|
10961
|
+
const jsenvPluginJsReferenceAnalysis = ({
|
|
10962
|
+
inlineContent,
|
|
10963
|
+
allowEscapeForVersioning
|
|
10964
|
+
}) => {
|
|
10965
|
+
return [{
|
|
10966
|
+
name: "jsenv:js_reference_analysis",
|
|
10967
|
+
appliesDuring: "*",
|
|
10968
|
+
transformUrlContent: {
|
|
10969
|
+
js_classic: (urlInfo, context) => parseAndTransformJsReferences(urlInfo, context, {
|
|
10970
|
+
inlineContent,
|
|
10971
|
+
allowEscapeForVersioning
|
|
10972
|
+
}),
|
|
10973
|
+
js_module: (urlInfo, context) => parseAndTransformJsReferences(urlInfo, context, {
|
|
10974
|
+
inlineContent,
|
|
10975
|
+
allowEscapeForVersioning
|
|
10976
|
+
})
|
|
10977
|
+
}
|
|
10978
|
+
}];
|
|
10979
|
+
};
|
|
10980
|
+
const parseAndTransformJsReferences = async (urlInfo, context, {
|
|
10981
|
+
inlineContent,
|
|
10982
|
+
allowEscapeForVersioning
|
|
10983
|
+
}) => {
|
|
10984
|
+
const magicSource = createMagicSource(urlInfo.content);
|
|
10985
|
+
const parallelActions = [];
|
|
10986
|
+
const sequentialActions = [];
|
|
10987
|
+
const onInlineReference = inlineReferenceInfo => {
|
|
10988
|
+
const inlineUrl = generateInlineContentUrl({
|
|
10989
|
+
url: urlInfo.url,
|
|
10990
|
+
extension: CONTENT_TYPE.asFileExtension(inlineReferenceInfo.contentType),
|
|
10991
|
+
line: inlineReferenceInfo.line,
|
|
10992
|
+
column: inlineReferenceInfo.column,
|
|
10993
|
+
lineEnd: inlineReferenceInfo.lineEnd,
|
|
10994
|
+
columnEnd: inlineReferenceInfo.columnEnd
|
|
10995
|
+
});
|
|
10996
|
+
let {
|
|
10997
|
+
quote
|
|
10998
|
+
} = inlineReferenceInfo;
|
|
10999
|
+
if (quote === "`" && !context.isSupportedOnCurrentClients("template_literals")) {
|
|
11000
|
+
// if quote is "`" and template literals are not supported
|
|
11001
|
+
// we'll use a regular string (single or double quote)
|
|
11002
|
+
// when rendering the string
|
|
11003
|
+
quote = JS_QUOTES.pickBest(inlineReferenceInfo.content);
|
|
11004
|
+
}
|
|
11005
|
+
const [inlineReference, inlineUrlInfo] = context.referenceUtils.foundInline({
|
|
11006
|
+
type: "js_inline_content",
|
|
11007
|
+
subtype: inlineReferenceInfo.type,
|
|
11008
|
+
// "new_blob_first_arg", "new_inline_content_first_arg", "json_parse_first_arg"
|
|
11009
|
+
isOriginalPosition: urlInfo.content === urlInfo.originalContent,
|
|
11010
|
+
specifierLine: inlineReferenceInfo.line,
|
|
11011
|
+
specifierColumn: inlineReferenceInfo.column,
|
|
11012
|
+
specifier: inlineUrl,
|
|
11013
|
+
contentType: inlineReferenceInfo.contentType,
|
|
11014
|
+
content: inlineReferenceInfo.content
|
|
11015
|
+
});
|
|
11016
|
+
inlineUrlInfo.jsQuote = quote;
|
|
11017
|
+
inlineReference.escape = value => JS_QUOTES.escapeSpecialChars(value.slice(1, -1), {
|
|
11018
|
+
quote
|
|
11019
|
+
});
|
|
11020
|
+
sequentialActions.push(async () => {
|
|
11021
|
+
await context.cook(inlineUrlInfo, {
|
|
11022
|
+
reference: inlineReference
|
|
11023
|
+
});
|
|
11024
|
+
const replacement = JS_QUOTES.escapeSpecialChars(inlineUrlInfo.content, {
|
|
11025
|
+
quote,
|
|
11026
|
+
allowEscapeForVersioning
|
|
11027
|
+
});
|
|
11028
|
+
magicSource.replace({
|
|
11029
|
+
start: inlineReferenceInfo.start,
|
|
11030
|
+
end: inlineReferenceInfo.end,
|
|
11031
|
+
replacement
|
|
11032
|
+
});
|
|
11033
|
+
});
|
|
11034
|
+
};
|
|
11035
|
+
const onExternalReference = externalReferenceInfo => {
|
|
11036
|
+
if (externalReferenceInfo.subtype === "import_static" || externalReferenceInfo.subtype === "import_dynamic") {
|
|
11037
|
+
urlInfo.data.usesImport = true;
|
|
11038
|
+
}
|
|
11039
|
+
const [reference] = context.referenceUtils.found({
|
|
11040
|
+
node: externalReferenceInfo.node,
|
|
11041
|
+
type: externalReferenceInfo.type,
|
|
11042
|
+
subtype: externalReferenceInfo.subtype,
|
|
11043
|
+
expectedType: externalReferenceInfo.expectedType,
|
|
11044
|
+
expectedSubtype: externalReferenceInfo.expectedSubtype || urlInfo.subtype,
|
|
11045
|
+
specifier: externalReferenceInfo.specifier,
|
|
11046
|
+
specifierStart: externalReferenceInfo.start,
|
|
11047
|
+
specifierEnd: externalReferenceInfo.end,
|
|
11048
|
+
specifierLine: externalReferenceInfo.line,
|
|
11049
|
+
specifierColumn: externalReferenceInfo.column,
|
|
11050
|
+
data: externalReferenceInfo.data,
|
|
11051
|
+
baseUrl: {
|
|
11052
|
+
"StringLiteral": externalReferenceInfo.baseUrl,
|
|
11053
|
+
"window.location": urlInfo.url,
|
|
11054
|
+
"window.origin": context.rootDirectoryUrl,
|
|
11055
|
+
"import.meta.url": urlInfo.url,
|
|
11056
|
+
"context.meta.url": urlInfo.url,
|
|
11057
|
+
"document.currentScript.src": urlInfo.url
|
|
11058
|
+
}[externalReferenceInfo.baseUrlType],
|
|
11059
|
+
assert: externalReferenceInfo.assert,
|
|
11060
|
+
assertNode: externalReferenceInfo.assertNode,
|
|
11061
|
+
typePropertyNode: externalReferenceInfo.typePropertyNode
|
|
11062
|
+
});
|
|
11063
|
+
parallelActions.push(async () => {
|
|
11064
|
+
const replacement = await context.referenceUtils.readGeneratedSpecifier(reference);
|
|
11065
|
+
magicSource.replace({
|
|
11066
|
+
start: externalReferenceInfo.start,
|
|
11067
|
+
end: externalReferenceInfo.end,
|
|
11068
|
+
replacement
|
|
11069
|
+
});
|
|
11070
|
+
if (reference.mutation) {
|
|
11071
|
+
reference.mutation(magicSource);
|
|
11072
|
+
}
|
|
11073
|
+
});
|
|
11074
|
+
};
|
|
11075
|
+
const jsReferenceInfos = await parseJsUrls({
|
|
11076
|
+
js: urlInfo.content,
|
|
11077
|
+
url: urlInfo.originalUrl,
|
|
11078
|
+
isJsModule: urlInfo.type === "js_module",
|
|
11079
|
+
isWebWorker: isWebWorkerUrlInfo(urlInfo),
|
|
11080
|
+
inlineContent
|
|
11081
|
+
});
|
|
11082
|
+
for (const jsReferenceInfo of jsReferenceInfos) {
|
|
11083
|
+
if (jsReferenceInfo.isInline) {
|
|
11084
|
+
onInlineReference(jsReferenceInfo);
|
|
11085
|
+
} else {
|
|
11086
|
+
onExternalReference(jsReferenceInfo);
|
|
11087
|
+
}
|
|
11088
|
+
}
|
|
11089
|
+
if (parallelActions.length > 0) {
|
|
11090
|
+
await Promise.all(parallelActions.map(action => action()));
|
|
11091
|
+
}
|
|
11092
|
+
if (sequentialActions.length > 0) {
|
|
11093
|
+
await sequentialActions.reduce(async (previous, action) => {
|
|
11094
|
+
await previous;
|
|
11095
|
+
await action();
|
|
11096
|
+
}, Promise.resolve());
|
|
11097
|
+
}
|
|
11098
|
+
const {
|
|
11099
|
+
content,
|
|
11100
|
+
sourcemap
|
|
11101
|
+
} = magicSource.toContentAndSourcemap();
|
|
11102
|
+
return {
|
|
11103
|
+
content,
|
|
11104
|
+
sourcemap
|
|
11105
|
+
};
|
|
11106
|
+
};
|
|
11107
|
+
|
|
11108
|
+
const jsenvPluginReferenceAnalysis = ({
|
|
11109
|
+
include,
|
|
11110
|
+
supportedProtocols = ["file:", "data:", "virtual:", "http:", "https:"],
|
|
11111
|
+
inlineContent = true,
|
|
11112
|
+
inlineConvertedScript = false,
|
|
11113
|
+
fetchInlineUrls = true,
|
|
11114
|
+
allowEscapeForVersioning = false
|
|
11115
|
+
}) => {
|
|
11116
|
+
return [jsenvPluginReferenceAnalysisInclude({
|
|
11117
|
+
include,
|
|
11118
|
+
supportedProtocols
|
|
11119
|
+
}), jsenvPluginDirectoryReferenceAnalysis(), jsenvPluginHtmlReferenceAnalysis({
|
|
11120
|
+
inlineContent,
|
|
11121
|
+
inlineConvertedScript
|
|
11122
|
+
}), jsenvPluginWebmanifestReferenceAnalysis(), jsenvPluginCssReferenceAnalysis(), jsenvPluginJsReferenceAnalysis({
|
|
11123
|
+
inlineContent,
|
|
11124
|
+
allowEscapeForVersioning
|
|
11125
|
+
}), ...(inlineContent ? [jsenvPluginDataUrlsAnalysis()] : []), ...(inlineContent && fetchInlineUrls ? [jsenvPluginInlineContentFetcher()] : []), jsenvPluginReferenceExpectedTypes()];
|
|
11126
|
+
};
|
|
11127
|
+
const jsenvPluginReferenceAnalysisInclude = ({
|
|
11128
|
+
include,
|
|
11129
|
+
supportedProtocols
|
|
11130
|
+
}) => {
|
|
11131
|
+
// eslint-disable-next-line no-unused-vars
|
|
11132
|
+
let getIncludeInfo = url => undefined;
|
|
11133
|
+
return {
|
|
11134
|
+
name: "jsenv:reference_analysis_include",
|
|
11135
|
+
appliesDuring: "*",
|
|
11136
|
+
init: ({
|
|
11137
|
+
rootDirectoryUrl
|
|
11138
|
+
}) => {
|
|
11139
|
+
if (include) {
|
|
11140
|
+
const associations = URL_META.resolveAssociations({
|
|
11141
|
+
include
|
|
11142
|
+
}, rootDirectoryUrl);
|
|
11143
|
+
getIncludeInfo = url => {
|
|
11144
|
+
const {
|
|
11145
|
+
include
|
|
11146
|
+
} = URL_META.applyAssociations({
|
|
11147
|
+
url,
|
|
11148
|
+
associations
|
|
11149
|
+
});
|
|
11150
|
+
return include;
|
|
11151
|
+
};
|
|
11152
|
+
}
|
|
11153
|
+
},
|
|
11154
|
+
redirectReference: reference => {
|
|
11155
|
+
if (reference.shouldHandle !== undefined) {
|
|
11156
|
+
return;
|
|
11157
|
+
}
|
|
11158
|
+
if (reference.specifier[0] === "#" &&
|
|
11159
|
+
// For Html, css and in general "#" refer to a resource in the page
|
|
10750
11160
|
// so that urls must be kept intact
|
|
10751
11161
|
// However for js import specifiers they have a different meaning and we want
|
|
10752
11162
|
// to resolve them (https://nodejs.org/api/packages.html#imports for instance)
|
|
@@ -10770,57 +11180,32 @@ const jsenvPluginUrlAnalysis = ({
|
|
|
10770
11180
|
if (protocolIsSupported) {
|
|
10771
11181
|
reference.shouldHandle = true;
|
|
10772
11182
|
}
|
|
10773
|
-
},
|
|
10774
|
-
transformUrlContent: {
|
|
10775
|
-
html: parseAndTransformHtmlUrls,
|
|
10776
|
-
css: parseAndTransformCssUrls,
|
|
10777
|
-
js_classic: parseAndTransformJsUrls,
|
|
10778
|
-
js_module: parseAndTransformJsUrls,
|
|
10779
|
-
webmanifest: parseAndTransformWebmanifestUrls,
|
|
10780
|
-
directory: (urlInfo, context) => {
|
|
10781
|
-
const originalDirectoryReference = findOriginalDirectoryReference(urlInfo, context);
|
|
10782
|
-
const directoryRelativeUrl = urlToRelativeUrl(urlInfo.url, context.rootDirectoryUrl);
|
|
10783
|
-
JSON.parse(urlInfo.content).forEach(directoryEntryName => {
|
|
10784
|
-
context.referenceUtils.found({
|
|
10785
|
-
type: "filesystem",
|
|
10786
|
-
subtype: "directory_entry",
|
|
10787
|
-
specifier: directoryEntryName,
|
|
10788
|
-
trace: {
|
|
10789
|
-
message: `"${directoryRelativeUrl}${directoryEntryName}" entry in directory referenced by ${originalDirectoryReference.trace.message}`
|
|
10790
|
-
}
|
|
10791
|
-
});
|
|
10792
|
-
});
|
|
10793
|
-
}
|
|
10794
11183
|
}
|
|
10795
|
-
}
|
|
11184
|
+
};
|
|
10796
11185
|
};
|
|
10797
|
-
const
|
|
10798
|
-
|
|
10799
|
-
|
|
10800
|
-
|
|
10801
|
-
|
|
10802
|
-
|
|
10803
|
-
|
|
10804
|
-
const found = findNonFileSystemAncestor(dependentUrlInfo);
|
|
10805
|
-
if (found) {
|
|
10806
|
-
return found;
|
|
11186
|
+
const jsenvPluginInlineContentFetcher = () => {
|
|
11187
|
+
return {
|
|
11188
|
+
name: "jsenv:inline_content_fetcher",
|
|
11189
|
+
appliesDuring: "*",
|
|
11190
|
+
fetchUrlContent: urlInfo => {
|
|
11191
|
+
if (!urlInfo.isInline) {
|
|
11192
|
+
return null;
|
|
10807
11193
|
}
|
|
11194
|
+
return {
|
|
11195
|
+
// we want to fetch the original content otherwise we might re-cook
|
|
11196
|
+
// content already cooked
|
|
11197
|
+
content: urlInfo.originalContent,
|
|
11198
|
+
contentType: urlInfo.contentType
|
|
11199
|
+
};
|
|
10808
11200
|
}
|
|
10809
|
-
return [];
|
|
10810
11201
|
};
|
|
10811
|
-
const [ancestor, child] = findNonFileSystemAncestor(urlInfo);
|
|
10812
|
-
if (!ancestor) {
|
|
10813
|
-
return null;
|
|
10814
|
-
}
|
|
10815
|
-
const ref = ancestor.references.find(ref => ref.url === child.url);
|
|
10816
|
-
return ref;
|
|
10817
11202
|
};
|
|
10818
11203
|
|
|
10819
11204
|
const jsenvPluginInliningAsDataUrl = () => {
|
|
10820
11205
|
return {
|
|
10821
11206
|
name: "jsenv:inlining_as_data_url",
|
|
10822
11207
|
appliesDuring: "*",
|
|
10823
|
-
|
|
11208
|
+
formatReference: {
|
|
10824
11209
|
// if the referenced url is a worker we could use
|
|
10825
11210
|
// https://www.oreilly.com/library/view/web-workers/9781449322120/ch04.html
|
|
10826
11211
|
// but maybe we should rather use ?object_url
|
|
@@ -10846,10 +11231,19 @@ const jsenvPluginInliningAsDataUrl = () => {
|
|
|
10846
11231
|
await context.cook(urlInfo, {
|
|
10847
11232
|
reference
|
|
10848
11233
|
});
|
|
11234
|
+
const contentAsBase64 = Buffer.from(urlInfo.content).toString("base64");
|
|
10849
11235
|
const specifier = DATA_URL.stringify({
|
|
10850
11236
|
mediaType: urlInfo.contentType,
|
|
10851
11237
|
base64Flag: true,
|
|
10852
|
-
data:
|
|
11238
|
+
data: contentAsBase64
|
|
11239
|
+
});
|
|
11240
|
+
context.referenceUtils.becomesInline(reference, {
|
|
11241
|
+
line: reference.line,
|
|
11242
|
+
column: reference.column,
|
|
11243
|
+
isOriginal: reference.isOriginal,
|
|
11244
|
+
specifier,
|
|
11245
|
+
content: contentAsBase64,
|
|
11246
|
+
contentType: urlInfo.contentType
|
|
10853
11247
|
});
|
|
10854
11248
|
return specifier;
|
|
10855
11249
|
})();
|
|
@@ -10932,795 +11326,87 @@ const jsenvPluginInliningIntoHtml = () => {
|
|
|
10932
11326
|
} = getHtmlNodePosition(scriptNode, {
|
|
10933
11327
|
preferOriginal: true
|
|
10934
11328
|
});
|
|
10935
|
-
context.referenceUtils.becomesInline(scriptReference, {
|
|
10936
|
-
line: line - 1,
|
|
10937
|
-
column,
|
|
10938
|
-
isOriginal,
|
|
10939
|
-
specifier: scriptReference.generatedSpecifier,
|
|
10940
|
-
content: scriptUrlInfo.content,
|
|
10941
|
-
contentType: scriptUrlInfo.contentType
|
|
10942
|
-
});
|
|
10943
|
-
mutations.push(() => {
|
|
10944
|
-
setHtmlNodeAttributes(scriptNode, {
|
|
10945
|
-
"inlined-from-src": src,
|
|
10946
|
-
"src": undefined,
|
|
10947
|
-
"crossorigin": undefined,
|
|
10948
|
-
"integrity": undefined,
|
|
10949
|
-
"jsenv-inlined-by": "jsenv:inlining_into_html"
|
|
10950
|
-
});
|
|
10951
|
-
setHtmlNodeText(scriptNode, scriptUrlInfo.content, {
|
|
10952
|
-
indentation: "auto"
|
|
10953
|
-
});
|
|
10954
|
-
});
|
|
10955
|
-
});
|
|
10956
|
-
};
|
|
10957
|
-
visitHtmlNodes(htmlAst, {
|
|
10958
|
-
link: linkNode => {
|
|
10959
|
-
const rel = getHtmlNodeAttribute(linkNode, "rel");
|
|
10960
|
-
if (rel !== "stylesheet") {
|
|
10961
|
-
return;
|
|
10962
|
-
}
|
|
10963
|
-
const href = getHtmlNodeAttribute(linkNode, "href");
|
|
10964
|
-
if (!href) {
|
|
10965
|
-
return;
|
|
10966
|
-
}
|
|
10967
|
-
onStyleSheet(linkNode, {
|
|
10968
|
-
href
|
|
10969
|
-
});
|
|
10970
|
-
},
|
|
10971
|
-
script: scriptNode => {
|
|
10972
|
-
const {
|
|
10973
|
-
type
|
|
10974
|
-
} = analyzeScriptNode(scriptNode);
|
|
10975
|
-
const scriptNodeText = getHtmlNodeText(scriptNode);
|
|
10976
|
-
if (scriptNodeText) {
|
|
10977
|
-
return;
|
|
10978
|
-
}
|
|
10979
|
-
const src = getHtmlNodeAttribute(scriptNode, "src");
|
|
10980
|
-
if (!src) {
|
|
10981
|
-
return;
|
|
10982
|
-
}
|
|
10983
|
-
onScriptWithSrc(scriptNode, {
|
|
10984
|
-
type,
|
|
10985
|
-
src
|
|
10986
|
-
});
|
|
10987
|
-
}
|
|
10988
|
-
});
|
|
10989
|
-
if (actions.length > 0) {
|
|
10990
|
-
await Promise.all(actions.map(action => action()));
|
|
10991
|
-
}
|
|
10992
|
-
mutations.forEach(mutation => mutation());
|
|
10993
|
-
const htmlModified = stringifyHtmlAst(htmlAst);
|
|
10994
|
-
return htmlModified;
|
|
10995
|
-
}
|
|
10996
|
-
}
|
|
10997
|
-
};
|
|
10998
|
-
};
|
|
10999
|
-
|
|
11000
|
-
const jsenvPluginInlining = () => {
|
|
11001
|
-
return [{
|
|
11002
|
-
name: "jsenv:inlining",
|
|
11003
|
-
appliesDuring: "*",
|
|
11004
|
-
redirectUrl: reference => {
|
|
11005
|
-
const {
|
|
11006
|
-
searchParams
|
|
11007
|
-
} = reference;
|
|
11008
|
-
if (searchParams.has("inline")) {
|
|
11009
|
-
const urlObject = new URL(reference.url);
|
|
11010
|
-
urlObject.searchParams.delete("inline");
|
|
11011
|
-
return urlObject.href;
|
|
11012
|
-
}
|
|
11013
|
-
return null;
|
|
11014
|
-
}
|
|
11015
|
-
}, jsenvPluginInliningAsDataUrl(), jsenvPluginInliningIntoHtml()];
|
|
11016
|
-
};
|
|
11017
|
-
|
|
11018
|
-
/*
|
|
11019
|
-
* This plugin ensure content inlined inside HTML is cooked (inline <script> for instance)
|
|
11020
|
-
* For <script hot-accept> the script content will be moved to a virtual file
|
|
11021
|
-
* to enable hot reloading
|
|
11022
|
-
*/
|
|
11023
|
-
const jsenvPluginHtmlInlineContentAnalysis = ({
|
|
11024
|
-
analyzeConvertedScripts
|
|
11025
|
-
}) => {
|
|
11026
|
-
const cookInlineContent = async ({
|
|
11027
|
-
context,
|
|
11028
|
-
inlineContentUrlInfo,
|
|
11029
|
-
inlineContentReference
|
|
11030
|
-
}) => {
|
|
11031
|
-
try {
|
|
11032
|
-
await context.cook(inlineContentUrlInfo, {
|
|
11033
|
-
reference: inlineContentReference
|
|
11034
|
-
});
|
|
11035
|
-
} catch (e) {
|
|
11036
|
-
if (e.code === "PARSE_ERROR") {
|
|
11037
|
-
// When something like <style> or <script> contains syntax error
|
|
11038
|
-
// the HTML in itself it still valid
|
|
11039
|
-
// keep the syntax error and continue with the HTML
|
|
11040
|
-
const messageStart = inlineContentUrlInfo.type === "css" ? `Syntax error on css declared inside <style>` : `Syntax error on js declared inside <script>`;
|
|
11041
|
-
context.logger.error(`${messageStart}: ${e.cause.reasonCode}
|
|
11042
|
-
${e.traceMessage}`);
|
|
11043
|
-
} else {
|
|
11044
|
-
throw e;
|
|
11045
|
-
}
|
|
11046
|
-
}
|
|
11047
|
-
};
|
|
11048
|
-
return {
|
|
11049
|
-
name: "jsenv:html_inline_content_analysis",
|
|
11050
|
-
appliesDuring: "*",
|
|
11051
|
-
transformUrlContent: {
|
|
11052
|
-
html: async (urlInfo, context) => {
|
|
11053
|
-
const htmlAst = parseHtmlString(urlInfo.content);
|
|
11054
|
-
const mutations = [];
|
|
11055
|
-
const actions = [];
|
|
11056
|
-
visitHtmlNodes(htmlAst, {
|
|
11057
|
-
style: styleNode => {
|
|
11058
|
-
const styleNodeText = getHtmlNodeText(styleNode);
|
|
11059
|
-
if (!styleNodeText) {
|
|
11060
|
-
return;
|
|
11061
|
-
}
|
|
11062
|
-
const {
|
|
11063
|
-
line,
|
|
11064
|
-
column,
|
|
11065
|
-
lineEnd,
|
|
11066
|
-
columnEnd,
|
|
11067
|
-
isOriginal
|
|
11068
|
-
} = getHtmlNodePosition(styleNode, {
|
|
11069
|
-
preferOriginal: true
|
|
11070
|
-
});
|
|
11071
|
-
const inlineStyleUrl = generateInlineContentUrl({
|
|
11072
|
-
url: urlInfo.url,
|
|
11073
|
-
extension: ".css",
|
|
11074
|
-
line,
|
|
11075
|
-
column,
|
|
11076
|
-
lineEnd,
|
|
11077
|
-
columnEnd
|
|
11078
|
-
});
|
|
11079
|
-
const debug = getHtmlNodeAttribute(styleNode, "jsenv-debug") !== undefined;
|
|
11080
|
-
const [inlineStyleReference, inlineStyleUrlInfo] = context.referenceUtils.foundInline({
|
|
11081
|
-
node: styleNode,
|
|
11082
|
-
type: "style",
|
|
11083
|
-
expectedType: "css",
|
|
11084
|
-
isOriginalPosition: isOriginal,
|
|
11085
|
-
// we remove 1 to the line because imagine the following html:
|
|
11086
|
-
// <style>body { color: red; }</style>
|
|
11087
|
-
// -> content starts same line as <style>
|
|
11088
|
-
specifierLine: line - 1,
|
|
11089
|
-
specifierColumn: column,
|
|
11090
|
-
specifier: inlineStyleUrl,
|
|
11091
|
-
contentType: "text/css",
|
|
11092
|
-
content: styleNodeText,
|
|
11093
|
-
debug
|
|
11094
|
-
});
|
|
11095
|
-
actions.push(async () => {
|
|
11096
|
-
await cookInlineContent({
|
|
11097
|
-
context,
|
|
11098
|
-
inlineContentUrlInfo: inlineStyleUrlInfo,
|
|
11099
|
-
inlineContentReference: inlineStyleReference
|
|
11100
|
-
});
|
|
11101
|
-
});
|
|
11102
|
-
mutations.push(() => {
|
|
11103
|
-
setHtmlNodeText(styleNode, inlineStyleUrlInfo.content, {
|
|
11104
|
-
indentation: false // indentation would decrease strack trace precision
|
|
11105
|
-
});
|
|
11106
|
-
|
|
11107
|
-
setHtmlNodeAttributes(styleNode, {
|
|
11108
|
-
"jsenv-cooked-by": "jsenv:html_inline_content_analysis"
|
|
11109
|
-
});
|
|
11110
|
-
});
|
|
11111
|
-
},
|
|
11112
|
-
script: scriptNode => {
|
|
11113
|
-
const scriptNodeText = getHtmlNodeText(scriptNode);
|
|
11114
|
-
if (!scriptNodeText) {
|
|
11115
|
-
return;
|
|
11116
|
-
}
|
|
11117
|
-
// If the inline script was already handled by an other plugin, ignore it
|
|
11118
|
-
// - we want to preserve inline scripts generated by html supervisor during dev
|
|
11119
|
-
// - we want to avoid cooking twice a script during build
|
|
11120
|
-
if (!analyzeConvertedScripts && getHtmlNodeAttribute(scriptNode, "jsenv-injected-by") === "jsenv:js_module_fallback") {
|
|
11121
|
-
return;
|
|
11122
|
-
}
|
|
11123
|
-
const hotAccept = getHtmlNodeAttribute(scriptNode, "hot-accept") !== undefined;
|
|
11124
|
-
const {
|
|
11125
|
-
type,
|
|
11126
|
-
contentType,
|
|
11127
|
-
extension
|
|
11128
|
-
} = analyzeScriptNode(scriptNode);
|
|
11129
|
-
const {
|
|
11130
|
-
line,
|
|
11131
|
-
column,
|
|
11132
|
-
lineEnd,
|
|
11133
|
-
columnEnd,
|
|
11134
|
-
isOriginal
|
|
11135
|
-
} = getHtmlNodePosition(scriptNode, {
|
|
11136
|
-
preferOriginal: true
|
|
11137
|
-
});
|
|
11138
|
-
let inlineScriptUrl = generateInlineContentUrl({
|
|
11139
|
-
url: urlInfo.url,
|
|
11140
|
-
extension: extension || CONTENT_TYPE.asFileExtension(contentType),
|
|
11141
|
-
line,
|
|
11142
|
-
column,
|
|
11143
|
-
lineEnd,
|
|
11144
|
-
columnEnd
|
|
11145
|
-
});
|
|
11146
|
-
const debug = getHtmlNodeAttribute(scriptNode, "jsenv-debug") !== undefined;
|
|
11147
|
-
const [inlineScriptReference, inlineScriptUrlInfo] = context.referenceUtils.foundInline({
|
|
11148
|
-
node: scriptNode,
|
|
11149
|
-
type: "script",
|
|
11150
|
-
expectedType: type,
|
|
11151
|
-
// we remove 1 to the line because imagine the following html:
|
|
11152
|
-
// <script>console.log('ok')</script>
|
|
11153
|
-
// -> content starts same line as <script>
|
|
11154
|
-
specifierLine: line - 1,
|
|
11155
|
-
specifierColumn: column,
|
|
11156
|
-
isOriginalPosition: isOriginal,
|
|
11157
|
-
specifier: inlineScriptUrl,
|
|
11158
|
-
contentType,
|
|
11159
|
-
content: scriptNodeText,
|
|
11160
|
-
debug
|
|
11161
|
-
});
|
|
11162
|
-
actions.push(async () => {
|
|
11163
|
-
await cookInlineContent({
|
|
11164
|
-
context,
|
|
11165
|
-
inlineContentUrlInfo: inlineScriptUrlInfo,
|
|
11166
|
-
inlineContentReference: inlineScriptReference
|
|
11167
|
-
});
|
|
11168
|
-
mutations.push(() => {
|
|
11169
|
-
const attributes = {
|
|
11170
|
-
"jsenv-cooked-by": "jsenv:html_inline_content_analysis",
|
|
11171
|
-
// 1. <script type="jsx"> becomes <script>
|
|
11172
|
-
// 2. <script type="module/jsx"> becomes <script type="module">
|
|
11173
|
-
...(extension ? {
|
|
11174
|
-
type: type === "js_module" ? "module" : undefined
|
|
11175
|
-
} : {})
|
|
11176
|
-
};
|
|
11177
|
-
if (hotAccept) {
|
|
11178
|
-
removeHtmlNodeText(scriptNode);
|
|
11179
|
-
setHtmlNodeAttributes(scriptNode, {
|
|
11180
|
-
...attributes
|
|
11181
|
-
});
|
|
11182
|
-
} else {
|
|
11183
|
-
setHtmlNodeText(scriptNode, inlineScriptUrlInfo.content, {
|
|
11184
|
-
indentation: false // indentation would decrease stack trace precision
|
|
11185
|
-
});
|
|
11186
|
-
|
|
11187
|
-
setHtmlNodeAttributes(scriptNode, {
|
|
11188
|
-
...attributes
|
|
11189
|
-
});
|
|
11190
|
-
}
|
|
11191
|
-
});
|
|
11192
|
-
});
|
|
11193
|
-
}
|
|
11194
|
-
});
|
|
11195
|
-
if (actions.length > 0) {
|
|
11196
|
-
await Promise.all(actions.map(action => action()));
|
|
11197
|
-
}
|
|
11198
|
-
if (mutations.length === 0) {
|
|
11199
|
-
return null;
|
|
11200
|
-
}
|
|
11201
|
-
mutations.forEach(mutation => mutation());
|
|
11202
|
-
const htmlModified = stringifyHtmlAst(htmlAst);
|
|
11203
|
-
return htmlModified;
|
|
11204
|
-
}
|
|
11205
|
-
}
|
|
11206
|
-
};
|
|
11207
|
-
};
|
|
11208
|
-
|
|
11209
|
-
const isEscaped = (i, string) => {
|
|
11210
|
-
let backslashBeforeCount = 0;
|
|
11211
|
-
while (i--) {
|
|
11212
|
-
const previousChar = string[i];
|
|
11213
|
-
if (previousChar === "\\") {
|
|
11214
|
-
backslashBeforeCount++;
|
|
11215
|
-
}
|
|
11216
|
-
break;
|
|
11217
|
-
}
|
|
11218
|
-
const isEven = backslashBeforeCount % 2 === 0;
|
|
11219
|
-
return !isEven;
|
|
11220
|
-
};
|
|
11221
|
-
|
|
11222
|
-
const JS_QUOTES = {
|
|
11223
|
-
pickBest: (string, {
|
|
11224
|
-
canUseTemplateString,
|
|
11225
|
-
defaultQuote = DOUBLE
|
|
11226
|
-
} = {}) => {
|
|
11227
|
-
// check default first, once tested do no re-test it
|
|
11228
|
-
if (!string.includes(defaultQuote)) {
|
|
11229
|
-
return defaultQuote;
|
|
11230
|
-
}
|
|
11231
|
-
if (defaultQuote !== DOUBLE && !string.includes(DOUBLE)) {
|
|
11232
|
-
return DOUBLE;
|
|
11233
|
-
}
|
|
11234
|
-
if (defaultQuote !== SINGLE && !string.includes(SINGLE)) {
|
|
11235
|
-
return SINGLE;
|
|
11236
|
-
}
|
|
11237
|
-
if (canUseTemplateString && defaultQuote !== BACKTICK && !string.includes(BACKTICK)) {
|
|
11238
|
-
return BACKTICK;
|
|
11239
|
-
}
|
|
11240
|
-
return defaultQuote;
|
|
11241
|
-
},
|
|
11242
|
-
escapeSpecialChars: (string, {
|
|
11243
|
-
quote = "pickBest",
|
|
11244
|
-
canUseTemplateString,
|
|
11245
|
-
defaultQuote,
|
|
11246
|
-
allowEscapeForVersioning = false
|
|
11247
|
-
}) => {
|
|
11248
|
-
quote = quote === "pickBest" ? JS_QUOTES.pickBest(string, {
|
|
11249
|
-
canUseTemplateString,
|
|
11250
|
-
defaultQuote
|
|
11251
|
-
}) : quote;
|
|
11252
|
-
const replacements = JS_QUOTE_REPLACEMENTS[quote];
|
|
11253
|
-
let result = "";
|
|
11254
|
-
let last = 0;
|
|
11255
|
-
let i = 0;
|
|
11256
|
-
while (i < string.length) {
|
|
11257
|
-
const char = string[i];
|
|
11258
|
-
i++;
|
|
11259
|
-
if (isEscaped(i - 1, string)) continue;
|
|
11260
|
-
const replacement = replacements[char];
|
|
11261
|
-
if (replacement) {
|
|
11262
|
-
if (allowEscapeForVersioning && char === quote && string.slice(i, i + 6) === "+__v__") {
|
|
11263
|
-
let isVersioningConcatenation = false;
|
|
11264
|
-
let j = i + 6; // start after the +
|
|
11265
|
-
while (j < string.length) {
|
|
11266
|
-
const lookAheadChar = string[j];
|
|
11267
|
-
j++;
|
|
11268
|
-
if (lookAheadChar === "+" && string[j] === quote && !isEscaped(j - 1, string)) {
|
|
11269
|
-
isVersioningConcatenation = true;
|
|
11270
|
-
break;
|
|
11271
|
-
}
|
|
11272
|
-
}
|
|
11273
|
-
if (isVersioningConcatenation) {
|
|
11274
|
-
// it's a concatenation
|
|
11275
|
-
// skip until the end of concatenation (the second +)
|
|
11276
|
-
// and resume from there
|
|
11277
|
-
i = j + 1;
|
|
11278
|
-
continue;
|
|
11279
|
-
}
|
|
11280
|
-
}
|
|
11281
|
-
if (last === i - 1) {
|
|
11282
|
-
result += replacement;
|
|
11283
|
-
} else {
|
|
11284
|
-
result += `${string.slice(last, i - 1)}${replacement}`;
|
|
11285
|
-
}
|
|
11286
|
-
last = i;
|
|
11287
|
-
}
|
|
11288
|
-
}
|
|
11289
|
-
if (last !== string.length) {
|
|
11290
|
-
result += string.slice(last);
|
|
11291
|
-
}
|
|
11292
|
-
return `${quote}${result}${quote}`;
|
|
11293
|
-
}
|
|
11294
|
-
};
|
|
11295
|
-
const DOUBLE = `"`;
|
|
11296
|
-
const SINGLE = `'`;
|
|
11297
|
-
const BACKTICK = "`";
|
|
11298
|
-
const lineEndingEscapes = {
|
|
11299
|
-
"\n": "\\n",
|
|
11300
|
-
"\r": "\\r",
|
|
11301
|
-
"\u2028": "\\u2028",
|
|
11302
|
-
"\u2029": "\\u2029"
|
|
11303
|
-
};
|
|
11304
|
-
const JS_QUOTE_REPLACEMENTS = {
|
|
11305
|
-
[DOUBLE]: {
|
|
11306
|
-
'"': '\\"',
|
|
11307
|
-
...lineEndingEscapes
|
|
11308
|
-
},
|
|
11309
|
-
[SINGLE]: {
|
|
11310
|
-
"'": "\\'",
|
|
11311
|
-
...lineEndingEscapes
|
|
11312
|
-
},
|
|
11313
|
-
[BACKTICK]: {
|
|
11314
|
-
"`": "\\`",
|
|
11315
|
-
"$": "\\$"
|
|
11316
|
-
}
|
|
11317
|
-
};
|
|
11318
|
-
|
|
11319
|
-
const jsenvPluginJsInlineContentAnalysis = ({
|
|
11320
|
-
allowEscapeForVersioning
|
|
11321
|
-
}) => {
|
|
11322
|
-
const parseAndTransformInlineContentCalls = async (urlInfo, context) => {
|
|
11323
|
-
const inlineContentInfos = await parseJsInlineContentInfos({
|
|
11324
|
-
js: urlInfo.content,
|
|
11325
|
-
url: urlInfo.originalUrl,
|
|
11326
|
-
isJsModule: urlInfo.type === "js_module"
|
|
11327
|
-
});
|
|
11328
|
-
if (inlineContentInfos.length === 0) {
|
|
11329
|
-
return null;
|
|
11330
|
-
}
|
|
11331
|
-
const magicSource = createMagicSource(urlInfo.content);
|
|
11332
|
-
await inlineContentInfos.reduce(async (previous, inlineContentInfo) => {
|
|
11333
|
-
await previous;
|
|
11334
|
-
const inlineUrl = generateInlineContentUrl({
|
|
11335
|
-
url: urlInfo.url,
|
|
11336
|
-
extension: CONTENT_TYPE.asFileExtension(inlineContentInfo.contentType),
|
|
11337
|
-
line: inlineContentInfo.line,
|
|
11338
|
-
column: inlineContentInfo.column,
|
|
11339
|
-
lineEnd: inlineContentInfo.lineEnd,
|
|
11340
|
-
columnEnd: inlineContentInfo.columnEnd
|
|
11341
|
-
});
|
|
11342
|
-
let {
|
|
11343
|
-
quote
|
|
11344
|
-
} = inlineContentInfo;
|
|
11345
|
-
if (quote === "`" && !context.isSupportedOnCurrentClients("template_literals")) {
|
|
11346
|
-
// if quote is "`" and template literals are not supported
|
|
11347
|
-
// we'll use a regular string (single or double quote)
|
|
11348
|
-
// when rendering the string
|
|
11349
|
-
quote = JS_QUOTES.pickBest(inlineContentInfo.content);
|
|
11350
|
-
}
|
|
11351
|
-
const [inlineReference, inlineUrlInfo] = context.referenceUtils.foundInline({
|
|
11352
|
-
type: "js_inline_content",
|
|
11353
|
-
subtype: inlineContentInfo.type,
|
|
11354
|
-
// "new_blob_first_arg", "new_inline_content_first_arg", "json_parse_first_arg"
|
|
11355
|
-
isOriginalPosition: urlInfo.content === urlInfo.originalContent,
|
|
11356
|
-
specifierLine: inlineContentInfo.line,
|
|
11357
|
-
specifierColumn: inlineContentInfo.column,
|
|
11358
|
-
specifier: inlineUrl,
|
|
11359
|
-
contentType: inlineContentInfo.contentType,
|
|
11360
|
-
content: inlineContentInfo.content
|
|
11361
|
-
});
|
|
11362
|
-
inlineUrlInfo.jsQuote = quote;
|
|
11363
|
-
inlineReference.escape = value => JS_QUOTES.escapeSpecialChars(value.slice(1, -1), {
|
|
11364
|
-
quote
|
|
11365
|
-
});
|
|
11366
|
-
await context.cook(inlineUrlInfo, {
|
|
11367
|
-
reference: inlineReference
|
|
11368
|
-
});
|
|
11369
|
-
magicSource.replace({
|
|
11370
|
-
start: inlineContentInfo.start,
|
|
11371
|
-
end: inlineContentInfo.end,
|
|
11372
|
-
replacement: JS_QUOTES.escapeSpecialChars(inlineUrlInfo.content, {
|
|
11373
|
-
quote,
|
|
11374
|
-
allowEscapeForVersioning
|
|
11375
|
-
})
|
|
11376
|
-
});
|
|
11377
|
-
}, Promise.resolve());
|
|
11378
|
-
return magicSource.toContentAndSourcemap();
|
|
11379
|
-
};
|
|
11380
|
-
return {
|
|
11381
|
-
name: "jsenv:js_inline_content_analysis",
|
|
11382
|
-
appliesDuring: "*",
|
|
11383
|
-
transformUrlContent: {
|
|
11384
|
-
js_classic: parseAndTransformInlineContentCalls,
|
|
11385
|
-
js_module: parseAndTransformInlineContentCalls
|
|
11386
|
-
}
|
|
11387
|
-
};
|
|
11388
|
-
};
|
|
11389
|
-
const parseJsInlineContentInfos = async ({
|
|
11390
|
-
js,
|
|
11391
|
-
url,
|
|
11392
|
-
isJsModule
|
|
11393
|
-
}) => {
|
|
11394
|
-
if (!js.includes("InlineContent") && !js.includes("new Blob(") && !js.includes("JSON.parse(")) {
|
|
11395
|
-
return [];
|
|
11396
|
-
}
|
|
11397
|
-
const {
|
|
11398
|
-
metadata
|
|
11399
|
-
} = await applyBabelPlugins({
|
|
11400
|
-
babelPlugins: [babelPluginMetadataInlineContents],
|
|
11401
|
-
urlInfo: {
|
|
11402
|
-
originalUrl: url,
|
|
11403
|
-
type: isJsModule ? "js_module" : "js_classic",
|
|
11404
|
-
content: js
|
|
11405
|
-
}
|
|
11406
|
-
});
|
|
11407
|
-
return metadata.inlineContentInfos;
|
|
11408
|
-
};
|
|
11409
|
-
const babelPluginMetadataInlineContents = () => {
|
|
11410
|
-
return {
|
|
11411
|
-
name: "metadata-inline-contents",
|
|
11412
|
-
visitor: {
|
|
11413
|
-
Program: (programPath, state) => {
|
|
11414
|
-
const inlineContentInfos = [];
|
|
11415
|
-
const onInlineContentInfo = inlineContentInfo => {
|
|
11416
|
-
inlineContentInfos.push(inlineContentInfo);
|
|
11417
|
-
};
|
|
11418
|
-
programPath.traverse({
|
|
11419
|
-
NewExpression: path => {
|
|
11420
|
-
if (isNewInlineContentCall(path)) {
|
|
11421
|
-
analyzeNewInlineContentCall(path.node, {
|
|
11422
|
-
onInlineContentInfo
|
|
11423
|
-
});
|
|
11424
|
-
return;
|
|
11425
|
-
}
|
|
11426
|
-
if (isNewBlobCall(path.node)) {
|
|
11427
|
-
analyzeNewBlobCall(path.node, {
|
|
11428
|
-
onInlineContentInfo
|
|
11429
|
-
});
|
|
11430
|
-
return;
|
|
11431
|
-
}
|
|
11432
|
-
},
|
|
11433
|
-
CallExpression: path => {
|
|
11434
|
-
const node = path.node;
|
|
11435
|
-
if (isJSONParseCall(node)) {
|
|
11436
|
-
analyzeJsonParseCall(node, {
|
|
11437
|
-
onInlineContentInfo
|
|
11438
|
-
});
|
|
11439
|
-
}
|
|
11440
|
-
}
|
|
11441
|
-
});
|
|
11442
|
-
state.file.metadata.inlineContentInfos = inlineContentInfos;
|
|
11443
|
-
}
|
|
11444
|
-
}
|
|
11445
|
-
};
|
|
11446
|
-
};
|
|
11447
|
-
const isNewInlineContentCall = path => {
|
|
11448
|
-
const node = path.node;
|
|
11449
|
-
if (node.callee.type === "Identifier") {
|
|
11450
|
-
// terser rename import to use a shorter name
|
|
11451
|
-
const name = getOriginalName(path, node.callee.name);
|
|
11452
|
-
return name === "InlineContent";
|
|
11453
|
-
}
|
|
11454
|
-
if (node.callee.id && node.callee.id.type === "Identifier") {
|
|
11455
|
-
const name = getOriginalName(path, node.callee.id.name);
|
|
11456
|
-
return name === "InlineContent";
|
|
11457
|
-
}
|
|
11458
|
-
return false;
|
|
11459
|
-
};
|
|
11460
|
-
const analyzeNewInlineContentCall = (node, {
|
|
11461
|
-
onInlineContentInfo
|
|
11462
|
-
}) => {
|
|
11463
|
-
analyzeArguments({
|
|
11464
|
-
node,
|
|
11465
|
-
onInlineContentInfo,
|
|
11466
|
-
nodeHoldingContent: node.arguments[0],
|
|
11467
|
-
type: "new_inline_content_first_arg"
|
|
11468
|
-
});
|
|
11469
|
-
};
|
|
11470
|
-
const isNewBlobCall = node => {
|
|
11471
|
-
return node.callee.type === "Identifier" && node.callee.name === "Blob";
|
|
11472
|
-
};
|
|
11473
|
-
const analyzeNewBlobCall = (node, {
|
|
11474
|
-
onInlineContentInfo
|
|
11475
|
-
}) => {
|
|
11476
|
-
const firstArg = node.arguments[0];
|
|
11477
|
-
if (!firstArg) {
|
|
11478
|
-
return;
|
|
11479
|
-
}
|
|
11480
|
-
if (firstArg.type !== "ArrayExpression") {
|
|
11481
|
-
return;
|
|
11482
|
-
}
|
|
11483
|
-
if (firstArg.elements.length !== 1) {
|
|
11484
|
-
return;
|
|
11485
|
-
}
|
|
11486
|
-
analyzeArguments({
|
|
11487
|
-
node,
|
|
11488
|
-
onInlineContentInfo,
|
|
11489
|
-
nodeHoldingContent: firstArg.elements[0],
|
|
11490
|
-
type: "new_blob_first_arg"
|
|
11491
|
-
});
|
|
11492
|
-
};
|
|
11493
|
-
const analyzeArguments = ({
|
|
11494
|
-
node,
|
|
11495
|
-
onInlineContentInfo,
|
|
11496
|
-
nodeHoldingContent,
|
|
11497
|
-
type
|
|
11498
|
-
}) => {
|
|
11499
|
-
if (node.arguments.length !== 2) {
|
|
11500
|
-
return;
|
|
11501
|
-
}
|
|
11502
|
-
const [, secondArg] = node.arguments;
|
|
11503
|
-
const typePropertyNode = getTypePropertyNode(secondArg);
|
|
11504
|
-
if (!typePropertyNode) {
|
|
11505
|
-
return;
|
|
11506
|
-
}
|
|
11507
|
-
const typePropertyValueNode = typePropertyNode.value;
|
|
11508
|
-
if (typePropertyValueNode.type !== "StringLiteral") {
|
|
11509
|
-
return;
|
|
11510
|
-
}
|
|
11511
|
-
const contentType = typePropertyValueNode.value;
|
|
11512
|
-
const contentDetails = extractContentDetails(nodeHoldingContent);
|
|
11513
|
-
if (contentDetails) {
|
|
11514
|
-
onInlineContentInfo({
|
|
11515
|
-
node: nodeHoldingContent,
|
|
11516
|
-
...getNodePosition(nodeHoldingContent),
|
|
11517
|
-
type,
|
|
11518
|
-
contentType,
|
|
11519
|
-
...contentDetails
|
|
11520
|
-
});
|
|
11521
|
-
}
|
|
11522
|
-
};
|
|
11523
|
-
const extractContentDetails = node => {
|
|
11524
|
-
if (node.type === "StringLiteral") {
|
|
11525
|
-
return {
|
|
11526
|
-
nodeType: "StringLiteral",
|
|
11527
|
-
quote: node.extra.raw[0],
|
|
11528
|
-
content: node.value
|
|
11529
|
-
};
|
|
11530
|
-
}
|
|
11531
|
-
if (node.type === "TemplateLiteral") {
|
|
11532
|
-
const quasis = node.quasis;
|
|
11533
|
-
if (quasis.length !== 1) {
|
|
11534
|
-
return null;
|
|
11535
|
-
}
|
|
11536
|
-
const templateElementNode = quasis[0];
|
|
11537
|
-
return {
|
|
11538
|
-
nodeType: "TemplateLiteral",
|
|
11539
|
-
quote: "`",
|
|
11540
|
-
content: templateElementNode.value.cooked
|
|
11541
|
-
};
|
|
11542
|
-
}
|
|
11543
|
-
return null;
|
|
11544
|
-
};
|
|
11545
|
-
const isJSONParseCall = node => {
|
|
11546
|
-
const callee = node.callee;
|
|
11547
|
-
return callee.type === "MemberExpression" && callee.object.type === "Identifier" && callee.object.name === "JSON" && callee.property.type === "Identifier" && callee.property.name === "parse";
|
|
11548
|
-
};
|
|
11549
|
-
const analyzeJsonParseCall = (node, {
|
|
11550
|
-
onInlineContentInfo
|
|
11551
|
-
}) => {
|
|
11552
|
-
const firstArgNode = node.arguments[0];
|
|
11553
|
-
const contentDetails = extractContentDetails(firstArgNode);
|
|
11554
|
-
if (contentDetails) {
|
|
11555
|
-
onInlineContentInfo({
|
|
11556
|
-
node: firstArgNode,
|
|
11557
|
-
...getNodePosition(firstArgNode),
|
|
11558
|
-
type: "json_parse_first_arg",
|
|
11559
|
-
contentType: "application/json",
|
|
11560
|
-
...contentDetails
|
|
11561
|
-
});
|
|
11562
|
-
}
|
|
11563
|
-
};
|
|
11564
|
-
const getNodePosition = node => {
|
|
11565
|
-
return {
|
|
11566
|
-
start: node.start,
|
|
11567
|
-
end: node.end,
|
|
11568
|
-
line: node.loc.start.line,
|
|
11569
|
-
column: node.loc.start.column,
|
|
11570
|
-
lineEnd: node.loc.end.line,
|
|
11571
|
-
columnEnd: node.loc.end.column
|
|
11572
|
-
};
|
|
11573
|
-
};
|
|
11574
|
-
const getOriginalName = (path, name) => {
|
|
11575
|
-
const binding = path.scope.getBinding(name);
|
|
11576
|
-
if (!binding) {
|
|
11577
|
-
return name;
|
|
11578
|
-
}
|
|
11579
|
-
if (binding.path.type === "ImportSpecifier") {
|
|
11580
|
-
const importedName = binding.path.node.imported.name;
|
|
11581
|
-
if (name === importedName) {
|
|
11582
|
-
return name;
|
|
11583
|
-
}
|
|
11584
|
-
return getOriginalName(path, importedName);
|
|
11585
|
-
}
|
|
11586
|
-
if (binding.path.type === "VariableDeclarator") {
|
|
11587
|
-
const {
|
|
11588
|
-
node
|
|
11589
|
-
} = binding.path;
|
|
11590
|
-
const {
|
|
11591
|
-
init
|
|
11592
|
-
} = node;
|
|
11593
|
-
if (init && init.type === "Identifier") {
|
|
11594
|
-
const previousName = init.name;
|
|
11595
|
-
return getOriginalName(path, previousName);
|
|
11596
|
-
}
|
|
11597
|
-
if (node.id && node.id.type === "Identifier") {
|
|
11598
|
-
const {
|
|
11599
|
-
constantViolations
|
|
11600
|
-
} = binding;
|
|
11601
|
-
if (constantViolations && constantViolations.length > 0) {
|
|
11602
|
-
const lastViolation = constantViolations[constantViolations.length - 1];
|
|
11603
|
-
if (lastViolation && lastViolation.node.type === "AssignmentExpression" && lastViolation.node.right.type === "MemberExpression" && lastViolation.node.right.property.type === "Identifier") {
|
|
11604
|
-
return lastViolation.node.right.property.name;
|
|
11605
|
-
}
|
|
11606
|
-
}
|
|
11607
|
-
}
|
|
11608
|
-
}
|
|
11609
|
-
return name;
|
|
11610
|
-
};
|
|
11611
|
-
const getTypePropertyNode = node => {
|
|
11612
|
-
if (node.type !== "ObjectExpression") {
|
|
11613
|
-
return null;
|
|
11614
|
-
}
|
|
11615
|
-
const {
|
|
11616
|
-
properties
|
|
11617
|
-
} = node;
|
|
11618
|
-
return properties.find(property => {
|
|
11619
|
-
return property.type === "ObjectProperty" && property.key.type === "Identifier" && property.key.name === "type";
|
|
11620
|
-
});
|
|
11621
|
-
};
|
|
11622
|
-
|
|
11623
|
-
const jsenvPluginDataUrls = () => {
|
|
11624
|
-
return {
|
|
11625
|
-
name: "jsenv:data_urls",
|
|
11626
|
-
appliesDuring: "*",
|
|
11627
|
-
resolveUrl: reference => {
|
|
11628
|
-
if (!reference.specifier.startsWith("data:")) {
|
|
11629
|
-
return null;
|
|
11630
|
-
}
|
|
11631
|
-
return reference.specifier;
|
|
11632
|
-
},
|
|
11633
|
-
fetchUrlContent: urlInfo => {
|
|
11634
|
-
if (!urlInfo.url.startsWith("data:")) {
|
|
11635
|
-
return null;
|
|
11636
|
-
}
|
|
11637
|
-
const {
|
|
11638
|
-
contentType,
|
|
11639
|
-
base64Flag,
|
|
11640
|
-
data: urlData
|
|
11641
|
-
} = DATA_URL.parse(urlInfo.url);
|
|
11642
|
-
urlInfo.data.base64Flag = base64Flag;
|
|
11643
|
-
return {
|
|
11644
|
-
content: contentFromUrlData({
|
|
11645
|
-
contentType,
|
|
11646
|
-
base64Flag,
|
|
11647
|
-
urlData
|
|
11648
|
-
}),
|
|
11649
|
-
contentType
|
|
11650
|
-
};
|
|
11651
|
-
},
|
|
11652
|
-
formatUrl: (reference, context) => {
|
|
11653
|
-
if (!reference.generatedUrl.startsWith("data:")) {
|
|
11654
|
-
return null;
|
|
11655
|
-
}
|
|
11656
|
-
if (reference.type === "sourcemap_comment") {
|
|
11657
|
-
return null;
|
|
11658
|
-
}
|
|
11659
|
-
return (async () => {
|
|
11660
|
-
const urlInfo = context.urlGraph.getUrlInfo(reference.url);
|
|
11661
|
-
await context.cook(urlInfo, {
|
|
11662
|
-
reference
|
|
11329
|
+
context.referenceUtils.becomesInline(scriptReference, {
|
|
11330
|
+
line: line - 1,
|
|
11331
|
+
column,
|
|
11332
|
+
isOriginal,
|
|
11333
|
+
specifier: scriptReference.generatedSpecifier,
|
|
11334
|
+
content: scriptUrlInfo.content,
|
|
11335
|
+
contentType: scriptUrlInfo.contentType
|
|
11336
|
+
});
|
|
11337
|
+
mutations.push(() => {
|
|
11338
|
+
setHtmlNodeAttributes(scriptNode, {
|
|
11339
|
+
"inlined-from-src": src,
|
|
11340
|
+
"src": undefined,
|
|
11341
|
+
"crossorigin": undefined,
|
|
11342
|
+
"integrity": undefined,
|
|
11343
|
+
"jsenv-inlined-by": "jsenv:inlining_into_html"
|
|
11344
|
+
});
|
|
11345
|
+
setHtmlNodeText(scriptNode, scriptUrlInfo.content, {
|
|
11346
|
+
indentation: "auto"
|
|
11347
|
+
});
|
|
11348
|
+
});
|
|
11349
|
+
});
|
|
11350
|
+
};
|
|
11351
|
+
visitHtmlNodes(htmlAst, {
|
|
11352
|
+
link: linkNode => {
|
|
11353
|
+
const rel = getHtmlNodeAttribute(linkNode, "rel");
|
|
11354
|
+
if (rel !== "stylesheet") {
|
|
11355
|
+
return;
|
|
11356
|
+
}
|
|
11357
|
+
const href = getHtmlNodeAttribute(linkNode, "href");
|
|
11358
|
+
if (!href) {
|
|
11359
|
+
return;
|
|
11360
|
+
}
|
|
11361
|
+
onStyleSheet(linkNode, {
|
|
11362
|
+
href
|
|
11363
|
+
});
|
|
11364
|
+
},
|
|
11365
|
+
script: scriptNode => {
|
|
11366
|
+
const {
|
|
11367
|
+
type
|
|
11368
|
+
} = analyzeScriptNode(scriptNode);
|
|
11369
|
+
const scriptNodeText = getHtmlNodeText(scriptNode);
|
|
11370
|
+
if (scriptNodeText) {
|
|
11371
|
+
return;
|
|
11372
|
+
}
|
|
11373
|
+
const src = getHtmlNodeAttribute(scriptNode, "src");
|
|
11374
|
+
if (!src) {
|
|
11375
|
+
return;
|
|
11376
|
+
}
|
|
11377
|
+
onScriptWithSrc(scriptNode, {
|
|
11378
|
+
type,
|
|
11379
|
+
src
|
|
11380
|
+
});
|
|
11381
|
+
}
|
|
11663
11382
|
});
|
|
11664
|
-
if (
|
|
11665
|
-
|
|
11383
|
+
if (actions.length > 0) {
|
|
11384
|
+
await Promise.all(actions.map(action => action()));
|
|
11666
11385
|
}
|
|
11667
|
-
|
|
11668
|
-
|
|
11669
|
-
|
|
11670
|
-
|
|
11671
|
-
});
|
|
11672
|
-
return specifier;
|
|
11673
|
-
})();
|
|
11386
|
+
mutations.forEach(mutation => mutation());
|
|
11387
|
+
const htmlModified = stringifyHtmlAst(htmlAst);
|
|
11388
|
+
return htmlModified;
|
|
11389
|
+
}
|
|
11674
11390
|
}
|
|
11675
11391
|
};
|
|
11676
11392
|
};
|
|
11677
|
-
const contentFromUrlData = ({
|
|
11678
|
-
contentType,
|
|
11679
|
-
base64Flag,
|
|
11680
|
-
urlData
|
|
11681
|
-
}) => {
|
|
11682
|
-
if (CONTENT_TYPE.isTextual(contentType)) {
|
|
11683
|
-
if (base64Flag) {
|
|
11684
|
-
return base64ToString(urlData);
|
|
11685
|
-
}
|
|
11686
|
-
return urlData;
|
|
11687
|
-
}
|
|
11688
|
-
if (base64Flag) {
|
|
11689
|
-
return base64ToBuffer(urlData);
|
|
11690
|
-
}
|
|
11691
|
-
return Buffer.from(urlData);
|
|
11692
|
-
};
|
|
11693
|
-
const base64ToBuffer = base64String => Buffer.from(base64String, "base64");
|
|
11694
|
-
const base64ToString = base64String => Buffer.from(base64String, "base64").toString("utf8");
|
|
11695
|
-
const dataToBase64 = data => Buffer.from(data).toString("base64");
|
|
11696
11393
|
|
|
11697
|
-
const
|
|
11698
|
-
|
|
11699
|
-
|
|
11700
|
-
allowEscapeForVersioning = false
|
|
11701
|
-
} = {}) => {
|
|
11702
|
-
return [...(fetchInlineUrls ? [jsenvPluginInlineContentFetcher()] : []), jsenvPluginHtmlInlineContentAnalysis({
|
|
11703
|
-
analyzeConvertedScripts
|
|
11704
|
-
}), jsenvPluginJsInlineContentAnalysis({
|
|
11705
|
-
allowEscapeForVersioning
|
|
11706
|
-
}), jsenvPluginDataUrls()];
|
|
11707
|
-
};
|
|
11708
|
-
const jsenvPluginInlineContentFetcher = () => {
|
|
11709
|
-
return {
|
|
11710
|
-
name: "jsenv:inline_content_fetcher",
|
|
11394
|
+
const jsenvPluginInlining = () => {
|
|
11395
|
+
return [{
|
|
11396
|
+
name: "jsenv:inlining",
|
|
11711
11397
|
appliesDuring: "*",
|
|
11712
|
-
|
|
11713
|
-
|
|
11714
|
-
|
|
11398
|
+
redirectReference: reference => {
|
|
11399
|
+
const {
|
|
11400
|
+
searchParams
|
|
11401
|
+
} = reference;
|
|
11402
|
+
if (searchParams.has("inline")) {
|
|
11403
|
+
const urlObject = new URL(reference.url);
|
|
11404
|
+
urlObject.searchParams.delete("inline");
|
|
11405
|
+
return urlObject.href;
|
|
11715
11406
|
}
|
|
11716
|
-
return
|
|
11717
|
-
// we want to fetch the original content otherwise we might re-cook
|
|
11718
|
-
// content already cooked
|
|
11719
|
-
content: urlInfo.originalContent,
|
|
11720
|
-
contentType: urlInfo.contentType
|
|
11721
|
-
};
|
|
11407
|
+
return null;
|
|
11722
11408
|
}
|
|
11723
|
-
};
|
|
11409
|
+
}, jsenvPluginInliningAsDataUrl(), jsenvPluginInliningIntoHtml()];
|
|
11724
11410
|
};
|
|
11725
11411
|
|
|
11726
11412
|
const requireFromJsenv = createRequire(import.meta.url);
|
|
@@ -15460,6 +15146,7 @@ const babelPluginRelativeImports = babel => {
|
|
|
15460
15146
|
* - propagate "?js_module_fallback" query string param on urls
|
|
15461
15147
|
* - perform conversion from js module to js classic when url uses "?js_module_fallback"
|
|
15462
15148
|
*/
|
|
15149
|
+
|
|
15463
15150
|
const jsenvPluginJsModuleConversion = ({
|
|
15464
15151
|
systemJsInjection,
|
|
15465
15152
|
systemJsClientFileUrl,
|
|
@@ -15499,7 +15186,7 @@ const jsenvPluginJsModuleConversion = ({
|
|
|
15499
15186
|
return {
|
|
15500
15187
|
name: "jsenv:js_module_conversion",
|
|
15501
15188
|
appliesDuring: "*",
|
|
15502
|
-
|
|
15189
|
+
redirectReference: (reference, context) => {
|
|
15503
15190
|
if (reference.searchParams.has("js_module_fallback")) {
|
|
15504
15191
|
markAsJsClassicProxy(reference);
|
|
15505
15192
|
return null;
|
|
@@ -15570,6 +15257,7 @@ const jsenvPluginJsModuleConversion = ({
|
|
|
15570
15257
|
* - js inside <script type="module"> is transformed into classic js
|
|
15571
15258
|
* - <link rel="modulepreload"> are converted to <link rel="preload">
|
|
15572
15259
|
*/
|
|
15260
|
+
|
|
15573
15261
|
const jsenvPluginJsModuleFallbackInsideHtml = ({
|
|
15574
15262
|
systemJsInjection,
|
|
15575
15263
|
systemJsClientFileUrl
|
|
@@ -15582,7 +15270,7 @@ const jsenvPluginJsModuleFallbackInsideHtml = ({
|
|
|
15582
15270
|
return {
|
|
15583
15271
|
name: "jsenv:js_module_fallback_inside_html",
|
|
15584
15272
|
appliesDuring: "*",
|
|
15585
|
-
|
|
15273
|
+
redirectReference: {
|
|
15586
15274
|
link_href: (reference, context) => {
|
|
15587
15275
|
if (context.systemJsTranspilation && reference.subtype === "modulepreload") {
|
|
15588
15276
|
return turnIntoJsClassicProxy(reference);
|
|
@@ -15771,6 +15459,7 @@ const isExpectingJsModule = reference => {
|
|
|
15771
15459
|
* transformed into
|
|
15772
15460
|
* new SharedWorker("shared_worker.js?js_module_fallback", { type: "classic" })
|
|
15773
15461
|
*/
|
|
15462
|
+
|
|
15774
15463
|
const jsenvPluginJsModuleFallbackOnWorkers = () => {
|
|
15775
15464
|
const turnIntoJsClassicProxy = reference => {
|
|
15776
15465
|
reference.mutation = magicSource => {
|
|
@@ -15787,7 +15476,7 @@ const jsenvPluginJsModuleFallbackOnWorkers = () => {
|
|
|
15787
15476
|
return {
|
|
15788
15477
|
name: "jsenv:js_module_fallback_on_workers",
|
|
15789
15478
|
appliesDuring: "*",
|
|
15790
|
-
|
|
15479
|
+
redirectReference: {
|
|
15791
15480
|
js_url: (reference, context) => {
|
|
15792
15481
|
if (reference.expectedType !== "js_module") {
|
|
15793
15482
|
return null;
|
|
@@ -15928,6 +15617,7 @@ const pathnameToParentPathname = pathname => {
|
|
|
15928
15617
|
};
|
|
15929
15618
|
|
|
15930
15619
|
// could be useful: https://url.spec.whatwg.org/#url-miscellaneous
|
|
15620
|
+
|
|
15931
15621
|
const resolveUrl = (specifier, baseUrl) => {
|
|
15932
15622
|
if (baseUrl) {
|
|
15933
15623
|
if (typeof baseUrl !== "string") {
|
|
@@ -16459,6 +16149,7 @@ const applyDefaultExtension = ({
|
|
|
16459
16149
|
* -> The importmap resolution implemented here takes a shortcut and does the following:
|
|
16460
16150
|
* - All importmap found are merged into a single one that is applied to every import specifiers
|
|
16461
16151
|
*/
|
|
16152
|
+
|
|
16462
16153
|
const jsenvPluginImportmap = () => {
|
|
16463
16154
|
let finalImportmap = null;
|
|
16464
16155
|
const importmaps = {};
|
|
@@ -16478,7 +16169,7 @@ const jsenvPluginImportmap = () => {
|
|
|
16478
16169
|
return {
|
|
16479
16170
|
name: "jsenv:importmap",
|
|
16480
16171
|
appliesDuring: "*",
|
|
16481
|
-
|
|
16172
|
+
resolveReference: {
|
|
16482
16173
|
js_import: reference => {
|
|
16483
16174
|
if (!finalImportmap) {
|
|
16484
16175
|
return null;
|
|
@@ -16636,6 +16327,20 @@ const jsenvPluginImportmap = () => {
|
|
|
16636
16327
|
};
|
|
16637
16328
|
};
|
|
16638
16329
|
|
|
16330
|
+
const urlTypeFromReference = (reference, context) => {
|
|
16331
|
+
if (reference.type === "sourcemap_comment") {
|
|
16332
|
+
return "sourcemap";
|
|
16333
|
+
}
|
|
16334
|
+
if (reference.injected) {
|
|
16335
|
+
return reference.expectedType;
|
|
16336
|
+
}
|
|
16337
|
+
const parentUrlInfo = context.urlGraph.getUrlInfo(reference.parentUrl);
|
|
16338
|
+
if (parentUrlInfo) {
|
|
16339
|
+
return parentUrlInfo.type;
|
|
16340
|
+
}
|
|
16341
|
+
return "entry_point";
|
|
16342
|
+
};
|
|
16343
|
+
|
|
16639
16344
|
const isSpecifierForNodeBuiltin = specifier => {
|
|
16640
16345
|
return specifier.startsWith("node:") || NODE_BUILTIN_MODULE_SPECIFIERS.includes(specifier);
|
|
16641
16346
|
};
|
|
@@ -17591,6 +17296,7 @@ const getExtensionsToTry = (magicExtensions, importer) => {
|
|
|
17591
17296
|
* if that comes from node resolution or anything else (not even magic resolution)
|
|
17592
17297
|
* it should likely be an other plugin happening after the others
|
|
17593
17298
|
*/
|
|
17299
|
+
|
|
17594
17300
|
const createNodeEsmResolver = ({
|
|
17595
17301
|
runtimeCompat,
|
|
17596
17302
|
packageConditions,
|
|
@@ -17603,6 +17309,16 @@ const createNodeEsmResolver = ({
|
|
|
17603
17309
|
if (reference.type === "package_json") {
|
|
17604
17310
|
return reference.specifier;
|
|
17605
17311
|
}
|
|
17312
|
+
if (reference.specifier === "/") {
|
|
17313
|
+
const {
|
|
17314
|
+
mainFilePath,
|
|
17315
|
+
rootDirectoryUrl
|
|
17316
|
+
} = context;
|
|
17317
|
+
return String(new URL(mainFilePath, rootDirectoryUrl));
|
|
17318
|
+
}
|
|
17319
|
+
if (reference.specifier[0] === "/") {
|
|
17320
|
+
return new URL(reference.specifier.slice(1), context.rootDirectoryUrl).href;
|
|
17321
|
+
}
|
|
17606
17322
|
const parentUrl = reference.baseUrl || reference.parentUrl;
|
|
17607
17323
|
if (!parentUrl.startsWith("file:")) {
|
|
17608
17324
|
return new URL(reference.specifier, parentUrl).href;
|
|
@@ -17681,126 +17397,64 @@ const addRelationshipWithPackageJson = ({
|
|
|
17681
17397
|
}
|
|
17682
17398
|
};
|
|
17683
17399
|
|
|
17684
|
-
|
|
17685
|
-
|
|
17686
|
-
* - A custom plugin implements a resolveUrl hook returning something
|
|
17687
|
-
* - The reference.type is "filesystem" -> it is handled by jsenv_plugin_file_urls.js
|
|
17688
|
-
*
|
|
17689
|
-
* By default node esm resolution applies inside js modules
|
|
17690
|
-
* and the rest uses the web standard url resolution (new URL):
|
|
17691
|
-
* - "http_request"
|
|
17692
|
-
* - "entry_point"
|
|
17693
|
-
* - "link_href"
|
|
17694
|
-
* - "style"
|
|
17695
|
-
* - "script"
|
|
17696
|
-
* - "a_href"
|
|
17697
|
-
* - "iframe_src
|
|
17698
|
-
* - "img_src"
|
|
17699
|
-
* - "img_srcset"
|
|
17700
|
-
* - "source_src"
|
|
17701
|
-
* - "source_srcset"
|
|
17702
|
-
* - "image_href"
|
|
17703
|
-
* - "use_href"
|
|
17704
|
-
* - "css_@import"
|
|
17705
|
-
* - "css_url"
|
|
17706
|
-
* - "js_import"
|
|
17707
|
-
* - "js_import_script"
|
|
17708
|
-
* - "js_url"
|
|
17709
|
-
* - "js_inline_content"
|
|
17710
|
-
* - "sourcemap_comment"
|
|
17711
|
-
* - "webmanifest_icon_src"
|
|
17712
|
-
* - "package_json"
|
|
17713
|
-
*/
|
|
17714
|
-
const jsenvPluginUrlResolution = ({
|
|
17715
|
-
runtimeCompat,
|
|
17716
|
-
defaultFileUrl,
|
|
17717
|
-
urlResolution
|
|
17718
|
-
}) => {
|
|
17719
|
-
const resolveUrlUsingWebResolution = reference => {
|
|
17720
|
-
return new URL(reference.specifier,
|
|
17721
|
-
// baseUrl happens second argument to new URL() is different from
|
|
17722
|
-
// import.meta.url or document.currentScript.src
|
|
17723
|
-
reference.baseUrl || reference.parentUrl).href;
|
|
17724
|
-
};
|
|
17400
|
+
const jsenvPluginNodeEsmResolution = (resolutionConfig = {}) => {
|
|
17401
|
+
let nodeEsmResolverDefault;
|
|
17725
17402
|
const resolvers = {};
|
|
17726
|
-
Object.keys(
|
|
17727
|
-
const
|
|
17728
|
-
if (
|
|
17729
|
-
|
|
17730
|
-
}
|
|
17731
|
-
|
|
17732
|
-
|
|
17733
|
-
node_esm,
|
|
17734
|
-
...rest
|
|
17735
|
-
} = resolver;
|
|
17736
|
-
const unexpectedKeys = Object.keys(rest);
|
|
17737
|
-
if (unexpectedKeys.length) {
|
|
17738
|
-
throw new TypeError(`${unexpectedKeys.join(",")}: there is no such configuration on "${urlType}"`);
|
|
17739
|
-
}
|
|
17740
|
-
if (node_esm === undefined) {
|
|
17741
|
-
node_esm = urlType === "js_import";
|
|
17742
|
-
}
|
|
17743
|
-
if (web === undefined) {
|
|
17744
|
-
web = true;
|
|
17745
|
-
}
|
|
17746
|
-
if (node_esm) {
|
|
17747
|
-
if (node_esm === true) node_esm = {};
|
|
17403
|
+
Object.keys(resolutionConfig).forEach(urlType => {
|
|
17404
|
+
const config = resolutionConfig[urlType];
|
|
17405
|
+
if (config === true) {
|
|
17406
|
+
resolvers[urlType] = (...args) => nodeEsmResolverDefault(...args);
|
|
17407
|
+
} else if (config === false) {
|
|
17408
|
+
resolvers[urlType] = () => null;
|
|
17409
|
+
} else if (typeof config === "object") {
|
|
17748
17410
|
const {
|
|
17411
|
+
runtimeCompat,
|
|
17749
17412
|
packageConditions,
|
|
17750
|
-
preservesSymlink
|
|
17751
|
-
|
|
17413
|
+
preservesSymlink,
|
|
17414
|
+
...rest
|
|
17415
|
+
} = config;
|
|
17416
|
+
const unexpectedKeys = Object.keys(rest);
|
|
17417
|
+
if (unexpectedKeys.length) {
|
|
17418
|
+
throw new TypeError(`${unexpectedKeys.join(",")}: there is no such configuration on "${urlType}"`);
|
|
17419
|
+
}
|
|
17752
17420
|
resolvers[urlType] = createNodeEsmResolver({
|
|
17753
17421
|
runtimeCompat,
|
|
17754
17422
|
packageConditions,
|
|
17755
17423
|
preservesSymlink
|
|
17756
17424
|
});
|
|
17757
|
-
} else
|
|
17758
|
-
|
|
17425
|
+
} else {
|
|
17426
|
+
throw new TypeError(`config must be true, false or an object, got ${config} on "${urlType}"`);
|
|
17759
17427
|
}
|
|
17760
17428
|
});
|
|
17761
|
-
const nodeEsmResolverDefault = createNodeEsmResolver({
|
|
17762
|
-
runtimeCompat,
|
|
17763
|
-
preservesSymlink: true
|
|
17764
|
-
});
|
|
17765
|
-
if (!resolvers.js_module) {
|
|
17766
|
-
resolvers.js_module = nodeEsmResolverDefault;
|
|
17767
|
-
}
|
|
17768
|
-
if (!resolvers.js_classic) {
|
|
17769
|
-
resolvers.js_classic = (reference, context) => {
|
|
17770
|
-
if (reference.subtype === "self_import_scripts_arg") {
|
|
17771
|
-
return nodeEsmResolverDefault(reference, context);
|
|
17772
|
-
}
|
|
17773
|
-
return resolveUrlUsingWebResolution(reference);
|
|
17774
|
-
};
|
|
17775
|
-
}
|
|
17776
|
-
if (!resolvers["*"]) {
|
|
17777
|
-
resolvers["*"] = resolveUrlUsingWebResolution;
|
|
17778
|
-
}
|
|
17779
17429
|
return {
|
|
17780
|
-
name: "jsenv:
|
|
17430
|
+
name: "jsenv:node_esm_resolution",
|
|
17781
17431
|
appliesDuring: "*",
|
|
17782
|
-
|
|
17783
|
-
|
|
17784
|
-
|
|
17785
|
-
|
|
17786
|
-
|
|
17787
|
-
|
|
17788
|
-
}
|
|
17789
|
-
if (
|
|
17790
|
-
|
|
17432
|
+
init: ({
|
|
17433
|
+
runtimeCompat
|
|
17434
|
+
}) => {
|
|
17435
|
+
nodeEsmResolverDefault = createNodeEsmResolver({
|
|
17436
|
+
runtimeCompat,
|
|
17437
|
+
preservesSymlink: true
|
|
17438
|
+
});
|
|
17439
|
+
if (!resolvers.js_module) {
|
|
17440
|
+
resolvers.js_module = nodeEsmResolverDefault;
|
|
17791
17441
|
}
|
|
17792
|
-
|
|
17793
|
-
|
|
17794
|
-
|
|
17795
|
-
|
|
17796
|
-
|
|
17797
|
-
|
|
17442
|
+
if (!resolvers.js_classic) {
|
|
17443
|
+
resolvers.js_classic = (reference, context) => {
|
|
17444
|
+
if (reference.subtype === "self_import_scripts_arg") {
|
|
17445
|
+
return nodeEsmResolverDefault(reference, context);
|
|
17446
|
+
}
|
|
17447
|
+
return null;
|
|
17448
|
+
};
|
|
17798
17449
|
}
|
|
17799
|
-
|
|
17800
|
-
|
|
17450
|
+
},
|
|
17451
|
+
resolveReference: (reference, context) => {
|
|
17452
|
+
const urlType = urlTypeFromReference(reference, context);
|
|
17453
|
+
const resolver = resolvers[urlType];
|
|
17454
|
+
return resolver ? resolver(reference, context) : null;
|
|
17801
17455
|
},
|
|
17802
17456
|
// when specifier is prefixed by "file:///@ignore/"
|
|
17803
|
-
// we return an empty js module
|
|
17457
|
+
// we return an empty js module
|
|
17804
17458
|
fetchUrlContent: urlInfo => {
|
|
17805
17459
|
if (urlInfo.url.startsWith("file:///@ignore/")) {
|
|
17806
17460
|
return {
|
|
@@ -17814,11 +17468,50 @@ const jsenvPluginUrlResolution = ({
|
|
|
17814
17468
|
};
|
|
17815
17469
|
};
|
|
17816
17470
|
|
|
17817
|
-
const
|
|
17471
|
+
const jsenvPluginWebResolution = (resolutionConfig = {}) => {
|
|
17472
|
+
const resolvers = {};
|
|
17473
|
+
const resolveUsingWebResolution = (reference, context) => {
|
|
17474
|
+
if (reference.specifier === "/") {
|
|
17475
|
+
const {
|
|
17476
|
+
mainFilePath,
|
|
17477
|
+
rootDirectoryUrl
|
|
17478
|
+
} = context;
|
|
17479
|
+
return String(new URL(mainFilePath, rootDirectoryUrl));
|
|
17480
|
+
}
|
|
17481
|
+
if (reference.specifier[0] === "/") {
|
|
17482
|
+
return new URL(reference.specifier.slice(1), context.rootDirectoryUrl).href;
|
|
17483
|
+
}
|
|
17484
|
+
return new URL(reference.specifier,
|
|
17485
|
+
// baseUrl happens second argument to new URL() is different from
|
|
17486
|
+
// import.meta.url or document.currentScript.src
|
|
17487
|
+
reference.baseUrl || reference.parentUrl).href;
|
|
17488
|
+
};
|
|
17489
|
+
Object.keys(resolutionConfig).forEach(urlType => {
|
|
17490
|
+
const config = resolutionConfig[urlType];
|
|
17491
|
+
if (config === true) {
|
|
17492
|
+
resolvers[urlType] = resolveUsingWebResolution;
|
|
17493
|
+
} else if (config === false) {
|
|
17494
|
+
resolvers[urlType] = () => null;
|
|
17495
|
+
} else {
|
|
17496
|
+
throw new TypeError(`config must be true or false, got ${config} on "${urlType}"`);
|
|
17497
|
+
}
|
|
17498
|
+
});
|
|
17499
|
+
return {
|
|
17500
|
+
name: "jsenv:web_resolution",
|
|
17501
|
+
appliesDuring: "*",
|
|
17502
|
+
resolveReference: (reference, context) => {
|
|
17503
|
+
const urlType = urlTypeFromReference(reference, context);
|
|
17504
|
+
const resolver = resolvers[urlType];
|
|
17505
|
+
return resolver ? resolver(reference, context) : resolveUsingWebResolution(reference, context);
|
|
17506
|
+
}
|
|
17507
|
+
};
|
|
17508
|
+
};
|
|
17509
|
+
|
|
17510
|
+
const jsenvPluginVersionSearchParam = () => {
|
|
17818
17511
|
return {
|
|
17819
|
-
name: "jsenv:
|
|
17512
|
+
name: "jsenv:version_search_param",
|
|
17820
17513
|
appliesDuring: "dev",
|
|
17821
|
-
|
|
17514
|
+
redirectReference: reference => {
|
|
17822
17515
|
// "v" search param goal is to enable long-term cache
|
|
17823
17516
|
// for server response headers
|
|
17824
17517
|
// it is also used by hmr to bypass browser cache
|
|
@@ -17834,7 +17527,7 @@ const jsenvPluginUrlVersion = () => {
|
|
|
17834
17527
|
}
|
|
17835
17528
|
return null;
|
|
17836
17529
|
},
|
|
17837
|
-
|
|
17530
|
+
transformReferenceSearchParams: reference => {
|
|
17838
17531
|
if (!reference.version) {
|
|
17839
17532
|
return null;
|
|
17840
17533
|
}
|
|
@@ -17857,7 +17550,7 @@ const jsenvPluginFileUrls = ({
|
|
|
17857
17550
|
return [{
|
|
17858
17551
|
name: "jsenv:file_url_resolution",
|
|
17859
17552
|
appliesDuring: "*",
|
|
17860
|
-
|
|
17553
|
+
redirectReference: reference => {
|
|
17861
17554
|
// http, https, data, about, ...
|
|
17862
17555
|
if (!reference.url.startsWith("file:")) {
|
|
17863
17556
|
return null;
|
|
@@ -17936,7 +17629,7 @@ const jsenvPluginFileUrls = ({
|
|
|
17936
17629
|
}, {
|
|
17937
17630
|
name: "jsenv:filesystem_resolution",
|
|
17938
17631
|
appliesDuring: "*",
|
|
17939
|
-
|
|
17632
|
+
resolveReference: {
|
|
17940
17633
|
filesystem: (reference, context) => {
|
|
17941
17634
|
const {
|
|
17942
17635
|
parentUrl
|
|
@@ -17952,14 +17645,14 @@ const jsenvPluginFileUrls = ({
|
|
|
17952
17645
|
// so absolute file urls needs to be relativized
|
|
17953
17646
|
// during build it's fine to use file:// urls
|
|
17954
17647
|
appliesDuring: "dev",
|
|
17955
|
-
|
|
17648
|
+
resolveReference: reference => {
|
|
17956
17649
|
if (reference.specifier.startsWith("/@fs/")) {
|
|
17957
17650
|
const fsRootRelativeUrl = reference.specifier.slice("/@fs/".length);
|
|
17958
17651
|
return `file:///${fsRootRelativeUrl}`;
|
|
17959
17652
|
}
|
|
17960
17653
|
return null;
|
|
17961
17654
|
},
|
|
17962
|
-
|
|
17655
|
+
formatReference: (reference, context) => {
|
|
17963
17656
|
if (!reference.generatedUrl.startsWith("file:")) {
|
|
17964
17657
|
return null;
|
|
17965
17658
|
}
|
|
@@ -18009,7 +17702,7 @@ const jsenvPluginHttpUrls = () => {
|
|
|
18009
17702
|
return {
|
|
18010
17703
|
name: "jsenv:http_urls",
|
|
18011
17704
|
appliesDuring: "*",
|
|
18012
|
-
|
|
17705
|
+
redirectReference: reference => {
|
|
18013
17706
|
if (reference.url.startsWith("http:") || reference.url.startsWith("https:")) {
|
|
18014
17707
|
reference.shouldHandle = false;
|
|
18015
17708
|
}
|
|
@@ -18056,6 +17749,7 @@ const jsenvPluginHttpUrls = () => {
|
|
|
18056
17749
|
* While dynamic import will work just fine
|
|
18057
17750
|
* and create a variable named "undefined"
|
|
18058
17751
|
*/
|
|
17752
|
+
|
|
18059
17753
|
const injectSupervisorIntoJs = async ({
|
|
18060
17754
|
webServer,
|
|
18061
17755
|
content,
|
|
@@ -18284,6 +17978,7 @@ const createSupervisionCall = ({
|
|
|
18284
17978
|
* -> No changes required on js source code, it's only the HTML that is modified
|
|
18285
17979
|
* - Also allow to catch syntax errors and export missing
|
|
18286
17980
|
*/
|
|
17981
|
+
|
|
18287
17982
|
const supervisorFileUrl$1 = new URL("./js/supervisor.js", import.meta.url).href;
|
|
18288
17983
|
const injectSupervisorIntoHTML = async ({
|
|
18289
17984
|
content,
|
|
@@ -18517,6 +18212,7 @@ const generateCodeToSuperviseScriptWithSrc = ({
|
|
|
18517
18212
|
/*
|
|
18518
18213
|
* This plugin provides a way for jsenv to know when js execution is done
|
|
18519
18214
|
*/
|
|
18215
|
+
|
|
18520
18216
|
const supervisorFileUrl = new URL("./js/supervisor.js", import.meta.url).href;
|
|
18521
18217
|
const jsenvPluginSupervisor = ({
|
|
18522
18218
|
logs = false,
|
|
@@ -18723,6 +18419,7 @@ const jsenvPluginSupervisor = ({
|
|
|
18723
18419
|
* - __dirname
|
|
18724
18420
|
* - global
|
|
18725
18421
|
*/
|
|
18422
|
+
|
|
18726
18423
|
const jsenvPluginCommonJsGlobals = () => {
|
|
18727
18424
|
const transformCommonJsGlobals = async (urlInfo, context) => {
|
|
18728
18425
|
if (!urlInfo.content.includes("process.env.NODE_ENV") && !urlInfo.content.includes("__filename") && !urlInfo.content.includes("__dirname")) {
|
|
@@ -18874,6 +18571,7 @@ const babelPluginMetadataExpressionPaths = (babel, {
|
|
|
18874
18571
|
* - left as is to be evaluated to undefined (import.meta.build but it's the dev server)
|
|
18875
18572
|
* - replaced by undefined (import.meta.dev but it's build; the goal is to ensure it's tree-shaked)
|
|
18876
18573
|
*/
|
|
18574
|
+
|
|
18877
18575
|
const jsenvPluginImportMetaScenarios = () => {
|
|
18878
18576
|
return {
|
|
18879
18577
|
name: "jsenv:import_meta_scenario",
|
|
@@ -19004,6 +18702,7 @@ const replacePlaceholders = (urlInfo, replacements) => {
|
|
|
19004
18702
|
* - __build__
|
|
19005
18703
|
* A global will be injected with true/false when needed
|
|
19006
18704
|
*/
|
|
18705
|
+
|
|
19007
18706
|
const jsenvPluginGlobalScenarios = () => {
|
|
19008
18707
|
const transformIfNeeded = (urlInfo, context) => {
|
|
19009
18708
|
return replacePlaceholders(urlInfo, {
|
|
@@ -19090,6 +18789,7 @@ const versionToBits = version => {
|
|
|
19090
18789
|
* do not support import assertions
|
|
19091
18790
|
* But for now (as it is simpler) we let the browser throw the error
|
|
19092
18791
|
*/
|
|
18792
|
+
|
|
19093
18793
|
const jsenvPluginImportAssertions = ({
|
|
19094
18794
|
json = "auto",
|
|
19095
18795
|
css = "auto",
|
|
@@ -19155,7 +18855,7 @@ const jsenvPluginImportAssertions = ({
|
|
|
19155
18855
|
transpilations.text = true;
|
|
19156
18856
|
}
|
|
19157
18857
|
},
|
|
19158
|
-
|
|
18858
|
+
redirectReference: (reference, context) => {
|
|
19159
18859
|
if (!reference.assert) {
|
|
19160
18860
|
return null;
|
|
19161
18861
|
}
|
|
@@ -19250,9 +18950,9 @@ const jsenvPluginAsModules = () => {
|
|
|
19250
18950
|
canUseTemplateString: true
|
|
19251
18951
|
});
|
|
19252
18952
|
return {
|
|
19253
|
-
content: `import
|
|
18953
|
+
content: `import ${JSON.stringify(inlineContentClientFileUrl)}
|
|
19254
18954
|
|
|
19255
|
-
const inlineContent = new
|
|
18955
|
+
const inlineContent = new __InlineContent__(${cssText}, { type: "text/css" })
|
|
19256
18956
|
const stylesheet = new CSSStyleSheet()
|
|
19257
18957
|
stylesheet.replaceSync(inlineContent.text)
|
|
19258
18958
|
export default stylesheet`,
|
|
@@ -19362,11 +19062,12 @@ const babelPluginReplaceTopLevelThis = () => {
|
|
|
19362
19062
|
* This plugin fix this issue by rewriting top level this into window
|
|
19363
19063
|
* and can be used like this for instance import("hls?as_js_module")
|
|
19364
19064
|
*/
|
|
19065
|
+
|
|
19365
19066
|
const jsenvPluginAsJsModule = () => {
|
|
19366
19067
|
return {
|
|
19367
19068
|
name: "jsenv:as_js_module",
|
|
19368
19069
|
appliesDuring: "*",
|
|
19369
|
-
|
|
19070
|
+
redirectReference: reference => {
|
|
19370
19071
|
if (reference.searchParams.has("as_js_module")) {
|
|
19371
19072
|
reference.expectedType = "js_module";
|
|
19372
19073
|
const filename = urlToFilename$1(reference.url);
|
|
@@ -20427,6 +20128,7 @@ const jsenvPluginImportMetaResolve = () => {
|
|
|
20427
20128
|
* Anything that is not standard (import.meta.dev for instance) is outside the scope
|
|
20428
20129
|
* of this plugin
|
|
20429
20130
|
*/
|
|
20131
|
+
|
|
20430
20132
|
const jsenvPluginTranspilation = ({
|
|
20431
20133
|
importAssertions = true,
|
|
20432
20134
|
css = true,
|
|
@@ -20819,7 +20521,7 @@ const jsenvPluginHmr = () => {
|
|
|
20819
20521
|
return {
|
|
20820
20522
|
name: "jsenv:hmr",
|
|
20821
20523
|
appliesDuring: "dev",
|
|
20822
|
-
|
|
20524
|
+
redirectReference: reference => {
|
|
20823
20525
|
if (!reference.searchParams.has("hmr")) {
|
|
20824
20526
|
reference.data.hmr = false;
|
|
20825
20527
|
return null;
|
|
@@ -20834,7 +20536,7 @@ const jsenvPluginHmr = () => {
|
|
|
20834
20536
|
urlObject.searchParams.delete("v");
|
|
20835
20537
|
return urlObject.href;
|
|
20836
20538
|
},
|
|
20837
|
-
|
|
20539
|
+
transformReferenceSearchParams: (reference, context) => {
|
|
20838
20540
|
if (reference.type === "package_json") {
|
|
20839
20541
|
// maybe the if above shoulb be .isImplicit but it's just a detail anyway
|
|
20840
20542
|
return null;
|
|
@@ -21137,72 +20839,6 @@ const jsenvPluginCacheControl = ({
|
|
|
21137
20839
|
};
|
|
21138
20840
|
const SECONDS_IN_30_DAYS$1 = 60 * 60 * 24 * 30;
|
|
21139
20841
|
|
|
21140
|
-
const explorerHtmlFileUrl = String(new URL("./html/explorer.html", import.meta.url));
|
|
21141
|
-
const jsenvPluginExplorer = ({
|
|
21142
|
-
groups = {
|
|
21143
|
-
src: {
|
|
21144
|
-
"./**/*.html": true,
|
|
21145
|
-
"./**/*.test.html": false
|
|
21146
|
-
},
|
|
21147
|
-
tests: {
|
|
21148
|
-
"./**/*.test.html": true
|
|
21149
|
-
}
|
|
21150
|
-
}
|
|
21151
|
-
}) => {
|
|
21152
|
-
const faviconClientFileUrl = new URL("./other/jsenv.png", import.meta.url);
|
|
21153
|
-
return {
|
|
21154
|
-
name: "jsenv:explorer",
|
|
21155
|
-
appliesDuring: "dev",
|
|
21156
|
-
transformUrlContent: {
|
|
21157
|
-
html: async (urlInfo, context) => {
|
|
21158
|
-
if (urlInfo.url !== explorerHtmlFileUrl) {
|
|
21159
|
-
return null;
|
|
21160
|
-
}
|
|
21161
|
-
let html = urlInfo.content;
|
|
21162
|
-
if (html.includes("ignore:FAVICON_HREF")) {
|
|
21163
|
-
html = html.replace("ignore:FAVICON_HREF", DATA_URL.stringify({
|
|
21164
|
-
contentType: CONTENT_TYPE.fromUrlExtension(faviconClientFileUrl),
|
|
21165
|
-
base64Flag: true,
|
|
21166
|
-
data: readFileSync$1(new URL(faviconClientFileUrl)).toString("base64")
|
|
21167
|
-
}));
|
|
21168
|
-
}
|
|
21169
|
-
if (html.includes("SERVER_PARAMS")) {
|
|
21170
|
-
const associationsForExplorable = {};
|
|
21171
|
-
Object.keys(groups).forEach(groupName => {
|
|
21172
|
-
const groupConfig = groups[groupName];
|
|
21173
|
-
associationsForExplorable[groupName] = {
|
|
21174
|
-
"**/.jsenv/": false,
|
|
21175
|
-
// avoid visting .jsenv directory in jsenv itself
|
|
21176
|
-
...groupConfig
|
|
21177
|
-
};
|
|
21178
|
-
});
|
|
21179
|
-
const matchingFileResultArray = await collectFiles({
|
|
21180
|
-
directoryUrl: context.rootDirectoryUrl,
|
|
21181
|
-
associations: associationsForExplorable,
|
|
21182
|
-
predicate: meta => Object.keys(meta).some(group => Boolean(meta[group]))
|
|
21183
|
-
});
|
|
21184
|
-
const files = matchingFileResultArray.map(({
|
|
21185
|
-
relativeUrl,
|
|
21186
|
-
meta
|
|
21187
|
-
}) => ({
|
|
21188
|
-
relativeUrl,
|
|
21189
|
-
meta
|
|
21190
|
-
}));
|
|
21191
|
-
html = html.replace("SERVER_PARAMS", JSON.stringify({
|
|
21192
|
-
rootDirectoryUrl: context.rootDirectoryUrl,
|
|
21193
|
-
groups,
|
|
21194
|
-
files
|
|
21195
|
-
}, null, " "));
|
|
21196
|
-
Object.assign(urlInfo.headers, {
|
|
21197
|
-
"cache-control": "no-store"
|
|
21198
|
-
});
|
|
21199
|
-
}
|
|
21200
|
-
return html;
|
|
21201
|
-
}
|
|
21202
|
-
}
|
|
21203
|
-
};
|
|
21204
|
-
};
|
|
21205
|
-
|
|
21206
20842
|
const jsenvPluginRibbon = ({
|
|
21207
20843
|
rootDirectoryUrl,
|
|
21208
20844
|
htmlInclude = "/**/*.html"
|
|
@@ -21255,10 +20891,10 @@ injectRibbon(${paramsJson});`
|
|
|
21255
20891
|
|
|
21256
20892
|
const getCorePlugins = ({
|
|
21257
20893
|
rootDirectoryUrl,
|
|
21258
|
-
defaultFileUrl,
|
|
21259
20894
|
runtimeCompat,
|
|
21260
|
-
|
|
21261
|
-
|
|
20895
|
+
referenceAnalysis = {},
|
|
20896
|
+
nodeEsmResolution = {},
|
|
20897
|
+
webResolution = {},
|
|
21262
20898
|
fileSystemMagicRedirection,
|
|
21263
20899
|
directoryReferenceAllowed,
|
|
21264
20900
|
supervisor,
|
|
@@ -21267,14 +20903,10 @@ const getCorePlugins = ({
|
|
|
21267
20903
|
clientAutoreload = false,
|
|
21268
20904
|
clientFileChangeCallbackList,
|
|
21269
20905
|
clientFilesPruneCallbackList,
|
|
21270
|
-
explorer,
|
|
21271
20906
|
cacheControl,
|
|
21272
20907
|
scenarioPlaceholders = true,
|
|
21273
20908
|
ribbon = true
|
|
21274
20909
|
} = {}) => {
|
|
21275
|
-
if (explorer === true) {
|
|
21276
|
-
explorer = {};
|
|
21277
|
-
}
|
|
21278
20910
|
if (cacheControl === true) {
|
|
21279
20911
|
cacheControl = {};
|
|
21280
20912
|
}
|
|
@@ -21290,30 +20922,25 @@ const getCorePlugins = ({
|
|
|
21290
20922
|
if (ribbon === true) {
|
|
21291
20923
|
ribbon = {};
|
|
21292
20924
|
}
|
|
21293
|
-
return [
|
|
21294
|
-
rootDirectoryUrl,
|
|
21295
|
-
...urlAnalysis
|
|
21296
|
-
}), jsenvPluginTranspilation(transpilation), jsenvPluginImportmap(),
|
|
21297
|
-
// before node esm to handle bare specifiers
|
|
21298
|
-
// + before node esm to handle importmap before inline content
|
|
21299
|
-
jsenvPluginInlineContentAnalysis(),
|
|
21300
|
-
// before "file urls" to resolve and load inline urls
|
|
21301
|
-
...(inlining ? [jsenvPluginInlining()] : []), ...(supervisor ? [jsenvPluginSupervisor(supervisor)] : []),
|
|
20925
|
+
return [jsenvPluginReferenceAnalysis(referenceAnalysis), jsenvPluginTranspilation(transpilation), jsenvPluginImportmap(), ...(inlining ? [jsenvPluginInlining()] : []), ...(supervisor ? [jsenvPluginSupervisor(supervisor)] : []),
|
|
21302
20926
|
// after inline as it needs inline script to be cooked
|
|
20927
|
+
|
|
20928
|
+
/* When resolving references the following applies by default:
|
|
20929
|
+
- http urls are resolved by jsenvPluginHttpUrls
|
|
20930
|
+
- reference.type === "filesystem" -> resolved by jsenv_plugin_file_urls.js
|
|
20931
|
+
- reference inside a js module -> resolved by node esm
|
|
20932
|
+
- All the rest uses web standard url resolution
|
|
20933
|
+
*/
|
|
21303
20934
|
jsenvPluginFileUrls({
|
|
21304
20935
|
directoryReferenceAllowed,
|
|
21305
20936
|
...fileSystemMagicRedirection
|
|
21306
|
-
}), jsenvPluginHttpUrls(),
|
|
21307
|
-
runtimeCompat,
|
|
21308
|
-
defaultFileUrl,
|
|
21309
|
-
urlResolution
|
|
21310
|
-
}), jsenvPluginUrlVersion(), jsenvPluginCommonJsGlobals(), jsenvPluginImportMetaScenarios(), ...(scenarioPlaceholders ? [jsenvPluginGlobalScenarios()] : []), jsenvPluginNodeRuntime({
|
|
20937
|
+
}), jsenvPluginHttpUrls(), ...(nodeEsmResolution ? [jsenvPluginNodeEsmResolution(nodeEsmResolution)] : []), jsenvPluginWebResolution(webResolution), jsenvPluginVersionSearchParam(), jsenvPluginCommonJsGlobals(), jsenvPluginImportMetaScenarios(), ...(scenarioPlaceholders ? [jsenvPluginGlobalScenarios()] : []), jsenvPluginNodeRuntime({
|
|
21311
20938
|
runtimeCompat
|
|
21312
20939
|
}), jsenvPluginImportMetaHot(), ...(clientAutoreload ? [jsenvPluginAutoreload({
|
|
21313
20940
|
...clientAutoreload,
|
|
21314
20941
|
clientFileChangeCallbackList,
|
|
21315
20942
|
clientFilesPruneCallbackList
|
|
21316
|
-
})] : []), ...(cacheControl ? [jsenvPluginCacheControl(cacheControl)] : []), ...(
|
|
20943
|
+
})] : []), ...(cacheControl ? [jsenvPluginCacheControl(cacheControl)] : []), ...(ribbon ? [jsenvPluginRibbon({
|
|
21317
20944
|
rootDirectoryUrl,
|
|
21318
20945
|
...ribbon
|
|
21319
20946
|
})] : [])];
|
|
@@ -21522,6 +21149,7 @@ const determineDirectoryPath = ({
|
|
|
21522
21149
|
};
|
|
21523
21150
|
|
|
21524
21151
|
// https://bundlers.tooling.report/hashing/avoid-cascade/
|
|
21152
|
+
|
|
21525
21153
|
const injectVersionMappingsAsGlobal = async ({
|
|
21526
21154
|
urlInfo,
|
|
21527
21155
|
kitchen,
|
|
@@ -21650,6 +21278,7 @@ const createVersionGenerator = () => {
|
|
|
21650
21278
|
* - injecting urls into service workers
|
|
21651
21279
|
*/
|
|
21652
21280
|
|
|
21281
|
+
|
|
21653
21282
|
// default runtimeCompat corresponds to
|
|
21654
21283
|
// "we can keep <script type="module"> intact":
|
|
21655
21284
|
// so script_type_module + dynamic_import + import_meta
|
|
@@ -21669,11 +21298,11 @@ const defaultRuntimeCompat = {
|
|
|
21669
21298
|
* @param {Object} buildParameters
|
|
21670
21299
|
* @param {string|url} buildParameters.sourceDirectoryUrl
|
|
21671
21300
|
* Directory containing source files
|
|
21301
|
+
* @param {string|url} buildParameters.buildDirectoryUrl
|
|
21302
|
+
* Directory where optimized files will be written
|
|
21672
21303
|
* @param {object} buildParameters.entryPoints
|
|
21673
21304
|
* Object where keys are paths to source files and values are their future name in the build directory.
|
|
21674
21305
|
* Keys are relative to sourceDirectoryUrl
|
|
21675
|
-
* @param {string|url} buildParameters.buildDirectoryUrl
|
|
21676
|
-
* Directory where optimized files will be written
|
|
21677
21306
|
* @param {object} buildParameters.runtimeCompat
|
|
21678
21307
|
* Code generated will be compatible with these runtimes
|
|
21679
21308
|
* @param {string} [buildParameters.assetsDirectory=""]
|
|
@@ -21699,16 +21328,15 @@ const build = async ({
|
|
|
21699
21328
|
handleSIGINT = true,
|
|
21700
21329
|
logLevel = "info",
|
|
21701
21330
|
sourceDirectoryUrl,
|
|
21702
|
-
entryPoints = {},
|
|
21703
21331
|
buildDirectoryUrl,
|
|
21332
|
+
entryPoints = {},
|
|
21704
21333
|
assetsDirectory = "",
|
|
21705
21334
|
runtimeCompat = defaultRuntimeCompat,
|
|
21706
21335
|
base = runtimeCompat.node ? "./" : "/",
|
|
21707
21336
|
plugins = [],
|
|
21708
|
-
|
|
21709
|
-
|
|
21710
|
-
|
|
21711
|
-
urlResolution,
|
|
21337
|
+
referenceAnalysis = {},
|
|
21338
|
+
nodeEsmResolution,
|
|
21339
|
+
webResolution,
|
|
21712
21340
|
fileSystemMagicRedirection,
|
|
21713
21341
|
directoryReferenceAllowed,
|
|
21714
21342
|
scenarioPlaceholders,
|
|
@@ -21722,6 +21350,8 @@ const build = async ({
|
|
|
21722
21350
|
cooldownBetweenFileEvents,
|
|
21723
21351
|
watch = false,
|
|
21724
21352
|
directoryToClean,
|
|
21353
|
+
sourcemaps = "none",
|
|
21354
|
+
sourcemapsSourcesContent,
|
|
21725
21355
|
writeOnFileSystem = true,
|
|
21726
21356
|
outDirectoryUrl,
|
|
21727
21357
|
assetManifest = versioningMethod === "filename",
|
|
@@ -21844,23 +21474,24 @@ build ${entryPointKeys.length} entry points`);
|
|
|
21844
21474
|
...contextSharedDuringBuild,
|
|
21845
21475
|
plugins: [...plugins, {
|
|
21846
21476
|
appliesDuring: "build",
|
|
21847
|
-
|
|
21848
|
-
if (context.reference.original) {
|
|
21849
|
-
rawRedirections.set(context.reference.original.url, context.reference.url);
|
|
21850
|
-
}
|
|
21851
|
-
},
|
|
21852
|
-
formatUrl: reference => {
|
|
21477
|
+
formatReference: reference => {
|
|
21853
21478
|
if (!reference.shouldHandle) {
|
|
21854
21479
|
return `ignore:${reference.specifier}`;
|
|
21855
21480
|
}
|
|
21856
21481
|
return null;
|
|
21482
|
+
},
|
|
21483
|
+
fetchUrlContent: (urlInfo, context) => {
|
|
21484
|
+
if (context.reference.original) {
|
|
21485
|
+
rawRedirections.set(context.reference.original.url, context.reference.url);
|
|
21486
|
+
}
|
|
21857
21487
|
}
|
|
21858
21488
|
}, ...getCorePlugins({
|
|
21859
21489
|
rootDirectoryUrl: sourceDirectoryUrl,
|
|
21860
21490
|
urlGraph: rawGraph,
|
|
21861
21491
|
runtimeCompat,
|
|
21862
|
-
|
|
21863
|
-
|
|
21492
|
+
referenceAnalysis,
|
|
21493
|
+
nodeEsmResolution,
|
|
21494
|
+
webResolution,
|
|
21864
21495
|
fileSystemMagicRedirection,
|
|
21865
21496
|
directoryReferenceAllowed,
|
|
21866
21497
|
transpilation: {
|
|
@@ -21894,10 +21525,6 @@ ${ANSI.color(buildUrl, ANSI.MAGENTA)}
|
|
|
21894
21525
|
const bundleUrlInfos = {};
|
|
21895
21526
|
const bundlers = {};
|
|
21896
21527
|
const finalGraph = createUrlGraph();
|
|
21897
|
-
const urlAnalysisPlugin = jsenvPluginUrlAnalysis({
|
|
21898
|
-
rootDirectoryUrl: sourceDirectoryUrl,
|
|
21899
|
-
...urlAnalysis
|
|
21900
|
-
});
|
|
21901
21528
|
const finalGraphKitchen = createKitchen({
|
|
21902
21529
|
logLevel,
|
|
21903
21530
|
rootDirectoryUrl: buildDirectoryUrl,
|
|
@@ -21905,14 +21532,15 @@ ${ANSI.color(buildUrl, ANSI.MAGENTA)}
|
|
|
21905
21532
|
build: true,
|
|
21906
21533
|
runtimeCompat,
|
|
21907
21534
|
...contextSharedDuringBuild,
|
|
21908
|
-
plugins: [
|
|
21909
|
-
|
|
21910
|
-
}), jsenvPluginInlineContentAnalysis({
|
|
21535
|
+
plugins: [jsenvPluginReferenceAnalysis({
|
|
21536
|
+
...referenceAnalysis,
|
|
21911
21537
|
fetchInlineUrls: false
|
|
21538
|
+
}), ...(lineBreakNormalization ? [jsenvPluginLineBreakNormalization()] : []), jsenvPluginJsModuleFallback({
|
|
21539
|
+
systemJsInjection: true
|
|
21912
21540
|
}), jsenvPluginInlining(), {
|
|
21913
21541
|
name: "jsenv:build",
|
|
21914
21542
|
appliesDuring: "build",
|
|
21915
|
-
|
|
21543
|
+
resolveReference: reference => {
|
|
21916
21544
|
const getUrl = () => {
|
|
21917
21545
|
if (reference.type === "filesystem") {
|
|
21918
21546
|
const parentRawUrl = buildDirectoryRedirections.get(reference.parentUrl);
|
|
@@ -21930,8 +21558,8 @@ ${ANSI.color(buildUrl, ANSI.MAGENTA)}
|
|
|
21930
21558
|
url = bundleInternalRedirections.get(url) || url;
|
|
21931
21559
|
return url;
|
|
21932
21560
|
},
|
|
21933
|
-
// redirecting
|
|
21934
|
-
|
|
21561
|
+
// redirecting references into the build directory
|
|
21562
|
+
redirectReference: reference => {
|
|
21935
21563
|
if (!reference.url.startsWith("file:")) {
|
|
21936
21564
|
return null;
|
|
21937
21565
|
}
|
|
@@ -21985,7 +21613,7 @@ ${ANSI.color(buildUrl, ANSI.MAGENTA)}
|
|
|
21985
21613
|
const urlBeforeRedirect = reference.original.url;
|
|
21986
21614
|
const urlAfterRedirect = reference.url;
|
|
21987
21615
|
const isEntryPoint = reference.isEntryPoint || isWebWorkerEntryPointReference(reference);
|
|
21988
|
-
// the url info do not exists yet (it will be created after this "
|
|
21616
|
+
// the url info do not exists yet (it will be created after this "redirectReference" hook)
|
|
21989
21617
|
// And the content will be generated when url is cooked by url graph loader.
|
|
21990
21618
|
// Here we just want to reserve an url for that file
|
|
21991
21619
|
const urlInfo = {
|
|
@@ -22056,7 +21684,7 @@ ${ANSI.color(buildUrl, ANSI.MAGENTA)}
|
|
|
22056
21684
|
});
|
|
22057
21685
|
return buildUrl;
|
|
22058
21686
|
},
|
|
22059
|
-
|
|
21687
|
+
formatReference: reference => {
|
|
22060
21688
|
if (!reference.generatedUrl.startsWith("file:")) {
|
|
22061
21689
|
if (!versioning && reference.generatedUrl.startsWith("ignore:")) {
|
|
22062
21690
|
return reference.generatedUrl.slice("ignore:".length);
|
|
@@ -22412,6 +22040,7 @@ ${ANSI.color(buildUrl, ANSI.MAGENTA)}
|
|
|
22412
22040
|
if (!versioning) {
|
|
22413
22041
|
break inject_version_in_urls;
|
|
22414
22042
|
}
|
|
22043
|
+
logger.debug("versioning start");
|
|
22415
22044
|
const versioningTask = createTaskLog("inject version in urls", {
|
|
22416
22045
|
disabled: logger.levels.debug || !logger.levels.info
|
|
22417
22046
|
});
|
|
@@ -22584,20 +22213,26 @@ ${ANSI.color(buildUrl, ANSI.MAGENTA)}
|
|
|
22584
22213
|
build: true,
|
|
22585
22214
|
runtimeCompat,
|
|
22586
22215
|
...contextSharedDuringBuild,
|
|
22587
|
-
plugins: [
|
|
22216
|
+
plugins: [jsenvPluginReferenceAnalysis({
|
|
22217
|
+
...referenceAnalysis,
|
|
22588
22218
|
fetchInlineUrls: false,
|
|
22589
|
-
|
|
22219
|
+
inlineConvertedScript: true,
|
|
22590
22220
|
// to be able to version their urls
|
|
22591
22221
|
allowEscapeForVersioning: true
|
|
22592
22222
|
}), {
|
|
22593
22223
|
name: "jsenv:versioning",
|
|
22594
22224
|
appliesDuring: "build",
|
|
22595
|
-
|
|
22225
|
+
resolveReference: reference => {
|
|
22596
22226
|
const buildUrl = buildUrls.get(reference.specifier);
|
|
22597
22227
|
if (buildUrl) {
|
|
22598
22228
|
return buildUrl;
|
|
22599
22229
|
}
|
|
22600
|
-
|
|
22230
|
+
let urlObject;
|
|
22231
|
+
if (reference.specifier[0] === "/") {
|
|
22232
|
+
urlObject = new URL(reference.specifier.slice(1), buildDirectoryUrl);
|
|
22233
|
+
} else {
|
|
22234
|
+
urlObject = new URL(reference.specifier, reference.baseUrl || reference.parentUrl);
|
|
22235
|
+
}
|
|
22601
22236
|
const url = urlObject.href;
|
|
22602
22237
|
// during versioning we revisit the deps
|
|
22603
22238
|
// but the code used to enforce trailing slash on directories
|
|
@@ -22612,7 +22247,7 @@ ${ANSI.color(buildUrl, ANSI.MAGENTA)}
|
|
|
22612
22247
|
}
|
|
22613
22248
|
return url;
|
|
22614
22249
|
},
|
|
22615
|
-
|
|
22250
|
+
formatReference: reference => {
|
|
22616
22251
|
if (!reference.shouldHandle) {
|
|
22617
22252
|
if (reference.generatedUrl.startsWith("ignore:")) {
|
|
22618
22253
|
return reference.generatedUrl.slice("ignore:".length);
|
|
@@ -23154,6 +22789,7 @@ const WEB_URL_CONVERTER = {
|
|
|
23154
22789
|
* This plugin is very special because it is here
|
|
23155
22790
|
* to provide "serverEvents" used by other plugins
|
|
23156
22791
|
*/
|
|
22792
|
+
|
|
23157
22793
|
const serverEventsClientFileUrl = new URL("./js/server_events_client.js", import.meta.url).href;
|
|
23158
22794
|
const jsenvPluginServerEventsClientInjection = () => {
|
|
23159
22795
|
return {
|
|
@@ -23218,14 +22854,14 @@ const createFileService = ({
|
|
|
23218
22854
|
sourceFilesConfig,
|
|
23219
22855
|
runtimeCompat,
|
|
23220
22856
|
plugins,
|
|
23221
|
-
|
|
23222
|
-
|
|
22857
|
+
referenceAnalysis,
|
|
22858
|
+
nodeEsmResolution,
|
|
22859
|
+
webResolution,
|
|
23223
22860
|
fileSystemMagicRedirection,
|
|
23224
22861
|
supervisor,
|
|
23225
22862
|
transpilation,
|
|
23226
22863
|
clientAutoreload,
|
|
23227
22864
|
cooldownBetweenFileEvents,
|
|
23228
|
-
explorer,
|
|
23229
22865
|
cacheControl,
|
|
23230
22866
|
ribbon,
|
|
23231
22867
|
sourcemaps,
|
|
@@ -23282,18 +22918,11 @@ const createFileService = ({
|
|
|
23282
22918
|
const clientRuntimeCompat = {
|
|
23283
22919
|
[runtimeName]: runtimeVersion
|
|
23284
22920
|
};
|
|
23285
|
-
let defaultFileUrl;
|
|
23286
|
-
if (explorer) {
|
|
23287
|
-
defaultFileUrl = String(explorerHtmlFileUrl);
|
|
23288
|
-
} else if (sourceMainFilePath) {
|
|
23289
|
-
defaultFileUrl = String(new URL(sourceMainFilePath, sourceDirectoryUrl));
|
|
23290
|
-
} else {
|
|
23291
|
-
defaultFileUrl = String(new URL("./index.html", sourceDirectoryUrl));
|
|
23292
|
-
}
|
|
23293
22921
|
const kitchen = createKitchen({
|
|
23294
22922
|
signal,
|
|
23295
22923
|
logLevel,
|
|
23296
22924
|
rootDirectoryUrl: sourceDirectoryUrl,
|
|
22925
|
+
mainFilePath: sourceMainFilePath,
|
|
23297
22926
|
urlGraph,
|
|
23298
22927
|
dev: true,
|
|
23299
22928
|
runtimeCompat,
|
|
@@ -23301,17 +22930,16 @@ const createFileService = ({
|
|
|
23301
22930
|
systemJsTranspilation: !RUNTIME_COMPAT.isSupported(clientRuntimeCompat, "script_type_module") || !RUNTIME_COMPAT.isSupported(clientRuntimeCompat, "import_dynamic") || !RUNTIME_COMPAT.isSupported(clientRuntimeCompat, "import_meta"),
|
|
23302
22931
|
plugins: [...plugins, ...getCorePlugins({
|
|
23303
22932
|
rootDirectoryUrl: sourceDirectoryUrl,
|
|
23304
|
-
defaultFileUrl,
|
|
23305
22933
|
runtimeCompat,
|
|
23306
|
-
|
|
23307
|
-
|
|
22934
|
+
referenceAnalysis,
|
|
22935
|
+
nodeEsmResolution,
|
|
22936
|
+
webResolution,
|
|
23308
22937
|
fileSystemMagicRedirection,
|
|
23309
22938
|
supervisor,
|
|
23310
22939
|
transpilation,
|
|
23311
22940
|
clientAutoreload,
|
|
23312
22941
|
clientFileChangeCallbackList,
|
|
23313
22942
|
clientFilesPruneCallbackList,
|
|
23314
|
-
explorer,
|
|
23315
22943
|
cacheControl,
|
|
23316
22944
|
ribbon
|
|
23317
22945
|
})],
|
|
@@ -23619,7 +23247,7 @@ const inferParentFromRequest = (request, sourceDirectoryUrl) => {
|
|
|
23619
23247
|
*/
|
|
23620
23248
|
const startDevServer = async ({
|
|
23621
23249
|
sourceDirectoryUrl,
|
|
23622
|
-
sourceMainFilePath,
|
|
23250
|
+
sourceMainFilePath = "./index.html",
|
|
23623
23251
|
port = 3456,
|
|
23624
23252
|
hostname,
|
|
23625
23253
|
acceptAnyIp,
|
|
@@ -23642,13 +23270,12 @@ const startDevServer = async ({
|
|
|
23642
23270
|
// code would be supported during dev but not after build
|
|
23643
23271
|
runtimeCompat = defaultRuntimeCompat,
|
|
23644
23272
|
plugins = [],
|
|
23645
|
-
|
|
23646
|
-
|
|
23273
|
+
referenceAnalysis = {},
|
|
23274
|
+
nodeEsmResolution,
|
|
23275
|
+
webResolution,
|
|
23647
23276
|
supervisor = true,
|
|
23648
23277
|
fileSystemMagicRedirection,
|
|
23649
23278
|
transpilation,
|
|
23650
|
-
explorer = true,
|
|
23651
|
-
// see jsenv_plugin_explorer.js
|
|
23652
23279
|
cacheControl = true,
|
|
23653
23280
|
ribbon = true,
|
|
23654
23281
|
// toolbar = false,
|
|
@@ -23666,6 +23293,9 @@ const startDevServer = async ({
|
|
|
23666
23293
|
throw new TypeError(`${unexpectedParamNames.join(",")}: there is no such param`);
|
|
23667
23294
|
}
|
|
23668
23295
|
sourceDirectoryUrl = assertAndNormalizeDirectoryUrl(sourceDirectoryUrl, "sourceDirectoryUrl");
|
|
23296
|
+
if (typeof sourceMainFilePath !== "string") {
|
|
23297
|
+
throw new TypeError(`sourceMainFilePath must be a string, got ${sourceMainFilePath}`);
|
|
23298
|
+
}
|
|
23669
23299
|
if (outDirectoryUrl === undefined) {
|
|
23670
23300
|
if (!process.env.CI) {
|
|
23671
23301
|
const packageDirectoryUrl = lookupPackageDirectory(sourceDirectoryUrl);
|
|
@@ -23759,14 +23389,14 @@ const startDevServer = async ({
|
|
|
23759
23389
|
sourceFilesConfig,
|
|
23760
23390
|
runtimeCompat,
|
|
23761
23391
|
plugins,
|
|
23762
|
-
|
|
23763
|
-
|
|
23392
|
+
referenceAnalysis,
|
|
23393
|
+
nodeEsmResolution,
|
|
23394
|
+
webResolution,
|
|
23764
23395
|
fileSystemMagicRedirection,
|
|
23765
23396
|
supervisor,
|
|
23766
23397
|
transpilation,
|
|
23767
23398
|
clientAutoreload,
|
|
23768
23399
|
cooldownBetweenFileEvents,
|
|
23769
|
-
explorer,
|
|
23770
23400
|
cacheControl,
|
|
23771
23401
|
ribbon,
|
|
23772
23402
|
sourcemaps,
|
|
@@ -23861,6 +23491,7 @@ const startDevServer = async ({
|
|
|
23861
23491
|
* we want to be in the user shoes and we should not alter build files.
|
|
23862
23492
|
*/
|
|
23863
23493
|
|
|
23494
|
+
|
|
23864
23495
|
/**
|
|
23865
23496
|
* Start a server for build files.
|
|
23866
23497
|
* @param {Object} buildServerParameters
|