@jsenv/core 27.8.0 → 28.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.
Files changed (38) hide show
  1. package/dist/js/autoreload.js +2 -2
  2. package/dist/js/html_supervisor_installer.js +3 -3
  3. package/dist/js/server_events_client.js +1 -1
  4. package/dist/main.js +520 -469
  5. package/package.json +2 -2
  6. package/readme.md +1 -1
  7. package/src/build/build.js +8 -8
  8. package/src/build/{resync_ressource_hints.js → resync_resource_hints.js} +10 -12
  9. package/src/build/start_build_server.js +6 -9
  10. package/src/dev/start_dev_server.js +2 -2
  11. package/src/execute/execute.js +14 -52
  12. package/src/execute/runtimes/browsers/from_playwright.js +19 -8
  13. package/src/main.js +3 -0
  14. package/src/omega/kitchen.js +5 -5
  15. package/src/omega/omega_server.js +2 -2
  16. package/src/omega/server/file_service.js +3 -3
  17. package/src/omega/url_graph/url_graph_load.js +4 -4
  18. package/src/omega/url_graph.js +3 -3
  19. package/src/ping_server.js +30 -0
  20. package/src/plugins/autoreload/client/reload.js +2 -2
  21. package/src/plugins/autoreload/jsenv_plugin_autoreload_client.js +1 -1
  22. package/src/plugins/autoreload/jsenv_plugin_autoreload_server.js +3 -3
  23. package/src/plugins/autoreload/jsenv_plugin_hmr.js +1 -1
  24. package/src/plugins/explorer/jsenv_plugin_explorer.js +1 -1
  25. package/src/plugins/html_supervisor/client/error_formatter.js +3 -3
  26. package/src/plugins/html_supervisor/jsenv_plugin_html_supervisor.js +5 -5
  27. package/src/plugins/import_meta_hot/html_hot_dependencies.js +4 -4
  28. package/src/plugins/import_meta_scenarios/jsenv_plugin_import_meta_scenarios.js +1 -9
  29. package/src/plugins/plugin_controller.js +2 -2
  30. package/src/plugins/server_events/client/server_events_client.js +1 -1
  31. package/src/plugins/toolbar/jsenv_plugin_toolbar.js +1 -1
  32. package/src/plugins/transpilation/as_js_classic/jsenv_plugin_as_js_classic.js +2 -2
  33. package/src/plugins/transpilation/as_js_classic/jsenv_plugin_as_js_classic_html.js +3 -3
  34. package/src/plugins/transpilation/babel/jsenv_plugin_babel.js +13 -0
  35. package/src/plugins/url_analysis/html/html_urls.js +2 -2
  36. package/src/plugins/url_analysis/jsenv_plugin_url_analysis.js +1 -1
  37. package/src/test/execute_plan.js +15 -68
  38. package/src/test/execute_test_plan.js +4 -26
