@jsenv/core 23.4.2 → 23.6.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 (24) hide show
  1. package/{LICENSE → license} +0 -0
  2. package/package.json +6 -7
  3. package/src/execute.js +0 -6
  4. package/src/executeTestPlan.js +3 -2
  5. package/src/internal/compiling/compile-directory/getOrGenerateCompiledFile.js +23 -30
  6. package/src/internal/compiling/compile-directory/validateCache.js +23 -15
  7. package/src/internal/compiling/compileFile.js +40 -57
  8. package/src/internal/compiling/compileHtml.js +1 -4
  9. package/src/internal/compiling/createCompiledFileService.js +4 -4
  10. package/src/internal/compiling/startCompileServer.js +3 -3
  11. package/src/internal/executing/coverage/reportToCoverage.js +97 -83
  12. package/src/internal/executing/{coverage_empty → coverage_missing}/createEmptyCoverage.js +0 -0
  13. package/src/internal/executing/{coverage_empty → coverage_missing}/list_files_not_covered.js +2 -2
  14. package/src/internal/executing/coverage_missing/missing_coverage.js +46 -0
  15. package/src/internal/executing/{coverage_empty → coverage_missing}/relativeUrlToEmptyCoverage.js +11 -7
  16. package/src/internal/executing/coverage_utils/v8_coverage_from_directory.js +41 -29
  17. package/src/internal/executing/coverage_utils/v8_coverage_to_istanbul.js +48 -38
  18. package/src/internal/executing/createSummaryLog.js +2 -8
  19. package/src/internal/executing/executeConcurrently.js +119 -93
  20. package/src/internal/executing/executePlan.js +13 -3
  21. package/src/internal/executing/executionLogs.js +66 -37
  22. package/src/internal/executing/execution_colors.js +2 -1
  23. package/src/internal/executing/launchAndExecute.js +16 -34
  24. package/src/internal/logs/msAsDuration.js +4 -3
File without changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jsenv/core",
3
- "version": "23.4.2",
3
+ "version": "23.6.0",
4
4
  "description": "Tool to develop, test and build js projects",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -11,8 +11,7 @@
11
11
  "node": ">=14.9.0"
12
12
  },
13
13
  "publishConfig": {
14
- "access": "public",
15
- "registry": "https://registry.npmjs.org"
14
+ "access": "public"
16
15
  },
17
16
  "type": "module",
