@jsenv/core 27.4.0 → 27.5.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.
- package/dist/js/autoreload.js +359 -0
- package/dist/js/execute_using_dynamic_import.js +1 -1
- package/dist/js/html_supervisor_installer.js +221 -73
- package/dist/js/html_supervisor_setup.js +3 -4
- package/dist/js/new_stylesheet.js +26 -58
- package/dist/js/server_events_client.js +307 -0
- package/dist/main.js +7483 -7281
- package/package.json +11 -10
- package/{README.md → readme.md} +8 -9
- package/src/build/build.js +12 -16
- package/src/build/start_build_server.js +24 -28
- package/src/dev/start_dev_server.js +30 -94
- package/src/execute/execute.js +17 -35
- package/src/omega/errors.js +20 -18
- package/src/omega/kitchen.js +7 -6
- package/src/omega/omega_server.js +96 -127
- package/src/omega/server/file_service.js +247 -46
- package/src/omega/url_graph.js +33 -20
- package/src/plugins/autoreload/client/autoreload.js +201 -0
- package/src/plugins/autoreload/{dev_sse/client → client}/autoreload_preference.js +0 -0
- package/src/plugins/autoreload/{dev_sse/client → client}/reload.js +29 -10
- package/src/plugins/autoreload/{dev_sse/client → client}/url_helpers.js +0 -0
- package/src/plugins/autoreload/jsenv_plugin_autoreload.js +4 -4
- package/src/plugins/autoreload/{dev_sse/jsenv_plugin_dev_sse_client.js → jsenv_plugin_autoreload_client.js} +8 -8
- package/src/plugins/autoreload/jsenv_plugin_autoreload_server.js +196 -0
- package/src/{dev/plugins → plugins}/explorer/client/explorer.html +0 -0
- package/src/{dev/plugins → plugins}/explorer/client/jsenv.png +0 -0
- package/src/{dev/plugins → plugins}/explorer/jsenv_plugin_explorer.js +1 -3
- package/src/plugins/html_supervisor/client/{error_in_document.js → error_overlay.js} +73 -17
- package/src/plugins/html_supervisor/client/html_supervisor_installer.js +127 -54
- package/src/plugins/html_supervisor/client/html_supervisor_setup.js +3 -4
- package/src/plugins/html_supervisor/jsenv_plugin_html_supervisor.js +19 -12
- package/src/plugins/inline/jsenv_plugin_html_inline_content.js +97 -117
- package/src/plugins/node_esm_resolution/jsenv_plugin_node_esm_resolution.js +66 -58
- package/src/plugins/plugin_controller.js +102 -67
- package/src/plugins/plugins.js +10 -8
- package/src/{helpers/event_source/event_source.js → plugins/server_events/client/event_source_connection.js} +102 -31
- package/src/plugins/server_events/client/server_events_client.js +17 -0
- package/src/plugins/server_events/jsenv_plugin_server_events_client_injection.js +48 -0
- package/src/plugins/server_events/server_events_dispatcher.js +69 -0
- package/src/{dev/plugins → plugins}/toolbar/client/animation/toolbar_animation.js +0 -0
- package/src/{dev/plugins → plugins}/toolbar/client/eventsource/eventsource.css +0 -0
- package/src/{dev/plugins → plugins}/toolbar/client/eventsource/toolbar_eventsource.js +0 -0
- package/src/{dev/plugins → plugins}/toolbar/client/execution/execution.css +0 -0
- package/src/{dev/plugins → plugins}/toolbar/client/execution/toolbar_execution.js +0 -0
- package/src/{dev/plugins → plugins}/toolbar/client/focus/focus.css +0 -0
- package/src/{dev/plugins → plugins}/toolbar/client/focus/toolbar_focus.js +0 -0
- package/src/{dev/plugins → plugins}/toolbar/client/jsenv_logo.svg +0 -0
- package/src/{dev/plugins → plugins}/toolbar/client/notification/toolbar_notification.js +0 -0
- package/src/{dev/plugins → plugins}/toolbar/client/responsive/overflow_menu.css +0 -0
- package/src/{dev/plugins → plugins}/toolbar/client/responsive/toolbar_responsive.js +0 -0
- package/src/{dev/plugins → plugins}/toolbar/client/settings/settings.css +0 -0
- package/src/{dev/plugins → plugins}/toolbar/client/settings/toolbar_settings.js +0 -0
- package/src/{dev/plugins → plugins}/toolbar/client/theme/jsenv_theme.css +0 -0
- package/src/{dev/plugins → plugins}/toolbar/client/theme/light_theme.css +0 -0
- package/src/{dev/plugins → plugins}/toolbar/client/theme/toolbar_theme.js +0 -0
- package/src/{dev/plugins → plugins}/toolbar/client/toolbar.html +0 -0
- package/src/{dev/plugins → plugins}/toolbar/client/toolbar_injector.js +0 -0
- package/src/{dev/plugins → plugins}/toolbar/client/toolbar_main.css +0 -0
- package/src/{dev/plugins → plugins}/toolbar/client/toolbar_main.js +0 -0
- package/src/{dev/plugins → plugins}/toolbar/client/tooltip/tooltip.css +0 -0
- package/src/{dev/plugins → plugins}/toolbar/client/tooltip/tooltip.js +0 -0
- package/src/{dev/plugins → plugins}/toolbar/client/util/animation.js +0 -0
- package/src/{dev/plugins → plugins}/toolbar/client/util/dom.js +0 -0
- package/src/{dev/plugins → plugins}/toolbar/client/util/fetch_using_xhr.js +0 -0
- package/src/{dev/plugins → plugins}/toolbar/client/util/fetching.js +0 -0
- package/src/{dev/plugins → plugins}/toolbar/client/util/iframe_to_parent_href.js +0 -0
- package/src/{dev/plugins → plugins}/toolbar/client/util/jsenv_logger.js +0 -0
- package/src/{dev/plugins → plugins}/toolbar/client/util/preferences.js +0 -0
- package/src/{dev/plugins → plugins}/toolbar/client/util/responsive.js +0 -0
- package/src/{dev/plugins → plugins}/toolbar/client/util/util.js +0 -0
- package/src/{dev/plugins → plugins}/toolbar/client/variant/variant.js +0 -0
- package/src/{dev/plugins → plugins}/toolbar/jsenv_plugin_toolbar.js +0 -0
- package/src/plugins/transpilation/as_js_classic/jsenv_plugin_as_js_classic_html.js +4 -3
- package/src/plugins/transpilation/babel/new_stylesheet/client/new_stylesheet.js +25 -55
- package/src/plugins/transpilation/import_assertions/jsenv_plugin_import_assertions.js +44 -24
- package/src/plugins/transpilation/jsenv_plugin_transpilation.js +6 -1
- package/src/plugins/url_analysis/html/html_urls.js +8 -8
- package/src/test/execute_plan.js +36 -54
- package/src/test/execute_test_plan.js +2 -2
- package/dist/js/event_source_client.js +0 -549
- package/src/helpers/event_source/sse_service.js +0 -53
- package/src/plugins/autoreload/dev_sse/client/event_source_client.js +0 -193
- package/src/plugins/autoreload/dev_sse/jsenv_plugin_dev_sse_server.js +0 -192
|
@@ -20,129 +20,109 @@ export const jsenvPluginHtmlInlineContent = ({ analyzeConvertedScripts }) => {
|
|
|
20
20
|
html: async (urlInfo, context) => {
|
|
21
21
|
const htmlAst = parseHtmlString(urlInfo.content)
|
|
22
22
|
const actions = []
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
23
|
+
visitHtmlNodes(htmlAst, {
|
|
24
|
+
style: (styleNode) => {
|
|
25
|
+
const styleNodeText = getHtmlNodeText(styleNode)
|
|
26
|
+
if (!styleNodeText) {
|
|
27
|
+
return
|
|
28
|
+
}
|
|
29
|
+
actions.push(async () => {
|
|
30
|
+
const { line, column, lineEnd, columnEnd, isOriginal } =
|
|
31
|
+
getHtmlNodePosition(styleNode, {
|
|
32
|
+
preferOriginal: true,
|
|
33
|
+
})
|
|
34
|
+
const inlineStyleUrl = generateInlineContentUrl({
|
|
35
|
+
url: urlInfo.url,
|
|
36
|
+
extension: ".css",
|
|
37
|
+
line,
|
|
38
|
+
column,
|
|
39
|
+
lineEnd,
|
|
40
|
+
columnEnd,
|
|
32
41
|
})
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
specifierColumn: column,
|
|
51
|
-
specifier: inlineStyleUrl,
|
|
52
|
-
contentType: "text/css",
|
|
53
|
-
content: htmlNodeText,
|
|
42
|
+
const [inlineStyleReference, inlineStyleUrlInfo] =
|
|
43
|
+
context.referenceUtils.foundInline({
|
|
44
|
+
node: styleNode,
|
|
45
|
+
type: "link_href",
|
|
46
|
+
expectedType: "css",
|
|
47
|
+
isOriginalPosition: isOriginal,
|
|
48
|
+
// we remove 1 to the line because imagine the following html:
|
|
49
|
+
// <style>body { color: red; }</style>
|
|
50
|
+
// -> content starts same line as <style>
|
|
51
|
+
specifierLine: line - 1,
|
|
52
|
+
specifierColumn: column,
|
|
53
|
+
specifier: inlineStyleUrl,
|
|
54
|
+
contentType: "text/css",
|
|
55
|
+
content: styleNodeText,
|
|
56
|
+
})
|
|
57
|
+
await context.cook(inlineStyleUrlInfo, {
|
|
58
|
+
reference: inlineStyleReference,
|
|
54
59
|
})
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
setHtmlNodeText(node, inlineStyleUrlInfo.content)
|
|
59
|
-
setHtmlNodeAttributes(node, {
|
|
60
|
-
"generated-by": "jsenv:html_inline_content",
|
|
61
|
-
})
|
|
62
|
-
})
|
|
63
|
-
}
|
|
64
|
-
const handleInlineScript = (node) => {
|
|
65
|
-
const htmlNodeText = getHtmlNodeText(node)
|
|
66
|
-
if (!htmlNodeText) {
|
|
67
|
-
return
|
|
68
|
-
}
|
|
69
|
-
// If the inline script was already handled by an other plugin, ignore it
|
|
70
|
-
// - we want to preserve inline scripts generated by html supervisor during dev
|
|
71
|
-
// - we want to avoid cooking twice a script during build
|
|
72
|
-
const generatedBy = getHtmlNodeAttribute(node, "generated-by")
|
|
73
|
-
if (
|
|
74
|
-
generatedBy === "jsenv:as_js_classic_html" &&
|
|
75
|
-
!analyzeConvertedScripts
|
|
76
|
-
) {
|
|
77
|
-
return
|
|
78
|
-
}
|
|
79
|
-
if (generatedBy === "jsenv:html_supervisor") {
|
|
80
|
-
return
|
|
81
|
-
}
|
|
82
|
-
actions.push(async () => {
|
|
83
|
-
const scriptCategory = analyzeScriptNode(node)
|
|
84
|
-
const { line, column, lineEnd, columnEnd, isOriginal } =
|
|
85
|
-
getHtmlNodePosition(node, {
|
|
86
|
-
preferOriginal: true,
|
|
60
|
+
setHtmlNodeText(styleNode, inlineStyleUrlInfo.content)
|
|
61
|
+
setHtmlNodeAttributes(styleNode, {
|
|
62
|
+
"generated-by": "jsenv:html_inline_content",
|
|
87
63
|
})
|
|
88
|
-
// from MDN about [type] attribute:
|
|
89
|
-
// "Any other value: The embedded content is treated as a data block
|
|
90
|
-
// which won't be processed by the browser. Developers must use a valid MIME type
|
|
91
|
-
// that is not a JavaScript MIME type to denote data blocks.
|
|
92
|
-
// The src attribute will be ignored."
|
|
93
|
-
// https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script#attr-type
|
|
94
|
-
const isJs =
|
|
95
|
-
scriptCategory === "classic" || scriptCategory === "module"
|
|
96
|
-
const isImportmap = scriptCategory === "importmap"
|
|
97
|
-
const contentType = isJs
|
|
98
|
-
? "text/javascript"
|
|
99
|
-
: isImportmap
|
|
100
|
-
? "application/importmap+json"
|
|
101
|
-
: scriptCategory
|
|
102
|
-
|
|
103
|
-
let inlineScriptUrl = generateInlineContentUrl({
|
|
104
|
-
url: urlInfo.url,
|
|
105
|
-
extension: CONTENT_TYPE.asFileExtension(contentType),
|
|
106
|
-
line,
|
|
107
|
-
column,
|
|
108
|
-
lineEnd,
|
|
109
|
-
columnEnd,
|
|
110
64
|
})
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
65
|
+
},
|
|
66
|
+
script: (scriptNode) => {
|
|
67
|
+
const scriptNodeText = getHtmlNodeText(scriptNode)
|
|
68
|
+
if (!scriptNodeText) {
|
|
69
|
+
return
|
|
70
|
+
}
|
|
71
|
+
// If the inline script was already handled by an other plugin, ignore it
|
|
72
|
+
// - we want to preserve inline scripts generated by html supervisor during dev
|
|
73
|
+
// - we want to avoid cooking twice a script during build
|
|
74
|
+
const generatedBy = getHtmlNodeAttribute(scriptNode, "generated-by")
|
|
75
|
+
if (
|
|
76
|
+
generatedBy === "jsenv:as_js_classic_html" &&
|
|
77
|
+
!analyzeConvertedScripts
|
|
78
|
+
) {
|
|
79
|
+
return
|
|
80
|
+
}
|
|
81
|
+
if (generatedBy === "jsenv:html_supervisor") {
|
|
82
|
+
return
|
|
83
|
+
}
|
|
84
|
+
actions.push(async () => {
|
|
85
|
+
const { type, contentType, extension } =
|
|
86
|
+
analyzeScriptNode(scriptNode)
|
|
87
|
+
const { line, column, lineEnd, columnEnd, isOriginal } =
|
|
88
|
+
getHtmlNodePosition(scriptNode, {
|
|
89
|
+
preferOriginal: true,
|
|
90
|
+
})
|
|
91
|
+
let inlineScriptUrl = generateInlineContentUrl({
|
|
92
|
+
url: urlInfo.url,
|
|
93
|
+
extension:
|
|
94
|
+
extension || CONTENT_TYPE.asFileExtension(contentType),
|
|
95
|
+
line,
|
|
96
|
+
column,
|
|
97
|
+
lineEnd,
|
|
98
|
+
columnEnd,
|
|
99
|
+
})
|
|
100
|
+
const [inlineScriptReference, inlineScriptUrlInfo] =
|
|
101
|
+
context.referenceUtils.foundInline({
|
|
102
|
+
node: scriptNode,
|
|
103
|
+
type: "script_src",
|
|
104
|
+
expectedType: type,
|
|
105
|
+
// we remove 1 to the line because imagine the following html:
|
|
106
|
+
// <script>console.log('ok')</script>
|
|
107
|
+
// -> content starts same line as <script>
|
|
108
|
+
specifierLine: line - 1,
|
|
109
|
+
specifierColumn: column,
|
|
110
|
+
isOriginalPosition: isOriginal,
|
|
111
|
+
specifier: inlineScriptUrl,
|
|
112
|
+
contentType,
|
|
113
|
+
content: scriptNodeText,
|
|
114
|
+
})
|
|
115
|
+
await context.cook(inlineScriptUrlInfo, {
|
|
116
|
+
reference: inlineScriptReference,
|
|
117
|
+
})
|
|
118
|
+
setHtmlNodeText(scriptNode, inlineScriptUrlInfo.content)
|
|
119
|
+
setHtmlNodeAttributes(scriptNode, {
|
|
120
|
+
"generated-by": "jsenv:html_inline_content",
|
|
121
|
+
...(extension
|
|
122
|
+
? { type: type === "js_module" ? "module" : undefined }
|
|
123
|
+
: {}),
|
|
129
124
|
})
|
|
130
|
-
|
|
131
|
-
await context.cook(inlineScriptUrlInfo, {
|
|
132
|
-
reference: inlineScriptReference,
|
|
133
|
-
})
|
|
134
|
-
setHtmlNodeText(node, inlineScriptUrlInfo.content)
|
|
135
|
-
setHtmlNodeAttributes(node, {
|
|
136
|
-
"generated-by": "jsenv:html_inline_content",
|
|
137
125
|
})
|
|
138
|
-
})
|
|
139
|
-
}
|
|
140
|
-
visitHtmlNodes(htmlAst, {
|
|
141
|
-
style: (node) => {
|
|
142
|
-
handleInlineStyle(node)
|
|
143
|
-
},
|
|
144
|
-
script: (node) => {
|
|
145
|
-
handleInlineScript(node)
|
|
146
126
|
},
|
|
147
127
|
})
|
|
148
128
|
if (actions.length === 0) {
|
|
@@ -17,72 +17,78 @@ import {
|
|
|
17
17
|
} from "@jsenv/node-esm-resolution"
|
|
18
18
|
|
|
19
19
|
export const jsenvPluginNodeEsmResolution = ({
|
|
20
|
-
rootDirectoryUrl,
|
|
21
|
-
urlGraph,
|
|
22
|
-
runtimeCompat,
|
|
23
20
|
packageConditions,
|
|
24
21
|
filesInvalidatingCache = ["package.json", "package-lock.json"],
|
|
25
22
|
}) => {
|
|
26
|
-
const nodeRuntimeEnabled = Object.keys(runtimeCompat).includes("node")
|
|
27
|
-
// https://nodejs.org/api/esm.html#resolver-algorithm-specification
|
|
28
|
-
packageConditions = packageConditions || [
|
|
29
|
-
...readCustomConditionsFromProcessArgs(),
|
|
30
|
-
nodeRuntimeEnabled ? "node" : "browser",
|
|
31
|
-
"import",
|
|
32
|
-
]
|
|
33
|
-
|
|
34
|
-
const packageScopesCache = new Map()
|
|
35
|
-
const lookupPackageScope = (url) => {
|
|
36
|
-
const fromCache = packageScopesCache.get(url)
|
|
37
|
-
if (fromCache) {
|
|
38
|
-
return fromCache
|
|
39
|
-
}
|
|
40
|
-
const packageScope = defaultLookupPackageScope(url)
|
|
41
|
-
packageScopesCache.set(url, packageScope)
|
|
42
|
-
return packageScope
|
|
43
|
-
}
|
|
44
|
-
const packageJsonsCache = new Map()
|
|
45
|
-
const readPackageJson = (url) => {
|
|
46
|
-
const fromCache = packageJsonsCache.get(url)
|
|
47
|
-
if (fromCache) {
|
|
48
|
-
return fromCache
|
|
49
|
-
}
|
|
50
|
-
const packageJson = defaultReadPackageJson(url)
|
|
51
|
-
packageJsonsCache.set(url, packageJson)
|
|
52
|
-
return packageJson
|
|
53
|
-
}
|
|
54
|
-
|
|
55
23
|
const unregisters = []
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
packageJsonsCache.clear()
|
|
59
|
-
urlGraph.urlInfoMap.forEach((urlInfo) => {
|
|
60
|
-
if (urlInfo.dependsOnPackageJson) {
|
|
61
|
-
urlGraph.considerModified(urlInfo)
|
|
62
|
-
}
|
|
63
|
-
})
|
|
64
|
-
}
|
|
65
|
-
filesInvalidatingCache.forEach((file) => {
|
|
66
|
-
const unregister = registerFileLifecycle(new URL(file, rootDirectoryUrl), {
|
|
67
|
-
added: () => {
|
|
68
|
-
onFileChange()
|
|
69
|
-
},
|
|
70
|
-
updated: () => {
|
|
71
|
-
onFileChange()
|
|
72
|
-
},
|
|
73
|
-
removed: () => {
|
|
74
|
-
onFileChange()
|
|
75
|
-
},
|
|
76
|
-
keepProcessAlive: false,
|
|
77
|
-
})
|
|
78
|
-
unregisters.push(unregister)
|
|
79
|
-
})
|
|
24
|
+
let lookupPackageScope // defined in "init"
|
|
25
|
+
let readPackageJson // defined in "init"
|
|
80
26
|
|
|
81
27
|
return {
|
|
82
28
|
name: "jsenv:node_esm_resolution",
|
|
83
29
|
appliesDuring: "*",
|
|
30
|
+
init: ({ rootDirectoryUrl, scenario, runtimeCompat, urlGraph }) => {
|
|
31
|
+
const nodeRuntimeEnabled = Object.keys(runtimeCompat).includes("node")
|
|
32
|
+
// https://nodejs.org/api/esm.html#resolver-algorithm-specification
|
|
33
|
+
packageConditions = packageConditions || [
|
|
34
|
+
...readCustomConditionsFromProcessArgs(),
|
|
35
|
+
nodeRuntimeEnabled ? "node" : "browser",
|
|
36
|
+
"import",
|
|
37
|
+
]
|
|
38
|
+
|
|
39
|
+
const packageScopesCache = new Map()
|
|
40
|
+
lookupPackageScope = (url) => {
|
|
41
|
+
const fromCache = packageScopesCache.get(url)
|
|
42
|
+
if (fromCache) {
|
|
43
|
+
return fromCache
|
|
44
|
+
}
|
|
45
|
+
const packageScope = defaultLookupPackageScope(url)
|
|
46
|
+
packageScopesCache.set(url, packageScope)
|
|
47
|
+
return packageScope
|
|
48
|
+
}
|
|
49
|
+
const packageJsonsCache = new Map()
|
|
50
|
+
readPackageJson = (url) => {
|
|
51
|
+
const fromCache = packageJsonsCache.get(url)
|
|
52
|
+
if (fromCache) {
|
|
53
|
+
return fromCache
|
|
54
|
+
}
|
|
55
|
+
const packageJson = defaultReadPackageJson(url)
|
|
56
|
+
packageJsonsCache.set(url, packageJson)
|
|
57
|
+
return packageJson
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (scenario === "dev") {
|
|
61
|
+
const onFileChange = () => {
|
|
62
|
+
packageScopesCache.clear()
|
|
63
|
+
packageJsonsCache.clear()
|
|
64
|
+
urlGraph.urlInfoMap.forEach((urlInfo) => {
|
|
65
|
+
if (urlInfo.dependsOnPackageJson) {
|
|
66
|
+
urlGraph.considerModified(urlInfo)
|
|
67
|
+
}
|
|
68
|
+
})
|
|
69
|
+
}
|
|
70
|
+
filesInvalidatingCache.forEach((file) => {
|
|
71
|
+
const unregister = registerFileLifecycle(
|
|
72
|
+
new URL(file, rootDirectoryUrl),
|
|
73
|
+
{
|
|
74
|
+
added: () => {
|
|
75
|
+
onFileChange()
|
|
76
|
+
},
|
|
77
|
+
updated: () => {
|
|
78
|
+
onFileChange()
|
|
79
|
+
},
|
|
80
|
+
removed: () => {
|
|
81
|
+
onFileChange()
|
|
82
|
+
},
|
|
83
|
+
keepProcessAlive: false,
|
|
84
|
+
},
|
|
85
|
+
)
|
|
86
|
+
unregisters.push(unregister)
|
|
87
|
+
})
|
|
88
|
+
}
|
|
89
|
+
},
|
|
84
90
|
resolveUrl: {
|
|
85
|
-
js_import_export: (reference) => {
|
|
91
|
+
js_import_export: (reference, context) => {
|
|
86
92
|
const { parentUrl, specifier } = reference
|
|
87
93
|
const { type, url } = applyNodeEsmResolution({
|
|
88
94
|
conditions: packageConditions,
|
|
@@ -100,7 +106,9 @@ export const jsenvPluginNodeEsmResolution = ({
|
|
|
100
106
|
type !== "relative_specifier" &&
|
|
101
107
|
type !== "absolute_specifier" &&
|
|
102
108
|
type !== "node_builtin_specifier"
|
|
103
|
-
const relatedUrlInfos = urlGraph.getRelatedUrlInfos(
|
|
109
|
+
const relatedUrlInfos = context.urlGraph.getRelatedUrlInfos(
|
|
110
|
+
reference.parentUrl,
|
|
111
|
+
)
|
|
104
112
|
relatedUrlInfos.forEach((relatedUrlInfo) => {
|
|
105
113
|
if (relatedUrlInfo.dependsOnPackageJson) {
|
|
106
114
|
// the url may depend due to an other reference
|
|
@@ -1,44 +1,63 @@
|
|
|
1
1
|
import { timeStart } from "@jsenv/server"
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
3
|
+
const HOOK_NAMES = [
|
|
4
|
+
"init",
|
|
5
|
+
"serve", // is called only during dev/tests
|
|
6
|
+
"resolveUrl",
|
|
7
|
+
"redirectUrl",
|
|
8
|
+
"fetchUrlContent",
|
|
9
|
+
"transformUrlContent",
|
|
10
|
+
"transformUrlSearchParams",
|
|
11
|
+
"formatUrl",
|
|
12
|
+
"finalizeUrlContent",
|
|
13
|
+
"bundle", // is called only during build
|
|
14
|
+
"optimizeUrlContent", // is called only during build
|
|
15
|
+
"cooked",
|
|
16
|
+
"augmentResponse", // is called only during dev/tests
|
|
17
|
+
"destroy",
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
export const createPluginController = ({ plugins, scenario }) => {
|
|
21
|
+
const flatPlugins = flattenAndFilterPlugins(plugins, { scenario })
|
|
22
|
+
// precompute a list of hooks per hookName for one major reason:
|
|
22
23
|
// - When debugging, there is less iteration
|
|
23
|
-
//
|
|
24
|
+
// also it should increase perf as there is less work to do
|
|
25
|
+
|
|
24
26
|
const hookGroups = {}
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
27
|
+
const addPlugin = (plugin, { position = "start" }) => {
|
|
28
|
+
Object.keys(plugin).forEach((key) => {
|
|
29
|
+
if (key === "name" || key === "appliesDuring" || key === "serverEvents") {
|
|
30
|
+
return
|
|
31
|
+
}
|
|
32
|
+
const isHook = HOOK_NAMES.includes(key)
|
|
33
|
+
if (!isHook) {
|
|
34
|
+
console.warn(`Unexpected "${key}" property on "${plugin.name}" plugin`)
|
|
35
|
+
}
|
|
36
|
+
const hookName = key
|
|
37
|
+
const hookValue = plugin[hookName]
|
|
38
|
+
if (hookValue) {
|
|
39
|
+
const group = hookGroups[hookName] || (hookGroups[hookName] = [])
|
|
40
|
+
const hook = {
|
|
31
41
|
plugin,
|
|
32
|
-
hookName,
|
|
33
|
-
value:
|
|
34
|
-
}
|
|
42
|
+
name: hookName,
|
|
43
|
+
value: hookValue,
|
|
44
|
+
}
|
|
45
|
+
if (position === "start") {
|
|
46
|
+
group.push(hook)
|
|
47
|
+
} else {
|
|
48
|
+
group.unshift(hook)
|
|
49
|
+
}
|
|
35
50
|
}
|
|
36
51
|
})
|
|
37
|
-
hookGroups[hookName] = hooks
|
|
38
|
-
return hooks
|
|
39
52
|
}
|
|
40
|
-
|
|
41
|
-
|
|
53
|
+
const pushPlugin = (plugin) => {
|
|
54
|
+
addPlugin(plugin, { position: "start" })
|
|
55
|
+
}
|
|
56
|
+
const unshiftPlugin = (plugin) => {
|
|
57
|
+
addPlugin(plugin, { position: "end" })
|
|
58
|
+
}
|
|
59
|
+
flatPlugins.forEach((plugin) => {
|
|
60
|
+
pushPlugin(plugin)
|
|
42
61
|
})
|
|
43
62
|
|
|
44
63
|
let currentPlugin = null
|
|
@@ -49,15 +68,18 @@ export const createPluginController = ({
|
|
|
49
68
|
return null
|
|
50
69
|
}
|
|
51
70
|
currentPlugin = hook.plugin
|
|
52
|
-
currentHookName = hook.
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
71
|
+
currentHookName = hook.name
|
|
72
|
+
let timeEnd
|
|
73
|
+
if (info.timing) {
|
|
74
|
+
timeEnd = timeStart(
|
|
75
|
+
`${currentHookName}-${currentPlugin.name.replace("jsenv:", "")}`,
|
|
76
|
+
)
|
|
77
|
+
}
|
|
56
78
|
let valueReturned = hookFn(info, context)
|
|
57
79
|
if (info.timing) {
|
|
58
80
|
Object.assign(info.timing, timeEnd())
|
|
59
81
|
}
|
|
60
|
-
valueReturned = assertAndNormalizeReturnValue(hook.
|
|
82
|
+
valueReturned = assertAndNormalizeReturnValue(hook.name, valueReturned)
|
|
61
83
|
currentPlugin = null
|
|
62
84
|
currentHookName = null
|
|
63
85
|
return valueReturned
|
|
@@ -68,15 +90,18 @@ export const createPluginController = ({
|
|
|
68
90
|
return null
|
|
69
91
|
}
|
|
70
92
|
currentPlugin = hook.plugin
|
|
71
|
-
currentHookName = hook.
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
93
|
+
currentHookName = hook.name
|
|
94
|
+
let timeEnd
|
|
95
|
+
if (info.timing) {
|
|
96
|
+
timeEnd = timeStart(
|
|
97
|
+
`${currentHookName}-${currentPlugin.name.replace("jsenv:", "")}`,
|
|
98
|
+
)
|
|
99
|
+
}
|
|
75
100
|
let valueReturned = await hookFn(info, context)
|
|
76
101
|
if (info.timing) {
|
|
77
102
|
Object.assign(info.timing, timeEnd())
|
|
78
103
|
}
|
|
79
|
-
valueReturned = assertAndNormalizeReturnValue(hook.
|
|
104
|
+
valueReturned = assertAndNormalizeReturnValue(hook.name, valueReturned)
|
|
80
105
|
currentPlugin = null
|
|
81
106
|
currentHookName = null
|
|
82
107
|
return valueReturned
|
|
@@ -84,36 +109,45 @@ export const createPluginController = ({
|
|
|
84
109
|
|
|
85
110
|
const callHooks = (hookName, info, context, callback) => {
|
|
86
111
|
const hooks = hookGroups[hookName]
|
|
87
|
-
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
-
|
|
112
|
+
if (hooks) {
|
|
113
|
+
for (const hook of hooks) {
|
|
114
|
+
const returnValue = callHook(hook, info, context)
|
|
115
|
+
if (returnValue && callback) {
|
|
116
|
+
callback(returnValue)
|
|
117
|
+
}
|
|
91
118
|
}
|
|
92
119
|
}
|
|
93
120
|
}
|
|
94
121
|
const callAsyncHooks = async (hookName, info, context, callback) => {
|
|
95
122
|
const hooks = hookGroups[hookName]
|
|
96
|
-
|
|
97
|
-
await previous
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
123
|
+
if (hooks) {
|
|
124
|
+
await hooks.reduce(async (previous, hook) => {
|
|
125
|
+
await previous
|
|
126
|
+
const returnValue = await callAsyncHook(hook, info, context)
|
|
127
|
+
if (returnValue && callback) {
|
|
128
|
+
await callback(returnValue)
|
|
129
|
+
}
|
|
130
|
+
}, Promise.resolve())
|
|
131
|
+
}
|
|
103
132
|
}
|
|
104
133
|
|
|
105
134
|
const callHooksUntil = (hookName, info, context) => {
|
|
106
135
|
const hooks = hookGroups[hookName]
|
|
107
|
-
|
|
108
|
-
const
|
|
109
|
-
|
|
110
|
-
|
|
136
|
+
if (hooks) {
|
|
137
|
+
for (const hook of hooks) {
|
|
138
|
+
const returnValue = callHook(hook, info, context)
|
|
139
|
+
if (returnValue) {
|
|
140
|
+
return returnValue
|
|
141
|
+
}
|
|
111
142
|
}
|
|
112
143
|
}
|
|
113
144
|
return null
|
|
114
145
|
}
|
|
115
146
|
const callAsyncHooksUntil = (hookName, info, context) => {
|
|
116
147
|
const hooks = hookGroups[hookName]
|
|
148
|
+
if (!hooks) {
|
|
149
|
+
return null
|
|
150
|
+
}
|
|
117
151
|
if (hooks.length === 0) {
|
|
118
152
|
return null
|
|
119
153
|
}
|
|
@@ -136,8 +170,9 @@ export const createPluginController = ({
|
|
|
136
170
|
}
|
|
137
171
|
|
|
138
172
|
return {
|
|
139
|
-
plugins,
|
|
140
|
-
|
|
173
|
+
plugins: flatPlugins,
|
|
174
|
+
pushPlugin,
|
|
175
|
+
unshiftPlugin,
|
|
141
176
|
getHookFunction,
|
|
142
177
|
callHook,
|
|
143
178
|
callAsyncHook,
|
|
@@ -152,8 +187,8 @@ export const createPluginController = ({
|
|
|
152
187
|
}
|
|
153
188
|
}
|
|
154
189
|
|
|
155
|
-
const flattenAndFilterPlugins = (
|
|
156
|
-
const
|
|
190
|
+
const flattenAndFilterPlugins = (plugins, { scenario }) => {
|
|
191
|
+
const flatPlugins = []
|
|
157
192
|
const visitPluginEntry = (pluginEntry) => {
|
|
158
193
|
if (Array.isArray(pluginEntry)) {
|
|
159
194
|
pluginEntry.forEach((value) => visitPluginEntry(value))
|
|
@@ -169,7 +204,7 @@ const flattenAndFilterPlugins = (pluginsRaw, { scenario }) => {
|
|
|
169
204
|
return
|
|
170
205
|
}
|
|
171
206
|
if (appliesDuring === "*") {
|
|
172
|
-
|
|
207
|
+
flatPlugins.push(pluginEntry)
|
|
173
208
|
return
|
|
174
209
|
}
|
|
175
210
|
if (typeof appliesDuring === "string") {
|
|
@@ -179,7 +214,7 @@ const flattenAndFilterPlugins = (pluginsRaw, { scenario }) => {
|
|
|
179
214
|
)
|
|
180
215
|
}
|
|
181
216
|
if (appliesDuring === scenario) {
|
|
182
|
-
|
|
217
|
+
flatPlugins.push(pluginEntry)
|
|
183
218
|
}
|
|
184
219
|
return
|
|
185
220
|
}
|
|
@@ -189,7 +224,7 @@ const flattenAndFilterPlugins = (pluginsRaw, { scenario }) => {
|
|
|
189
224
|
)
|
|
190
225
|
}
|
|
191
226
|
if (appliesDuring[scenario]) {
|
|
192
|
-
|
|
227
|
+
flatPlugins.push(pluginEntry)
|
|
193
228
|
return
|
|
194
229
|
}
|
|
195
230
|
if (pluginEntry.destroy) {
|
|
@@ -199,8 +234,8 @@ const flattenAndFilterPlugins = (pluginsRaw, { scenario }) => {
|
|
|
199
234
|
}
|
|
200
235
|
throw new Error(`plugin must be objects, got ${pluginEntry}`)
|
|
201
236
|
}
|
|
202
|
-
|
|
203
|
-
return
|
|
237
|
+
plugins.forEach((plugin) => visitPluginEntry(plugin))
|
|
238
|
+
return flatPlugins
|
|
204
239
|
}
|
|
205
240
|
|
|
206
241
|
const getHookFunction = (
|