@jsenv/core 33.0.2 → 34.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/js/autoreload.js +1 -4
- package/dist/js/supervisor.js +498 -290
- package/dist/jsenv.js +938 -370
- package/package.json +2 -3
- package/src/basic_fetch.js +23 -13
- package/src/build/start_build_server.js +3 -2
- package/src/dev/file_service.js +1 -1
- package/src/dev/start_dev_server.js +9 -6
- package/src/execute/execute.js +7 -18
- package/src/execute/runtimes/browsers/from_playwright.js +168 -32
- package/src/execute/runtimes/browsers/webkit.js +1 -1
- package/src/execute/web_server_param.js +68 -0
- package/src/kitchen/compat/features_compatibility.js +3 -0
- package/src/plugins/autoreload/client/reload.js +1 -4
- package/src/plugins/inline/jsenv_plugin_html_inline_content.js +30 -18
- package/src/plugins/plugins.js +1 -1
- package/src/plugins/ribbon/jsenv_plugin_ribbon.js +3 -2
- package/src/plugins/supervisor/client/supervisor.js +467 -287
- package/src/plugins/supervisor/html_supervisor_injection.js +281 -0
- package/src/plugins/supervisor/js_supervisor_injection.js +283 -0
- package/src/plugins/supervisor/jsenv_plugin_supervisor.js +48 -233
- package/src/plugins/transpilation/as_js_classic/convert_js_module_to_js_classic.js +67 -30
- package/src/plugins/transpilation/as_js_classic/jsenv_plugin_as_js_classic_html.js +1 -1
- package/src/plugins/transpilation/babel/jsenv_plugin_babel.js +5 -0
- package/src/plugins/transpilation/jsenv_plugin_top_level_await.js +1 -1
- package/src/test/execute_steps.js +10 -18
- package/src/test/execute_test_plan.js +12 -60
- package/src/test/logs_file_execution.js +74 -28
- package/dist/js/babel_plugin_transform_modules_systemjs.cjs +0 -392
- package/dist/js/script_type_module_supervisor.js +0 -109
- package/src/plugins/supervisor/client/script_type_module_supervisor.js +0 -98
- package/src/plugins/transpilation/as_js_classic/babel_plugin_transform_modules_systemjs.cjs +0 -608
package/dist/jsenv.js
CHANGED
|
@@ -15,15 +15,15 @@ import { Readable, Stream, Writable } from "node:stream";
|
|
|
15
15
|
import { Http2ServerResponse } from "node:http2";
|
|
16
16
|
import { lookup } from "node:dns";
|
|
17
17
|
import { SOURCEMAP, generateSourcemapFileUrl, composeTwoSourcemaps, generateSourcemapDataUrl, createMagicSource, getOriginalPosition } from "@jsenv/sourcemap";
|
|
18
|
-
import { parseHtmlString, stringifyHtmlAst, getHtmlNodeAttribute, visitHtmlNodes, analyzeScriptNode, setHtmlNodeAttributes, parseSrcSet, getHtmlNodePosition, getHtmlNodeAttributePosition, parseCssUrls, parseJsUrls, getHtmlNodeText, setHtmlNodeText, applyBabelPlugins, injectScriptNodeAsEarlyAsPossible, createHtmlNode, findHtmlNode, removeHtmlNode,
|
|
18
|
+
import { parseHtmlString, stringifyHtmlAst, getHtmlNodeAttribute, visitHtmlNodes, analyzeScriptNode, setHtmlNodeAttributes, parseSrcSet, getHtmlNodePosition, getHtmlNodeAttributePosition, parseCssUrls, parseJsUrls, getHtmlNodeText, setHtmlNodeText, removeHtmlNodeText, applyBabelPlugins, injectScriptNodeAsEarlyAsPossible, createHtmlNode, findHtmlNode, removeHtmlNode, injectJsImport, analyzeLinkNode, injectHtmlNode, insertHtmlNodeAfter } from "@jsenv/ast";
|
|
19
19
|
import { createRequire } from "node:module";
|
|
20
20
|
import babelParser from "@babel/parser";
|
|
21
21
|
import { bundleJsModules } from "@jsenv/plugin-bundling";
|
|
22
22
|
import v8, { takeCoverage } from "node:v8";
|
|
23
|
-
import wrapAnsi from "wrap-ansi";
|
|
24
23
|
import stripAnsi from "strip-ansi";
|
|
25
24
|
import { createId } from "@paralleldrive/cuid2";
|
|
26
25
|
import { runInNewContext } from "node:vm";
|
|
26
|
+
import wrapAnsi from "wrap-ansi";
|
|
27
27
|
import { fork } from "node:child_process";
|
|
28
28
|
import { Worker } from "node:worker_threads";
|
|
29
29
|
|
|
@@ -8131,7 +8131,9 @@ const featuresCompatMap = {
|
|
|
8131
8131
|
samsung: "9.2"
|
|
8132
8132
|
},
|
|
8133
8133
|
import_meta_resolve: {
|
|
8134
|
-
chrome: "107"
|
|
8134
|
+
chrome: "107",
|
|
8135
|
+
edge: "105",
|
|
8136
|
+
firefox: "106"
|
|
8135
8137
|
},
|
|
8136
8138
|
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import#browser_compatibility
|
|
8137
8139
|
import_dynamic: {
|
|
@@ -8161,7 +8163,8 @@ const featuresCompatMap = {
|
|
|
8161
8163
|
chrome: "89",
|
|
8162
8164
|
opera: "76",
|
|
8163
8165
|
samsung: "15",
|
|
8164
|
-
firefox: "108"
|
|
8166
|
+
firefox: "108",
|
|
8167
|
+
safari: "16.4"
|
|
8165
8168
|
},
|
|
8166
8169
|
import_type_json: {
|
|
8167
8170
|
chrome: "91",
|
|
@@ -10411,6 +10414,11 @@ const findOriginalDirectoryReference = (urlInfo, context) => {
|
|
|
10411
10414
|
return ref;
|
|
10412
10415
|
};
|
|
10413
10416
|
|
|
10417
|
+
/*
|
|
10418
|
+
* This plugin ensure content inlined inside HTML is cooked (inline <script> for instance)
|
|
10419
|
+
* For <script hot-accept> the script content will be moved to a virtual file
|
|
10420
|
+
* to enable hot reloading
|
|
10421
|
+
*/
|
|
10414
10422
|
const jsenvPluginHtmlInlineContent = ({
|
|
10415
10423
|
analyzeConvertedScripts
|
|
10416
10424
|
}) => {
|
|
@@ -10508,9 +10516,7 @@ ${e.traceMessage}`);
|
|
|
10508
10516
|
if (!analyzeConvertedScripts && getHtmlNodeAttribute(scriptNode, "jsenv-injected-by") === "jsenv:as_js_classic_html") {
|
|
10509
10517
|
return;
|
|
10510
10518
|
}
|
|
10511
|
-
|
|
10512
|
-
return;
|
|
10513
|
-
}
|
|
10519
|
+
const hotAccept = getHtmlNodeAttribute(scriptNode, "hot-accept") !== undefined;
|
|
10514
10520
|
const {
|
|
10515
10521
|
type,
|
|
10516
10522
|
contentType,
|
|
@@ -10555,14 +10561,26 @@ ${e.traceMessage}`);
|
|
|
10555
10561
|
inlineContentUrlInfo: inlineScriptUrlInfo,
|
|
10556
10562
|
inlineContentReference: inlineScriptReference
|
|
10557
10563
|
});
|
|
10558
|
-
|
|
10559
|
-
|
|
10560
|
-
|
|
10561
|
-
|
|
10562
|
-
|
|
10563
|
-
|
|
10564
|
-
|
|
10565
|
-
|
|
10564
|
+
mutations.push(() => {
|
|
10565
|
+
const attributes = {
|
|
10566
|
+
"jsenv-cooked-by": "jsenv:html_inline_content",
|
|
10567
|
+
// 1. <script type="jsx"> becomes <script>
|
|
10568
|
+
// 2. <script type="module/jsx"> becomes <script type="module">
|
|
10569
|
+
...(extension ? {
|
|
10570
|
+
type: type === "js_module" ? "module" : undefined
|
|
10571
|
+
} : {})
|
|
10572
|
+
};
|
|
10573
|
+
if (hotAccept) {
|
|
10574
|
+
removeHtmlNodeText(scriptNode);
|
|
10575
|
+
setHtmlNodeAttributes(scriptNode, {
|
|
10576
|
+
...attributes
|
|
10577
|
+
});
|
|
10578
|
+
} else {
|
|
10579
|
+
setHtmlNodeText(scriptNode, inlineScriptUrlInfo.content);
|
|
10580
|
+
setHtmlNodeAttributes(scriptNode, {
|
|
10581
|
+
...attributes
|
|
10582
|
+
});
|
|
10583
|
+
}
|
|
10566
10584
|
});
|
|
10567
10585
|
});
|
|
10568
10586
|
}
|
|
@@ -14735,21 +14753,7 @@ function default_1({
|
|
|
14735
14753
|
};
|
|
14736
14754
|
}
|
|
14737
14755
|
|
|
14738
|
-
/*
|
|
14739
|
-
* When systemjs format is used by babel, it will generated UID based on
|
|
14740
|
-
* the import specifier:
|
|
14741
|
-
* https://github.com/babel/babel/blob/97d1967826077f15e766778c0d64711399e9a72a/packages/babel-plugin-transform-modules-systemjs/src/index.ts#L498
|
|
14742
|
-
* But at this stage import specifier are absolute file urls
|
|
14743
|
-
* So without minification these specifier are long and dependent
|
|
14744
|
-
* on where the files are on the filesystem.
|
|
14745
|
-
* This can be mitigated by minification that will rename them.
|
|
14746
|
-
* But to fix this issue once and for all I have copy-pasted
|
|
14747
|
-
* "@babel/plugin-transform-modules-systemjs" to introduce
|
|
14748
|
-
* "generateIdentifierHint" options and prevent that from hapenning
|
|
14749
|
-
*/
|
|
14750
|
-
const TRANSFORM_MODULES_SYSTEMJS_PATH = fileURLToPath(new URL("./js/babel_plugin_transform_modules_systemjs.cjs", import.meta.url));
|
|
14751
14756
|
const convertJsModuleToJsClassic = async ({
|
|
14752
|
-
rootDirectoryUrl,
|
|
14753
14757
|
systemJsInjection,
|
|
14754
14758
|
systemJsClientFileUrl,
|
|
14755
14759
|
urlInfo,
|
|
@@ -14774,15 +14778,8 @@ const convertJsModuleToJsClassic = async ({
|
|
|
14774
14778
|
babelPlugins: [...(jsClassicFormat === "system" ? [
|
|
14775
14779
|
// proposal-dynamic-import required with systemjs for babel8:
|
|
14776
14780
|
// https://github.com/babel/babel/issues/10746
|
|
14777
|
-
requireFromJsenv("@babel/plugin-proposal-dynamic-import"), [
|
|
14778
|
-
|
|
14779
|
-
requireFromJsenv(TRANSFORM_MODULES_SYSTEMJS_PATH), {
|
|
14780
|
-
generateIdentifierHint: key => {
|
|
14781
|
-
if (key.startsWith("file://")) {
|
|
14782
|
-
return urlToRelativeUrl(key, rootDirectoryUrl);
|
|
14783
|
-
}
|
|
14784
|
-
return key;
|
|
14785
|
-
}
|
|
14781
|
+
requireFromJsenv("@babel/plugin-proposal-dynamic-import"), requireFromJsenv("@babel/plugin-transform-modules-systemjs"), [babelPluginRelativeImports, {
|
|
14782
|
+
rootUrl: jsModuleUrlInfo.url
|
|
14786
14783
|
}], [default_1, {
|
|
14787
14784
|
asyncAwait: false,
|
|
14788
14785
|
// already handled + we might not needs it at all
|
|
@@ -14791,7 +14788,9 @@ const convertJsModuleToJsClassic = async ({
|
|
|
14791
14788
|
asyncAwait: false,
|
|
14792
14789
|
// already handled + we might not needs it at all
|
|
14793
14790
|
topLevelAwait: "simple"
|
|
14794
|
-
}], babelPluginTransformImportMetaUrl, babelPluginTransformImportMetaResolve, requireFromJsenv("@babel/plugin-transform-modules-umd")
|
|
14791
|
+
}], babelPluginTransformImportMetaUrl, babelPluginTransformImportMetaResolve, requireFromJsenv("@babel/plugin-transform-modules-umd"), [babelPluginRelativeImports, {
|
|
14792
|
+
rootUrl: jsModuleUrlInfo.url
|
|
14793
|
+
}]])],
|
|
14795
14794
|
urlInfo: jsModuleUrlInfo
|
|
14796
14795
|
});
|
|
14797
14796
|
let sourcemap = jsModuleUrlInfo.sourcemap;
|
|
@@ -14828,6 +14827,68 @@ const convertJsModuleToJsClassic = async ({
|
|
|
14828
14827
|
};
|
|
14829
14828
|
};
|
|
14830
14829
|
|
|
14830
|
+
/*
|
|
14831
|
+
* When systemjs or umd format is used by babel, it will generated UID based on
|
|
14832
|
+
* the import specifier:
|
|
14833
|
+
* https://github.com/babel/babel/blob/97d1967826077f15e766778c0d64711399e9a72a/packages/babel-plugin-transform-modules-systemjs/src/index.ts#L498
|
|
14834
|
+
* But at this stage import specifier are absolute file urls
|
|
14835
|
+
* This can be mitigated by minification that will rename them.
|
|
14836
|
+
* But to fix this issue once and for all there is babelPluginRelativeImports below
|
|
14837
|
+
*/
|
|
14838
|
+
const babelPluginRelativeImports = babel => {
|
|
14839
|
+
const t = babel.types;
|
|
14840
|
+
const replaceSpecifierAtPath = (path, state) => {
|
|
14841
|
+
const specifier = path.node.value;
|
|
14842
|
+
if (specifier.startsWith("file://")) {
|
|
14843
|
+
const specifierRelative = urlToRelativeUrl(specifier, state.opts.rootUrl);
|
|
14844
|
+
path.replaceWith(t.stringLiteral(specifierRelative));
|
|
14845
|
+
}
|
|
14846
|
+
};
|
|
14847
|
+
return {
|
|
14848
|
+
name: "relative-imports",
|
|
14849
|
+
visitor: {
|
|
14850
|
+
CallExpression: (path, state) => {
|
|
14851
|
+
if (path.node.callee.type !== "Import") {
|
|
14852
|
+
// Some other function call, not import();
|
|
14853
|
+
return;
|
|
14854
|
+
}
|
|
14855
|
+
if (path.node.arguments[0].type !== "StringLiteral") {
|
|
14856
|
+
// Non-string argument, probably a variable or expression, e.g.
|
|
14857
|
+
// import(moduleId)
|
|
14858
|
+
// import('./' + moduleName)
|
|
14859
|
+
return;
|
|
14860
|
+
}
|
|
14861
|
+
const sourcePath = path.get("arguments")[0];
|
|
14862
|
+
if (sourcePath.node.type === "StringLiteral") {
|
|
14863
|
+
replaceSpecifierAtPath(sourcePath, state);
|
|
14864
|
+
}
|
|
14865
|
+
},
|
|
14866
|
+
ImportDeclaration: (path, state) => {
|
|
14867
|
+
const sourcePath = path.get("source");
|
|
14868
|
+
replaceSpecifierAtPath(sourcePath, state);
|
|
14869
|
+
},
|
|
14870
|
+
ExportAllDeclaration: (path, state) => {
|
|
14871
|
+
const sourcePath = path.get("source");
|
|
14872
|
+
replaceSpecifierAtPath(sourcePath, state);
|
|
14873
|
+
},
|
|
14874
|
+
ExportNamedDeclaration: (path, state) => {
|
|
14875
|
+
if (!path.node.source) {
|
|
14876
|
+
// This export has no "source", so it's probably
|
|
14877
|
+
// a local variable or function, e.g.
|
|
14878
|
+
// export { varName }
|
|
14879
|
+
// export const constName = ...
|
|
14880
|
+
// export function funcName() {}
|
|
14881
|
+
return;
|
|
14882
|
+
}
|
|
14883
|
+
const sourcePath = path.get("source");
|
|
14884
|
+
if (sourcePath.node.type === "StringLiteral") {
|
|
14885
|
+
replaceSpecifierAtPath(sourcePath, state);
|
|
14886
|
+
}
|
|
14887
|
+
}
|
|
14888
|
+
}
|
|
14889
|
+
};
|
|
14890
|
+
};
|
|
14891
|
+
|
|
14831
14892
|
/*
|
|
14832
14893
|
* - propagate ?as_js_classic to urls
|
|
14833
14894
|
* - perform conversion from js module to js classic when url uses ?as_js_classic
|
|
@@ -15062,7 +15123,7 @@ const jsenvPluginAsJsClassicHtml = ({
|
|
|
15062
15123
|
break;
|
|
15063
15124
|
}
|
|
15064
15125
|
} catch (e) {
|
|
15065
|
-
if (context.dev) {
|
|
15126
|
+
if (context.dev && e.code !== "PARSE_ERROR") {
|
|
15066
15127
|
needsSystemJs = true;
|
|
15067
15128
|
// ignore cooking error, the browser will trigger it again on fetch
|
|
15068
15129
|
// + disable cache for this html file because when browser will reload
|
|
@@ -17484,49 +17545,502 @@ const jsenvPluginHttpUrls = () => {
|
|
|
17484
17545
|
};
|
|
17485
17546
|
|
|
17486
17547
|
/*
|
|
17487
|
-
*
|
|
17488
|
-
*
|
|
17548
|
+
* ```js
|
|
17549
|
+
* console.log(42)
|
|
17550
|
+
* ```
|
|
17551
|
+
* becomes
|
|
17552
|
+
* ```js
|
|
17553
|
+
* window.__supervisor__.jsClassicStart('main.html@L10-L13.js')
|
|
17554
|
+
* try {
|
|
17555
|
+
* console.log(42)
|
|
17556
|
+
* window.__supervisor__.jsClassicEnd('main.html@L10-L13.js')
|
|
17557
|
+
* } catch(e) {
|
|
17558
|
+
* window.__supervisor__.jsClassicError('main.html@L10-L13.js', e)
|
|
17559
|
+
* }
|
|
17560
|
+
* ```
|
|
17561
|
+
*
|
|
17562
|
+
* ```js
|
|
17563
|
+
* import value from "./file.js"
|
|
17564
|
+
* console.log(value)
|
|
17565
|
+
* ```
|
|
17566
|
+
* becomes
|
|
17567
|
+
* ```js
|
|
17568
|
+
* window.__supervisor__.jsModuleStart('main.html@L10-L13.js')
|
|
17569
|
+
* try {
|
|
17570
|
+
* const value = await import("./file.js")
|
|
17571
|
+
* console.log(value)
|
|
17572
|
+
* window.__supervisor__.jsModuleEnd('main.html@L10-L13.js')
|
|
17573
|
+
* } catch(e) {
|
|
17574
|
+
* window.__supervisor__.jsModuleError('main.html@L10-L13.js', e)
|
|
17575
|
+
* }
|
|
17576
|
+
* ```
|
|
17489
17577
|
*
|
|
17578
|
+
* -> TO KEEP IN MIND:
|
|
17579
|
+
* Static import can throw errors like
|
|
17580
|
+
* The requested module '/js_module_export_not_found/foo.js' does not provide an export named 'answerr'
|
|
17581
|
+
* While dynamic import will work just fine
|
|
17582
|
+
* and create a variable named "undefined"
|
|
17583
|
+
*/
|
|
17584
|
+
const injectSupervisorIntoJs = async ({
|
|
17585
|
+
webServer,
|
|
17586
|
+
content,
|
|
17587
|
+
url,
|
|
17588
|
+
type,
|
|
17589
|
+
inlineSrc
|
|
17590
|
+
}) => {
|
|
17591
|
+
const babelPluginJsSupervisor = type === "js_module" ? babelPluginJsModuleSupervisor : babelPluginJsClassicSupervisor;
|
|
17592
|
+
const result = await applyBabelPlugins({
|
|
17593
|
+
urlInfo: {
|
|
17594
|
+
content,
|
|
17595
|
+
originalUrl: url,
|
|
17596
|
+
type
|
|
17597
|
+
},
|
|
17598
|
+
babelPlugins: [[babelPluginJsSupervisor, {
|
|
17599
|
+
inlineSrc
|
|
17600
|
+
}]]
|
|
17601
|
+
});
|
|
17602
|
+
let code = result.code;
|
|
17603
|
+
let map = result.map;
|
|
17604
|
+
const sourcemapDataUrl = generateSourcemapDataUrl(map);
|
|
17605
|
+
code = SOURCEMAP.writeComment({
|
|
17606
|
+
contentType: "text/javascript",
|
|
17607
|
+
content: code,
|
|
17608
|
+
specifier: sourcemapDataUrl
|
|
17609
|
+
});
|
|
17610
|
+
code = `${code}
|
|
17611
|
+
//# sourceURL=${urlToRelativeUrl(url, webServer.rootDirectoryUrl)}`;
|
|
17612
|
+
return code;
|
|
17613
|
+
};
|
|
17614
|
+
const babelPluginJsModuleSupervisor = babel => {
|
|
17615
|
+
const t = babel.types;
|
|
17616
|
+
return {
|
|
17617
|
+
name: "js-module-supervisor",
|
|
17618
|
+
visitor: {
|
|
17619
|
+
Program: (programPath, state) => {
|
|
17620
|
+
const {
|
|
17621
|
+
inlineSrc
|
|
17622
|
+
} = state.opts;
|
|
17623
|
+
if (state.file.metadata.jsExecutionInstrumented) return;
|
|
17624
|
+
state.file.metadata.jsExecutionInstrumented = true;
|
|
17625
|
+
const urlNode = t.stringLiteral(inlineSrc);
|
|
17626
|
+
const startCallNode = createSupervisionCall({
|
|
17627
|
+
t,
|
|
17628
|
+
urlNode,
|
|
17629
|
+
methodName: "jsModuleStart"
|
|
17630
|
+
});
|
|
17631
|
+
const endCallNode = createSupervisionCall({
|
|
17632
|
+
t,
|
|
17633
|
+
urlNode,
|
|
17634
|
+
methodName: "jsModuleEnd"
|
|
17635
|
+
});
|
|
17636
|
+
const errorCallNode = createSupervisionCall({
|
|
17637
|
+
t,
|
|
17638
|
+
urlNode,
|
|
17639
|
+
methodName: "jsModuleError",
|
|
17640
|
+
args: [t.identifier("e")]
|
|
17641
|
+
});
|
|
17642
|
+
const bodyPath = programPath.get("body");
|
|
17643
|
+
const importNodes = [];
|
|
17644
|
+
const topLevelNodes = [];
|
|
17645
|
+
for (const topLevelNodePath of bodyPath) {
|
|
17646
|
+
const topLevelNode = topLevelNodePath.node;
|
|
17647
|
+
if (t.isImportDeclaration(topLevelNode)) {
|
|
17648
|
+
importNodes.push(topLevelNode);
|
|
17649
|
+
} else {
|
|
17650
|
+
topLevelNodes.push(topLevelNode);
|
|
17651
|
+
}
|
|
17652
|
+
}
|
|
17653
|
+
|
|
17654
|
+
// replace all import nodes with dynamic imports
|
|
17655
|
+
const dynamicImports = [];
|
|
17656
|
+
importNodes.forEach(importNode => {
|
|
17657
|
+
const dynamicImportConversion = convertStaticImportIntoDynamicImport(importNode, t);
|
|
17658
|
+
if (Array.isArray(dynamicImportConversion)) {
|
|
17659
|
+
dynamicImports.push(...dynamicImportConversion);
|
|
17660
|
+
} else {
|
|
17661
|
+
dynamicImports.push(dynamicImportConversion);
|
|
17662
|
+
}
|
|
17663
|
+
});
|
|
17664
|
+
const tryCatchNode = t.tryStatement(t.blockStatement([...dynamicImports, ...topLevelNodes, endCallNode]), t.catchClause(t.identifier("e"), t.blockStatement([errorCallNode])));
|
|
17665
|
+
programPath.replaceWith(t.program([startCallNode, tryCatchNode]));
|
|
17666
|
+
}
|
|
17667
|
+
}
|
|
17668
|
+
};
|
|
17669
|
+
};
|
|
17670
|
+
const convertStaticImportIntoDynamicImport = (staticImportNode, t) => {
|
|
17671
|
+
const awaitExpression = t.awaitExpression(t.callExpression(t.import(), [t.stringLiteral(staticImportNode.source.value)]));
|
|
17672
|
+
|
|
17673
|
+
// import "./file.js" -> await import("./file.js")
|
|
17674
|
+
if (staticImportNode.specifiers.length === 0) {
|
|
17675
|
+
return t.expressionStatement(awaitExpression);
|
|
17676
|
+
}
|
|
17677
|
+
if (staticImportNode.specifiers.length === 1) {
|
|
17678
|
+
const [firstSpecifier] = staticImportNode.specifiers;
|
|
17679
|
+
if (firstSpecifier.type === "ImportNamespaceSpecifier") {
|
|
17680
|
+
return t.variableDeclaration("const", [t.variableDeclarator(t.identifier(firstSpecifier.local.name), awaitExpression)]);
|
|
17681
|
+
}
|
|
17682
|
+
}
|
|
17683
|
+
if (staticImportNode.specifiers.length === 2) {
|
|
17684
|
+
const [first, second] = staticImportNode.specifiers;
|
|
17685
|
+
if (first.type === "ImportDefaultSpecifier" && second.type === "ImportNamespaceSpecifier") {
|
|
17686
|
+
const namespaceDeclaration = t.variableDeclaration("const", [t.variableDeclarator(t.identifier(second.local.name), awaitExpression)]);
|
|
17687
|
+
const defaultDeclaration = t.variableDeclaration("const", [t.variableDeclarator(t.identifier(first.local.name), t.memberExpression(t.identifier(second.local.name), t.identifier("default")))]);
|
|
17688
|
+
return [namespaceDeclaration, defaultDeclaration];
|
|
17689
|
+
}
|
|
17690
|
+
}
|
|
17691
|
+
|
|
17692
|
+
// import { name } from "./file.js" -> const { name } = await import("./file.js")
|
|
17693
|
+
// import toto, { name } from "./file.js" -> const { name, default as toto } = await import("./file.js")
|
|
17694
|
+
const objectPattern = t.objectPattern(staticImportNode.specifiers.map(specifier => {
|
|
17695
|
+
if (specifier.type === "ImportDefaultSpecifier") {
|
|
17696
|
+
return t.objectProperty(t.identifier("default"), t.identifier(specifier.local.name), false,
|
|
17697
|
+
// computed
|
|
17698
|
+
false // shorthand
|
|
17699
|
+
);
|
|
17700
|
+
}
|
|
17701
|
+
// if (specifier.type === "ImportNamespaceSpecifier") {
|
|
17702
|
+
// return t.restElement(t.identifier(specifier.local.name))
|
|
17703
|
+
// }
|
|
17704
|
+
const isRenamed = specifier.imported.name !== specifier.local.name;
|
|
17705
|
+
if (isRenamed) {
|
|
17706
|
+
return t.objectProperty(t.identifier(specifier.imported.name), t.identifier(specifier.local.name), false,
|
|
17707
|
+
// computed
|
|
17708
|
+
false // shorthand
|
|
17709
|
+
);
|
|
17710
|
+
}
|
|
17711
|
+
// shorthand must be true
|
|
17712
|
+
return t.objectProperty(t.identifier(specifier.local.name), t.identifier(specifier.local.name), false,
|
|
17713
|
+
// computed
|
|
17714
|
+
true // shorthand
|
|
17715
|
+
);
|
|
17716
|
+
}));
|
|
17717
|
+
|
|
17718
|
+
const variableDeclarator = t.variableDeclarator(objectPattern, awaitExpression);
|
|
17719
|
+
const variableDeclaration = t.variableDeclaration("const", [variableDeclarator]);
|
|
17720
|
+
return variableDeclaration;
|
|
17721
|
+
};
|
|
17722
|
+
const babelPluginJsClassicSupervisor = babel => {
|
|
17723
|
+
const t = babel.types;
|
|
17724
|
+
return {
|
|
17725
|
+
name: "js-classic-supervisor",
|
|
17726
|
+
visitor: {
|
|
17727
|
+
Program: (programPath, state) => {
|
|
17728
|
+
const {
|
|
17729
|
+
inlineSrc
|
|
17730
|
+
} = state.opts;
|
|
17731
|
+
if (state.file.metadata.jsExecutionInstrumented) return;
|
|
17732
|
+
state.file.metadata.jsExecutionInstrumented = true;
|
|
17733
|
+
const urlNode = t.stringLiteral(inlineSrc);
|
|
17734
|
+
const startCallNode = createSupervisionCall({
|
|
17735
|
+
t,
|
|
17736
|
+
urlNode,
|
|
17737
|
+
methodName: "jsClassicStart"
|
|
17738
|
+
});
|
|
17739
|
+
const endCallNode = createSupervisionCall({
|
|
17740
|
+
t,
|
|
17741
|
+
urlNode,
|
|
17742
|
+
methodName: "jsClassicEnd"
|
|
17743
|
+
});
|
|
17744
|
+
const errorCallNode = createSupervisionCall({
|
|
17745
|
+
t,
|
|
17746
|
+
urlNode,
|
|
17747
|
+
methodName: "jsClassicError",
|
|
17748
|
+
args: [t.identifier("e")]
|
|
17749
|
+
});
|
|
17750
|
+
const topLevelNodes = programPath.node.body;
|
|
17751
|
+
const tryCatchNode = t.tryStatement(t.blockStatement([...topLevelNodes, endCallNode]), t.catchClause(t.identifier("e"), t.blockStatement([errorCallNode])));
|
|
17752
|
+
programPath.replaceWith(t.program([startCallNode, tryCatchNode]));
|
|
17753
|
+
}
|
|
17754
|
+
}
|
|
17755
|
+
};
|
|
17756
|
+
};
|
|
17757
|
+
const createSupervisionCall = ({
|
|
17758
|
+
t,
|
|
17759
|
+
methodName,
|
|
17760
|
+
urlNode,
|
|
17761
|
+
args = []
|
|
17762
|
+
}) => {
|
|
17763
|
+
return t.expressionStatement(t.callExpression(t.memberExpression(t.memberExpression(t.identifier("window"), t.identifier("__supervisor__")), t.identifier(methodName)), [urlNode, ...args]), [], null);
|
|
17764
|
+
};
|
|
17765
|
+
|
|
17766
|
+
/*
|
|
17767
|
+
* Jsenv needs to track js execution in order to:
|
|
17768
|
+
* 1. report errors
|
|
17769
|
+
* 2. wait for all js execution inside an HTML page before killing the browser
|
|
17770
|
+
*
|
|
17771
|
+
* A naive approach would rely on "load" events on window but:
|
|
17490
17772
|
* scenario | covered by window "load"
|
|
17491
17773
|
* ------------------------------------------- | -------------------------
|
|
17492
17774
|
* js referenced by <script src> | yes
|
|
17493
17775
|
* js inlined into <script> | yes
|
|
17494
17776
|
* js referenced by <script type="module" src> | partially (not for import and top level await)
|
|
17495
17777
|
* js inlined into <script type="module"> | not at all
|
|
17496
|
-
*
|
|
17497
|
-
* This plugin provides a way for jsenv to know when js execution is done
|
|
17498
|
-
* As a side effect this plugin enables ability to hot reload js inlined into <script hot-accept>
|
|
17778
|
+
* Same for "error" event on window who is not enough
|
|
17499
17779
|
*
|
|
17500
17780
|
* <script src="file.js">
|
|
17501
17781
|
* becomes
|
|
17502
17782
|
* <script>
|
|
17503
|
-
* window.__supervisor__.superviseScript(
|
|
17783
|
+
* window.__supervisor__.superviseScript('file.js')
|
|
17504
17784
|
* </script>
|
|
17505
17785
|
*
|
|
17506
17786
|
* <script>
|
|
17507
17787
|
* console.log(42)
|
|
17508
17788
|
* </script>
|
|
17509
17789
|
* becomes
|
|
17510
|
-
* <script>
|
|
17511
|
-
* window.
|
|
17790
|
+
* <script inlined-from-src="main.html@L10-C5.js">
|
|
17791
|
+
* window.__supervisor.__superviseScript("main.html@L10-C5.js")
|
|
17512
17792
|
* </script>
|
|
17513
17793
|
*
|
|
17514
17794
|
* <script type="module" src="module.js"></script>
|
|
17515
17795
|
* becomes
|
|
17516
17796
|
* <script type="module">
|
|
17517
|
-
*
|
|
17518
|
-
* superviseScriptTypeModule({ src: "module.js" })
|
|
17797
|
+
* window.__supervisor__.superviseScriptTypeModule('module.js')
|
|
17519
17798
|
* </script>
|
|
17520
17799
|
*
|
|
17521
17800
|
* <script type="module">
|
|
17522
17801
|
* console.log(42)
|
|
17523
17802
|
* </script>
|
|
17524
17803
|
* becomes
|
|
17525
|
-
* <script type="module">
|
|
17526
|
-
*
|
|
17527
|
-
* superviseScriptTypeModule({ src: 'main.html@L10-L13.js' })
|
|
17804
|
+
* <script type="module" inlined-from-src="main.html@L10-C5.js">
|
|
17805
|
+
* window.__supervisor__.superviseScriptTypeModule('main.html@L10-C5.js')
|
|
17528
17806
|
* </script>
|
|
17807
|
+
*
|
|
17808
|
+
* Why Inline scripts are converted to files dynamically?
|
|
17809
|
+
* -> No changes required on js source code, it's only the HTML that is modified
|
|
17810
|
+
* - Also allow to catch syntax errors and export missing
|
|
17529
17811
|
*/
|
|
17812
|
+
const supervisorFileUrl$1 = new URL("./js/supervisor.js", import.meta.url).href;
|
|
17813
|
+
const injectSupervisorIntoHTML = async ({
|
|
17814
|
+
content,
|
|
17815
|
+
url
|
|
17816
|
+
}, {
|
|
17817
|
+
supervisorScriptSrc = supervisorFileUrl$1,
|
|
17818
|
+
supervisorOptions,
|
|
17819
|
+
webServer,
|
|
17820
|
+
onInlineScript = () => {},
|
|
17821
|
+
generateInlineScriptSrc = ({
|
|
17822
|
+
inlineScriptUrl
|
|
17823
|
+
}) => urlToRelativeUrl(inlineScriptUrl, webServer.rootDirectoryUrl),
|
|
17824
|
+
inlineAsRemote
|
|
17825
|
+
}) => {
|
|
17826
|
+
const htmlAst = parseHtmlString(content);
|
|
17827
|
+
const mutations = [];
|
|
17828
|
+
const actions = [];
|
|
17829
|
+
const scriptInfos = [];
|
|
17830
|
+
// 1. Find inline and remote scripts
|
|
17831
|
+
{
|
|
17832
|
+
const handleInlineScript = (scriptNode, {
|
|
17833
|
+
type,
|
|
17834
|
+
extension,
|
|
17835
|
+
textContent
|
|
17836
|
+
}) => {
|
|
17837
|
+
const {
|
|
17838
|
+
line,
|
|
17839
|
+
column,
|
|
17840
|
+
lineEnd,
|
|
17841
|
+
columnEnd,
|
|
17842
|
+
isOriginal
|
|
17843
|
+
} = getHtmlNodePosition(scriptNode, {
|
|
17844
|
+
preferOriginal: true
|
|
17845
|
+
});
|
|
17846
|
+
const inlineScriptUrl = generateInlineContentUrl({
|
|
17847
|
+
url,
|
|
17848
|
+
extension: extension || ".js",
|
|
17849
|
+
line,
|
|
17850
|
+
column,
|
|
17851
|
+
lineEnd,
|
|
17852
|
+
columnEnd
|
|
17853
|
+
});
|
|
17854
|
+
const inlineScriptSrc = generateInlineScriptSrc({
|
|
17855
|
+
type,
|
|
17856
|
+
textContent,
|
|
17857
|
+
inlineScriptUrl,
|
|
17858
|
+
isOriginal,
|
|
17859
|
+
line,
|
|
17860
|
+
column
|
|
17861
|
+
});
|
|
17862
|
+
onInlineScript({
|
|
17863
|
+
type,
|
|
17864
|
+
textContent,
|
|
17865
|
+
url: inlineScriptUrl,
|
|
17866
|
+
isOriginal,
|
|
17867
|
+
line,
|
|
17868
|
+
column,
|
|
17869
|
+
src: inlineScriptSrc
|
|
17870
|
+
});
|
|
17871
|
+
if (inlineAsRemote) {
|
|
17872
|
+
// prefere la version src
|
|
17873
|
+
scriptInfos.push({
|
|
17874
|
+
type,
|
|
17875
|
+
src: inlineScriptSrc
|
|
17876
|
+
});
|
|
17877
|
+
const remoteJsSupervised = generateCodeToSuperviseScriptWithSrc({
|
|
17878
|
+
type,
|
|
17879
|
+
src: inlineScriptSrc
|
|
17880
|
+
});
|
|
17881
|
+
mutations.push(() => {
|
|
17882
|
+
setHtmlNodeText(scriptNode, remoteJsSupervised);
|
|
17883
|
+
setHtmlNodeAttributes(scriptNode, {
|
|
17884
|
+
"jsenv-cooked-by": "jsenv:supervisor",
|
|
17885
|
+
"src": undefined,
|
|
17886
|
+
"inlined-from-src": inlineScriptSrc
|
|
17887
|
+
});
|
|
17888
|
+
});
|
|
17889
|
+
} else {
|
|
17890
|
+
scriptInfos.push({
|
|
17891
|
+
type,
|
|
17892
|
+
src: inlineScriptSrc,
|
|
17893
|
+
isInline: true
|
|
17894
|
+
});
|
|
17895
|
+
actions.push(async () => {
|
|
17896
|
+
try {
|
|
17897
|
+
const inlineJsSupervised = await injectSupervisorIntoJs({
|
|
17898
|
+
webServer,
|
|
17899
|
+
content: textContent,
|
|
17900
|
+
url: inlineScriptUrl,
|
|
17901
|
+
type,
|
|
17902
|
+
inlineSrc: inlineScriptSrc
|
|
17903
|
+
});
|
|
17904
|
+
mutations.push(() => {
|
|
17905
|
+
setHtmlNodeText(scriptNode, inlineJsSupervised);
|
|
17906
|
+
setHtmlNodeAttributes(scriptNode, {
|
|
17907
|
+
"jsenv-cooked-by": "jsenv:supervisor"
|
|
17908
|
+
});
|
|
17909
|
+
});
|
|
17910
|
+
} catch (e) {
|
|
17911
|
+
if (e.code === "PARSE_ERROR") {
|
|
17912
|
+
// mutations.push(() => {
|
|
17913
|
+
// setHtmlNodeAttributes(scriptNode, {
|
|
17914
|
+
// "jsenv-cooked-by": "jsenv:supervisor",
|
|
17915
|
+
// })
|
|
17916
|
+
// })
|
|
17917
|
+
// on touche a rien
|
|
17918
|
+
return;
|
|
17919
|
+
}
|
|
17920
|
+
throw e;
|
|
17921
|
+
}
|
|
17922
|
+
});
|
|
17923
|
+
}
|
|
17924
|
+
};
|
|
17925
|
+
const handleScriptWithSrc = (scriptNode, {
|
|
17926
|
+
type,
|
|
17927
|
+
src
|
|
17928
|
+
}) => {
|
|
17929
|
+
scriptInfos.push({
|
|
17930
|
+
type,
|
|
17931
|
+
src
|
|
17932
|
+
});
|
|
17933
|
+
const remoteJsSupervised = generateCodeToSuperviseScriptWithSrc({
|
|
17934
|
+
type,
|
|
17935
|
+
src
|
|
17936
|
+
});
|
|
17937
|
+
mutations.push(() => {
|
|
17938
|
+
setHtmlNodeText(scriptNode, remoteJsSupervised);
|
|
17939
|
+
setHtmlNodeAttributes(scriptNode, {
|
|
17940
|
+
"jsenv-cooked-by": "jsenv:supervisor",
|
|
17941
|
+
"src": undefined,
|
|
17942
|
+
"inlined-from-src": src
|
|
17943
|
+
});
|
|
17944
|
+
});
|
|
17945
|
+
};
|
|
17946
|
+
visitHtmlNodes(htmlAst, {
|
|
17947
|
+
script: scriptNode => {
|
|
17948
|
+
const {
|
|
17949
|
+
type,
|
|
17950
|
+
extension
|
|
17951
|
+
} = analyzeScriptNode(scriptNode);
|
|
17952
|
+
if (type !== "js_classic" && type !== "js_module") {
|
|
17953
|
+
return;
|
|
17954
|
+
}
|
|
17955
|
+
if (getHtmlNodeAttribute(scriptNode, "jsenv-injected-by")) {
|
|
17956
|
+
return;
|
|
17957
|
+
}
|
|
17958
|
+
const noSupervisor = getHtmlNodeAttribute(scriptNode, "no-supervisor");
|
|
17959
|
+
if (noSupervisor !== undefined) {
|
|
17960
|
+
return;
|
|
17961
|
+
}
|
|
17962
|
+
const scriptNodeText = getHtmlNodeText(scriptNode);
|
|
17963
|
+
if (scriptNodeText) {
|
|
17964
|
+
handleInlineScript(scriptNode, {
|
|
17965
|
+
type,
|
|
17966
|
+
extension,
|
|
17967
|
+
textContent: scriptNodeText
|
|
17968
|
+
});
|
|
17969
|
+
return;
|
|
17970
|
+
}
|
|
17971
|
+
const src = getHtmlNodeAttribute(scriptNode, "src");
|
|
17972
|
+
if (src) {
|
|
17973
|
+
handleScriptWithSrc(scriptNode, {
|
|
17974
|
+
type,
|
|
17975
|
+
src
|
|
17976
|
+
});
|
|
17977
|
+
return;
|
|
17978
|
+
}
|
|
17979
|
+
}
|
|
17980
|
+
});
|
|
17981
|
+
}
|
|
17982
|
+
// 2. Inject supervisor js file + setup call
|
|
17983
|
+
{
|
|
17984
|
+
const setupParamsSource = stringifyParams({
|
|
17985
|
+
...supervisorOptions,
|
|
17986
|
+
serverIsJsenvDevServer: webServer.isJsenvDevServer,
|
|
17987
|
+
rootDirectoryUrl: webServer.rootDirectoryUrl,
|
|
17988
|
+
scriptInfos
|
|
17989
|
+
}, " ");
|
|
17990
|
+
injectScriptNodeAsEarlyAsPossible(htmlAst, createHtmlNode({
|
|
17991
|
+
tagName: "script",
|
|
17992
|
+
textContent: `
|
|
17993
|
+
window.__supervisor__.setup({
|
|
17994
|
+
${setupParamsSource}
|
|
17995
|
+
})
|
|
17996
|
+
`
|
|
17997
|
+
}), "jsenv:supervisor");
|
|
17998
|
+
const supervisorScript = createHtmlNode({
|
|
17999
|
+
tagName: "script",
|
|
18000
|
+
src: supervisorScriptSrc
|
|
18001
|
+
});
|
|
18002
|
+
injectScriptNodeAsEarlyAsPossible(htmlAst, supervisorScript, "jsenv:supervisor");
|
|
18003
|
+
}
|
|
18004
|
+
// 3. Perform actions (transforming inline script content) and html mutations
|
|
18005
|
+
if (actions.length > 0) {
|
|
18006
|
+
await Promise.all(actions.map(action => action()));
|
|
18007
|
+
}
|
|
18008
|
+
mutations.forEach(mutation => mutation());
|
|
18009
|
+
const htmlModified = stringifyHtmlAst(htmlAst);
|
|
18010
|
+
return {
|
|
18011
|
+
content: htmlModified
|
|
18012
|
+
};
|
|
18013
|
+
};
|
|
18014
|
+
const stringifyParams = (params, prefix = "") => {
|
|
18015
|
+
const source = JSON.stringify(params, null, prefix);
|
|
18016
|
+
if (prefix.length) {
|
|
18017
|
+
// remove leading "{\n"
|
|
18018
|
+
// remove leading prefix
|
|
18019
|
+
// remove trailing "\n}"
|
|
18020
|
+
return source.slice(2 + prefix.length, -2);
|
|
18021
|
+
}
|
|
18022
|
+
// remove leading "{"
|
|
18023
|
+
// remove trailing "}"
|
|
18024
|
+
return source.slice(1, -1);
|
|
18025
|
+
};
|
|
18026
|
+
const generateCodeToSuperviseScriptWithSrc = ({
|
|
18027
|
+
type,
|
|
18028
|
+
src
|
|
18029
|
+
}) => {
|
|
18030
|
+
if (type === "js_module") {
|
|
18031
|
+
return `
|
|
18032
|
+
window.__supervisor__.superviseScriptTypeModule(${JSON.stringify(src)}, (url) => import(url));
|
|
18033
|
+
`;
|
|
18034
|
+
}
|
|
18035
|
+
return `
|
|
18036
|
+
window.__supervisor__.superviseScript(${JSON.stringify(src)});
|
|
18037
|
+
`;
|
|
18038
|
+
};
|
|
18039
|
+
|
|
18040
|
+
/*
|
|
18041
|
+
* This plugin provides a way for jsenv to know when js execution is done
|
|
18042
|
+
*/
|
|
18043
|
+
const supervisorFileUrl = new URL("./js/supervisor.js", import.meta.url).href;
|
|
17530
18044
|
const jsenvPluginSupervisor = ({
|
|
17531
18045
|
logs = false,
|
|
17532
18046
|
measurePerf = false,
|
|
@@ -17534,8 +18048,6 @@ const jsenvPluginSupervisor = ({
|
|
|
17534
18048
|
openInEditor = true,
|
|
17535
18049
|
errorBaseUrl
|
|
17536
18050
|
}) => {
|
|
17537
|
-
const supervisorFileUrl = new URL("./js/supervisor.js", import.meta.url).href;
|
|
17538
|
-
const scriptTypeModuleSupervisorFileUrl = new URL("./js/script_type_module_supervisor.js", import.meta.url).href;
|
|
17539
18051
|
return {
|
|
17540
18052
|
name: "jsenv:supervisor",
|
|
17541
18053
|
appliesDuring: "dev",
|
|
@@ -17677,170 +18189,50 @@ const jsenvPluginSupervisor = ({
|
|
|
17677
18189
|
url,
|
|
17678
18190
|
content
|
|
17679
18191
|
}, context) => {
|
|
17680
|
-
const htmlAst = parseHtmlString(content);
|
|
17681
|
-
const scriptsToSupervise = [];
|
|
17682
|
-
const handleInlineScript = (node, htmlNodeText) => {
|
|
17683
|
-
const {
|
|
17684
|
-
type,
|
|
17685
|
-
extension
|
|
17686
|
-
} = analyzeScriptNode(node);
|
|
17687
|
-
const {
|
|
17688
|
-
line,
|
|
17689
|
-
column,
|
|
17690
|
-
lineEnd,
|
|
17691
|
-
columnEnd,
|
|
17692
|
-
isOriginal
|
|
17693
|
-
} = getHtmlNodePosition(node, {
|
|
17694
|
-
preferOriginal: true
|
|
17695
|
-
});
|
|
17696
|
-
let inlineScriptUrl = generateInlineContentUrl({
|
|
17697
|
-
url,
|
|
17698
|
-
extension: extension || ".js",
|
|
17699
|
-
line,
|
|
17700
|
-
column,
|
|
17701
|
-
lineEnd,
|
|
17702
|
-
columnEnd
|
|
17703
|
-
});
|
|
17704
|
-
const [inlineScriptReference] = context.referenceUtils.foundInline({
|
|
17705
|
-
type: "script",
|
|
17706
|
-
subtype: "inline",
|
|
17707
|
-
expectedType: type,
|
|
17708
|
-
isOriginalPosition: isOriginal,
|
|
17709
|
-
specifierLine: line - 1,
|
|
17710
|
-
specifierColumn: column,
|
|
17711
|
-
specifier: inlineScriptUrl,
|
|
17712
|
-
contentType: "text/javascript",
|
|
17713
|
-
content: htmlNodeText
|
|
17714
|
-
});
|
|
17715
|
-
removeHtmlNodeText(node);
|
|
17716
|
-
if (extension) {
|
|
17717
|
-
setHtmlNodeAttributes(node, {
|
|
17718
|
-
type: type === "js_module" ? "module" : undefined
|
|
17719
|
-
});
|
|
17720
|
-
}
|
|
17721
|
-
scriptsToSupervise.push({
|
|
17722
|
-
node,
|
|
17723
|
-
isInline: true,
|
|
17724
|
-
type,
|
|
17725
|
-
src: inlineScriptReference.generatedSpecifier
|
|
17726
|
-
});
|
|
17727
|
-
};
|
|
17728
|
-
const handleScriptWithSrc = (node, src) => {
|
|
17729
|
-
const {
|
|
17730
|
-
type
|
|
17731
|
-
} = analyzeScriptNode(node);
|
|
17732
|
-
const integrity = getHtmlNodeAttribute(node, "integrity");
|
|
17733
|
-
const crossorigin = getHtmlNodeAttribute(node, "crossorigin") !== undefined;
|
|
17734
|
-
const defer = getHtmlNodeAttribute(node, "defer") !== undefined;
|
|
17735
|
-
const async = getHtmlNodeAttribute(node, "async") !== undefined;
|
|
17736
|
-
scriptsToSupervise.push({
|
|
17737
|
-
node,
|
|
17738
|
-
type,
|
|
17739
|
-
src,
|
|
17740
|
-
defer,
|
|
17741
|
-
async,
|
|
17742
|
-
integrity,
|
|
17743
|
-
crossorigin
|
|
17744
|
-
});
|
|
17745
|
-
};
|
|
17746
|
-
visitHtmlNodes(htmlAst, {
|
|
17747
|
-
script: node => {
|
|
17748
|
-
const {
|
|
17749
|
-
type
|
|
17750
|
-
} = analyzeScriptNode(node);
|
|
17751
|
-
if (type !== "js_classic" && type !== "js_module") {
|
|
17752
|
-
return;
|
|
17753
|
-
}
|
|
17754
|
-
if (getHtmlNodeAttribute(node, "jsenv-cooked-by") || getHtmlNodeAttribute(node, "jsenv-inlined-by") || getHtmlNodeAttribute(node, "jsenv-injected-by")) {
|
|
17755
|
-
return;
|
|
17756
|
-
}
|
|
17757
|
-
const noSupervisor = getHtmlNodeAttribute(node, "no-supervisor");
|
|
17758
|
-
if (noSupervisor !== undefined) {
|
|
17759
|
-
return;
|
|
17760
|
-
}
|
|
17761
|
-
const htmlNodeText = getHtmlNodeText(node);
|
|
17762
|
-
if (htmlNodeText) {
|
|
17763
|
-
handleInlineScript(node, htmlNodeText);
|
|
17764
|
-
return;
|
|
17765
|
-
}
|
|
17766
|
-
const src = getHtmlNodeAttribute(node, "src");
|
|
17767
|
-
if (src) {
|
|
17768
|
-
handleScriptWithSrc(node, src);
|
|
17769
|
-
return;
|
|
17770
|
-
}
|
|
17771
|
-
}
|
|
17772
|
-
});
|
|
17773
|
-
const [scriptTypeModuleSupervisorFileReference] = context.referenceUtils.inject({
|
|
17774
|
-
type: "js_import",
|
|
17775
|
-
expectedType: "js_module",
|
|
17776
|
-
specifier: scriptTypeModuleSupervisorFileUrl
|
|
17777
|
-
});
|
|
17778
18192
|
const [supervisorFileReference] = context.referenceUtils.inject({
|
|
17779
18193
|
type: "script",
|
|
17780
18194
|
expectedType: "js_classic",
|
|
17781
18195
|
specifier: supervisorFileUrl
|
|
17782
18196
|
});
|
|
17783
|
-
|
|
17784
|
-
|
|
17785
|
-
|
|
17786
|
-
|
|
17787
|
-
|
|
18197
|
+
return injectSupervisorIntoHTML({
|
|
18198
|
+
content,
|
|
18199
|
+
url
|
|
18200
|
+
}, {
|
|
18201
|
+
supervisorScriptSrc: supervisorFileReference.generatedSpecifier,
|
|
18202
|
+
supervisorOptions: {
|
|
17788
18203
|
errorBaseUrl,
|
|
17789
18204
|
logs,
|
|
17790
18205
|
measurePerf,
|
|
17791
18206
|
errorOverlay,
|
|
17792
18207
|
openInEditor
|
|
17793
|
-
},
|
|
17794
|
-
|
|
17795
|
-
|
|
17796
|
-
|
|
17797
|
-
|
|
17798
|
-
|
|
17799
|
-
|
|
17800
|
-
|
|
17801
|
-
|
|
17802
|
-
|
|
17803
|
-
|
|
17804
|
-
|
|
17805
|
-
|
|
17806
|
-
|
|
17807
|
-
|
|
17808
|
-
|
|
17809
|
-
|
|
17810
|
-
|
|
17811
|
-
|
|
17812
|
-
|
|
17813
|
-
|
|
17814
|
-
|
|
17815
|
-
|
|
17816
|
-
|
|
17817
|
-
});
|
|
17818
|
-
if (type === "js_module") {
|
|
17819
|
-
setHtmlNodeText(node, `
|
|
17820
|
-
import { superviseScriptTypeModule } from ${scriptTypeModuleSupervisorFileReference.generatedSpecifier}
|
|
17821
|
-
superviseScriptTypeModule(${paramsAsJson})
|
|
17822
|
-
`);
|
|
17823
|
-
} else {
|
|
17824
|
-
setHtmlNodeText(node, `
|
|
17825
|
-
window.__supervisor__.superviseScript(${paramsAsJson})
|
|
17826
|
-
`);
|
|
17827
|
-
}
|
|
17828
|
-
if (src) {
|
|
17829
|
-
setHtmlNodeAttributes(node, {
|
|
17830
|
-
"jsenv-inlined-by": "jsenv:supervisor",
|
|
17831
|
-
"src": undefined,
|
|
17832
|
-
"inlined-from-src": src
|
|
17833
|
-
});
|
|
17834
|
-
} else {
|
|
17835
|
-
setHtmlNodeAttributes(node, {
|
|
17836
|
-
"jsenv-cooked-by": "jsenv:supervisor"
|
|
18208
|
+
},
|
|
18209
|
+
webServer: {
|
|
18210
|
+
rootDirectoryUrl: context.rootDirectoryUrl,
|
|
18211
|
+
isJsenvDevServer: true
|
|
18212
|
+
},
|
|
18213
|
+
inlineAsRemote: true,
|
|
18214
|
+
generateInlineScriptSrc: ({
|
|
18215
|
+
type,
|
|
18216
|
+
textContent,
|
|
18217
|
+
inlineScriptUrl,
|
|
18218
|
+
isOriginal,
|
|
18219
|
+
line,
|
|
18220
|
+
column
|
|
18221
|
+
}) => {
|
|
18222
|
+
const [inlineScriptReference] = context.referenceUtils.foundInline({
|
|
18223
|
+
type: "script",
|
|
18224
|
+
subtype: "inline",
|
|
18225
|
+
expectedType: type,
|
|
18226
|
+
isOriginalPosition: isOriginal,
|
|
18227
|
+
specifierLine: line - 1,
|
|
18228
|
+
specifierColumn: column,
|
|
18229
|
+
specifier: inlineScriptUrl,
|
|
18230
|
+
contentType: "text/javascript",
|
|
18231
|
+
content: textContent
|
|
17837
18232
|
});
|
|
18233
|
+
return inlineScriptReference.generatedSpecifier;
|
|
17838
18234
|
}
|
|
17839
18235
|
});
|
|
17840
|
-
const htmlModified = stringifyHtmlAst(htmlAst);
|
|
17841
|
-
return {
|
|
17842
|
-
content: htmlModified
|
|
17843
|
-
};
|
|
17844
18236
|
}
|
|
17845
18237
|
}
|
|
17846
18238
|
};
|
|
@@ -19451,7 +19843,12 @@ const jsenvPluginBabel = ({
|
|
|
19451
19843
|
map
|
|
19452
19844
|
} = await applyBabelPlugins({
|
|
19453
19845
|
babelPlugins,
|
|
19454
|
-
urlInfo
|
|
19846
|
+
urlInfo,
|
|
19847
|
+
options: {
|
|
19848
|
+
generatorOpts: {
|
|
19849
|
+
retainLines: context.dev
|
|
19850
|
+
}
|
|
19851
|
+
}
|
|
19455
19852
|
});
|
|
19456
19853
|
return {
|
|
19457
19854
|
content: code,
|
|
@@ -19539,7 +19936,7 @@ const babelPluginMetadataUsesTopLevelAwait = () => {
|
|
|
19539
19936
|
programPath.traverse({
|
|
19540
19937
|
AwaitExpression: path => {
|
|
19541
19938
|
const closestFunction = path.getFunctionParent();
|
|
19542
|
-
if (!closestFunction) {
|
|
19939
|
+
if (!closestFunction || closestFunction.type === "Program") {
|
|
19543
19940
|
usesTopLevelAwait = true;
|
|
19544
19941
|
path.stop();
|
|
19545
19942
|
}
|
|
@@ -20418,9 +20815,10 @@ const jsenvPluginRibbon = ({
|
|
|
20418
20815
|
tagName: "script",
|
|
20419
20816
|
type: "module",
|
|
20420
20817
|
textContent: `
|
|
20421
|
-
import { injectRibbon} from "${ribbonClientFileReference.generatedSpecifier}"
|
|
20818
|
+
import { injectRibbon } from "${ribbonClientFileReference.generatedSpecifier}"
|
|
20422
20819
|
|
|
20423
|
-
injectRibbon(${paramsJson})
|
|
20820
|
+
injectRibbon(${paramsJson})
|
|
20821
|
+
`
|
|
20424
20822
|
});
|
|
20425
20823
|
injectHtmlNode(htmlAst, scriptNode, "jsenv:ribbon");
|
|
20426
20824
|
return stringifyHtmlAst(htmlAst);
|
|
@@ -20468,13 +20866,13 @@ const getCorePlugins = ({
|
|
|
20468
20866
|
return [jsenvPluginUrlAnalysis({
|
|
20469
20867
|
rootDirectoryUrl,
|
|
20470
20868
|
...urlAnalysis
|
|
20471
|
-
}), jsenvPluginTranspilation(transpilation),
|
|
20472
|
-
// before inline as it turns inline <script> into <script src>
|
|
20473
|
-
jsenvPluginImportmap(),
|
|
20869
|
+
}), jsenvPluginTranspilation(transpilation), jsenvPluginImportmap(),
|
|
20474
20870
|
// before node esm to handle bare specifiers
|
|
20475
20871
|
// + before node esm to handle importmap before inline content
|
|
20476
20872
|
jsenvPluginInline(),
|
|
20477
20873
|
// before "file urls" to resolve and load inline urls
|
|
20874
|
+
...(supervisor ? [jsenvPluginSupervisor(supervisor)] : []),
|
|
20875
|
+
// after inline as it needs inline script to be cooked
|
|
20478
20876
|
jsenvPluginFileUrls({
|
|
20479
20877
|
directoryReferenceAllowed,
|
|
20480
20878
|
...fileSystemMagicRedirection
|
|
@@ -22387,7 +22785,7 @@ const createFileService = ({
|
|
|
22387
22785
|
const {
|
|
22388
22786
|
runtimeName,
|
|
22389
22787
|
runtimeVersion
|
|
22390
|
-
} = parseUserAgentHeader(request.headers["user-agent"]);
|
|
22788
|
+
} = parseUserAgentHeader(request.headers["user-agent"] || "");
|
|
22391
22789
|
const runtimeId = `${runtimeName}@${runtimeVersion}`;
|
|
22392
22790
|
const existingContext = contextCache.get(runtimeId);
|
|
22393
22791
|
if (existingContext) {
|
|
@@ -22846,7 +23244,7 @@ const startDevServer = async ({
|
|
|
22846
23244
|
stopOnExit: false,
|
|
22847
23245
|
stopOnSIGINT: handleSIGINT,
|
|
22848
23246
|
stopOnInternalError: false,
|
|
22849
|
-
keepProcessAlive,
|
|
23247
|
+
keepProcessAlive: process.env.IMPORTED_BY_TEST_PLAN ? false : keepProcessAlive,
|
|
22850
23248
|
logLevel: serverLogLevel,
|
|
22851
23249
|
startLog: false,
|
|
22852
23250
|
https,
|
|
@@ -22855,7 +23253,13 @@ const startDevServer = async ({
|
|
|
22855
23253
|
hostname,
|
|
22856
23254
|
port,
|
|
22857
23255
|
requestWaitingMs: 60_000,
|
|
22858
|
-
services: [
|
|
23256
|
+
services: [{
|
|
23257
|
+
injectResponseHeaders: () => {
|
|
23258
|
+
return {
|
|
23259
|
+
"x-server-name": "jsenv_dev_server"
|
|
23260
|
+
};
|
|
23261
|
+
}
|
|
23262
|
+
}, jsenvServiceCORS({
|
|
22859
23263
|
accessControlAllowRequestOrigin: true,
|
|
22860
23264
|
accessControlAllowRequestMethod: true,
|
|
22861
23265
|
accessControlAllowRequestHeaders: true,
|
|
@@ -22864,7 +23268,7 @@ const startDevServer = async ({
|
|
|
22864
23268
|
timingAllowOrigin: true
|
|
22865
23269
|
}), {
|
|
22866
23270
|
handleRequest: request => {
|
|
22867
|
-
if (request.pathname === "/
|
|
23271
|
+
if (request.pathname === "/__params__.json") {
|
|
22868
23272
|
const json = JSON.stringify({
|
|
22869
23273
|
sourceDirectoryUrl
|
|
22870
23274
|
});
|
|
@@ -22877,12 +23281,6 @@ const startDevServer = async ({
|
|
|
22877
23281
|
body: json
|
|
22878
23282
|
};
|
|
22879
23283
|
}
|
|
22880
|
-
if (request.pathname === "/__stop__") {
|
|
22881
|
-
server.stop();
|
|
22882
|
-
return {
|
|
22883
|
-
status: 200
|
|
22884
|
-
};
|
|
22885
|
-
}
|
|
22886
23284
|
return null;
|
|
22887
23285
|
}
|
|
22888
23286
|
}, ...services, {
|
|
@@ -23041,18 +23439,28 @@ const basicFetch = async (url, {
|
|
|
23041
23439
|
headers
|
|
23042
23440
|
});
|
|
23043
23441
|
req.on("response", response => {
|
|
23044
|
-
|
|
23045
|
-
|
|
23046
|
-
|
|
23047
|
-
|
|
23048
|
-
|
|
23049
|
-
|
|
23050
|
-
|
|
23051
|
-
|
|
23052
|
-
|
|
23053
|
-
|
|
23054
|
-
|
|
23055
|
-
|
|
23442
|
+
resolve({
|
|
23443
|
+
status: response.statusCode,
|
|
23444
|
+
headers: response.headers,
|
|
23445
|
+
json: () => {
|
|
23446
|
+
req.setTimeout(0);
|
|
23447
|
+
req.destroy();
|
|
23448
|
+
return new Promise(resolve => {
|
|
23449
|
+
if (response.headers["content-type"] !== "application/json") {
|
|
23450
|
+
console.warn("not json");
|
|
23451
|
+
}
|
|
23452
|
+
let responseBody = "";
|
|
23453
|
+
response.setEncoding("utf8");
|
|
23454
|
+
response.on("data", chunk => {
|
|
23455
|
+
responseBody += chunk;
|
|
23456
|
+
});
|
|
23457
|
+
response.on("end", () => {
|
|
23458
|
+
resolve(JSON.parse(responseBody));
|
|
23459
|
+
});
|
|
23460
|
+
response.on("error", e => {
|
|
23461
|
+
reject(e);
|
|
23462
|
+
});
|
|
23463
|
+
});
|
|
23056
23464
|
}
|
|
23057
23465
|
});
|
|
23058
23466
|
});
|
|
@@ -23061,6 +23469,57 @@ const basicFetch = async (url, {
|
|
|
23061
23469
|
});
|
|
23062
23470
|
};
|
|
23063
23471
|
|
|
23472
|
+
const assertAndNormalizeWebServer = async webServer => {
|
|
23473
|
+
if (!webServer) {
|
|
23474
|
+
throw new TypeError(`webServer is required when running tests on browser(s)`);
|
|
23475
|
+
}
|
|
23476
|
+
const unexpectedParamNames = Object.keys(webServer).filter(key => {
|
|
23477
|
+
return !["origin", "moduleUrl", "rootDirectoryUrl"].includes(key);
|
|
23478
|
+
});
|
|
23479
|
+
if (unexpectedParamNames.length > 0) {
|
|
23480
|
+
throw new TypeError(`${unexpectedParamNames.join(",")}: there is no such param to webServer`);
|
|
23481
|
+
}
|
|
23482
|
+
let aServerIsListening = await pingServer(webServer.origin);
|
|
23483
|
+
if (!aServerIsListening) {
|
|
23484
|
+
if (!webServer.moduleUrl) {
|
|
23485
|
+
throw new TypeError(`webServer.moduleUrl is required as there is no server listening "${webServer.origin}"`);
|
|
23486
|
+
}
|
|
23487
|
+
try {
|
|
23488
|
+
process.env.IMPORTED_BY_TEST_PLAN = "1";
|
|
23489
|
+
await import(webServer.moduleUrl);
|
|
23490
|
+
delete process.env.IMPORTED_BY_TEST_PLAN;
|
|
23491
|
+
} catch (e) {
|
|
23492
|
+
if (e.code === "ERR_MODULE_NOT_FOUND") {
|
|
23493
|
+
throw new Error(`webServer.moduleUrl does not lead to a file at "${webServer.moduleUrl}"`);
|
|
23494
|
+
}
|
|
23495
|
+
throw e;
|
|
23496
|
+
}
|
|
23497
|
+
aServerIsListening = await pingServer(webServer.origin);
|
|
23498
|
+
if (!aServerIsListening) {
|
|
23499
|
+
throw new Error(`webServer.moduleUrl did not start a server listening at "${webServer.origin}", check file at "${webServer.moduleUrl}"`);
|
|
23500
|
+
}
|
|
23501
|
+
}
|
|
23502
|
+
const {
|
|
23503
|
+
headers
|
|
23504
|
+
} = await basicFetch(webServer.origin);
|
|
23505
|
+
if (headers["x-server-name"] === "jsenv_dev_server") {
|
|
23506
|
+
webServer.isJsenvDevServer = true;
|
|
23507
|
+
const {
|
|
23508
|
+
json
|
|
23509
|
+
} = await basicFetch(`${webServer.origin}/__params__.json`, {
|
|
23510
|
+
rejectUnauthorized: false
|
|
23511
|
+
});
|
|
23512
|
+
if (webServer.rootDirectoryUrl === undefined) {
|
|
23513
|
+
const jsenvDevServerParams = await json();
|
|
23514
|
+
webServer.rootDirectoryUrl = jsenvDevServerParams.sourceDirectoryUrl;
|
|
23515
|
+
} else {
|
|
23516
|
+
webServer.rootDirectoryUrl = assertAndNormalizeDirectoryUrl(webServer.rootDirectoryUrl, "webServer.rootDirectoryUrl");
|
|
23517
|
+
}
|
|
23518
|
+
} else {
|
|
23519
|
+
webServer.rootDirectoryUrl = assertAndNormalizeDirectoryUrl(webServer.rootDirectoryUrl, "webServer.rootDirectoryUrl");
|
|
23520
|
+
}
|
|
23521
|
+
};
|
|
23522
|
+
|
|
23064
23523
|
const generateCoverageJsonFile = async ({
|
|
23065
23524
|
coverage,
|
|
23066
23525
|
coverageJsonFileUrl,
|
|
@@ -23887,29 +24346,49 @@ const createExecutionLog = ({
|
|
|
23887
24346
|
timeEllapsed,
|
|
23888
24347
|
memoryHeap
|
|
23889
24348
|
});
|
|
24349
|
+
let log;
|
|
23890
24350
|
if (completedExecutionLogAbbreviation && status === "completed") {
|
|
23891
|
-
|
|
24351
|
+
log = `${description}${summary}`;
|
|
24352
|
+
} else {
|
|
24353
|
+
const {
|
|
24354
|
+
consoleCalls = [],
|
|
24355
|
+
errors = []
|
|
24356
|
+
} = executionResult;
|
|
24357
|
+
const consoleOutput = formatConsoleCalls(consoleCalls);
|
|
24358
|
+
const errorsOutput = formatErrors(errors);
|
|
24359
|
+
log = formatExecution({
|
|
24360
|
+
label: `${description}${summary}`,
|
|
24361
|
+
details: {
|
|
24362
|
+
file: fileRelativeUrl,
|
|
24363
|
+
...(logRuntime ? {
|
|
24364
|
+
runtime: `${runtimeName}/${runtimeVersion}`
|
|
24365
|
+
} : {}),
|
|
24366
|
+
...(logEachDuration ? {
|
|
24367
|
+
duration: status === "executing" ? msAsEllapsedTime(Date.now() - startMs) : msAsDuration(endMs - startMs)
|
|
24368
|
+
} : {})
|
|
24369
|
+
},
|
|
24370
|
+
consoleOutput,
|
|
24371
|
+
errorsOutput
|
|
24372
|
+
});
|
|
23892
24373
|
}
|
|
23893
24374
|
const {
|
|
23894
|
-
|
|
23895
|
-
|
|
23896
|
-
|
|
23897
|
-
|
|
23898
|
-
|
|
23899
|
-
|
|
23900
|
-
label: `${description}${summary}`,
|
|
23901
|
-
details: {
|
|
23902
|
-
file: fileRelativeUrl,
|
|
23903
|
-
...(logRuntime ? {
|
|
23904
|
-
runtime: `${runtimeName}/${runtimeVersion}`
|
|
23905
|
-
} : {}),
|
|
23906
|
-
...(logEachDuration ? {
|
|
23907
|
-
duration: status === "executing" ? msAsEllapsedTime(Date.now() - startMs) : msAsDuration(endMs - startMs)
|
|
23908
|
-
} : {})
|
|
23909
|
-
},
|
|
23910
|
-
consoleOutput,
|
|
23911
|
-
errorsOutput
|
|
24375
|
+
columns = 80
|
|
24376
|
+
} = process.stdout;
|
|
24377
|
+
log = wrapAnsi(log, columns, {
|
|
24378
|
+
trim: false,
|
|
24379
|
+
hard: true,
|
|
24380
|
+
wordWrap: false
|
|
23912
24381
|
});
|
|
24382
|
+
if (endMs) {
|
|
24383
|
+
if (completedExecutionLogAbbreviation) {
|
|
24384
|
+
return `${log}\n`;
|
|
24385
|
+
}
|
|
24386
|
+
if (executionIndex === counters.total - 1) {
|
|
24387
|
+
return `${log}\n`;
|
|
24388
|
+
}
|
|
24389
|
+
return `${log}\n\n`;
|
|
24390
|
+
}
|
|
24391
|
+
return log;
|
|
23913
24392
|
};
|
|
23914
24393
|
const formatErrors = errors => {
|
|
23915
24394
|
if (errors.length === 0) {
|
|
@@ -24022,39 +24501,51 @@ const descriptionFormatters = {
|
|
|
24022
24501
|
index,
|
|
24023
24502
|
total
|
|
24024
24503
|
}) => {
|
|
24025
|
-
return ANSI.color(`executing ${index
|
|
24504
|
+
return ANSI.color(`executing ${padNumber(index, total)} of ${total}`, EXECUTION_COLORS.executing);
|
|
24026
24505
|
},
|
|
24027
24506
|
aborted: ({
|
|
24028
24507
|
index,
|
|
24029
24508
|
total
|
|
24030
24509
|
}) => {
|
|
24031
|
-
return ANSI.color(`${UNICODE.FAILURE_RAW} execution ${index
|
|
24510
|
+
return ANSI.color(`${UNICODE.FAILURE_RAW} execution ${padNumber(index, total)} of ${total} aborted`, EXECUTION_COLORS.aborted);
|
|
24032
24511
|
},
|
|
24033
24512
|
timedout: ({
|
|
24034
24513
|
index,
|
|
24035
24514
|
total,
|
|
24036
24515
|
executionParams
|
|
24037
24516
|
}) => {
|
|
24038
|
-
return ANSI.color(`${UNICODE.FAILURE_RAW} execution ${index
|
|
24517
|
+
return ANSI.color(`${UNICODE.FAILURE_RAW} execution ${padNumber(index, total)} of ${total} timeout after ${executionParams.allocatedMs}ms`, EXECUTION_COLORS.timedout);
|
|
24039
24518
|
},
|
|
24040
24519
|
failed: ({
|
|
24041
24520
|
index,
|
|
24042
24521
|
total
|
|
24043
24522
|
}) => {
|
|
24044
|
-
return ANSI.color(`${UNICODE.FAILURE_RAW} execution ${index
|
|
24523
|
+
return ANSI.color(`${UNICODE.FAILURE_RAW} execution ${padNumber(index, total)} of ${total} failed`, EXECUTION_COLORS.failed);
|
|
24045
24524
|
},
|
|
24046
24525
|
completed: ({
|
|
24047
24526
|
index,
|
|
24048
24527
|
total
|
|
24049
24528
|
}) => {
|
|
24050
|
-
return ANSI.color(`${UNICODE.OK_RAW} execution ${index
|
|
24529
|
+
return ANSI.color(`${UNICODE.OK_RAW} execution ${padNumber(index, total)} of ${total} completed`, EXECUTION_COLORS.completed);
|
|
24051
24530
|
},
|
|
24052
24531
|
cancelled: ({
|
|
24053
24532
|
index,
|
|
24054
24533
|
total
|
|
24055
24534
|
}) => {
|
|
24056
|
-
return ANSI.color(`${UNICODE.FAILURE_RAW} execution ${index
|
|
24535
|
+
return ANSI.color(`${UNICODE.FAILURE_RAW} execution ${padNumber(index, total)} of ${total} cancelled`, EXECUTION_COLORS.cancelled);
|
|
24536
|
+
}
|
|
24537
|
+
};
|
|
24538
|
+
const padNumber = (index, total) => {
|
|
24539
|
+
const number = index + 1;
|
|
24540
|
+
const numberWidth = String(number).length;
|
|
24541
|
+
const totalWith = String(total).length;
|
|
24542
|
+
let missingWidth = totalWith - numberWidth;
|
|
24543
|
+
let padded = "";
|
|
24544
|
+
while (missingWidth--) {
|
|
24545
|
+
padded += "0";
|
|
24057
24546
|
}
|
|
24547
|
+
padded += number;
|
|
24548
|
+
return padded;
|
|
24058
24549
|
};
|
|
24059
24550
|
const formatConsoleCalls = consoleCalls => {
|
|
24060
24551
|
if (consoleCalls.length === 0) {
|
|
@@ -24200,8 +24691,7 @@ const executeSteps = async (executionSteps, {
|
|
|
24200
24691
|
completedExecutionLogMerging,
|
|
24201
24692
|
completedExecutionLogAbbreviation,
|
|
24202
24693
|
rootDirectoryUrl,
|
|
24203
|
-
|
|
24204
|
-
sourceDirectoryUrl,
|
|
24694
|
+
webServer,
|
|
24205
24695
|
keepRunning,
|
|
24206
24696
|
defaultMsAllocatedPerExecution,
|
|
24207
24697
|
maxExecutionsInParallel,
|
|
@@ -24280,8 +24770,7 @@ const executeSteps = async (executionSteps, {
|
|
|
24280
24770
|
}
|
|
24281
24771
|
let runtimeParams = {
|
|
24282
24772
|
rootDirectoryUrl,
|
|
24283
|
-
|
|
24284
|
-
sourceDirectoryUrl,
|
|
24773
|
+
webServer,
|
|
24285
24774
|
coverageEnabled,
|
|
24286
24775
|
coverageConfig,
|
|
24287
24776
|
coverageMethodForBrowsers,
|
|
@@ -24425,7 +24914,7 @@ const executeSteps = async (executionSteps, {
|
|
|
24425
24914
|
global.gc();
|
|
24426
24915
|
}
|
|
24427
24916
|
if (executionLogsEnabled) {
|
|
24428
|
-
|
|
24917
|
+
const log = createExecutionLog(afterExecutionInfo, {
|
|
24429
24918
|
completedExecutionLogAbbreviation,
|
|
24430
24919
|
counters,
|
|
24431
24920
|
logRuntime,
|
|
@@ -24437,18 +24926,6 @@ const executeSteps = async (executionSteps, {
|
|
|
24437
24926
|
memoryHeap: memoryUsage().heapUsed
|
|
24438
24927
|
} : {})
|
|
24439
24928
|
});
|
|
24440
|
-
log = `${log}
|
|
24441
|
-
|
|
24442
|
-
`;
|
|
24443
|
-
const {
|
|
24444
|
-
columns = 80
|
|
24445
|
-
} = process.stdout;
|
|
24446
|
-
log = wrapAnsi(log, columns, {
|
|
24447
|
-
trim: false,
|
|
24448
|
-
hard: true,
|
|
24449
|
-
wordWrap: false
|
|
24450
|
-
});
|
|
24451
|
-
|
|
24452
24929
|
// replace spinner with this execution result
|
|
24453
24930
|
if (spinner) spinner.stop();
|
|
24454
24931
|
executionLog.write(log);
|
|
@@ -24466,7 +24943,12 @@ const executeSteps = async (executionSteps, {
|
|
|
24466
24943
|
});
|
|
24467
24944
|
}
|
|
24468
24945
|
}
|
|
24469
|
-
|
|
24946
|
+
const isLastExecutionLog = executionIndex === executionSteps.length - 1;
|
|
24947
|
+
const cancelRemaining = failFast && executionResult.status !== "completed" && counters.done < counters.total;
|
|
24948
|
+
if (isLastExecutionLog) {
|
|
24949
|
+
executionLog.write("\n");
|
|
24950
|
+
}
|
|
24951
|
+
if (cancelRemaining) {
|
|
24470
24952
|
logger.info(`"failFast" enabled -> cancel remaining executions`);
|
|
24471
24953
|
failFastAbortController.abort();
|
|
24472
24954
|
}
|
|
@@ -24571,7 +25053,7 @@ const executeInParallel = async ({
|
|
|
24571
25053
|
* Execute a list of files and log how it goes.
|
|
24572
25054
|
* @param {Object} testPlanParameters
|
|
24573
25055
|
* @param {string|url} testPlanParameters.rootDirectoryUrl Directory containing test files;
|
|
24574
|
-
* @param {
|
|
25056
|
+
* @param {Object} [testPlanParameters.webServer] Web server info; required when executing test on browsers
|
|
24575
25057
|
* @param {Object} testPlanParameters.testPlan Object associating files with runtimes where they will be executed
|
|
24576
25058
|
* @param {boolean} [testPlanParameters.completedExecutionLogAbbreviation=false] Abbreviate completed execution information to shorten terminal output
|
|
24577
25059
|
* @param {boolean} [testPlanParameters.completedExecutionLogMerging=false] Merge completed execution logs to shorten terminal output
|
|
@@ -24598,8 +25080,7 @@ const executeTestPlan = async ({
|
|
|
24598
25080
|
completedExecutionLogAbbreviation = false,
|
|
24599
25081
|
completedExecutionLogMerging = false,
|
|
24600
25082
|
rootDirectoryUrl,
|
|
24601
|
-
|
|
24602
|
-
devServerOrigin,
|
|
25083
|
+
webServer,
|
|
24603
25084
|
testPlan,
|
|
24604
25085
|
updateProcessExitCode = true,
|
|
24605
25086
|
maxExecutionsInParallel = 1,
|
|
@@ -24644,8 +25125,6 @@ const executeTestPlan = async ({
|
|
|
24644
25125
|
}) => {
|
|
24645
25126
|
let someNeedsServer = false;
|
|
24646
25127
|
let someNodeRuntime = false;
|
|
24647
|
-
let stopDevServerNeeded = false;
|
|
24648
|
-
let sourceDirectoryUrl;
|
|
24649
25128
|
const runtimes = {};
|
|
24650
25129
|
// param validation
|
|
24651
25130
|
{
|
|
@@ -24680,34 +25159,7 @@ const executeTestPlan = async ({
|
|
|
24680
25159
|
});
|
|
24681
25160
|
});
|
|
24682
25161
|
if (someNeedsServer) {
|
|
24683
|
-
|
|
24684
|
-
throw new TypeError(`devServerOrigin is required when running tests on browser(s)`);
|
|
24685
|
-
}
|
|
24686
|
-
let devServerStarted = await pingServer(devServerOrigin);
|
|
24687
|
-
if (!devServerStarted) {
|
|
24688
|
-
if (!devServerModuleUrl) {
|
|
24689
|
-
throw new TypeError(`devServerModuleUrl is required when dev server is not started in order to run tests on browser(s)`);
|
|
24690
|
-
}
|
|
24691
|
-
try {
|
|
24692
|
-
process.env.IMPORTED_BY_TEST_PLAN = "1";
|
|
24693
|
-
await import(devServerModuleUrl);
|
|
24694
|
-
delete process.env.IMPORTED_BY_TEST_PLAN;
|
|
24695
|
-
} catch (e) {
|
|
24696
|
-
if (e.code === "ERR_MODULE_NOT_FOUND") {
|
|
24697
|
-
throw new Error(`Cannot find file responsible to start dev server at "${devServerModuleUrl}"`);
|
|
24698
|
-
}
|
|
24699
|
-
throw e;
|
|
24700
|
-
}
|
|
24701
|
-
devServerStarted = await pingServer(devServerOrigin);
|
|
24702
|
-
if (!devServerStarted) {
|
|
24703
|
-
throw new Error(`dev server not started after importing "${devServerModuleUrl}", ensure this module file is starting a server at "${devServerOrigin}"`);
|
|
24704
|
-
}
|
|
24705
|
-
stopDevServerNeeded = true;
|
|
24706
|
-
}
|
|
24707
|
-
const devServerParams = await basicFetch(`${devServerOrigin}/__server_params__.json`, {
|
|
24708
|
-
rejectUnauthorized: false
|
|
24709
|
-
});
|
|
24710
|
-
sourceDirectoryUrl = devServerParams.sourceDirectoryUrl;
|
|
25162
|
+
await assertAndNormalizeWebServer(webServer);
|
|
24711
25163
|
}
|
|
24712
25164
|
if (coverageEnabled) {
|
|
24713
25165
|
if (typeof coverageConfig !== "object") {
|
|
@@ -24785,6 +25237,8 @@ const executeTestPlan = async ({
|
|
|
24785
25237
|
}
|
|
24786
25238
|
}
|
|
24787
25239
|
testPlan = {
|
|
25240
|
+
"file:///**/node_modules/": null,
|
|
25241
|
+
"**/*./": null,
|
|
24788
25242
|
...testPlan,
|
|
24789
25243
|
"**/.jsenv/": null
|
|
24790
25244
|
};
|
|
@@ -24809,8 +25263,7 @@ const executeTestPlan = async ({
|
|
|
24809
25263
|
completedExecutionLogMerging,
|
|
24810
25264
|
completedExecutionLogAbbreviation,
|
|
24811
25265
|
rootDirectoryUrl,
|
|
24812
|
-
|
|
24813
|
-
sourceDirectoryUrl,
|
|
25266
|
+
webServer,
|
|
24814
25267
|
maxExecutionsInParallel,
|
|
24815
25268
|
defaultMsAllocatedPerExecution,
|
|
24816
25269
|
failFast,
|
|
@@ -24825,17 +25278,6 @@ const executeTestPlan = async ({
|
|
|
24825
25278
|
coverageV8ConflictWarning,
|
|
24826
25279
|
coverageTempDirectoryUrl
|
|
24827
25280
|
});
|
|
24828
|
-
if (stopDevServerNeeded) {
|
|
24829
|
-
// we are expecting ECONNRESET because server will be stopped by the request
|
|
24830
|
-
basicFetch(`${devServerOrigin}/__stop__`, {
|
|
24831
|
-
rejectUnauthorized: false
|
|
24832
|
-
}).catch(e => {
|
|
24833
|
-
if (e.code === "ECONNRESET") {
|
|
24834
|
-
return;
|
|
24835
|
-
}
|
|
24836
|
-
throw e;
|
|
24837
|
-
});
|
|
24838
|
-
}
|
|
24839
25281
|
if (updateProcessExitCode && result.planSummary.counters.total !== result.planSummary.counters.completed) {
|
|
24840
25282
|
process.exitCode = 1;
|
|
24841
25283
|
}
|
|
@@ -24884,7 +25326,7 @@ const createRuntimeFromPlaywright = ({
|
|
|
24884
25326
|
browserName,
|
|
24885
25327
|
browserVersion,
|
|
24886
25328
|
coveragePlaywrightAPIAvailable = false,
|
|
24887
|
-
|
|
25329
|
+
shouldIgnoreError = () => false,
|
|
24888
25330
|
transformErrorHook = error => error,
|
|
24889
25331
|
isolatedTab = false
|
|
24890
25332
|
}) => {
|
|
@@ -24898,9 +25340,8 @@ const createRuntimeFromPlaywright = ({
|
|
|
24898
25340
|
signal = new AbortController().signal,
|
|
24899
25341
|
logger,
|
|
24900
25342
|
rootDirectoryUrl,
|
|
25343
|
+
webServer,
|
|
24901
25344
|
fileRelativeUrl,
|
|
24902
|
-
devServerOrigin,
|
|
24903
|
-
sourceDirectoryUrl,
|
|
24904
25345
|
// measurePerformance,
|
|
24905
25346
|
collectPerformance,
|
|
24906
25347
|
coverageEnabled = false,
|
|
@@ -24915,6 +25356,19 @@ const createRuntimeFromPlaywright = ({
|
|
|
24915
25356
|
playwrightLaunchOptions = {},
|
|
24916
25357
|
ignoreHTTPSErrors = true
|
|
24917
25358
|
}) => {
|
|
25359
|
+
const fileUrl = new URL(fileRelativeUrl, rootDirectoryUrl).href;
|
|
25360
|
+
if (!urlIsInsideOf(fileUrl, webServer.rootDirectoryUrl)) {
|
|
25361
|
+
throw new Error(`Cannot execute file that is outside web server root directory
|
|
25362
|
+
--- file ---
|
|
25363
|
+
${fileUrl}
|
|
25364
|
+
--- web server root directory url ---
|
|
25365
|
+
${webServer.rootDirectoryUrl}`);
|
|
25366
|
+
}
|
|
25367
|
+
const fileServerUrl = moveUrl({
|
|
25368
|
+
url: fileUrl,
|
|
25369
|
+
from: webServer.rootDirectoryUrl,
|
|
25370
|
+
to: `${webServer.origin}/`
|
|
25371
|
+
});
|
|
24918
25372
|
const cleanupCallbackList = createCallbackListNotifiedOnce();
|
|
24919
25373
|
const cleanup = memoize(async reason => {
|
|
24920
25374
|
await cleanupCallbackList.notify({
|
|
@@ -24978,6 +25432,13 @@ const createRuntimeFromPlaywright = ({
|
|
|
24978
25432
|
} : {})
|
|
24979
25433
|
}
|
|
24980
25434
|
});
|
|
25435
|
+
if (!webServer.isJsenvDevServer) {
|
|
25436
|
+
await initJsExecutionMiddleware(page, {
|
|
25437
|
+
webServer,
|
|
25438
|
+
fileUrl,
|
|
25439
|
+
fileServerUrl
|
|
25440
|
+
});
|
|
25441
|
+
}
|
|
24981
25442
|
const closePage = async () => {
|
|
24982
25443
|
try {
|
|
24983
25444
|
await page.close();
|
|
@@ -25006,8 +25467,8 @@ const createRuntimeFromPlaywright = ({
|
|
|
25006
25467
|
const v8CoveragesWithFsUrls = v8CoveragesWithWebUrls.map(v8CoveragesWithWebUrl => {
|
|
25007
25468
|
const fsUrl = moveUrl({
|
|
25008
25469
|
url: v8CoveragesWithWebUrl.url,
|
|
25009
|
-
from: `${
|
|
25010
|
-
to:
|
|
25470
|
+
from: `${webServer.origin}/`,
|
|
25471
|
+
to: webServer.rootDirectoryUrl
|
|
25011
25472
|
});
|
|
25012
25473
|
return {
|
|
25013
25474
|
...v8CoveragesWithWebUrl,
|
|
@@ -25069,19 +25530,7 @@ const createRuntimeFromPlaywright = ({
|
|
|
25069
25530
|
result.performance = performance;
|
|
25070
25531
|
});
|
|
25071
25532
|
}
|
|
25072
|
-
|
|
25073
|
-
if (!urlIsInsideOf(fileUrl, sourceDirectoryUrl)) {
|
|
25074
|
-
throw new Error(`Cannot execute file that is outside source directory
|
|
25075
|
-
--- file ---
|
|
25076
|
-
${fileUrl}
|
|
25077
|
-
--- source directory ---
|
|
25078
|
-
${sourceDirectoryUrl}`);
|
|
25079
|
-
}
|
|
25080
|
-
const fileDevServerUrl = moveUrl({
|
|
25081
|
-
url: fileUrl,
|
|
25082
|
-
from: sourceDirectoryUrl,
|
|
25083
|
-
to: `${devServerOrigin}/`
|
|
25084
|
-
});
|
|
25533
|
+
|
|
25085
25534
|
// https://github.com/GoogleChrome/puppeteer/blob/v1.4.0/docs/api.md#event-console
|
|
25086
25535
|
const removeConsoleListener = registerEvent({
|
|
25087
25536
|
object: page,
|
|
@@ -25109,7 +25558,7 @@ ${sourceDirectoryUrl}`);
|
|
|
25109
25558
|
object: page,
|
|
25110
25559
|
eventType: "error",
|
|
25111
25560
|
callback: error => {
|
|
25112
|
-
if (
|
|
25561
|
+
if (shouldIgnoreError(error, "error")) {
|
|
25113
25562
|
return;
|
|
25114
25563
|
}
|
|
25115
25564
|
cb(transformErrorHook(error));
|
|
@@ -25122,7 +25571,10 @@ ${sourceDirectoryUrl}`);
|
|
|
25122
25571
|
// object: page,
|
|
25123
25572
|
// eventType: "pageerror",
|
|
25124
25573
|
// callback: (error) => {
|
|
25125
|
-
// if (
|
|
25574
|
+
// if (
|
|
25575
|
+
// webServer.isJsenvDevServer ||
|
|
25576
|
+
// shouldIgnoreError(error, "pageerror")
|
|
25577
|
+
// ) {
|
|
25126
25578
|
// return
|
|
25127
25579
|
// }
|
|
25128
25580
|
// result.errors.push(transformErrorHook(error))
|
|
@@ -25164,16 +25616,28 @@ ${sourceDirectoryUrl}`);
|
|
|
25164
25616
|
},
|
|
25165
25617
|
response: async cb => {
|
|
25166
25618
|
try {
|
|
25167
|
-
await page.goto(
|
|
25619
|
+
await page.goto(fileServerUrl, {
|
|
25168
25620
|
timeout: 0
|
|
25169
25621
|
});
|
|
25170
25622
|
const returnValue = await page.evaluate( /* eslint-disable no-undef */
|
|
25171
25623
|
/* istanbul ignore next */
|
|
25172
|
-
() => {
|
|
25624
|
+
async () => {
|
|
25625
|
+
let startTime;
|
|
25626
|
+
try {
|
|
25627
|
+
startTime = window.performance.timing.navigationStart;
|
|
25628
|
+
} catch (e) {
|
|
25629
|
+
startTime = Date.now();
|
|
25630
|
+
}
|
|
25173
25631
|
if (!window.__supervisor__) {
|
|
25174
|
-
throw new Error(
|
|
25632
|
+
throw new Error("window.__supervisor__ is undefined");
|
|
25175
25633
|
}
|
|
25176
|
-
|
|
25634
|
+
const executionResultFromJsenvSupervisor = await window.__supervisor__.getDocumentExecutionResult();
|
|
25635
|
+
return {
|
|
25636
|
+
type: "window_supervisor",
|
|
25637
|
+
startTime,
|
|
25638
|
+
endTime: Date.now(),
|
|
25639
|
+
executionResults: executionResultFromJsenvSupervisor.executionResults
|
|
25640
|
+
};
|
|
25177
25641
|
}
|
|
25178
25642
|
/* eslint-enable no-undef */);
|
|
25179
25643
|
|
|
@@ -25196,12 +25660,18 @@ ${sourceDirectoryUrl}`);
|
|
|
25196
25660
|
result.errors.push(error);
|
|
25197
25661
|
return;
|
|
25198
25662
|
}
|
|
25663
|
+
if (winner.name === "pageerror") {
|
|
25664
|
+
let error = winner.data;
|
|
25665
|
+
result.status = "failed";
|
|
25666
|
+
result.errors.push(error);
|
|
25667
|
+
return;
|
|
25668
|
+
}
|
|
25199
25669
|
if (winner.name === "closed") {
|
|
25200
25670
|
result.status = "failed";
|
|
25201
25671
|
result.errors.push(isBrowserDedicatedToExecution ? new Error(`browser disconnected during execution`) : new Error(`page closed during execution`));
|
|
25202
25672
|
return;
|
|
25203
25673
|
}
|
|
25204
|
-
// winner.name
|
|
25674
|
+
// winner.name === "response"
|
|
25205
25675
|
const {
|
|
25206
25676
|
executionResults
|
|
25207
25677
|
} = winner.data;
|
|
@@ -25211,10 +25681,17 @@ ${sourceDirectoryUrl}`);
|
|
|
25211
25681
|
const executionResult = executionResults[key];
|
|
25212
25682
|
if (executionResult.status === "failed") {
|
|
25213
25683
|
result.status = "failed";
|
|
25214
|
-
|
|
25215
|
-
|
|
25216
|
-
|
|
25217
|
-
|
|
25684
|
+
if (executionResult.exception) {
|
|
25685
|
+
result.errors.push({
|
|
25686
|
+
...executionResult.exception,
|
|
25687
|
+
stack: executionResult.exception.text
|
|
25688
|
+
});
|
|
25689
|
+
} else {
|
|
25690
|
+
result.errors.push({
|
|
25691
|
+
...executionResult.error,
|
|
25692
|
+
stack: executionResult.error.stack
|
|
25693
|
+
});
|
|
25694
|
+
}
|
|
25218
25695
|
}
|
|
25219
25696
|
});
|
|
25220
25697
|
};
|
|
@@ -25243,7 +25720,7 @@ ${sourceDirectoryUrl}`);
|
|
|
25243
25720
|
browserName,
|
|
25244
25721
|
browserVersion,
|
|
25245
25722
|
coveragePlaywrightAPIAvailable,
|
|
25246
|
-
|
|
25723
|
+
shouldIgnoreError,
|
|
25247
25724
|
transformErrorHook,
|
|
25248
25725
|
isolatedTab: true
|
|
25249
25726
|
});
|
|
@@ -25361,6 +25838,106 @@ const extractTextFromConsoleMessage = consoleMessage => {
|
|
|
25361
25838
|
// return text
|
|
25362
25839
|
};
|
|
25363
25840
|
|
|
25841
|
+
const initJsExecutionMiddleware = async (page, {
|
|
25842
|
+
webServer,
|
|
25843
|
+
fileUrl,
|
|
25844
|
+
fileServerUrl
|
|
25845
|
+
}) => {
|
|
25846
|
+
const inlineScriptContents = new Map();
|
|
25847
|
+
const interceptHtmlToExecute = async ({
|
|
25848
|
+
route
|
|
25849
|
+
}) => {
|
|
25850
|
+
// Fetch original response.
|
|
25851
|
+
const response = await route.fetch();
|
|
25852
|
+
// Add a prefix to the title.
|
|
25853
|
+
const originalBody = await response.text();
|
|
25854
|
+
const injectionResult = await injectSupervisorIntoHTML({
|
|
25855
|
+
content: originalBody,
|
|
25856
|
+
url: fileUrl
|
|
25857
|
+
}, {
|
|
25858
|
+
supervisorScriptSrc: `/@fs/${supervisorFileUrl$1.slice("file:///".length)}`,
|
|
25859
|
+
supervisorOptions: {},
|
|
25860
|
+
inlineAsRemote: true,
|
|
25861
|
+
webServer,
|
|
25862
|
+
onInlineScript: ({
|
|
25863
|
+
src,
|
|
25864
|
+
textContent
|
|
25865
|
+
}) => {
|
|
25866
|
+
const inlineScriptWebUrl = new URL(src, `${webServer.origin}/`).href;
|
|
25867
|
+
inlineScriptContents.set(inlineScriptWebUrl, textContent);
|
|
25868
|
+
}
|
|
25869
|
+
});
|
|
25870
|
+
route.fulfill({
|
|
25871
|
+
response,
|
|
25872
|
+
body: injectionResult.content,
|
|
25873
|
+
headers: {
|
|
25874
|
+
...response.headers(),
|
|
25875
|
+
"content-length": Buffer.byteLength(injectionResult.content)
|
|
25876
|
+
}
|
|
25877
|
+
});
|
|
25878
|
+
};
|
|
25879
|
+
const interceptInlineScript = ({
|
|
25880
|
+
url,
|
|
25881
|
+
route
|
|
25882
|
+
}) => {
|
|
25883
|
+
const inlineScriptContent = inlineScriptContents.get(url);
|
|
25884
|
+
route.fulfill({
|
|
25885
|
+
status: 200,
|
|
25886
|
+
body: inlineScriptContent,
|
|
25887
|
+
headers: {
|
|
25888
|
+
"content-type": "text/javascript",
|
|
25889
|
+
"content-length": Buffer.byteLength(inlineScriptContent)
|
|
25890
|
+
}
|
|
25891
|
+
});
|
|
25892
|
+
};
|
|
25893
|
+
const interceptFileSystemUrl = ({
|
|
25894
|
+
url,
|
|
25895
|
+
route
|
|
25896
|
+
}) => {
|
|
25897
|
+
const relativeUrl = url.slice(webServer.origin.length);
|
|
25898
|
+
const fsPath = relativeUrl.slice("/@fs/".length);
|
|
25899
|
+
const fsUrl = `file:///${fsPath}`;
|
|
25900
|
+
const fileContent = readFileSync$1(new URL(fsUrl), "utf8");
|
|
25901
|
+
route.fulfill({
|
|
25902
|
+
status: 200,
|
|
25903
|
+
body: fileContent,
|
|
25904
|
+
headers: {
|
|
25905
|
+
"content-type": "text/javascript",
|
|
25906
|
+
"content-length": Buffer.byteLength(fileContent)
|
|
25907
|
+
}
|
|
25908
|
+
});
|
|
25909
|
+
};
|
|
25910
|
+
await page.route("**", async route => {
|
|
25911
|
+
const request = route.request();
|
|
25912
|
+
const url = request.url();
|
|
25913
|
+
if (url === fileServerUrl && urlToExtension$1(url) === ".html") {
|
|
25914
|
+
interceptHtmlToExecute({
|
|
25915
|
+
url,
|
|
25916
|
+
request,
|
|
25917
|
+
route
|
|
25918
|
+
});
|
|
25919
|
+
return;
|
|
25920
|
+
}
|
|
25921
|
+
if (inlineScriptContents.has(url)) {
|
|
25922
|
+
interceptInlineScript({
|
|
25923
|
+
url,
|
|
25924
|
+
request,
|
|
25925
|
+
route
|
|
25926
|
+
});
|
|
25927
|
+
return;
|
|
25928
|
+
}
|
|
25929
|
+
const fsServerUrl = new URL("/@fs/", webServer.origin);
|
|
25930
|
+
if (url.startsWith(fsServerUrl)) {
|
|
25931
|
+
interceptFileSystemUrl({
|
|
25932
|
+
url,
|
|
25933
|
+
request,
|
|
25934
|
+
route
|
|
25935
|
+
});
|
|
25936
|
+
return;
|
|
25937
|
+
}
|
|
25938
|
+
route.fallback();
|
|
25939
|
+
});
|
|
25940
|
+
};
|
|
25364
25941
|
const registerEvent = ({
|
|
25365
25942
|
object,
|
|
25366
25943
|
eventType,
|
|
@@ -25394,7 +25971,7 @@ const webkit = createRuntimeFromPlaywright({
|
|
|
25394
25971
|
// browserVersion will be set by "browser._initializer.version"
|
|
25395
25972
|
// see also https://github.com/microsoft/playwright/releases
|
|
25396
25973
|
browserVersion: "unset",
|
|
25397
|
-
|
|
25974
|
+
shouldIgnoreError: error => {
|
|
25398
25975
|
// we catch error during execution but safari throw unhandled rejection
|
|
25399
25976
|
// in a non-deterministic way.
|
|
25400
25977
|
// I suppose it's due to some race condition to decide if the promise is catched or not
|
|
@@ -26321,8 +26898,7 @@ const startBuildServer = async ({
|
|
|
26321
26898
|
stopOnExit: false,
|
|
26322
26899
|
stopOnSIGINT: false,
|
|
26323
26900
|
stopOnInternalError: false,
|
|
26324
|
-
|
|
26325
|
-
keepProcessAlive,
|
|
26901
|
+
keepProcessAlive: process.env.IMPORTED_BY_TEST_PLAN ? false : keepProcessAlive,
|
|
26326
26902
|
logLevel: serverLogLevel,
|
|
26327
26903
|
startLog: false,
|
|
26328
26904
|
https,
|
|
@@ -26406,8 +26982,7 @@ const execute = async ({
|
|
|
26406
26982
|
handleSIGINT = true,
|
|
26407
26983
|
logLevel,
|
|
26408
26984
|
rootDirectoryUrl,
|
|
26409
|
-
|
|
26410
|
-
devServerOrigin,
|
|
26985
|
+
webServer,
|
|
26411
26986
|
fileRelativeUrl,
|
|
26412
26987
|
allocatedMs,
|
|
26413
26988
|
mirrorConsole = true,
|
|
@@ -26433,23 +27008,16 @@ const execute = async ({
|
|
|
26433
27008
|
}, abort);
|
|
26434
27009
|
});
|
|
26435
27010
|
}
|
|
27011
|
+
if (runtime.type === "browser") {
|
|
27012
|
+
await assertAndNormalizeWebServer(webServer);
|
|
27013
|
+
}
|
|
26436
27014
|
let resultTransformer = result => result;
|
|
26437
27015
|
runtimeParams = {
|
|
26438
27016
|
rootDirectoryUrl,
|
|
26439
|
-
|
|
26440
|
-
devServerOrigin,
|
|
27017
|
+
webServer,
|
|
26441
27018
|
fileRelativeUrl,
|
|
26442
27019
|
...runtimeParams
|
|
26443
27020
|
};
|
|
26444
|
-
if (runtime.type === "browser") {
|
|
26445
|
-
if (!devServerOrigin) {
|
|
26446
|
-
throw new TypeError(`devServerOrigin is required to execute file on a browser`);
|
|
26447
|
-
}
|
|
26448
|
-
const devServerStarted = await pingServer(devServerOrigin);
|
|
26449
|
-
if (!devServerStarted) {
|
|
26450
|
-
throw new Error(`no server listening at ${devServerOrigin}. It is required to execute file`);
|
|
26451
|
-
}
|
|
26452
|
-
}
|
|
26453
27021
|
let result = await run({
|
|
26454
27022
|
signal: executeOperation.signal,
|
|
26455
27023
|
logger,
|