18
17
  "exports": {
@@ -63,12 +62,12 @@
63
62
  "@babel/plugin-syntax-numeric-separator": "7.10.4",
64
63
  "@babel/plugin-transform-modules-systemjs": "7.15.4",
65
64
  "@c88/v8-coverage": "0.1.1",
66
- "@jsenv/abort": "4.0.0",
67
- "@jsenv/filesystem": "2.5.0",
65
+ "@jsenv/abort": "4.1.1",
66
+ "@jsenv/filesystem": "2.5.1",
68
67
  "@jsenv/importmap": "1.1.0",
69
- "@jsenv/log": "1.1.0",
68
+ "@jsenv/log": "1.4.0",
70
69
  "@jsenv/logger": "4.0.1",
71
- "@jsenv/server": "10.0.0",
70
+ "@jsenv/server": "10.0.4",
72
71
  "@jsenv/uneval": "1.6.0",
73
72
  "@jsenv/workers": "1.2.0",
74
73
  "@rollup/plugin-commonjs": "21.0.0",
package/src/execute.js CHANGED
@@ -27,11 +27,8 @@ export const execute = async ({
27
27
  runtimeParams,
28
28
 
29
29
  allocatedMs,
30
- measureDuration,
31
30
  mirrorConsole = true,
32
31
  captureConsole,
33
- collectRuntimeName,
34
- collectRuntimeVersion,
35
32
  inheritCoverage,
36
33
  collectCoverage,
37
34
  measurePerformance,
@@ -139,11 +136,8 @@ export const execute = async ({
139
136
  },
140
137
 
141
138
  allocatedMs,
142
- measureDuration,
143
139
  mirrorConsole,
144
140
  captureConsole,
145
- collectRuntimeName,
146
- collectRuntimeVersion,
147
141
  inheritCoverage,
148
142
  collectCoverage,
149
143
  measurePerformance,
@@ -33,13 +33,13 @@ export const executeTestPlan = async ({
33
33
 
34
34
  testPlan,
35
35
  defaultMsAllocatedPerExecution,
36
+ cooldownBetweenExecutions,
36
37
 
37
38
  maxExecutionsInParallel,
38
39
 
39
40
  completedExecutionLogAbbreviation = false,
40
41
  completedExecutionLogMerging = false,
41
42
  logSummary = true,
42
- measureGlobalDuration = true,
43
43
  updateProcessExitCode = true,
44
44
 
45
45
  coverage = process.argv.includes("--cover") ||
@@ -144,10 +144,10 @@ export const executeTestPlan = async ({
144
144
 
145
145
  defaultMsAllocatedPerExecution,
146
146
  maxExecutionsInParallel,
147
+ cooldownBetweenExecutions,
147
148
  completedExecutionLogMerging,
148
149
  completedExecutionLogAbbreviation,
149
150
  logSummary,
150
- measureGlobalDuration,
151
151
 
152
152
  coverage,
153
153
  coverageConfig,
@@ -225,6 +225,7 @@ export const executeTestPlan = async ({
225
225
  }
226
226
 
227
227
  return {
228
+ testPlanAborted: result.aborted,
228
229
  testPlanSummary: result.planSummary,
229
230
  testPlanReport: result.planReport,
230
231
  testPlanCoverage: planCoverage,
@@ -14,14 +14,11 @@ export const getOrGenerateCompiledFile = async ({
14
14
  projectDirectoryUrl,
15
15
  originalFileUrl,
16
16
  compiledFileUrl = originalFileUrl,
17
- useFilesystemAsCache,
17
+ compileCacheStrategy,
18
18
  compileCacheSourcesValidation,
19
19
  compileCacheAssetsValidation,
20
20
  fileContentFallback,
21
- clientNeedsEtagHeader,
22
- ifEtagMatch,
23
- clientNeedsLastModifiedHeader,
24
- ifModifiedSinceDate,
21
+ request,
25
22
  compile,
26
23
  }) => {
27
24
  if (typeof projectDirectoryUrl !== "string") {
@@ -69,13 +66,10 @@ export const getOrGenerateCompiledFile = async ({
69
66
  compiledFileUrl,
70
67
  compile,
71
68
  fileContentFallback,
72
- clientNeedsEtagHeader,
73
- ifEtagMatch,
74
- clientNeedsLastModifiedHeader,
75
- ifModifiedSinceDate,
76
- useFilesystemAsCache,
69
+ compileCacheStrategy,
77
70
  compileCacheSourcesValidation,
78
71
  compileCacheAssetsValidation,
72
+ request,
79
73
  logger,
80
74
  })
81
75
 
@@ -101,38 +95,32 @@ const computeCompileReport = async ({
101
95
  compiledFileUrl,
102
96
  compile,
103
97
  fileContentFallback,
104
- clientNeedsEtagHeader,
105
- ifEtagMatch,
106
- clientNeedsLastModifiedHeader,
107
- ifModifiedSinceDate,
108
- useFilesystemAsCache,
98
+ compileCacheStrategy,
109
99
  compileCacheSourcesValidation,
110
100
  compileCacheAssetsValidation,
101
+ request,
111
102
  logger,
112
103
  }) => {
113
104
  const [readCacheTiming, cacheValidity] = await timeFunction(
114
105
  "read cache",
115
106
  () => {
116
- if (!useFilesystemAsCache) {
117
- return {
118
- isValid: false,
119
- code: "META_FILE_NOT_FOUND",
120
- meta: {
121
- isValid: false,
122
- code: "META_FILE_NOT_FOUND",
123
- },
124
- }
125
- }
107
+ // if (!useFilesystemAsCache) {
108
+ // return {
109
+ // isValid: false,
110
+ // code: "META_FILE_NOT_FOUND",
111
+ // meta: {
112
+ // isValid: false,
113
+ // code: "META_FILE_NOT_FOUND",
114
+ // },
115
+ // }
116
+ // }
126
117
  return validateCache({
127
118
  logger,
128
- useFilesystemAsCache,
129
119
  compiledFileUrl,
130
- clientNeedsEtagHeader,
131
- ifEtagMatch,
132
- clientNeedsLastModifiedHeader,
133
- ifModifiedSinceDate,
120
+ compileCacheStrategy,
134
121
  compileCacheSourcesValidation,
135
122
  compileCacheAssetsValidation,
123
+ request,
136
124
  })
137
125
  },
138
126
  )
@@ -149,6 +137,7 @@ const computeCompileReport = async ({
149
137
  logger,
150
138
  originalFileUrl,
151
139
  fileContentFallback,
140
+ request,
152
141
  compile,
153
142
  }),
154
143
  )
@@ -189,6 +178,7 @@ const callCompile = async ({
189
178
  logger,
190
179
  originalFileUrl,
191
180
  fileContentFallback,
181
+ request,
192
182
  compile,
193
183
  }) => {
194
184
  logger.debug(`compile ${originalFileUrl}`)
@@ -201,6 +191,7 @@ const callCompile = async ({
201
191
  const compileReturnValue = await compile({
202
192
  code: codeBeforeCompile,
203
193
  map: undefined,
194
+ request,
204
195
  })
205
196
  if (typeof compileReturnValue !== "object" || compileReturnValue === null) {
206
197
  throw new TypeError(
@@ -214,6 +205,7 @@ const callCompile = async ({
214
205
  sourcesContent = [],
215
206
  assets = [],
216
207
  assetsContent = [],
208
+ responseHeaders,
217
209
  } = compileReturnValue
218
210
  if (typeof contentType !== "string") {
219
211
  throw new TypeError(
@@ -233,6 +225,7 @@ const callCompile = async ({
233
225
  sourcesContent,
234
226
  assets,
235
227
  assetsContent,
228
+ responseHeaders,
236
229
  }
237
230
  }
238
231
 
@@ -5,10 +5,7 @@ import { readFileSync, statSync } from "node:fs"
5
5
 
6
6
  export const validateCache = async ({
7
7
  compiledFileUrl,
8
- clientNeedsEtagHeader,
9
- ifEtagMatch,
10
- clientNeedsLastModifiedHeader,
11
- ifModifiedSinceDate,
8
+ compileCacheStrategy,
12
9
  compileCacheSourcesValidation = true,
13
10
  // When "compileCacheAssetsValidation" is enabled, code ensures that
14
11
  // - asset file exists
@@ -19,6 +16,7 @@ export const validateCache = async ({
19
16
  // so by default "compileCacheAssetsValidation" is disabled
20
17
  // to avoid checking things for nothing
21
18
  compileCacheAssetsValidation = false,
19
+ request,
22
20
  }) => {
23
21
  const validity = { isValid: true }
24
22
 
@@ -31,10 +29,8 @@ export const validateCache = async ({
31
29
 
32
30
  const compiledFileValidation = await validateCompiledFile({
33
31
  compiledFileUrl,
34
- clientNeedsEtagHeader,
35
- ifEtagMatch,
36
- clientNeedsLastModifiedHeader,
37
- ifModifiedSinceDate,
32
+ request,
33
+ compileCacheStrategy,
38
34
  })
39
35
  mergeValidity(validity, "compiledFile", compiledFileValidation)
40
36
  if (!validity.isValid) {
@@ -111,31 +107,43 @@ const validateMetaFile = async (metaJsonFileUrl) => {
111
107
 
112
108
  const validateCompiledFile = async ({
113
109
  compiledFileUrl,
114
- clientNeedsEtagHeader,
115
- ifEtagMatch,
116
- clientNeedsLastModifiedHeader,
117
- ifModifiedSinceDate,
110
+ compileCacheStrategy,
111
+ request,
118
112
  }) => {
119
113
  const validity = { isValid: true, data: {} }
120
114
 
115
+ const clientCacheDisabled = request.headers["cache-control"] === "no-cache"
116
+
121
117
  try {
122
118
  const compiledSourceBuffer = readFileSync(fileURLToPath(compiledFileUrl))
123
119
  validity.data.compiledSourceBuffer = compiledSourceBuffer
124
120
 
125
- if (clientNeedsEtagHeader) {
121
+ if (!clientCacheDisabled && compileCacheStrategy === "etag") {
126
122
  const compiledEtag = bufferToEtag(compiledSourceBuffer)
127
123
  validity.data.compiledEtag = compiledEtag
128
- if (ifEtagMatch && ifEtagMatch !== compiledEtag) {
124
+ const ifNoneMatch = request.headers["if-none-match"]
125
+ if (ifNoneMatch && ifNoneMatch !== compiledEtag) {
129
126
  validity.isValid = false
130
127
  validity.code = "COMPILED_FILE_ETAG_MISMATCH"
131
128
  return validity
132
129
  }
133
130
  }
134
131
 
135
- if (clientNeedsLastModifiedHeader) {
132
+ if (!clientCacheDisabled && compileCacheStrategy === "mtime") {
136
133
  const stats = statSync(fileURLToPath(compiledFileUrl))
137
134
  const compiledMtime = Math.floor(stats.mtimeMs)
138
135
  validity.data.compiledMtime = compiledMtime
136
+
137
+ const ifModifiedSince = request.headers["if-modified-since"]
138
+ let ifModifiedSinceDate
139
+ try {
140
+ ifModifiedSinceDate = new Date(ifModifiedSince)
141
+ } catch (e) {
142
+ ifModifiedSinceDate = null
143
+ // ideally we should rather respond with
144
+ // 400 "if-modified-since header is not a valid date"
145
+ }
146
+
139
147
  if (
140
148
  ifModifiedSinceDate &&
141
149
  ifModifiedSinceDate < dateToSecondsPrecision(compiledMtime)
@@ -19,47 +19,21 @@ export const compileFile = async ({
19
19
  projectFileRequestedCallback = () => {},
20
20
  request,
21
21
  compile,
22
- writeOnFilesystem,
23
- useFilesystemAsCache,
24
22
  compileCacheStrategy = "etag",
25
23
  compileCacheSourcesValidation,
26
24
  compileCacheAssetsValidation,
27
25
  }) => {
28
26
  if (
29
- writeOnFilesystem &&
30
27
  compileCacheStrategy !== "etag" &&
31
- compileCacheStrategy !== "mtime"
28
+ compileCacheStrategy !== "mtime" &&
29
+ compileCacheStrategy !== "none"
32
30
  ) {
33
31
  throw new Error(
34
- `compileCacheStrategy must be etag or mtime , got ${compileCacheStrategy}`,
32
+ `compileCacheStrategy must be "etag", "mtime" or "none", got ${compileCacheStrategy}`,
35
33
  )
36
34
  }
37
35
 
38
- const { headers = {} } = request
39
- const clientCacheDisabled = headers["cache-control"] === "no-cache"
40
- const cacheWithETag = writeOnFilesystem && compileCacheStrategy === "etag"
41
-
42
- let ifEtagMatch
43
- if (cacheWithETag && "if-none-match" in headers) {
44
- ifEtagMatch = headers["if-none-match"]
45
- }
46
-
47
- const cacheWithMtime = writeOnFilesystem && compileCacheStrategy === "mtime"
48
- let ifModifiedSinceDate
49
- if (cacheWithMtime && "if-modified-since" in headers) {
50
- const ifModifiedSince = headers["if-modified-since"]
51
- try {
52
- ifModifiedSinceDate = new Date(ifModifiedSince)
53
- } catch (e) {
54
- return {
55
- status: 400,
56
- statusText: "if-modified-since header is not a valid date",
57
- }
58
- }
59
- }
60
-
61
- const clientNeedsEtagHeader = cacheWithETag && !clientCacheDisabled
62
- const clientNeedsLastModifiedHeader = cacheWithMtime && !clientCacheDisabled
36
+ const clientCacheDisabled = request.headers["cache-control"] === "no-cache"
63
37
 
64
38
  try {
65
39
  const { meta, compileResult, compileResultStatus, timing } =
@@ -69,25 +43,21 @@ export const compileFile = async ({
69
43
  originalFileUrl,
70
44
  compiledFileUrl,
71
45
  fileContentFallback,
72
- clientNeedsEtagHeader,
73
- clientNeedsLastModifiedHeader,
74
- ifEtagMatch,
75
- ifModifiedSinceDate,
76
- useFilesystemAsCache,
46
+ request,
47
+ compileCacheStrategy,
77
48
  compileCacheSourcesValidation,
78
49
  compileCacheAssetsValidation,
79
50
  compile,
80
51
  })
81
52
 
82
- if (clientNeedsEtagHeader && !compileResult.compiledEtag) {
53
+ if (compileCacheStrategy === "etag" && !compileResult.compiledEtag) {
83
54
  // happens when file was just compiled so etag was not computed
84
-
85
55
  compileResult.compiledEtag = bufferToEtag(
86
56
  Buffer.from(compileResult.compiledSource),
87
57
  )
88
58
  }
89
59
 
90
- if (clientNeedsLastModifiedHeader && !compileResult.compiledMtime) {
60
+ if (compileCacheStrategy === "mtime" && !compileResult.compiledMtime) {
91
61
  // happens when file was just compiled so it's not yet written on filesystem
92
62
  // Here we know the compiled file will be written on the filesystem
93
63
  // We could wait for the file to be written before responding to the client
@@ -107,20 +77,29 @@ export const compileFile = async ({
107
77
  compileResult.compiledMtime = Date.now()
108
78
  }
109
79
 
80
+ const {
81
+ contentType,
82
+ compiledEtag,
83
+ compiledMtime,
84
+ compiledSource,
85
+ responseHeaders = {},
86
+ } = compileResult
87
+
110
88
  if (
111
- compileResultStatus === "created" ||
112
- compileResultStatus === "updated"
89
+ compileResultStatus !== "cached" &&
90
+ compileCacheStrategy !== "none" &&
91
+ // a cutom compiler explicitely disables cache by returning "cache-control": "no-store"
92
+ // this file must not be cached on the filesystem and always re-generated
93
+ responseHeaders["cache-control"] !== "no-store"
113
94
  ) {
114
- if (writeOnFilesystem) {
115
- updateMeta({
116
- logger,
117
- meta,
118
- compileResult,
119
- compileResultStatus,
120
- compiledFileUrl,
121
- // originalFileUrl,
122
- })
123
- }
95
+ updateMeta({
96
+ logger,
97
+ meta,
98
+ compileResult,
99
+ compileResultStatus,
100
+ compiledFileUrl,
101
+ // originalFileUrl,
102
+ })
124
103
  }
125
104
 
126
105
  compileResult.sources.forEach((source) => {
@@ -131,9 +110,6 @@ export const compileFile = async ({
131
110
  )
132
111
  })
133
112
 
134
- const { contentType, compiledEtag, compiledMtime, compiledSource } =
135
- compileResult
136
-
137
113
  // when a compiled version of the source file was just created or updated
138
114
  // we don't want to rely on filesystem because we might want to delay
139
115
  // when the file is written for perf reasons
@@ -144,6 +120,7 @@ export const compileFile = async ({
144
120
  headers: {
145
121
  "content-length": Buffer.byteLength(compiledSource),
146
122
  "content-type": contentType,
123
+ ...responseHeaders,
147
124
  },
148
125
  body: compiledSource,
149
126
  timing,
@@ -152,8 +129,11 @@ export const compileFile = async ({
152
129
  return response
153
130
  }
154
131
 
155
- if (clientNeedsEtagHeader) {
156
- if (ifEtagMatch && compileResultStatus === "cached") {
132
+ if (!clientCacheDisabled && compileCacheStrategy === "etag") {
133
+ if (
134
+ request.headers["if-none-match"] &&
135
+ compileResultStatus === "cached"
136
+ ) {
157
137
  return {
158
138
  status: 304,
159
139
  timing,
@@ -165,8 +145,11 @@ export const compileFile = async ({
165
145
  })
166
146
  }
167
147
 
168
- if (clientNeedsLastModifiedHeader) {
169
- if (ifModifiedSinceDate && compileResultStatus === "cached") {
148
+ if (!clientCacheDisabled && compileCacheStrategy === "mtime") {
149
+ if (
150
+ request.headers["if-modified-since"] &&
151
+ compileResultStatus === "cached"
152
+ ) {
170
153
  return {
171
154
  status: 304,
172
155
  timing,
@@ -86,10 +86,7 @@ export const getHtmlNodeAttributeByName = (htmlNode, attributeName) => {
86
86
  }
87
87
 
88
88
  export const removeHtmlNodeAttribute = (htmlNode, attributeToRemove) => {
89
- let attrIndex
90
- if (typeof attributeToRemove === "object") {
91
- attrIndex = htmlNode.attrs.indexOf(attributeToRemove)
92
- }
89
+ const attrIndex = htmlNode.attrs.indexOf(attributeToRemove)
93
90
  if (attrIndex === -1) {
94
91
  return false
95
92
  }
@@ -48,7 +48,6 @@ export const createCompiledFileService = ({
48
48
  jsenvToolbarInjection,
49
49
 
50
50
  projectFileRequestedCallback,
51
- useFilesystemAsCache,
52
51
  compileCacheStrategy,
53
52
  sourcemapMethod,
54
53
  sourcemapExcludeSources,
@@ -153,8 +152,6 @@ export const createCompiledFileService = ({
153
152
  originalFileUrl,
154
153
  compiledFileUrl,
155
154
 
156
- writeOnFilesystem: true, // we always need them
157
- useFilesystemAsCache,
158
155
  compileCacheStrategy,
159
156
  projectFileRequestedCallback,
160
157
  request,
@@ -226,7 +223,10 @@ const getCompiler = ({ originalFileUrl, compileMeta }) => {
226
223
  code: customResult.compiledSource,
227
224
  map: customResult.sourcemap,
228
225
  })
229
- return jsenvResult
226
+ return {
227
+ ...customResult,
228
+ ...jsenvResult,
229
+ }
230
230
  }
231
231
  }
232
232
 
@@ -316,11 +316,11 @@ export const startCompileServer = async ({
316
316
  jsenvToolbarInjection,
317
317
 
318
318
  projectFileRequestedCallback,
319
- useFilesystemAsCache: compileServerCanReadFromFilesystem,
320
- writeOnFilesystem: compileServerCanWriteOnFilesystem,
321
319
  sourcemapMethod,
322
320
  sourcemapExcludeSources,
323
- compileCacheStrategy,
321
+ compileCacheStrategy: compileServerCanReadFromFilesystem
322
+ ? compileCacheStrategy
323
+ : "none",
324
324
  }),
325
325
  ...(transformHtmlSourceFiles
326
326
  ? {