@jsenv/core 23.7.1 → 23.8.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 (34) hide show
  1. package/dist/jsenv_browser_system.js.map +1 -1
  2. package/dist/jsenv_compile_proxy.js.map +1 -1
  3. package/dist/jsenv_exploring_redirector.js.map +1 -1
  4. package/dist/jsenv_toolbar.js +0 -2
  5. package/dist/jsenv_toolbar.js.map +3 -3
  6. package/package.json +2 -2
  7. package/src/buildProject.js +300 -300
  8. package/src/execute.js +184 -184
  9. package/src/internal/browser-launcher/jsenv-browser-system.js +199 -199
  10. package/src/internal/compiling/babel_plugin_import_assertions.js +121 -100
  11. package/src/internal/compiling/babel_plugin_import_metadata.js +22 -0
  12. package/src/internal/compiling/babel_plugin_import_visitor.js +84 -0
  13. package/src/internal/compiling/compile-directory/getOrGenerateCompiledFile.js +268 -265
  14. package/src/internal/compiling/compile-directory/updateMeta.js +154 -150
  15. package/src/internal/compiling/compile-directory/validateCache.js +265 -265
  16. package/src/internal/compiling/compileFile.js +215 -194
  17. package/src/internal/compiling/compileHtml.js +550 -494
  18. package/src/internal/compiling/createCompiledFileService.js +291 -290
  19. package/src/internal/compiling/html_source_file_service.js +403 -379
  20. package/src/internal/compiling/js-compilation-service/jsenvTransform.js +270 -269
  21. package/src/internal/compiling/jsenvCompilerForHtml.js +300 -293
  22. package/src/internal/compiling/startCompileServer.js +1048 -1052
  23. package/src/internal/compiling/transformResultToCompilationResult.js +220 -217
  24. package/src/internal/executing/executePlan.js +183 -183
  25. package/src/internal/executing/launchAndExecute.js +458 -458
  26. package/src/internal/runtime/createBrowserRuntime/scanBrowserRuntimeFeatures.js +246 -246
  27. package/src/internal/runtime/createNodeRuntime/scanNodeRuntimeFeatures.js +112 -112
  28. package/src/internal/toolbar/toolbar.main.css +196 -188
  29. package/src/internal/toolbar/toolbar.main.js +227 -228
  30. package/src/internal/url_conversion.js +317 -317
  31. package/src/startExploring.js +309 -309
  32. package/src/internal/compiling/babel_plugin_transform_import_specifier.js +0 -86
  33. package/src/internal/toolbar/animation/animation.css +0 -5
  34. package/src/internal/toolbar/variant/variant.css +0 -3
