@jsenv/core 23.8.2 → 23.8.7

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 (133) hide show
  1. package/dist/jsenv_browser_system.js +46 -39
  2. package/dist/jsenv_browser_system.js.map +14 -14
  3. package/dist/jsenv_compile_proxy.js.map +6 -6
  4. package/dist/jsenv_exploring_index.js.map +5 -5
  5. package/dist/jsenv_exploring_redirector.js.map +12 -12
  6. package/dist/jsenv_toolbar.js.map +7 -7
  7. package/dist/jsenv_toolbar_injector.js.map +5 -5
  8. package/helpers/babel/.eslintrc.cjs +24 -24
  9. package/helpers/babel/AsyncGenerator/AsyncGenerator.js +81 -81
  10. package/helpers/babel/AwaitValue/AwaitValue.js +3 -3
  11. package/helpers/babel/applyDecoratorDescriptor/applyDecoratorDescriptor.js +33 -33
  12. package/helpers/babel/arrayLikeToArray/arrayLikeToArray.js +7 -7
  13. package/helpers/babel/arrayWithHoles/arrayWithHoles.js +4 -4
  14. package/helpers/babel/arrayWithoutHoles/arrayWithoutHoles.js +6 -6
  15. package/helpers/babel/assertThisInitialized/assertThisInitialized.js +7 -7
  16. package/helpers/babel/asyncGeneratorDelegate/asyncGeneratorDelegate.js +40 -40
  17. package/helpers/babel/asyncIterator/asyncIterator.js +12 -12
  18. package/helpers/babel/asyncToGenerator/asyncToGenerator.js +34 -34
  19. package/helpers/babel/awaitAsyncGenerator/awaitAsyncGenerator.js +5 -5
  20. package/helpers/babel/classApplyDescriptorDestructureSet/classApplyDescriptorDestructureSet.js +20 -20
  21. package/helpers/babel/classApplyDescriptorGet/classApplyDescriptorGet.js +6 -6
  22. package/helpers/babel/classApplyDescriptorSet/classApplyDescriptorSet.js +13 -13
  23. package/helpers/babel/classCallCheck/classCallCheck.js +5 -5
  24. package/helpers/babel/classCheckPrivateStaticAccess/classCheckPrivateStaticAccess.js +5 -5
  25. package/helpers/babel/classCheckPrivateStaticFieldDescriptor/classCheckPrivateStaticFieldDescriptor.js +6 -6
  26. package/helpers/babel/classExtractFieldDescriptor/classExtractFieldDescriptor.js +7 -7
  27. package/helpers/babel/classNameTDZError/classNameTDZError.js +4 -4
  28. package/helpers/babel/classPrivateFieldDestructureSet/classPrivateFieldDestructureSet.js +7 -7
  29. package/helpers/babel/classPrivateFieldGet/classPrivateFieldGet.js +7 -7
  30. package/helpers/babel/classPrivateFieldLooseBase/classPrivateFieldLooseBase.js +6 -6
  31. package/helpers/babel/classPrivateFieldLooseKey/classPrivateFieldLooseKey.js +5 -5
  32. package/helpers/babel/classPrivateFieldSet/classPrivateFieldSet.js +8 -8
  33. package/helpers/babel/classPrivateMethodGet/classPrivateMethodGet.js +6 -6
  34. package/helpers/babel/classPrivateMethodSet/classPrivateMethodSet.js +3 -3
  35. package/helpers/babel/classStaticPrivateFieldSpecGet/classStaticPrivateFieldSpecGet.js +9 -9
  36. package/helpers/babel/classStaticPrivateFieldSpecSet/classStaticPrivateFieldSpecSet.js +15 -15
  37. package/helpers/babel/classStaticPrivateMethodGet/classStaticPrivateMethodGet.js +6 -6
  38. package/helpers/babel/classStaticPrivateMethodSet/classStaticPrivateMethodSet.js +3 -3
  39. package/helpers/babel/construct/construct.js +16 -16
  40. package/helpers/babel/createClass/createClass.js +15 -15
  41. package/helpers/babel/createForOfIteratorHelper/createForOfIteratorHelper.js +60 -60
  42. package/helpers/babel/createForOfIteratorHelperLoose/createForOfIteratorHelperLoose.js +23 -23
  43. package/helpers/babel/createRawReactElement/createRawReactElement.js +50 -50
  44. package/helpers/babel/createSuper/createSuper.js +22 -22
  45. package/helpers/babel/decorate/decorate.js +403 -403
  46. package/helpers/babel/defaults/defaults.js +11 -11
  47. package/helpers/babel/defineEnumerableProperties/defineEnumerableProperties.js +23 -23
  48. package/helpers/babel/defineProperty/defineProperty.js +18 -18
  49. package/helpers/babel/extends/extends.js +14 -14
  50. package/helpers/babel/get/get.js +13 -13
  51. package/helpers/babel/getPrototypeOf/getPrototypeOf.js +4 -4
  52. package/helpers/babel/inherits/inherits.js +15 -15
  53. package/helpers/babel/inheritsLoose/inheritsLoose.js +7 -7
  54. package/helpers/babel/initializerDefineProperty/initializerDefineProperty.js +10 -10
  55. package/helpers/babel/initializerWarningHelper/initializerWarningHelper.js +6 -6
  56. package/helpers/babel/instanceof/instanceof.js +6 -6
  57. package/helpers/babel/interopRequireDefault/interopRequireDefault.js +3 -3
  58. package/helpers/babel/interopRequireWildcard/interopRequireWildcard.js +37 -37
  59. package/helpers/babel/isNativeFunction/isNativeFunction.js +4 -4
  60. package/helpers/babel/isNativeReflectConstruct/isNativeReflectConstruct.js +21 -21
  61. package/helpers/babel/iterableToArray/iterableToArray.js +7 -7
  62. package/helpers/babel/iterableToArrayLimit/iterableToArrayLimit.js +36 -36
  63. package/helpers/babel/iterableToArrayLimitLoose/iterableToArrayLimitLoose.js +10 -10
  64. package/helpers/babel/jsx/jsx.js +45 -45
  65. package/helpers/babel/maybeArrayLike/maybeArrayLike.js +10 -10
  66. package/helpers/babel/newArrowCheck/newArrowCheck.js +5 -5
  67. package/helpers/babel/nonIterableRest/nonIterableRest.js +5 -5
  68. package/helpers/babel/nonIterableSpread/nonIterableSpread.js +5 -5
  69. package/helpers/babel/objectDestructuringEmpty/objectDestructuringEmpty.js +3 -3
  70. package/helpers/babel/objectSpread/objectSpread.js +23 -23
  71. package/helpers/babel/objectSpread2/objectSpread2.js +33 -33
  72. package/helpers/babel/objectWithoutProperties/objectWithoutProperties.js +19 -19
  73. package/helpers/babel/objectWithoutPropertiesLoose/objectWithoutPropertiesLoose.js +13 -13
  74. package/helpers/babel/possibleConstructorReturn/possibleConstructorReturn.js +10 -10
  75. package/helpers/babel/readOnlyError/readOnlyError.js +4 -4
  76. package/helpers/babel/readme.md +9 -9
  77. package/helpers/babel/set/set.js +44 -44
  78. package/helpers/babel/setPrototypeOf/setPrototypeOf.js +6 -6
  79. package/helpers/babel/skipFirstGeneratorNext/skipFirstGeneratorNext.js +8 -8
  80. package/helpers/babel/slicedToArray/slicedToArray.js +10 -10
  81. package/helpers/babel/slicedToArrayLoose/slicedToArrayLoose.js +13 -13
  82. package/helpers/babel/superPropBase/superPropBase.js +10 -10
  83. package/helpers/babel/taggedTemplateLiteral/taggedTemplateLiteral.js +10 -10
  84. package/helpers/babel/taggedTemplateLiteralLoose/taggedTemplateLiteralLoose.js +7 -7
  85. package/helpers/babel/tdz/tdz.js +4 -4
  86. package/helpers/babel/temporalRef/temporalRef.js +6 -6
  87. package/helpers/babel/temporalUndefined/temporalUndefined.js +3 -3
  88. package/helpers/babel/toArray/toArray.js +10 -10
  89. package/helpers/babel/toConsumableArray/toConsumableArray.js +10 -10
  90. package/helpers/babel/toPrimitive/toPrimitive.js +10 -10
  91. package/helpers/babel/toPropertyKey/toPropertyKey.js +6 -6
  92. package/helpers/babel/typeof/typeof.js +14 -14
  93. package/helpers/babel/unsupportedIterableToArray/unsupportedIterableToArray.js +12 -12
  94. package/helpers/babel/wrapAsyncGenerator/wrapAsyncGenerator.js +8 -8
  95. package/helpers/babel/wrapNativeSuper/wrapNativeSuper.js +30 -30
  96. package/helpers/babel/wrapRegExp/wrapRegExp.js +63 -63
  97. package/helpers/babel/writeOnlyError/writeOnlyError.js +4 -4
  98. package/helpers/regenerator-runtime/regenerator-runtime.js +748 -748
  99. package/{LICENSE → license} +21 -21
  100. package/package.json +2 -2
  101. package/src/buildProject.js +300 -300
  102. package/src/execute.js +184 -184
  103. package/src/internal/browser-launcher/jsenv-browser-system.js +203 -199
  104. package/src/internal/building/buildUsingRollup.js +2 -10
  105. package/src/internal/compiling/babel_plugin_import_assertions.js +121 -121
  106. package/src/internal/compiling/babel_plugin_import_metadata.js +22 -22
  107. package/src/internal/compiling/babel_plugin_import_visitor.js +84 -84
  108. package/src/internal/compiling/compile-directory/getOrGenerateCompiledFile.js +268 -268
  109. package/src/internal/compiling/compile-directory/updateMeta.js +154 -154
  110. package/src/internal/compiling/compile-directory/validateCache.js +265 -265
  111. package/src/internal/compiling/compileFile.js +233 -224
  112. package/src/internal/compiling/compileHtml.js +550 -550
  113. package/src/internal/compiling/createCompiledFileService.js +291 -291
  114. package/src/internal/compiling/html_source_file_service.js +403 -404
  115. package/src/internal/compiling/js-compilation-service/jsenvTransform.js +272 -270
  116. package/src/internal/compiling/jsenvCompilerForHtml.js +374 -308
  117. package/src/internal/compiling/jsenvCompilerForJavaScript.js +2 -0
  118. package/src/internal/compiling/startCompileServer.js +1086 -1048
  119. package/src/internal/compiling/transformResultToCompilationResult.js +220 -220
  120. package/src/internal/executing/coverage/babel_plugin_instrument.js +90 -90
  121. package/src/internal/executing/coverage/reportToCoverage.js +193 -187
  122. package/src/internal/executing/executePlan.js +183 -183
  123. package/src/internal/executing/launchAndExecute.js +458 -458
  124. package/src/internal/generateGroupMap/featuresCompatMap.js +29 -0
  125. package/src/internal/generateGroupMap/jsenvBabelPluginCompatMap.js +1 -8
  126. package/src/internal/runtime/createBrowserRuntime/scanBrowserRuntimeFeatures.js +246 -246
  127. package/src/internal/runtime/createNodeRuntime/scanNodeRuntimeFeatures.js +112 -112
  128. package/src/internal/runtime/s.js +727 -727
  129. package/src/internal/toolbar/jsenv-logo.svg +144 -144
  130. package/src/internal/toolbar/toolbar.main.css +196 -196
  131. package/src/internal/toolbar/toolbar.main.js +227 -227
  132. package/src/internal/url_conversion.js +317 -317
  133. package/src/startExploring.js +309 -309