@@ -45,7 +45,7 @@ export const jsenvPluginHtmlSupervisor = ({
45
45
  name: "jsenv:html_supervisor",
46
46
  appliesDuring: "dev",
47
47
  serve: async (request, context) => {
48
- if (request.ressource.startsWith("/__get_code_frame__/")) {
48
+ if (request.pathname.startsWith("/__get_code_frame__/")) {
49
49
  const { pathname, searchParams } = new URL(request.url)
50
50
  const urlWithLineAndColumn = pathname.slice(
51
51
  "/__get_code_frame__/".length,
@@ -95,8 +95,8 @@ export const jsenvPluginHtmlSupervisor = ({
95
95
  body: codeFrame,
96
96
  }
97
97
  }
98
- if (request.ressource.startsWith("/__get_error_cause__/")) {
99
- const file = request.ressource.slice("/__get_error_cause__/".length)
98
+ if (request.pathname.startsWith("/__get_error_cause__/")) {
99
+ const file = request.pathname.slice("/__get_error_cause__/".length)
100
100
  if (!file) {
101
101
  return {
102
102
  status: 400,
@@ -148,8 +148,8 @@ export const jsenvPluginHtmlSupervisor = ({
148
148
  body,
149
149
  }
150
150
  }
151
- if (request.ressource.startsWith("/__open_in_editor__/")) {
152
- const file = request.ressource.slice("/__open_in_editor__/".length)
151
+ if (request.pathname.startsWith("/__open_in_editor__/")) {
152
+ const file = request.pathname.slice("/__open_in_editor__/".length)
153
153
  if (!file) {
154
154
  return {
155
155
  status: 400,
@@ -119,14 +119,14 @@ const getNodeContext = (node) => {
119
119
 
120
120
  const htmlNodeCanHotReload = (node) => {
121
121
  if (node.nodeName === "link") {
122
- const { isStylesheet, isRessourceHint, rel } = analyzeLinkNode(node)
122
+ const { isStylesheet, isResourceHint, rel } = analyzeLinkNode(node)
123
123
  if (isStylesheet) {
124
124
  // stylesheets can be hot replaced by default
125
125
  return true
126
126
  }
127
- if (isRessourceHint) {
128
- // for ressource hints html will be notified the underlying ressource has changed
129
- // but we won't do anything (if the ressource is deleted we should?)
127
+ if (isResourceHint) {
128
+ // for resource hints html will be notified the underlying resource has changed
129
+ // but we won't do anything (if the resource is deleted we should?)
130
130
  return true
131
131
  }
132
132
  if (rel === "icon") {
@@ -28,7 +28,7 @@ export const jsenvPluginImportMetaScenarios = () => {
28
28
  babelPlugins: [babelPluginMetadataImportMetaScenarios],
29
29
  urlInfo,
30
30
  })
31
- const { dev = [], test = [], build = [] } = metadata.importMetaScenarios
31
+ const { dev = [], build = [] } = metadata.importMetaScenarios
32
32
  const replacements = []
33
33
  const replace = (path, value) => {
34
34
  replacements.push({ path, value })
@@ -38,9 +38,6 @@ export const jsenvPluginImportMetaScenarios = () => {
38
38
  dev.forEach((path) => {
39
39
  replace(path, "undefined")
40
40
  })
41
- test.forEach((path) => {
42
- replace(path, context.scenarios.test ? "true" : "undefined")
43
- })
44
41
  build.forEach((path) => {
45
42
  replace(path, "true")
46
43
  })
@@ -52,11 +49,6 @@ export const jsenvPluginImportMetaScenarios = () => {
52
49
  dev.forEach((path) => {
53
50
  replace(path, "true")
54
51
  })
55
- if (context.scenarios.test) {
56
- test.forEach((path) => {
57
- replace(path, "true")
58
- })
59
- }
60
52
  }
61
53
  const magicSource = createMagicSource(urlInfo.content)
62
54
  replacements.forEach(({ path, value }) => {
@@ -208,9 +208,9 @@ const flattenAndFilterPlugins = (plugins, { scenarios }) => {
208
208
  return
209
209
  }
210
210
  if (typeof appliesDuring === "string") {
211
- if (!["dev", "test", "build"].includes(appliesDuring)) {
211
+ if (!["dev", "build"].includes(appliesDuring)) {
212
212
  throw new Error(
213
- `"appliesDuring" must be "dev", "test" or "build", got ${appliesDuring}`,
213
+ `"appliesDuring" must be "dev" or "build", got ${appliesDuring}`,
214
214
  )
215
215
  }
216
216
  if (scenarios[appliesDuring]) {
@@ -2,7 +2,7 @@
2
2
 
3
3
  import { createWebSocketConnection } from "./web_socket_connection.js"
4
4
 
5
- const websocketScheme = self.location.protocol === "https" ? "wss" : "ws"
5
+ const websocketScheme = self.location.protocol === "https:" ? "wss" : "ws"
6
6
  const websocketUrl = `${websocketScheme}://${self.location.host}${self.location.pathname}${self.location.search}`
7
7
  const websocketConnection = createWebSocketConnection(websocketUrl, {
8
8
  retry: true,
@@ -17,7 +17,7 @@ export const jsenvPluginToolbar = ({ logs = false } = {}) => {
17
17
 
18
18
  return {
19
19
  name: "jsenv:toolbar",
20
- appliesDuring: { dev: true, test: false },
20
+ appliesDuring: "dev",
21
21
  transformUrlContent: {
22
22
  html: ({ url, content }, { referenceUtils }) => {
23
23
  if (url === toolbarHtmlClientFileUrl) {
@@ -75,7 +75,7 @@ const jsenvPluginAsJsClassicConversion = ({
75
75
  // - import specifier (static/dynamic import + re-export)
76
76
  // - url specifier when inside System.register/_context.import()
77
77
  // (because it's the transpiled equivalent of static and dynamic imports)
78
- // And not other references otherwise we could try to transform inline ressources
78
+ // And not other references otherwise we could try to transform inline resources
79
79
  // or specifiers inside new URL()...
80
80
  js_import_export: propagateJsClassicSearchParam,
81
81
  js_url_specifier: (reference, context) => {
@@ -94,7 +94,7 @@ const jsenvPluginAsJsClassicConversion = ({
94
94
  context,
95
95
  searchParam: "as_js_classic",
96
96
  // override the expectedType to "js_module"
97
- // because when there is ?as_js_classic it means the underlying ressource
97
+ // because when there is ?as_js_classic it means the underlying resource
98
98
  // is a js_module
99
99
  expectedType: "js_module",
100
100
  })
@@ -75,10 +75,10 @@ export const jsenvPluginAsJsClassicHtml = ({
75
75
  const getReferenceAsJsClassic = async (
76
76
  reference,
77
77
  {
78
- // we don't cook ressource hints
79
- // because they might refer to ressource that will be modified during build
78
+ // we don't cook resource hints
79
+ // because they might refer to resource that will be modified during build
80
80
  // It also means something else HAVE to reference that url in order to cook it
81
- // so that the preload is deleted by "resync_ressource_hints.js" otherwise
81
+ // so that the preload is deleted by "resync_resource_hints.js" otherwise
82
82
  cookIt = false,
83
83
  } = {},
84
84
  ) => {
@@ -1,5 +1,6 @@
1
1
  import { applyBabelPlugins } from "@jsenv/ast"
2
2
 
3
+ import { babelPluginInstrument } from "@jsenv/core/src/test/coverage/babel_plugin_instrument.js"
3
4
  import { RUNTIME_COMPAT } from "@jsenv/core/src/omega/compat/runtime_compat.js"
4
5
  import { getBaseBabelPluginStructure } from "./helpers/babel_plugin_structure.js"
5
6
  import { babelPluginBabelHelpersAsJsenvImports } from "./helpers/babel_plugin_babel_helpers_as_jsenv_imports.js"
@@ -54,6 +55,18 @@ export const jsenvPluginBabel = ({
54
55
  isJsModule,
55
56
  getImportSpecifier,
56
57
  })
58
+ if (context.scenarios.dev) {
59
+ const requestHeaders = context.request.headers
60
+ if (requestHeaders["x-coverage-instanbul"]) {
61
+ babelPluginStructure["transform-instrument"] = [
62
+ babelPluginInstrument,
63
+ {
64
+ rootDirectoryUrl: context.rootDirectoryUrl,
65
+ coverageConfig: JSON.parse(requestHeaders["x-coverage-instanbul"]),
66
+ },
67
+ ]
68
+ }
69
+ }
57
70
  if (getCustomBabelPlugins) {
58
71
  Object.assign(babelPluginStructure, getCustomBabelPlugins(context))
59
72
  }
@@ -35,7 +35,7 @@ export const parseAndTransformHtmlUrls = async (urlInfo, context) => {
35
35
  }) => {
36
36
  const { crossorigin, integrity } = readFetchMetas(node)
37
37
 
38
- const isRessourceHint = [
38
+ const isResourceHint = [
39
39
  "preconnect",
40
40
  "dns-prefetch",
41
41
  "prefetch",
@@ -50,7 +50,7 @@ export const parseAndTransformHtmlUrls = async (urlInfo, context) => {
50
50
  specifier,
51
51
  specifierLine: line,
52
52
  specifierColumn: column,
53
- isRessourceHint,
53
+ isResourceHint,
54
54
  crossorigin,
55
55
  integrity,
56
56
  })
@@ -32,7 +32,7 @@ export const jsenvPluginUrlAnalysis = ({
32
32
  }
33
33
  if (
34
34
  reference.specifier[0] === "#" &&
35
- // For Html, css and in general "#" refer to a ressource in the page
35
+ // For Html, css and in general "#" refer to a resource in the page
36
36
  // so that urls must be kept intact
37
37
  // However for js import specifiers they have a different meaning and we want
38
38
  // to resolve them (https://nodejs.org/api/packages.html#imports for instance)
@@ -14,11 +14,10 @@ import {
14
14
  import { Abort, raceProcessTeardownEvents } from "@jsenv/abort"
15
15
  import { ensureEmptyDirectory, writeFileSync } from "@jsenv/filesystem"
16
16
 
17
- import { babelPluginInstrument } from "./coverage/babel_plugin_instrument.js"
18
17
  import { reportToCoverage } from "./coverage/report_to_coverage.js"
19
- import { startOmegaServer } from "@jsenv/core/src/omega/omega_server.js"
20
18
  import { run } from "@jsenv/core/src/execute/run.js"
21
19
 
20
+ import { pingServer } from "../ping_server.js"
22
21
  import { ensureGlobalGc } from "./gc.js"
23
22
  import { generateExecutionSteps } from "./execution_steps.js"
24
23
  import { createExecutionLog, createSummaryLog } from "./logs_file_execution.js"
@@ -37,10 +36,10 @@ export const executePlan = async (
37
36
  logFileRelativeUrl,
38
37
  completedExecutionLogMerging,
39
38
  completedExecutionLogAbbreviation,
40
-
41
39
  rootDirectoryUrl,
40
+ devServerOrigin,
41
+
42
42
  keepRunning,
43
- services,
44
43
  defaultMsAllocatedPerExecution,
45
44
  maxExecutionsInParallel,
46
45
  failFast,
@@ -55,20 +54,6 @@ export const executePlan = async (
55
54
  coverageV8ConflictWarning,
56
55
  coverageTempDirectoryRelativeUrl,
57
56
 
58
- scenarios,
59
- sourcemaps,
60
- plugins,
61
- nodeEsmResolution,
62
- fileSystemMagicResolution,
63
- transpilation,
64
- writeGeneratedFiles,
65
-
66
- protocol,
67
- privateKey,
68
- certificate,
69
- host,
70
- port,
71
-
72
57
  beforeExecutionCallback = () => {},
73
58
  afterExecutionCallback = () => {},
74
59
  } = {},
@@ -88,7 +73,7 @@ export const executePlan = async (
88
73
  const { runtime } = executionConfig
89
74
  if (runtime) {
90
75
  runtimes[runtime.name] = runtime.version
91
- if (runtime.needsServer) {
76
+ if (runtime.type === "browser") {
92
77
  someNeedsServer = true
93
78
  }
94
79
  if (runtime.type === "node") {
@@ -189,6 +174,7 @@ export const executePlan = async (
189
174
 
190
175
  let runtimeParams = {
191
176
  rootDirectoryUrl,
177
+ devServerOrigin,
192
178
  coverageEnabled,
193
179
  coverageConfig,
194
180
  coverageMethodForBrowsers,
@@ -196,55 +182,16 @@ export const executePlan = async (
196
182
  stopAfterAllSignal,
197
183
  }
198
184
  if (someNeedsServer) {
199
- const server = await startOmegaServer({
200
- signal: multipleExecutionsOperation.signal,
201
- logLevel: "warn",
202
- keepProcessAlive: false,
203
- port,
204
- host,
205
- protocol,
206
- certificate,
207
- privateKey,
208
- services,
209
-
210
- rootDirectoryUrl,
211
- scenarios,
212
- runtimeCompat: runtimes,
213
-
214
- plugins,
215
- htmlSupervisor: true,
216
- nodeEsmResolution,
217
- fileSystemMagicResolution,
218
- transpilation: {
219
- ...transpilation,
220
- getCustomBabelPlugins: ({ clientRuntimeCompat }) => {
221
- if (
222
- coverageEnabled &&
223
- (coverageMethodForBrowsers !== "playwright_api" ||
224
- Object.keys(clientRuntimeCompat)[0] !== "chrome")
225
- ) {
226
- return {
227
- "transform-instrument": [
228
- babelPluginInstrument,
229
- {
230
- rootDirectoryUrl,
231
- coverageConfig,
232
- },
233
- ],
234
- }
235
- }
236
- return {}
237
- },
238
- },
239
- sourcemaps,
240
- writeGeneratedFiles,
241
- })
242
- multipleExecutionsOperation.addEndCallback(async () => {
243
- await server.stop()
244
- })
245
- runtimeParams = {
246
- ...runtimeParams,
247
- server,
185
+ if (!devServerOrigin) {
186
+ throw new TypeError(
187
+ `devServerOrigin is required when running tests on browser(s)`,
188
+ )
189
+ }
190
+ const devServerStarted = await pingServer(devServerOrigin)
191
+ if (!devServerStarted) {
192
+ throw new Error(
193
+ `dev server not started at ${devServerOrigin}. It is required to run tests`,
194
+ )
248
195
  }
249
196
  }
250
197
 
@@ -17,9 +17,10 @@ import { generateCoverageTextLog } from "./coverage/coverage_reporter_text_log.j
17
17
  import { executePlan } from "./execute_plan.js"
18
18
 
19
19
  /**
20
- * Execute a list of files and log how it goes
20
+ * Execute a list of files and log how it goes.
21
21
  * @param {Object} testPlanParameters
22
22
  * @param {string|url} testPlanParameters.rootDirectoryUrl Root directory of the project
23
+ * @param {string|url} [testPlanParameters.serverOrigin=undefined] Jsenv dev server origin; required when executing test on browsers
23
24
  * @param {Object} testPlanParameters.testPlan Object associating patterns leading to files to runtimes where they should be executed
24
25
  * @param {boolean} [testPlanParameters.completedExecutionLogAbbreviation=false] Abbreviate completed execution information to shorten terminal output
25
26
  * @param {boolean} [testPlanParameters.completedExecutionLogMerging=false] Merge completed execution logs to shorten terminal output
@@ -45,6 +46,7 @@ export const executeTestPlan = async ({
45
46
  completedExecutionLogAbbreviation = false,
46
47
  completedExecutionLogMerging = false,
47
48
  rootDirectoryUrl,
49
+ devServerOrigin,
48
50
 
49
51
  testPlan,
50
52
  updateProcessExitCode = true,
@@ -79,18 +81,6 @@ export const executeTestPlan = async ({
79
81
  coverageReportTextLog = true,
80
82
  coverageReportJsonFile = process.env.CI ? null : "./.coverage/coverage.json",
81
83
  coverageReportHtmlDirectory = process.env.CI ? "./.coverage/" : null,
82
-
83
- sourcemaps = "inline",
84
- plugins = [],
85
- nodeEsmResolution,
86
- fileSystemMagicResolution,
87
- writeGeneratedFiles = false,
88
-
89
- protocol,
90
- privateKey,
91
- certificate,
92
- host,
93
- port,
94
84
  }) => {
95
85
  const logger = createLogger({ logLevel })
96
86
  rootDirectoryUrl = assertAndNormalizeDirectoryUrl(rootDirectoryUrl)
@@ -150,6 +140,7 @@ export const executeTestPlan = async ({
150
140
  completedExecutionLogMerging,
151
141
  completedExecutionLogAbbreviation,
152
142
  rootDirectoryUrl,
143
+ devServerOrigin,
153
144
 
154
145
  maxExecutionsInParallel,
155
146
  defaultMsAllocatedPerExecution,
@@ -165,19 +156,6 @@ export const executeTestPlan = async ({
165
156
  coverageMethodForNodeJs,
166
157
  coverageV8ConflictWarning,
167
158
  coverageTempDirectoryRelativeUrl,
168
-
169
- scenarios: { dev: true, test: true },
170
- sourcemaps,
171
- plugins,
172
- nodeEsmResolution,
173
- fileSystemMagicResolution,
174
- writeGeneratedFiles,
175
-
176
- protocol,
177
- privateKey,
178
- certificate,
179
- host,
180
- port,
181
159
  })
182
160
  if (
183
161
  updateProcessExitCode &&