@@ -0,0 +1,84 @@
1
+ /*
2
+ * Not meant to be used directly
3
+ * Will be used either to put import specifier in metadata
4
+ * or to transform import specifiers
5
+ *
6
+ * see also
7
+ * https://github.com/jamiebuilds/babel-handbook/blob/master/translations/en/plugin-handbook.md
8
+ * https://github.com/mjackson/babel-plugin-import-visitor
9
+ *
10
+ */
11
+
12
+ export const babelPluginImportVisitor = (babel, importVisitor = () => {}) => {
13
+ return {
14
+ name: "import-visitor",
15
+
16
+ // manipulateOptions(opts, parserOpts) {
17
+ // parserOpts.plugins.push(
18
+ // "dynamicImport",
19
+ // "exportDefaultFrom",
20
+ // "exportNamespaceFrom",
21
+ // "importMeta",
22
+ // )
23
+ // },
24
+
25
+ visitor: {
26
+ CallExpression: (path, state) => {
27
+ if (path.node.callee.type !== "Import") {
28
+ // Some other function call, not import();
29
+ return
30
+ }
31
+
32
+ if (path.node.arguments[0].type !== "StringLiteral") {
33
+ // Non-string argument, probably a variable or expression, e.g.
34
+ // import(moduleId)
35
+ // import('./' + moduleName)
36
+ return
37
+ }
38
+
39
+ importVisitor({
40
+ importPath: path,
41
+ specifierPath: path.get("arguments")[0],
42
+ state,
43
+ babel,
44
+ })
45
+ },
46
+
47
+ ExportAllDeclaration: (path, state) => {
48
+ importVisitor({
49
+ importPath: path,
50
+ specifierPath: path.get("source"),
51
+ state,
52
+ babel,
53
+ })
54
+ },
55
+
56
+ ExportNamedDeclaration: (path, state) => {
57
+ if (!path.node.source) {
58
+ // This export has no "source", so it's probably
59
+ // a local variable or function, e.g.
60
+ // export { varName }
61
+ // export const constName = ...
62
+ // export function funcName() {}
63
+ return
64
+ }
65
+
66
+ importVisitor({
67
+ importPath: path,
68
+ specifierPath: path.get("source"),
69
+ state,
70
+ babel,
71
+ })
72
+ },
73
+
74
+ ImportDeclaration: (path, state) => {
75
+ importVisitor({
76
+ importPath: path,
77
+ specifierPath: path.get("source"),
78
+ state,
79
+ babel,
80
+ })
81
+ },
82
+ },
83
+ }
84
+ }
@@ -1,265 +1,268 @@
1
- import { urlToFileSystemPath } from "@jsenv/filesystem"
2
- import { createDetailedMessage } from "@jsenv/logger"
3
- import { timeStart, timeFunction } from "@jsenv/server"
4
- import { readFileContent } from "./fs-optimized-for-cache.js"
5
- import { validateCache } from "./validateCache.js"
6
- import { getMetaJsonFileUrl } from "./compile-asset.js"
7
- import { createLockRegistry } from "./createLockRegistry.js"
8
-
9
- const { lockForRessource } = createLockRegistry()
10
-
11
- export const getOrGenerateCompiledFile = async ({
12
- logger,
13
-
14
- projectDirectoryUrl,
15
- originalFileUrl,
16
- compiledFileUrl = originalFileUrl,
17
- compileCacheStrategy,
18
- compileCacheSourcesValidation,
19
- compileCacheAssetsValidation,
20
- fileContentFallback,
21
- request,
22
- compile,
23
- }) => {
24
- if (typeof projectDirectoryUrl !== "string") {
25
- throw new TypeError(
26
- `projectDirectoryUrl must be a string, got ${projectDirectoryUrl}`,
27
- )
28
- }
29
- if (typeof originalFileUrl !== "string") {
30
- throw new TypeError(
31
- `originalFileUrl must be a string, got ${originalFileUrl}`,
32
- )
33
- }
34
- if (!originalFileUrl.startsWith(projectDirectoryUrl)) {
35
- throw new Error(
36
- createDetailedMessage(`origin file must be inside project`, {
37
- ["original file url"]: originalFileUrl,
38
- ["project directory url"]: projectDirectoryUrl,
39
- }),
40
- )
41
- }
42
- if (typeof compiledFileUrl !== "string") {
43
- throw new TypeError(
44
- `compiledFileUrl must be a string, got ${compiledFileUrl}`,
45
- )
46
- }
47
- if (!compiledFileUrl.startsWith(projectDirectoryUrl)) {
48
- throw new Error(
49
- createDetailedMessage(`compiled file must be inside project`, {
50
- ["compiled file url"]: compiledFileUrl,
51
- ["project directory url"]: projectDirectoryUrl,
52
- }),
53
- )
54
- }
55
- if (typeof compile !== "function") {
56
- throw new TypeError(`compile must be a function, got ${compile}`)
57
- }
58
-
59
- const lockTimeEnd = timeStart("lock")
60
- return startAsap(
61
- async () => {
62
- const lockTiming = lockTimeEnd()
63
- const { meta, compileResult, compileResultStatus, timing } =
64
- await computeCompileReport({
65
- originalFileUrl,
66
- compiledFileUrl,
67
- compile,
68
- fileContentFallback,
69
- compileCacheStrategy,
70
- compileCacheSourcesValidation,
71
- compileCacheAssetsValidation,
72
- request,
73
- logger,
74
- })
75
-
76
- return {
77
- meta,
78
- compileResult,
79
- compileResultStatus,
80
- timing: {
81
- ...lockTiming,
82
- ...timing,
83
- },
84
- }
85
- },
86
- {
87
- compiledFileUrl,
88
- logger,
89
- },
90
- )
91
- }
92
-
93
- const computeCompileReport = async ({
94
- originalFileUrl,
95
- compiledFileUrl,
96
- compile,
97
- fileContentFallback,
98
- compileCacheStrategy,
99
- compileCacheSourcesValidation,
100
- compileCacheAssetsValidation,
101
- request,
102
- logger,
103
- }) => {
104
- const [readCacheTiming, cacheValidity] = await timeFunction(
105
- "read cache",
106
- () => {
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
- // }
117
- return validateCache({
118
- logger,
119
- compiledFileUrl,
120
- compileCacheStrategy,
121
- compileCacheSourcesValidation,
122
- compileCacheAssetsValidation,
123
- request,
124
- })
125
- },
126
- )
127
-
128
- if (!cacheValidity.isValid) {
129
- if (cacheValidity.code === "SOURCES_EMPTY") {
130
- logger.warn(`WARNING: meta.sources is empty for ${compiledFileUrl}`)
131
- }
132
-
133
- const metaIsValid = cacheValidity.meta.isValid
134
-
135
- const [compileTiming, compileResult] = await timeFunction("compile", () =>
136
- callCompile({
137
- logger,
138
- originalFileUrl,
139
- fileContentFallback,
140
- compile,
141
- }),
142
- )
143
-
144
- return {
145
- meta: metaIsValid ? cacheValidity.meta.data : null,
146
- compileResult,
147
- compileResultStatus: metaIsValid ? "updated" : "created",
148
- timing: {
149
- ...readCacheTiming,
150
- ...compileTiming,
151
- },
152
- }
153
- }
154
-
155
- const meta = cacheValidity.meta.data
156
- const { contentType, sources, assets } = meta
157
- return {
158
- meta,
159
- compileResult: {
160
- compiledSource: String(
161
- cacheValidity.compiledFile.data.compiledSourceBuffer,
162
- ),
163
- compiledEtag: cacheValidity.compiledFile.data.compiledEtag,
164
- compiledMtime: cacheValidity.compiledFile.data.compiledMtime,
165
- contentType,
166
- sources,
167
- assets,
168
- },
169
- compileResultStatus: "cached",
170
- timing: {
171
- ...readCacheTiming,
172
- },
173
- }
174
- }
175
-
176
- const callCompile = async ({
177
- logger,
178
- originalFileUrl,
179
- fileContentFallback,
180
- compile,
181
- }) => {
182
- logger.debug(`compile ${originalFileUrl}`)
183
-
184
- const codeBeforeCompile =
185
- compile.length === 0
186
- ? ""
187
- : await getCodeToCompile({ originalFileUrl, fileContentFallback })
188
-
189
- const compileReturnValue = await compile({
190
- code: codeBeforeCompile,
191
- map: undefined,
192
- })
193
- if (typeof compileReturnValue !== "object" || compileReturnValue === null) {
194
- throw new TypeError(
195
- `compile must return an object, got ${compileReturnValue}`,
196
- )
197
- }
198
- const {
199
- contentType,
200
- compiledSource,
201
- sources = [],
202
- sourcesContent = [],
203
- assets = [],
204
- assetsContent = [],
205
- responseHeaders,
206
- } = compileReturnValue
207
- if (typeof contentType !== "string") {
208
- throw new TypeError(
209
- `compile must return a contentType string, got ${contentType}`,
210
- )
211
- }
212
- if (typeof compiledSource !== "string") {
213
- throw new TypeError(
214
- `compile must return a compiledSource string, got ${compiledSource}`,
215
- )
216
- }
217
-
218
- return {
219
- contentType,
220
- compiledSource,
221
- sources,
222
- sourcesContent,
223
- assets,
224
- assetsContent,
225
- responseHeaders,
226
- }
227
- }
228
-
229
- const getCodeToCompile = async ({ originalFileUrl, fileContentFallback }) => {
230
- let fileContent
231
- if (fileContentFallback) {
232
- try {
233
- fileContent = await readFileContent(originalFileUrl)
234
- } catch (e) {
235
- if (e.code === "ENOENT") {
236
- fileContent = await fileContentFallback()
237
- } else {
238
- throw e
239
- }
240
- }
241
- } else {
242
- fileContent = await readFileContent(originalFileUrl)
243
- }
244
- return fileContent
245
- }
246
-
247
- const startAsap = async (fn, { logger, compiledFileUrl }) => {
248
- const metaJsonFileUrl = getMetaJsonFileUrl(compiledFileUrl)
249
- const metaJsonFilePath = urlToFileSystemPath(metaJsonFileUrl)
250
-
251
- logger.debug(`lock ${metaJsonFilePath}`)
252
- // in case this process try to concurrently access meta we wait for previous to be done
253
- const unlockLocal = await lockForRessource(metaJsonFilePath)
254
-
255
- let unlockInterProcessLock = () => {}
256
-
257
- try {
258
- return await fn()
259
- } finally {
260
- // we want to unlock in case of error too
261
- logger.debug(`unlock ${metaJsonFilePath}`)
262
- unlockLocal()
263
- unlockInterProcessLock()
264
- }
265
- }
1
+ import { urlToFileSystemPath } from "@jsenv/filesystem"
2
+ import { createDetailedMessage } from "@jsenv/logger"
3
+ import { timeStart, timeFunction } from "@jsenv/server"
4
+ import { readFileContent } from "./fs-optimized-for-cache.js"
5
+ import { validateCache } from "./validateCache.js"
6
+ import { getMetaJsonFileUrl } from "./compile-asset.js"
7
+ import { createLockRegistry } from "./createLockRegistry.js"
8
+
9
+ const { lockForRessource } = createLockRegistry()
10
+
11
+ export const getOrGenerateCompiledFile = async ({
12
+ logger,
13
+
14
+ projectDirectoryUrl,
15
+ originalFileUrl,
16
+ compiledFileUrl = originalFileUrl,
17
+ compileCacheStrategy,
18
+ compileCacheSourcesValidation,
19
+ compileCacheAssetsValidation,
20
+ fileContentFallback,
21
+ request,
22
+ compile,
23
+ }) => {
24
+ if (typeof projectDirectoryUrl !== "string") {
25
+ throw new TypeError(
26
+ `projectDirectoryUrl must be a string, got ${projectDirectoryUrl}`,
27
+ )
28
+ }
29
+ if (typeof originalFileUrl !== "string") {
30
+ throw new TypeError(
31
+ `originalFileUrl must be a string, got ${originalFileUrl}`,
32
+ )
33
+ }
34
+ if (!originalFileUrl.startsWith(projectDirectoryUrl)) {
35
+ throw new Error(
36
+ createDetailedMessage(`origin file must be inside project`, {
37
+ ["original file url"]: originalFileUrl,
38
+ ["project directory url"]: projectDirectoryUrl,
39
+ }),
40
+ )
41
+ }
42
+ if (typeof compiledFileUrl !== "string") {
43
+ throw new TypeError(
44
+ `compiledFileUrl must be a string, got ${compiledFileUrl}`,
45
+ )
46
+ }
47
+ if (!compiledFileUrl.startsWith(projectDirectoryUrl)) {
48
+ throw new Error(
49
+ createDetailedMessage(`compiled file must be inside project`, {
50
+ ["compiled file url"]: compiledFileUrl,
51
+ ["project directory url"]: projectDirectoryUrl,
52
+ }),
53
+ )
54
+ }
55
+ if (typeof compile !== "function") {
56
+ throw new TypeError(`compile must be a function, got ${compile}`)
57
+ }
58
+
59
+ const lockTimeEnd = timeStart("lock")
60
+ return startAsap(
61
+ async () => {
62
+ const lockTiming = lockTimeEnd()
63
+ const { meta, compileResult, compileResultStatus, timing } =
64
+ await computeCompileReport({
65
+ originalFileUrl,
66
+ compiledFileUrl,
67
+ compile,
68
+ fileContentFallback,
69
+ compileCacheStrategy,
70
+ compileCacheSourcesValidation,
71
+ compileCacheAssetsValidation,
72
+ request,
73
+ logger,
74
+ })
75
+
76
+ return {
77
+ meta,
78
+ compileResult,
79
+ compileResultStatus,
80
+ timing: {
81
+ ...lockTiming,
82
+ ...timing,
83
+ },
84
+ }
85
+ },
86
+ {
87
+ compiledFileUrl,
88
+ logger,
89
+ },
90
+ )
91
+ }
92
+
93
+ const computeCompileReport = async ({
94
+ originalFileUrl,
95
+ compiledFileUrl,
96
+ compile,
97
+ fileContentFallback,
98
+ compileCacheStrategy,
99
+ compileCacheSourcesValidation,
100
+ compileCacheAssetsValidation,
101
+ request,
102
+ logger,
103
+ }) => {
104
+ const [readCacheTiming, cacheValidity] = await timeFunction(
105
+ "read cache",
106
+ () => {
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
+ // }
117
+ return validateCache({
118
+ logger,
119
+ compiledFileUrl,
120
+ compileCacheStrategy,
121
+ compileCacheSourcesValidation,
122
+ compileCacheAssetsValidation,
123
+ request,
124
+ })
125
+ },
126
+ )
127
+
128
+ if (!cacheValidity.isValid) {
129
+ if (cacheValidity.code === "SOURCES_EMPTY") {
130
+ logger.warn(`WARNING: meta.sources is empty for ${compiledFileUrl}`)
131
+ }
132
+
133
+ const metaIsValid = cacheValidity.meta.isValid
134
+
135
+ const [compileTiming, compileResult] = await timeFunction("compile", () =>
136
+ callCompile({
137
+ logger,
138
+ originalFileUrl,
139
+ fileContentFallback,
140
+ compile,
141
+ }),
142
+ )
143
+
144
+ return {
145
+ meta: metaIsValid ? cacheValidity.meta.data : null,
146
+ compileResult,
147
+ compileResultStatus: metaIsValid ? "updated" : "created",
148
+ timing: {
149
+ ...readCacheTiming,
150
+ ...compileTiming,
151
+ },
152
+ }
153
+ }
154
+
155
+ const meta = cacheValidity.meta.data
156
+ const { contentType, sources, assets, dependencies } = meta
157
+ return {
158
+ meta,
159
+ compileResult: {
160
+ compiledSource: String(
161
+ cacheValidity.compiledFile.data.compiledSourceBuffer,
162
+ ),
163
+ compiledEtag: cacheValidity.compiledFile.data.compiledEtag,
164
+ compiledMtime: cacheValidity.compiledFile.data.compiledMtime,
165
+ contentType,
166
+ sources,
167
+ assets,
168
+ dependencies,
169
+ },
170
+ compileResultStatus: "cached",
171
+ timing: {
172
+ ...readCacheTiming,
173
+ },
174
+ }
175
+ }
176
+
177
+ const callCompile = async ({
178
+ logger,
179
+ originalFileUrl,
180
+ fileContentFallback,
181
+ compile,
182
+ }) => {
183
+ logger.debug(`compile ${originalFileUrl}`)
184
+
185
+ const codeBeforeCompile =
186
+ compile.length === 0
187
+ ? ""
188
+ : await getCodeToCompile({ originalFileUrl, fileContentFallback })
189
+
190
+ const compileReturnValue = await compile({
191
+ code: codeBeforeCompile,
192
+ map: undefined,
193
+ })
194
+ if (typeof compileReturnValue !== "object" || compileReturnValue === null) {
195
+ throw new TypeError(
196
+ `compile must return an object, got ${compileReturnValue}`,
197
+ )
198
+ }
199
+ const {
200
+ contentType,
201
+ compiledSource,
202
+ sources = [],
203
+ sourcesContent = [],
204
+ assets = [],
205
+ assetsContent = [],
206
+ dependencies = [],
207
+ responseHeaders,
208
+ } = compileReturnValue
209
+ if (typeof contentType !== "string") {
210
+ throw new TypeError(
211
+ `compile must return a contentType string, got ${contentType}`,
212
+ )
213
+ }
214
+ if (typeof compiledSource !== "string") {
215
+ throw new TypeError(
216
+ `compile must return a compiledSource string, got ${compiledSource}`,
217
+ )
218
+ }
219
+
220
+ return {
221
+ contentType,
222
+ compiledSource,
223
+ sources,
224
+ sourcesContent,
225
+ assets,
226
+ assetsContent,
227
+ dependencies,
228
+ responseHeaders,
229
+ }
230
+ }
231
+
232
+ const getCodeToCompile = async ({ originalFileUrl, fileContentFallback }) => {
233
+ let fileContent
234
+ if (fileContentFallback) {
235
+ try {
236
+ fileContent = await readFileContent(originalFileUrl)
237
+ } catch (e) {
238
+ if (e.code === "ENOENT") {
239
+ fileContent = await fileContentFallback()
240
+ } else {
241
+ throw e
242
+ }
243
+ }
244
+ } else {
245
+ fileContent = await readFileContent(originalFileUrl)
246
+ }
247
+ return fileContent
248
+ }
249
+
250
+ const startAsap = async (fn, { logger, compiledFileUrl }) => {
251
+ const metaJsonFileUrl = getMetaJsonFileUrl(compiledFileUrl)
252
+ const metaJsonFilePath = urlToFileSystemPath(metaJsonFileUrl)
253
+
254
+ logger.debug(`lock ${metaJsonFilePath}`)
255
+ // in case this process try to concurrently access meta we wait for previous to be done
256
+ const unlockLocal = await lockForRessource(metaJsonFilePath)
257
+
258
+ let unlockInterProcessLock = () => {}
259
+
260
+ try {
261
+ return await fn()
262
+ } finally {
263
+ // we want to unlock in case of error too
264
+ logger.debug(`unlock ${metaJsonFilePath}`)
265
+ unlockLocal()
266
+ unlockInterProcessLock()
267
+ }
268
+ }