@jsenv/core 22.5.1 → 23.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.
Files changed (99) hide show
  1. package/dist/jsenv_browser_system.js +203 -49
  2. package/dist/jsenv_browser_system.js.map +39 -8
  3. package/dist/jsenv_compile_proxy.js +186 -108
  4. package/dist/jsenv_compile_proxy.js.map +48 -42
  5. package/dist/jsenv_exploring_redirector.js +148 -71
  6. package/dist/jsenv_exploring_redirector.js.map +26 -20
  7. package/dist/jsenv_toolbar.js +215 -104
  8. package/dist/jsenv_toolbar.js.map +39 -26
  9. package/helpers/new_stylesheet/new_stylesheet.js +411 -0
  10. package/{LICENSE → license} +0 -0
  11. package/main.js +7 -7
  12. package/package.json +23 -19
  13. package/readme.md +5 -4
  14. package/src/execute.js +23 -10
  15. package/src/executeTestPlan.js +0 -4
  16. package/src/importUsingChildProcess.js +36 -32
  17. package/src/internal/{babel-plugin-replace-expressions.js → babel_plugin_replace_expressions.js} +0 -0
  18. package/src/internal/{babel-plugin-transform-import-meta.js → babel_plugin_transform_import_meta.js} +0 -0
  19. package/src/internal/browser-launcher/executeHtmlFile.js +6 -8
  20. package/src/internal/browser-launcher/jsenv-browser-system.js +3 -0
  21. package/src/internal/building/asset_url_versioning.js +5 -9
  22. package/src/internal/building/buildServiceWorker.js +6 -13
  23. package/src/internal/building/buildUsingRollup.js +34 -0
  24. package/src/internal/building/build_logs.js +11 -0
  25. package/src/internal/building/build_stats.js +7 -1
  26. package/src/internal/building/createJsenvRollupPlugin.js +380 -297
  27. package/src/internal/building/css/parseCssRessource.js +67 -71
  28. package/src/internal/building/css/parseCssUrls.js +2 -2
  29. package/src/internal/building/css/{postcss-urlhash-plugin.js → postcss_plugin_url_visitor.js} +43 -21
  30. package/src/internal/building/css/replaceCssUrls.js +17 -14
  31. package/src/internal/building/css_module.js +47 -0
  32. package/src/internal/building/html/parseHtmlRessource.js +44 -43
  33. package/src/internal/building/import_references.js +81 -0
  34. package/src/internal/building/importmap/parseImportmapRessource.js +5 -2
  35. package/src/internal/building/js/minifyJs.js +30 -3
  36. package/src/internal/building/js/parseJsRessource.js +70 -77
  37. package/src/internal/building/json/parseJsonRessource.js +3 -2
  38. package/src/internal/building/parseRessource.js +11 -8
  39. package/src/internal/building/parsing.utils.js +4 -15
  40. package/src/internal/building/ressource_builder.js +142 -114
  41. package/src/internal/building/ressource_builder_util.js +31 -18
  42. package/src/internal/building/{fetchSourcemap.js → sourcemap_loader.js} +29 -27
  43. package/src/internal/building/svg/parseSvgRessource.js +7 -3
  44. package/src/internal/building/url-versioning.js +2 -1
  45. package/src/internal/building/url_fetcher.js +79 -0
  46. package/src/internal/building/url_loader.js +267 -0
  47. package/src/internal/building/webmanifest/parseWebmanifestRessource.js +9 -4
  48. package/src/internal/compiling/{js-compilation-service/ensureGlobalThisImportBabelPlugin.js → babel_plugin_global_this_as_jsenv_import.js} +4 -2
  49. package/src/internal/compiling/babel_plugin_import_assertions.js +100 -0
  50. package/src/internal/compiling/babel_plugin_new_stylesheet_as_jsenv_import.js +109 -0
  51. package/src/internal/compiling/babel_plugin_transform_import_specifier.js +86 -0
  52. package/src/internal/compiling/babel_plugins.js +2 -0
  53. package/src/internal/compiling/createCompiledFileService.js +6 -8
  54. package/src/internal/compiling/html_source_file_service.js +2 -2
  55. package/src/internal/compiling/js-compilation-service/{transformBabelHelperToImportBabelPlugin.js → babel_plugin_babel_helpers_as_jsenv_imports.js} +1 -1
  56. package/src/internal/compiling/js-compilation-service/{ensureRegeneratorRuntimeImportBabelPlugin.js → babel_plugin_regenerator_runtime_as_jsenv_import.js} +1 -1
  57. package/src/internal/compiling/js-compilation-service/jsenvTransform.js +7 -16
  58. package/src/internal/compiling/js-compilation-service/transformJs.js +0 -2
  59. package/src/internal/compiling/rollup_plugin_commonjs_named_exports.js +2 -2
  60. package/src/internal/compiling/startCompileServer.js +11 -4
  61. package/src/internal/escapeTemplateStringSpecialCharacters.js +20 -0
  62. package/src/internal/executing/coverage/{babel-plugin-instrument.js → babel_plugin_instrument.js} +17 -6
  63. package/src/internal/executing/coverage/relativeUrlToEmptyCoverage.js +1 -1
  64. package/src/internal/executing/executeConcurrently.js +2 -2
  65. package/src/internal/executing/executePlan.js +16 -2
  66. package/src/internal/executing/generateFileExecutionSteps.js +2 -1
  67. package/src/internal/executing/launchAndExecute.js +43 -69
  68. package/src/internal/exploring/exploring.css +2 -1
  69. package/src/internal/exploring/exploring.redirector.js +0 -1
  70. package/src/internal/generateGroupMap/generateGroupMap.js +14 -10
  71. package/src/internal/generateGroupMap/jsenvBabelPluginCompatMap.js +30 -0
  72. package/src/internal/generateGroupMap/jsenvPluginCompatMap.js +0 -6
  73. package/src/internal/generateGroupMap/one_runtime_compat.js +9 -38
  74. package/src/internal/generateGroupMap/runtime_compat.js +9 -24
  75. package/src/internal/generateGroupMap/runtime_compat_composition.js +2 -12
  76. package/src/internal/generateGroupMap/runtime_support.js +53 -0
  77. package/src/internal/jsenvInternalFiles.js +0 -1
  78. package/src/internal/node-launcher/createControllableNodeProcess.js +2 -3
  79. package/src/internal/response_validation.js +143 -0
  80. package/src/internal/runtime/createBrowserRuntime/createBrowserRuntime.js +8 -3
  81. package/src/internal/runtime/createBrowserRuntime/createBrowserSystem.js +117 -0
  82. package/src/internal/runtime/createBrowserRuntime/displayErrorInDocument.js +1 -1
  83. package/src/internal/runtime/createBrowserRuntime/scanBrowserRuntimeFeatures.js +124 -68
  84. package/src/internal/runtime/createNodeRuntime/createNodeRuntime.js +8 -86
  85. package/src/internal/runtime/createNodeRuntime/scanNodeRuntimeFeatures.js +115 -0
  86. package/src/internal/runtime/module-registration.js +1 -2
  87. package/src/internal/runtime/resolveGroup.js +2 -3
  88. package/src/internal/toolbar/compilation/toolbar.compilation.js +15 -17
  89. package/src/internal/toolbar/eventsource/toolbar.eventsource.js +35 -8
  90. package/src/internal/toolbar/toolbar.main.js +7 -4
  91. package/src/internal/url_utils.js +20 -0
  92. package/src/launchBrowser.js +47 -34
  93. package/src/launchNode.js +6 -3
  94. package/src/requireUsingChildProcess.js +36 -32
  95. package/src/startExploring.js +23 -11
  96. package/src/internal/building/transformImportMetaUrlReferences.js +0 -71
  97. package/src/internal/runtime/resolveBrowserGroup.js +0 -5
  98. package/src/internal/runtime/resolveNodeGroup.js +0 -5
  99. package/src/internal/validateResponseStatusIsOk.js +0 -91