@@ -1,265 +1,265 @@
1
- import { resolveUrl, bufferToEtag } from "@jsenv/filesystem"
2
-
3
- import { fileURLToPath } from "node:url"
4
- import { readFileSync, statSync } from "node:fs"
5
-
6
- export const validateCache = async ({
7
- compiledFileUrl,
8
- compileCacheStrategy,
9
- compileCacheSourcesValidation = true,
10
- // When "compileCacheAssetsValidation" is enabled, code ensures that
11
- // - asset file exists
12
- // - asset file content matches an etag generated when the file was compiled
13
- // In practice a compiled file asset is a sourcemap file or a coverage.json file.
14
- // It's unlikely that something or someone would update an asset file
15
- // and even when it happens it would be a bit strict to invalidate the cache
16
- // so by default "compileCacheAssetsValidation" is disabled
17
- // to avoid checking things for nothing
18
- compileCacheAssetsValidation = false,
19
- request,
20
- }) => {
21
- const validity = { isValid: true }
22
-
23
- const metaJsonFileUrl = `${compiledFileUrl}__asset__meta.json`
24
- const metaValidity = await validateMetaFile(metaJsonFileUrl)
25
- mergeValidity(validity, "meta", metaValidity)
26
- if (!validity.isValid) {
27
- return validity
28
- }
29
-
30
- const compiledFileValidation = await validateCompiledFile({
31
- compiledFileUrl,
32
- request,
33
- compileCacheStrategy,
34
- })
35
- mergeValidity(validity, "compiledFile", compiledFileValidation)
36
- if (!validity.isValid) {
37
- return validity
38
- }
39
-
40
- const meta = metaValidity.data
41
- const [sourcesValidity, assetsValidity] = await Promise.all([
42
- compileCacheSourcesValidation
43
- ? validateSources({
44
- meta,
45
- metaJsonFileUrl,
46
- })
47
- : { isValid: true, code: "SOURCES_VALIDATION_DISABLED" },
48
- compileCacheAssetsValidation
49
- ? validateAssets({
50
- meta,
51
- metaJsonFileUrl,
52
- })
53
- : { isValid: true, code: "ASSETS_VALIDATION_DISABLED" },
54
- ])
55
- mergeValidity(validity, "sources", sourcesValidity)
56
- if (!validity.valid) {
57
- return validity
58
- }
59
- mergeValidity(validity, "assets", assetsValidity)
60
-
61
- return validity
62
- }
63
-
64
- const mergeValidity = (parentValidity, childValidityName, childValidity) => {
65
- parentValidity.isValid = childValidity.isValid
66
- if (childValidity.code) parentValidity.code = childValidity.code
67
- parentValidity[childValidityName] = childValidity
68
- }
69
-
70
- const validateMetaFile = async (metaJsonFileUrl) => {
71
- const validity = { isValid: true, data: {} }
72
-
73
- let metaJsonBuffer
74
- try {
75
- metaJsonBuffer = readFileSync(fileURLToPath(metaJsonFileUrl))
76
- } catch (error) {
77
- if (error && error.code === "ENOENT") {
78
- validity.isValid = false
79
- validity.code = "META_FILE_NOT_FOUND"
80
- return validity
81
- }
82
- throw error
83
- }
84
-
85
- const metaJsonString = String(metaJsonBuffer)
86
- let meta
87
- try {
88
- meta = JSON.parse(metaJsonString)
89
- } catch (error) {
90
- if (error && error.name === "SyntaxError") {
91
- validity.isValid = false
92
- validity.code = "META_FILE_SYNTAX_ERROR"
93
- return validity
94
- }
95
- throw error
96
- }
97
-
98
- validity.data = meta
99
- if (meta.sources.length === 0) {
100
- validity.isValid = false
101
- validity.code = "SOURCES_EMPTY"
102
- return validity
103
- }
104
-
105
- return validity
106
- }
107
-
108
- const validateCompiledFile = async ({
109
- compiledFileUrl,
110
- compileCacheStrategy,
111
- request,
112
- }) => {
113
- const validity = { isValid: true, data: {} }
114
-
115
- const clientCacheDisabled = request.headers["cache-control"] === "no-cache"
116
-
117
- try {
118
- const compiledSourceBuffer = readFileSync(fileURLToPath(compiledFileUrl))
119
- validity.data.compiledSourceBuffer = compiledSourceBuffer
120
-
121
- if (!clientCacheDisabled && compileCacheStrategy === "etag") {
122
- const compiledEtag = bufferToEtag(compiledSourceBuffer)
123
- validity.data.compiledEtag = compiledEtag
124
- const ifNoneMatch = request.headers["if-none-match"]
125
- if (ifNoneMatch && ifNoneMatch !== compiledEtag) {
126
- validity.isValid = false
127
- validity.code = "COMPILED_FILE_ETAG_MISMATCH"
128
- return validity
129
- }
130
- }
131
-
132
- if (!clientCacheDisabled && compileCacheStrategy === "mtime") {
133
- const stats = statSync(fileURLToPath(compiledFileUrl))
134
- const compiledMtime = Math.floor(stats.mtimeMs)
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
-
147
- if (
148
- ifModifiedSinceDate &&
149
- ifModifiedSinceDate < dateToSecondsPrecision(compiledMtime)
150
- ) {
151
- validity.isValid = false
152
- validity.code = "COMPILED_FILE_MTIME_OUTDATED"
153
- return validity
154
- }
155
- }
156
-
157
- return validity
158
- } catch (error) {
159
- if (error && error.code === "ENOENT") {
160
- validity.isValid = false
161
- validity.code = "COMPILED_FILE_NOT_FOUND"
162
- return validity
163
- }
164
- throw error
165
- }
166
- }
167
-
168
- const validateSources = async ({ meta, metaJsonFileUrl }) => {
169
- const sourcesValidity = { isValid: true }
170
- await Promise.all(
171
- meta.sources.map(async (source, index) => {
172
- const sourceValidity = await validateSource({
173
- metaJsonFileUrl,
174
- source,
175
- eTag: meta.sourcesEtag[index],
176
- })
177
- mergeValidity(sourcesValidity, source, sourceValidity)
178
- }),
179
- )
180
- return sourcesValidity
181
- }
182
-
183
- const validateSource = async ({ metaJsonFileUrl, source, eTag }) => {
184
- const validity = { isValid: true, data: {} }
185
- const sourceFileUrl = resolveUrl(source, metaJsonFileUrl)
186
-
187
- try {
188
- const sourceBuffer = readFileSync(fileURLToPath(sourceFileUrl))
189
- const sourceETag = bufferToEtag(sourceBuffer)
190
- validity.data.sourceBuffer = sourceBuffer
191
- validity.data.sourceETag = sourceETag
192
-
193
- if (sourceETag !== eTag) {
194
- validity.isValid = false
195
- validity.code = "SOURCE_ETAG_MISMATCH"
196
- return validity
197
- }
198
-
199
- return validity
200
- } catch (e) {
201
- if (e && e.code === "ENOENT") {
202
- // missing source invalidates the cache because
203
- // we cannot check its validity
204
- // HOWEVER inside writeMeta we will check if a source can be found
205
- // when it cannot we will not put it as a dependency
206
- // to invalidate the cache.
207
- // It is important because some files are constructed on other files
208
- // which are not truly on the filesystem
209
- // (IN theory the above happens only for convertCommonJsWithRollup because jsenv
210
- // always have a concrete file especially to avoid that kind of thing)
211
- validity.isValid = false
212
- validity.code = "SOURCE_NOT_FOUND"
213
- return validity
214
- }
215
- throw e
216
- }
217
- }
218
-
219
- const validateAssets = async ({ metaJsonFileUrl, meta }) => {
220
- const assetsValidity = { isValid: true }
221
- await Promise.all(
222
- meta.assets.map(async (asset, index) => {
223
- const assetValidity = await validateAsset({
224
- asset,
225
- metaJsonFileUrl,
226
- eTag: meta.assetsEtag[index],
227
- })
228
- mergeValidity(assetsValidity, asset, assetValidity)
229
- }),
230
- )
231
- return assetsValidity
232
- }
233
-
234
- const validateAsset = async ({ asset, metaJsonFileUrl, eTag }) => {
235
- const validity = { isValid: true, data: {} }
236
- const assetFileUrl = resolveUrl(asset, metaJsonFileUrl)
237
-
238
- try {
239
- const assetBuffer = readFileSync(fileURLToPath(assetFileUrl))
240
- const assetContentETag = bufferToEtag(assetBuffer)
241
- validity.data.buffer = assetBuffer
242
- validity.data.etag = assetContentETag
243
-
244
- if (eTag !== assetContentETag) {
245
- validity.isValid = false
246
- validity.code = "ASSET_ETAG_MISMATCH"
247
- return validity
248
- }
249
-
250
- return validity
251
- } catch (error) {
252
- if (error && error.code === "ENOENT") {
253
- validity.isValid = false
254
- validity.code = "ASSET_FILE_NOT_FOUND"
255
- return validity
256
- }
257
- throw error
258
- }
259
- }
260
-
261
- const dateToSecondsPrecision = (date) => {
262
- const dateWithSecondsPrecision = new Date(date)
263
- dateWithSecondsPrecision.setMilliseconds(0)
264
- return dateWithSecondsPrecision
265
- }
1
+ import { resolveUrl, bufferToEtag } from "@jsenv/filesystem"
2
+
3
+ import { fileURLToPath } from "node:url"
4
+ import { readFileSync, statSync } from "node:fs"
5
+
6
+ export const validateCache = async ({
7
+ compiledFileUrl,
8
+ compileCacheStrategy,
9
+ compileCacheSourcesValidation = true,
10
+ // When "compileCacheAssetsValidation" is enabled, code ensures that
11
+ // - asset file exists
12
+ // - asset file content matches an etag generated when the file was compiled
13
+ // In practice a compiled file asset is a sourcemap file or a coverage.json file.
14
+ // It's unlikely that something or someone would update an asset file
15
+ // and even when it happens it would be a bit strict to invalidate the cache
16
+ // so by default "compileCacheAssetsValidation" is disabled
17
+ // to avoid checking things for nothing
18
+ compileCacheAssetsValidation = false,
19
+ request,
20
+ }) => {
21
+ const validity = { isValid: true }
22
+
23
+ const metaJsonFileUrl = `${compiledFileUrl}__asset__meta.json`
24
+ const metaValidity = await validateMetaFile(metaJsonFileUrl)
25
+ mergeValidity(validity, "meta", metaValidity)
26
+ if (!validity.isValid) {
27
+ return validity
28
+ }
29
+
30
+ const compiledFileValidation = await validateCompiledFile({
31
+ compiledFileUrl,
32
+ request,
33
+ compileCacheStrategy,
34
+ })
35
+ mergeValidity(validity, "compiledFile", compiledFileValidation)
36
+ if (!validity.isValid) {
37
+ return validity
38
+ }
39
+
40
+ const meta = metaValidity.data
41
+ const [sourcesValidity, assetsValidity] = await Promise.all([
42
+ compileCacheSourcesValidation
43
+ ? validateSources({
44
+ meta,
45
+ metaJsonFileUrl,
46
+ })
47
+ : { isValid: true, code: "SOURCES_VALIDATION_DISABLED" },
48
+ compileCacheAssetsValidation
49
+ ? validateAssets({
50
+ meta,
51
+ metaJsonFileUrl,
52
+ })
53
+ : { isValid: true, code: "ASSETS_VALIDATION_DISABLED" },
54
+ ])
55
+ mergeValidity(validity, "sources", sourcesValidity)
56
+ if (!validity.valid) {
57
+ return validity
58
+ }
59
+ mergeValidity(validity, "assets", assetsValidity)
60
+
61
+ return validity
62
+ }
63
+
64
+ const mergeValidity = (parentValidity, childValidityName, childValidity) => {
65
+ parentValidity.isValid = childValidity.isValid
66
+ if (childValidity.code) parentValidity.code = childValidity.code
67
+ parentValidity[childValidityName] = childValidity
68
+ }
69
+
70
+ const validateMetaFile = async (metaJsonFileUrl) => {
71
+ const validity = { isValid: true, data: {} }
72
+
73
+ let metaJsonBuffer
74
+ try {
75
+ metaJsonBuffer = readFileSync(fileURLToPath(metaJsonFileUrl))
76
+ } catch (error) {
77
+ if (error && error.code === "ENOENT") {
78
+ validity.isValid = false
79
+ validity.code = "META_FILE_NOT_FOUND"
80
+ return validity
81
+ }
82
+ throw error
83
+ }
84
+
85
+ const metaJsonString = String(metaJsonBuffer)
86
+ let meta
87
+ try {
88
+ meta = JSON.parse(metaJsonString)
89
+ } catch (error) {
90
+ if (error && error.name === "SyntaxError") {
91
+ validity.isValid = false
92
+ validity.code = "META_FILE_SYNTAX_ERROR"
93
+ return validity
94
+ }
95
+ throw error
96
+ }
97
+
98
+ validity.data = meta
99
+ if (meta.sources.length === 0) {
100
+ validity.isValid = false
101
+ validity.code = "SOURCES_EMPTY"
102
+ return validity
103
+ }
104
+
105
+ return validity
106
+ }
107
+
108
+ const validateCompiledFile = async ({
109
+ compiledFileUrl,
110
+ compileCacheStrategy,
111
+ request,
112
+ }) => {
113
+ const validity = { isValid: true, data: {} }
114
+
115
+ const clientCacheDisabled = request.headers["cache-control"] === "no-cache"
116
+
117
+ try {
118
+ const compiledSourceBuffer = readFileSync(fileURLToPath(compiledFileUrl))
119
+ validity.data.compiledSourceBuffer = compiledSourceBuffer
120
+
121
+ if (!clientCacheDisabled && compileCacheStrategy === "etag") {
122
+ const compiledEtag = bufferToEtag(compiledSourceBuffer)
123
+ validity.data.compiledEtag = compiledEtag
124
+ const ifNoneMatch = request.headers["if-none-match"]
125
+ if (ifNoneMatch && ifNoneMatch !== compiledEtag) {
126
+ validity.isValid = false
127
+ validity.code = "COMPILED_FILE_ETAG_MISMATCH"
128
+ return validity
129
+ }
130
+ }
131
+
132
+ if (!clientCacheDisabled && compileCacheStrategy === "mtime") {
133
+ const stats = statSync(fileURLToPath(compiledFileUrl))
134
+ const compiledMtime = Math.floor(stats.mtimeMs)
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
+
147
+ if (
148
+ ifModifiedSinceDate &&
149
+ ifModifiedSinceDate < dateToSecondsPrecision(compiledMtime)
150
+ ) {
151
+ validity.isValid = false
152
+ validity.code = "COMPILED_FILE_MTIME_OUTDATED"
153
+ return validity
154
+ }
155
+ }
156
+
157
+ return validity
158
+ } catch (error) {
159
+ if (error && error.code === "ENOENT") {
160
+ validity.isValid = false
161
+ validity.code = "COMPILED_FILE_NOT_FOUND"
162
+ return validity
163
+ }
164
+ throw error
165
+ }
166
+ }
167
+
168
+ const validateSources = async ({ meta, metaJsonFileUrl }) => {
169
+ const sourcesValidity = { isValid: true }
170
+ await Promise.all(
171
+ meta.sources.map(async (source, index) => {
172
+ const sourceValidity = await validateSource({
173
+ metaJsonFileUrl,
174
+ source,
175
+ eTag: meta.sourcesEtag[index],
176
+ })
177
+ mergeValidity(sourcesValidity, source, sourceValidity)
178
+ }),
179
+ )
180
+ return sourcesValidity
181
+ }
182
+
183
+ const validateSource = async ({ metaJsonFileUrl, source, eTag }) => {
184
+ const validity = { isValid: true, data: {} }
185
+ const sourceFileUrl = resolveUrl(source, metaJsonFileUrl)
186
+
187
+ try {
188
+ const sourceBuffer = readFileSync(fileURLToPath(sourceFileUrl))
189
+ const sourceETag = bufferToEtag(sourceBuffer)
190
+ validity.data.sourceBuffer = sourceBuffer
191
+ validity.data.sourceETag = sourceETag
192
+
193
+ if (sourceETag !== eTag) {
194
+ validity.isValid = false
195
+ validity.code = "SOURCE_ETAG_MISMATCH"
196
+ return validity
197
+ }
198
+
199
+ return validity
200
+ } catch (e) {
201
+ if (e && e.code === "ENOENT") {
202
+ // missing source invalidates the cache because
203
+ // we cannot check its validity
204
+ // HOWEVER inside writeMeta we will check if a source can be found
205
+ // when it cannot we will not put it as a dependency
206
+ // to invalidate the cache.
207
+ // It is important because some files are constructed on other files
208
+ // which are not truly on the filesystem
209
+ // (IN theory the above happens only for convertCommonJsWithRollup because jsenv
210
+ // always have a concrete file especially to avoid that kind of thing)
211
+ validity.isValid = false
212
+ validity.code = "SOURCE_NOT_FOUND"
213
+ return validity
214
+ }
215
+ throw e
216
+ }
217
+ }
218
+
219
+ const validateAssets = async ({ metaJsonFileUrl, meta }) => {
220
+ const assetsValidity = { isValid: true }
221
+ await Promise.all(
222
+ meta.assets.map(async (asset, index) => {
223
+ const assetValidity = await validateAsset({
224
+ asset,
225
+ metaJsonFileUrl,
226
+ eTag: meta.assetsEtag[index],
227
+ })
228
+ mergeValidity(assetsValidity, asset, assetValidity)
229
+ }),
230
+ )
231
+ return assetsValidity
232
+ }
233
+
234
+ const validateAsset = async ({ asset, metaJsonFileUrl, eTag }) => {
235
+ const validity = { isValid: true, data: {} }
236
+ const assetFileUrl = resolveUrl(asset, metaJsonFileUrl)
237
+
238
+ try {
239
+ const assetBuffer = readFileSync(fileURLToPath(assetFileUrl))
240
+ const assetContentETag = bufferToEtag(assetBuffer)
241
+ validity.data.buffer = assetBuffer
242
+ validity.data.etag = assetContentETag
243
+
244
+ if (eTag !== assetContentETag) {
245
+ validity.isValid = false
246
+ validity.code = "ASSET_ETAG_MISMATCH"
247
+ return validity
248
+ }
249
+
250
+ return validity
251
+ } catch (error) {
252
+ if (error && error.code === "ENOENT") {
253
+ validity.isValid = false
254
+ validity.code = "ASSET_FILE_NOT_FOUND"
255
+ return validity
256
+ }
257
+ throw error
258
+ }
259
+ }
260
+
261
+ const dateToSecondsPrecision = (date) => {
262
+ const dateWithSecondsPrecision = new Date(date)
263
+ dateWithSecondsPrecision.setMilliseconds(0)
264
+ return dateWithSecondsPrecision
265
+ }