@@ -1,8 +1,4 @@
1
- import { nodeSupportsDynamicImport } from "../node-feature-detect/nodeSupportsDynamicImport.js"
2
- import { nodeSupportsTopLevelAwait } from "../node-feature-detect/nodeSupportsTopLevelAwait.js"
3
- import { computeCompileIdFromGroupId } from "../computeCompileIdFromGroupId.js"
4
- import { resolveNodeGroup } from "../resolveNodeGroup.js"
5
- import { fetchSource } from "./fetchSource.js"
1
+ import { scanNodeRuntimeFeatures } from "./scanNodeRuntimeFeatures.js"
6
2
  import { createNodeExecutionWithSystemJs } from "./createNodeExecutionWithSystemJs.js"
7
3
  import { createNodeExecutionWithDynamicImport } from "./createNodeExecutionWithDynamicImport.js"
8
4
 
@@ -10,33 +6,16 @@ export const createNodeRuntime = async ({
10
6
  projectDirectoryUrl,
11
7
  compileServerOrigin,
12
8
  outDirectoryRelativeUrl,
13
- canUseNativeModuleSystem,
9
+ canUseNativeModuleSystem = true,
14
10
  }) => {
15
- const outDirectoryServerUrl = `${compileServerOrigin}/${outDirectoryRelativeUrl}`
16
- const groupMapServerUrl = String(
17
- new URL("groupMap.json", outDirectoryServerUrl),
18
- )
19
- const envFileServerUrl = String(new URL("env.json", outDirectoryServerUrl))
20
- const [groupMap, envJson] = await Promise.all([
21
- importJson(groupMapServerUrl),
22
- importJson(envFileServerUrl),
23
- ])
24
-
25
- const { importDefaultExtension } = envJson
26
-
27
- const compileId = computeCompileIdFromGroupId({
28
- groupId: resolveNodeGroup(groupMap),
29
- groupMap,
11
+ const nodeFeatures = await scanNodeRuntimeFeatures({
12
+ compileServerOrigin,
13
+ outDirectoryRelativeUrl,
30
14
  })
31
- const groupInfo = groupMap[compileId]
32
- if (canUseNativeModuleSystem === undefined) {
33
- canUseNativeModuleSystem = await nodeRuntimeSupportsAllFeatures({
34
- groupInfo,
35
- importDefaultExtension,
36
- })
37
- }
15
+ const { canAvoidCompilation, compileId, importDefaultExtension } =
16
+ nodeFeatures
38
17
 
39
- if (canUseNativeModuleSystem) {
18
+ if (canAvoidCompilation && canUseNativeModuleSystem) {
40
19
  return createNodeExecutionWithDynamicImport({
41
20
  projectDirectoryUrl,
42
21
  compileServerOrigin,
@@ -51,60 +30,3 @@ export const createNodeRuntime = async ({
51
30
  importDefaultExtension,
52
31
  })
53
32
  }
54
-
55
- const importJson = async (url) => {
56
- const response = await fetchSource(url)
57
- const status = response.status
58
- if (status !== 200) {
59
- throw new Error(`unexpected response status for ${url}, got ${status}`)
60
- }
61
- const object = await response.json()
62
- return object
63
- }
64
-
65
- const nodeRuntimeSupportsAllFeatures = async ({
66
- groupInfo,
67
- importDefaultExtension,
68
- }) => {
69
- // node native resolution will not auto add extension
70
- if (importDefaultExtension) {
71
- return false
72
- }
73
-
74
- const requiredBabelPluginCount = countRequiredBabelPlugins(groupInfo)
75
- if (requiredBabelPluginCount > 0) {
76
- return false
77
- }
78
-
79
- if (groupInfo.jsenvPluginRequiredNameArray.length > 0) {
80
- return false
81
- }
82
-
83
- const hasDynamicImport = await nodeSupportsDynamicImport()
84
- if (!hasDynamicImport) {
85
- return false
86
- }
87
-
88
- const hasTopLevelAwait = await nodeSupportsTopLevelAwait()
89
- if (!hasTopLevelAwait) {
90
- return false
91
- }
92
-
93
- return true
94
- }
95
-
96
- const countRequiredBabelPlugins = (groupInfo) => {
97
- const { babelPluginRequiredNameArray } = groupInfo
98
- let count = babelPluginRequiredNameArray.length
99
-
100
- // https://nodejs.org/docs/latest-v15.x/api/cli.html#cli_node_v8_coverage_dir
101
- // instrumentation CAN be handed by process.env.NODE_V8_COVERAGE
102
- // "transform-instrument" becomes non mandatory
103
- const transformInstrumentIndex = babelPluginRequiredNameArray.indexOf(
104
- "transform-instrument",
105
- )
106
- if (transformInstrumentIndex > -1 && process.env.NODE_V8_COVERAGE) {
107
- count--
108
- }
109
- return count
110
- }
@@ -0,0 +1,115 @@
1
+ import { detectNode } from "../detectNode/detectNode.js"
2
+ import { resolveGroup } from "../resolveGroup.js"
3
+ import { computeCompileIdFromGroupId } from "../computeCompileIdFromGroupId.js"
4
+ import { nodeSupportsDynamicImport } from "../node-feature-detect/nodeSupportsDynamicImport.js"
5
+ import { nodeSupportsTopLevelAwait } from "../node-feature-detect/nodeSupportsTopLevelAwait.js"
6
+ import { fetchSource } from "./fetchSource.js"
7
+
8
+ export const scanNodeRuntimeFeatures = async ({
9
+ compileServerOrigin,
10
+ outDirectoryRelativeUrl,
11
+ }) => {
12
+ const outDirectoryServerUrl = `${compileServerOrigin}/${outDirectoryRelativeUrl}`
13
+ const groupMapServerUrl = String(
14
+ new URL("groupMap.json", outDirectoryServerUrl),
15
+ )
16
+ const envFileServerUrl = String(new URL("env.json", outDirectoryServerUrl))
17
+ const [groupMap, envJson] = await Promise.all([
18
+ importJson(groupMapServerUrl),
19
+ importJson(envFileServerUrl),
20
+ ])
21
+
22
+ const { importDefaultExtension, customCompilerPatterns } = envJson
23
+
24
+ const node = detectNode()
25
+ const compileId = computeCompileIdFromGroupId({
26
+ groupId: resolveGroup(node, groupMap),
27
+ groupMap,
28
+ })
29
+ const groupInfo = groupMap[compileId]
30
+
31
+ const featuresReport = {
32
+ dynamicImport: undefined,
33
+ topLevelAwait: undefined,
34
+ }
35
+ await detectSupportedFeatures({
36
+ featuresReport,
37
+ failFastOnFeatureDetection: true,
38
+ })
39
+ const pluginRequiredNameArray = pluginRequiredNamesFromGroupInfo(groupInfo, {
40
+ featuresReport,
41
+ // https://nodejs.org/docs/latest-v15.x/api/cli.html#cli_node_v8_coverage_dir
42
+ // instrumentation CAN be handed by process.env.NODE_V8_COVERAGE
43
+ // "transform-instrument" becomes non mandatory
44
+ coverageHandledFromOutside: process.env.NODE_V8_COVERAGE,
45
+ })
46
+
47
+ const canAvoidCompilation =
48
+ // node native resolution will not auto add extension
49
+ !importDefaultExtension &&
50
+ customCompilerPatterns.length === 0 &&
51
+ pluginRequiredNameArray.length === 0 &&
52
+ featuresReport.dynamicImport &&
53
+ featuresReport.topLevelAwait
54
+
55
+ return {
56
+ canAvoidCompilation,
57
+ featuresReport,
58
+ pluginRequiredNameArray,
59
+ compileId,
60
+ importDefaultExtension,
61
+ node,
62
+ }
63
+ }
64
+
65
+ const detectSupportedFeatures = async ({
66
+ featuresReport,
67
+ failFastOnFeatureDetection,
68
+ }) => {
69
+ const dynamicImport = await nodeSupportsDynamicImport()
70
+ featuresReport.dynamicImport = dynamicImport
71
+ if (failFastOnFeatureDetection && !dynamicImport) {
72
+ return
73
+ }
74
+
75
+ const topLevelAwait = await nodeSupportsTopLevelAwait()
76
+ featuresReport.topLevelAwait = topLevelAwait
77
+ if (failFastOnFeatureDetection && !topLevelAwait) {
78
+ return
79
+ }
80
+ }
81
+
82
+ const importJson = async (url) => {
83
+ const response = await fetchSource(url)
84
+ const status = response.status
85
+ if (status !== 200) {
86
+ throw new Error(`unexpected response status for ${url}, got ${status}`)
87
+ }
88
+ const object = await response.json()
89
+ return object
90
+ }
91
+
92
+ const pluginRequiredNamesFromGroupInfo = (
93
+ groupInfo,
94
+ { coverageHandledFromOutside },
95
+ ) => {
96
+ const { pluginRequiredNameArray } = groupInfo
97
+ const requiredPluginNames = pluginRequiredNameArray.slice()
98
+ const markPluginAsSupported = (name) => {
99
+ const index = requiredPluginNames.indexOf(name)
100
+ if (index > -1) {
101
+ requiredPluginNames.splice(index, 1)
102
+ }
103
+ }
104
+
105
+ if (coverageHandledFromOutside) {
106
+ markPluginAsSupported("transform-instrument")
107
+ }
108
+ // We assume import assertions and constructable stylesheet won't be used
109
+ // in code executed in Node.js
110
+ // so event they are conceptually required, they are ignored
111
+ markPluginAsSupported("transform-import-assertions")
112
+ markPluginAsSupported("new-stylesheet-as-jsenv-import")
113
+
114
+ return requiredPluginNames
115
+ }
@@ -108,8 +108,7 @@ export const getJavaScriptModuleResponseError = async (
108
108
  compileServerOrigin,
109
109
  compileDirectoryRelativeUrl,
110
110
  }),
111
- "suggestion": `Prefer import.meta.url as documented in https://github.com/jsenv/jsenv-core/blob/master/docs/building/readme.md#How-to-reference-js-assets`,
112
- "suggestion 2": `Use customCompilers to convert non-js to js`,
111
+ suggestion: `Use import.meta.url or import assertions as documented in https://github.com/jsenv/jsenv-core/blob/master/docs/building/readme.md#How-to-reference-assets`,
113
112
  },
114
113
  ),
115
114
  )
@@ -3,11 +3,10 @@ import { findHighestVersion } from "../semantic-versioning/index.js"
3
3
  export const resolveGroup = ({ name, version }, groupMap) => {
4
4
  return Object.keys(groupMap).find((compileIdCandidate) => {
5
5
  const { minRuntimeVersions } = groupMap[compileIdCandidate]
6
- if (name in minRuntimeVersions === false) {
6
+ const versionForGroup = minRuntimeVersions[name]
7
+ if (!versionForGroup) {
7
8
  return false
8
9
  }
9
- const versionForGroup = minRuntimeVersions[name]
10
-
11
10
  const highestVersion = findHighestVersion(version, versionForGroup)
12
11
  return highestVersion === version
13
12
  })
@@ -11,8 +11,10 @@ export const renderCompilationInToolbar = ({ compileGroup }) => {
11
11
 
12
12
  scanBrowserRuntimeFeatures().then(
13
13
  ({
14
- featuresReport,
15
14
  canAvoidCompilation,
15
+ featuresReport,
16
+ customCompilerPatterns,
17
+ pluginRequiredNameArray,
16
18
  inlineImportMapIntoHTML,
17
19
  outDirectoryRelativeUrl,
18
20
  compileId,
@@ -35,6 +37,8 @@ export const renderCompilationInToolbar = ({ compileGroup }) => {
35
37
  {
36
38
  missingOnly: true,
37
39
  featuresReport,
40
+ customCompilerPatterns,
41
+ pluginRequiredNameArray,
38
42
  inlineImportMapIntoHTML,
39
43
  },
40
44
  )}`,
@@ -49,6 +53,8 @@ export const renderCompilationInToolbar = ({ compileGroup }) => {
49
53
  `Source files (except html) can be executed directly in this browser because: ${getBrowserSupportMessage(
50
54
  {
51
55
  featuresReport,
56
+ customCompilerPatterns,
57
+ pluginRequiredNameArray,
52
58
  inlineImportMapIntoHTML,
53
59
  },
54
60
  )}`,
@@ -63,6 +69,8 @@ export const renderCompilationInToolbar = ({ compileGroup }) => {
63
69
  `Source files can be executed directly in this browser because: ${getBrowserSupportMessage(
64
70
  {
65
71
  featuresReport,
72
+ customCompilerPatterns,
73
+ pluginRequiredNameArray,
66
74
  inlineImportMapIntoHTML,
67
75
  },
68
76
  )}`,
@@ -119,6 +127,8 @@ export const renderCompilationInToolbar = ({ compileGroup }) => {
119
127
  const getBrowserSupportMessage = ({
120
128
  missingOnly,
121
129
  featuresReport,
130
+ customCompilerPatterns,
131
+ pluginRequiredNameArray,
122
132
  inlineImportMapIntoHTML,
123
133
  }) => {
124
134
  const parts = []
@@ -154,19 +164,17 @@ const getBrowserSupportMessage = ({
154
164
  parts.push(`top level await is not supported`)
155
165
  }
156
166
 
157
- const { babelPluginRequiredNames } = featuresReport
158
- const babelPluginRequiredCount = babelPluginRequiredNames.length
159
- if (babelPluginRequiredCount === 0) {
167
+ const pluginRequiredCount = pluginRequiredNameArray.length
168
+ if (pluginRequiredCount === 0) {
160
169
  if (!missingOnly) {
161
- parts.push(`all babel plugins are natively supported`)
170
+ parts.push(`all plugins are natively supported`)
162
171
  }
163
172
  } else {
164
173
  parts.push(
165
- `${babelPluginRequiredCount} babel plugins are mandatory: ${babelPluginRequiredNames}`,
174
+ `${pluginRequiredCount} plugins are mandatory: ${pluginRequiredNameArray}`,
166
175
  )
167
176
  }
168
177
 
169
- const { customCompilerPatterns } = featuresReport
170
178
  const customCompilerCount = customCompilerPatterns.length
171
179
  if (customCompilerCount === 0) {
172
180
  // no need to talk about something unused
@@ -176,16 +184,6 @@ const getBrowserSupportMessage = ({
176
184
  )
177
185
  }
178
186
 
179
- const { jsenvPluginRequiredNames } = featuresReport
180
- const jsenvPluginRequiredCount = jsenvPluginRequiredNames.length
181
- if (jsenvPluginRequiredCount === 0) {
182
- // no need to talk about something unused
183
- } else {
184
- parts.push(
185
- `${jsenvPluginRequiredCount} jsenv plugins are mandatory: ${jsenvPluginRequiredNames}`,
186
- )
187
- }
188
-
189
187
  return `
190
188
  - ${parts.join(`
191
189
  - `)}`
@@ -18,8 +18,13 @@ export const initToolbarEventSource = ({
18
18
  executedFileRelativeUrl,
19
19
  livereloading,
20
20
  }) => {
21
+ const getLivereloadCallback = (originalFileProjectRelativeUrl) => {
22
+ const callbacks = window.parent.__jsenv__.livereloadingCallbacks
23
+ return callbacks[originalFileProjectRelativeUrl]
24
+ }
25
+
21
26
  removeForceHideElement(document.querySelector("#eventsource-indicator"))
22
- connectEventSource(executedFileRelativeUrl)
27
+ connectEventSource({ executedFileRelativeUrl, getLivereloadCallback })
23
28
  livereloadingAvailableOnServer = livereloading
24
29
  if (!livereloadingAvailableOnServer) {
25
30
  disableLivereloadSetting()
@@ -54,11 +59,18 @@ let eventSourceHooks = {}
54
59
  let eventSourceConnection
55
60
  let connectionReadyPromise
56
61
 
57
- const handleFileChange = (file, type) => {
58
- latestChangeMap[file] = type
62
+ const handleFileChange = ({ file, eventType, livereloadCallback }) => {
63
+ latestChangeMap[file] = eventType
59
64
  updateEventSourceIndicator()
65
+
60
66
  if (shouldLivereload()) {
61
- if (
67
+ if (livereloadCallback) {
68
+ livereloadCallback({
69
+ file,
70
+ latestChangeMap,
71
+ reloadPage,
72
+ })
73
+ } else if (
62
74
  file.endsWith(".css") ||
63
75
  file.endsWith(".scss") ||
64
76
  file.endsWith(".sass")
@@ -109,7 +121,10 @@ const reloadChanges = () => {
109
121
  }
110
122
  }
111
123
 
112
- const connectEventSource = (executedFileRelativeUrl) => {
124
+ const connectEventSource = ({
125
+ executedFileRelativeUrl,
126
+ getLivereloadCallback,
127
+ }) => {
113
128
  updateEventSourceIndicator()
114
129
  connectionReadyPromise = createPromiseAndHooks()
115
130
 
@@ -117,13 +132,25 @@ const connectEventSource = (executedFileRelativeUrl) => {
117
132
  executedFileRelativeUrl,
118
133
  {
119
134
  onFileModified: (file) => {
120
- handleFileChange(file, "modified")
135
+ handleFileChange({
136
+ file,
137
+ eventType: "modified",
138
+ livereloadCallback: getLivereloadCallback(file),
139
+ })
121
140
  },
122
141
  onFileRemoved: (file) => {
123
- handleFileChange(file, "removed")
142
+ handleFileChange({
143
+ file,
144
+ eventType: "removed",
145
+ livereloadCallback: getLivereloadCallback(file),
146
+ })
124
147
  },
125
148
  onFileAdded: (file) => {
126
- handleFileChange(file, "added")
149
+ handleFileChange({
150
+ file,
151
+ eventType: "added",
152
+ livereloadCallback: getLivereloadCallback(file),
153
+ })
127
154
  },
128
155
  onConnecting: ({ cancel }) => {
129
156
  eventSourceState = "connecting"
@@ -80,7 +80,10 @@ const renderToolbar = async () => {
80
80
  renderCompilationInToolbar({ compileGroup })
81
81
  // this might become active but we need to detect this somehow
82
82
  deactivateToolbarSection(document.querySelector("#file-list-link"))
83
- initToolbarEventSource({ executedFileRelativeUrl, livereloading })
83
+ initToolbarEventSource({
84
+ executedFileRelativeUrl,
85
+ livereloading,
86
+ })
84
87
 
85
88
  // if user click enter or space quickly while closing toolbar
86
89
  // it will cancel the closing
@@ -188,13 +191,13 @@ const getCompileGroup = ({
188
191
  outDirectoryRelativeUrl,
189
192
  compileServerOrigin,
190
193
  }) => {
191
- const outDirectoryRemoteUrl = String(
194
+ const outDirectoryServerUrl = String(
192
195
  new URL(outDirectoryRelativeUrl, compileServerOrigin),
193
196
  )
194
- if (urlIsInsideOf(executedFileCompiledUrl, outDirectoryRemoteUrl)) {
197
+ if (urlIsInsideOf(executedFileCompiledUrl, outDirectoryServerUrl)) {
195
198
  const afterCompileDirectory = urlToRelativeUrl(
196
199
  executedFileCompiledUrl,
197
- outDirectoryRemoteUrl,
200
+ outDirectoryServerUrl,
198
201
  )
199
202
  const slashIndex = afterCompileDirectory.indexOf("/")
200
203
  const fileRelativeUrl = afterCompileDirectory.slice(slashIndex + 1)
@@ -11,3 +11,23 @@ export const setUrlExtension = (url, extension) => {
11
11
  const newPathname = `${pathnameWithoutExtension}${extension}`
12
12
  return `${origin}${newPathname}${search ? `?${search}` : ""}`
13
13
  }
14
+
15
+ export const getUrlSearchParamsDescriptor = (url) => {
16
+ const urlObject = new URL(url)
17
+ const { searchParams } = urlObject
18
+ const searchParamsDescriptor = {}
19
+ Array.from(searchParams.keys()).forEach((key) => {
20
+ const value = searchParams.getAll(key)
21
+ searchParamsDescriptor[key] = value.length === 1 ? value[0] : value
22
+ })
23
+ return searchParamsDescriptor
24
+ }
25
+
26
+ export const setUrlSearchParamsDescriptor = (url, searchParamsDescriptor) => {
27
+ const urlObject = new URL(url)
28
+ const { searchParams } = urlObject
29
+ Object.keys(searchParamsDescriptor).forEach((key) => {
30
+ searchParams.set(key, searchParamsDescriptor[key])
31
+ })
32
+ return String(urlObject)
33
+ }
@@ -5,11 +5,12 @@ import {
5
5
  createCancellationToken,
6
6
  createStoppableOperation,
7
7
  } from "@jsenv/cancellation"
8
+ import { createDetailedMessage } from "@jsenv/logger"
8
9
  import { teardownSignal } from "@jsenv/node-signals"
9
10
 
10
11
  import { trackRessources } from "./internal/trackRessources.js"
11
12
  import { fetchUrl } from "./internal/fetchUrl.js"
12
- import { validateResponseStatusIsOk } from "./internal/validateResponseStatusIsOk.js"
13
+ import { validateResponse } from "./internal/response_validation.js"
13
14
  import { trackPageToNotify } from "./internal/browser-launcher/trackPageToNotify.js"
14
15
  import { createSharing } from "./internal/browser-launcher/createSharing.js"
15
16
  import { executeHtmlFile } from "./internal/browser-launcher/executeHtmlFile.js"
@@ -20,8 +21,11 @@ import {
20
21
  } from "./playwright_browser_versions.js"
21
22
 
22
23
  const chromiumSharing = createSharing()
23
-
24
- export const launchChromium = async ({
24
+ export const chromiumRuntime = {
25
+ name: "chromium",
26
+ version: PLAYWRIGHT_CHROMIUM_VERSION,
27
+ }
28
+ chromiumRuntime.launch = async ({
25
29
  browserServerLogLevel,
26
30
  cancellationToken = createCancellationToken(),
27
31
  chromiumExecutablePath,
@@ -91,9 +95,11 @@ export const launchChromium = async ({
91
95
  cancellationToken,
92
96
  ignoreHttpsError: true,
93
97
  })
94
- const { valid, message } = await validateResponseStatusIsOk(browserResponse)
95
- if (!valid) {
96
- throw new Error(message)
98
+ const { isValid, message, details } = await validateResponse(
99
+ browserResponse,
100
+ )
101
+ if (!isValid) {
102
+ throw new Error(createDetailedMessage(message, details))
97
103
  }
98
104
 
99
105
  const browserResponseObject = JSON.parse(browserResponse.body)
@@ -103,8 +109,6 @@ export const launchChromium = async ({
103
109
 
104
110
  return {
105
111
  browser,
106
- runtimeName: "chromium",
107
- runtimeVersion: PLAYWRIGHT_CHROMIUM_VERSION,
108
112
  stop: ressourceTracker.cleanup,
109
113
  ...browserToRuntimeHooks(browser, {
110
114
  browserServerLogLevel,
@@ -124,16 +128,21 @@ export const launchChromium = async ({
124
128
  }),
125
129
  }
126
130
  }
127
-
128
- export const launchChromiumTab = (namedArgs) =>
129
- launchChromium({
130
- share: true,
131
- ...namedArgs,
132
- })
131
+ export const chromiumTabRuntime = {
132
+ ...chromiumRuntime,
133
+ launch: (params) =>
134
+ chromiumRuntime.launch({
135
+ shared: true,
136
+ ...params,
137
+ }),
138
+ }
133
139
 
134
140
  const firefoxSharing = createSharing()
135
-
136
- export const launchFirefox = async ({
141
+ export const firefoxRuntime = {
142
+ name: "firefox",
143
+ version: PLAYWRIGHT_FIREFOX_VERSION,
144
+ }
145
+ firefoxRuntime.launch = async ({
137
146
  cancellationToken = createCancellationToken(),
138
147
  firefoxExecutablePath,
139
148
  browserServerLogLevel,
@@ -179,8 +188,6 @@ export const launchFirefox = async ({
179
188
 
180
189
  return {
181
190
  browser,
182
- runtimeName: "firefox",
183
- runtimeVersion: PLAYWRIGHT_FIREFOX_VERSION,
184
191
  stop: ressourceTracker.cleanup,
185
192
  ...browserToRuntimeHooks(browser, {
186
193
  browserServerLogLevel,
@@ -199,16 +206,21 @@ export const launchFirefox = async ({
199
206
  }),
200
207
  }
201
208
  }
202
-
203
- export const launchFirefoxTab = (namedArgs) =>
204
- launchFirefox({
205
- share: true,
206
- ...namedArgs,
207
- })
209
+ export const firefoxTabRuntime = {
210
+ ...firefoxRuntime,
211
+ launch: (params) =>
212
+ firefoxRuntime.launch({
213
+ shared: true,
214
+ ...params,
215
+ }),
216
+ }
208
217
 
209
218
  const webkitSharing = createSharing()
210
-
211
- export const launchWebkit = async ({
219
+ export const webkitRuntime = {
220
+ name: "webkit",
221
+ version: PLAYWRIGHT_WEBKIT_VERSION,
222
+ }
223
+ webkitRuntime.launch = async ({
212
224
  browserServerLogLevel,
213
225
  cancellationToken = createCancellationToken(),
214
226
  webkitExecutablePath,
@@ -254,8 +266,7 @@ export const launchWebkit = async ({
254
266
 
255
267
  return {
256
268
  browser,
257
- runtimeName: "webkit",
258
- runtimeVersion: PLAYWRIGHT_WEBKIT_VERSION,
269
+
259
270
  stop: ressourceTracker.cleanup,
260
271
  ...browserToRuntimeHooks(browser, {
261
272
  browserServerLogLevel,
@@ -274,12 +285,14 @@ export const launchWebkit = async ({
274
285
  }),
275
286
  }
276
287
  }
277
-
278
- export const launchWebkitTab = (namedArgs) =>
279
- launchWebkit({
280
- share: true,
281
- ...namedArgs,
282
- })
288
+ export const webkitTabRuntime = {
289
+ ...webkitRuntime,
290
+ launch: (params) =>
291
+ webkitRuntime.launch({
292
+ shared: true,
293
+ ...params,
294
+ }),
295
+ }
283
296
 
284
297
  const launchBrowser = async (
285
298
  browserName,
package/src/launchNode.js CHANGED
@@ -1,6 +1,5 @@
1
1
  /* eslint-disable import/max-dependencies */
2
- import { Script } from "vm"
3
-
2
+ import { Script } from "node:vm"
4
3
  import cuid from "cuid"
5
4
  import { loggerToLogLevel } from "@jsenv/logger"
6
5
  import { createCancellationToken } from "@jsenv/cancellation"
@@ -17,7 +16,11 @@ import { escapeRegexpSpecialCharacters } from "./internal/escapeRegexpSpecialCha
17
16
  import { createControllableNodeProcess } from "./internal/node-launcher/createControllableNodeProcess.js"
18
17
  import { v8CoverageFromNodeV8Directory } from "./internal/executing/coverage/v8CoverageFromNodeV8Directory.js"
19
18
 
20
- export const launchNode = async ({
19
+ export const nodeRuntime = {
20
+ name: "node",
21
+ version: process.version.slice(1),
22
+ }
23
+ nodeRuntime.launch = async ({
21
24
  logger,
22
25
  logProcessCommand,
23
26
  cancellationToken = createCancellationToken(),