@jsenv/core 39.9.3 → 39.9.5
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 +51 -20
- package/dist/js/import_meta_hot.js +1 -0
- package/dist/js/new_stylesheet.js +1 -1
- package/dist/js/regenerator_runtime.js +1 -1
- package/dist/js/ws.js +7 -7
- package/dist/jsenv_core.js +125 -108
- package/package.json +10 -11
- package/src/dev/start_dev_server.js +8 -6
- package/src/kitchen/url_graph/references.js +2 -2
- package/src/kitchen/url_graph/url_graph.js +1 -1
- package/src/kitchen/url_graph/url_info_transformations.js +1 -1
- package/src/plugins/autoreload/client/autoreload.js +58 -22
- package/src/plugins/directory_reference_effect/jsenv_plugin_directory_reference_effect.js +0 -1
- package/src/plugins/import_meta_hot/client/import_meta_hot.js +1 -0
- package/src/plugins/plugins.js +13 -0
- package/src/plugins/protocol_file/jsenv_plugin_fs_redirection.js +34 -22
- package/src/plugins/protocol_file/jsenv_plugin_protocol_file.js +47 -48
- package/src/plugins/reference_analysis/html/jsenv_plugin_html_reference_analysis.js +4 -7
- package/src/plugins/resolution_node_esm/node_esm_resolver.js +0 -5
- package/src/plugins/resolution_web/jsenv_plugin_web_resolution.js +3 -6
package/dist/js/autoreload.js
CHANGED
|
@@ -52,7 +52,29 @@ const initAutoreload = ({ mainFilePath }) => {
|
|
|
52
52
|
currentExecution: null,
|
|
53
53
|
reload: () => {
|
|
54
54
|
const someEffectIsFullReload = reloader.changes.value.some(
|
|
55
|
-
(reloadMessage) =>
|
|
55
|
+
(reloadMessage) => {
|
|
56
|
+
if (reloadMessage.type === "full") {
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
if (reloadMessage.type === "hot") {
|
|
60
|
+
for (const reloadInstruction of reloadMessage.hotInstructions) {
|
|
61
|
+
if (reloadInstruction.type === "html") {
|
|
62
|
+
const acceptedByUrl = new URL(
|
|
63
|
+
reloadInstruction.acceptedBy,
|
|
64
|
+
`${window.location.origin}/`,
|
|
65
|
+
).href;
|
|
66
|
+
const isCurrentHtmlFile = compareTwoUrlPaths(
|
|
67
|
+
acceptedByUrl,
|
|
68
|
+
window.location.href,
|
|
69
|
+
);
|
|
70
|
+
if (isCurrentHtmlFile) {
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return false;
|
|
77
|
+
},
|
|
56
78
|
);
|
|
57
79
|
if (someEffectIsFullReload) {
|
|
58
80
|
dispatchBeforeFullReload();
|
|
@@ -86,7 +108,7 @@ This could be due to syntax errors or importing non-existent modules (see errors
|
|
|
86
108
|
},
|
|
87
109
|
);
|
|
88
110
|
};
|
|
89
|
-
reloader.changes.value
|
|
111
|
+
for (const reloadMessage of reloader.changes.value) {
|
|
90
112
|
if (reloadMessage.type === "hot") {
|
|
91
113
|
const promise = addToHotQueue(() => {
|
|
92
114
|
return applyHotReload(reloadMessage);
|
|
@@ -95,7 +117,7 @@ This could be due to syntax errors or importing non-existent modules (see errors
|
|
|
95
117
|
} else {
|
|
96
118
|
setReloadMessagePromise(reloadMessage, Promise.resolve());
|
|
97
119
|
}
|
|
98
|
-
}
|
|
120
|
+
}
|
|
99
121
|
},
|
|
100
122
|
};
|
|
101
123
|
|
|
@@ -136,30 +158,32 @@ This could be due to syntax errors or importing non-existent modules (see errors
|
|
|
136
158
|
// - code was not executed (code splitting with dynamic import)
|
|
137
159
|
// - import.meta.hot.accept() is not called (happens for HTML and CSS)
|
|
138
160
|
if (type === "prune") {
|
|
139
|
-
if (urlHotMeta) {
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
161
|
+
if (!urlHotMeta) {
|
|
162
|
+
// code not executed for this url, no need to prune
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
dispatchBeforePrune();
|
|
166
|
+
delete urlHotMetas[urlToFetch];
|
|
167
|
+
if (urlHotMeta.disposeCallback) {
|
|
168
|
+
console.log(
|
|
169
|
+
`[jsenv] cleanup ${boundary} (no longer referenced by ${acceptedBy})`,
|
|
170
|
+
);
|
|
171
|
+
await urlHotMeta.disposeCallback();
|
|
148
172
|
}
|
|
149
173
|
continue;
|
|
150
174
|
}
|
|
151
|
-
if (acceptedBy === boundary) {
|
|
152
|
-
console.log(`[jsenv] hot reloading ${boundary} (${cause})`);
|
|
153
|
-
} else {
|
|
154
|
-
console.log(
|
|
155
|
-
`[jsenv] hot reloading ${acceptedBy} usage in ${boundary} (${cause})`,
|
|
156
|
-
);
|
|
157
|
-
}
|
|
158
175
|
if (type === "js_module") {
|
|
159
176
|
if (!urlHotMeta) {
|
|
160
|
-
// code
|
|
177
|
+
// code not yet executed for this url, no need to re-execute it
|
|
161
178
|
continue;
|
|
162
179
|
}
|
|
180
|
+
if (acceptedBy === boundary) {
|
|
181
|
+
console.log(`[jsenv] hot reload ${boundary} (${cause})`);
|
|
182
|
+
} else {
|
|
183
|
+
console.log(
|
|
184
|
+
`[jsenv] hot reload ${acceptedBy} usage in ${boundary} (${cause})`,
|
|
185
|
+
);
|
|
186
|
+
}
|
|
163
187
|
if (urlHotMeta.disposeCallback) {
|
|
164
188
|
await urlHotMeta.disposeCallback();
|
|
165
189
|
}
|
|
@@ -189,6 +213,13 @@ This could be due to syntax errors or importing non-existent modules (see errors
|
|
|
189
213
|
// we are not in that HTML page
|
|
190
214
|
continue;
|
|
191
215
|
}
|
|
216
|
+
if (acceptedBy === boundary) {
|
|
217
|
+
console.log(`[jsenv] hot reload ${boundary} (${cause})`);
|
|
218
|
+
} else {
|
|
219
|
+
console.log(
|
|
220
|
+
`[jsenv] hot reload ${acceptedBy} usage in ${boundary} (${cause})`,
|
|
221
|
+
);
|
|
222
|
+
}
|
|
192
223
|
const urlToReload = new URL(acceptedBy, `${window.location.origin}/`)
|
|
193
224
|
.href;
|
|
194
225
|
const domNodesUsingUrl = getDOMNodesUsingUrl(urlToReload);
|
|
@@ -225,7 +225,7 @@ var runtime = (function (exports) {
|
|
|
225
225
|
// AsyncIterator objects; they just return a Promise for the value of
|
|
226
226
|
// the final result produced by the iterator.
|
|
227
227
|
exports.async = function(innerFn, outerFn, self, tryLocsList, PromiseImpl) {
|
|
228
|
-
if (PromiseImpl ===
|
|
228
|
+
if (PromiseImpl === undefined) PromiseImpl = Promise;
|
|
229
229
|
|
|
230
230
|
var iter = new AsyncIterator(
|
|
231
231
|
wrap(innerFn, outerFn, self, tryLocsList),
|
package/dist/js/ws.js
CHANGED
|
@@ -1738,8 +1738,8 @@ function requireBuffer () {
|
|
|
1738
1738
|
byteOffset = 0;
|
|
1739
1739
|
} else if (byteOffset > 0x7fffffff) {
|
|
1740
1740
|
byteOffset = 0x7fffffff;
|
|
1741
|
-
} else if (byteOffset < -
|
|
1742
|
-
byteOffset = -
|
|
1741
|
+
} else if (byteOffset < -2147483648) {
|
|
1742
|
+
byteOffset = -2147483648;
|
|
1743
1743
|
}
|
|
1744
1744
|
byteOffset = +byteOffset; // Coerce to Number.
|
|
1745
1745
|
if (numberIsNaN(byteOffset)) {
|
|
@@ -2480,7 +2480,7 @@ function requireBuffer () {
|
|
|
2480
2480
|
Buffer.prototype.writeInt8 = function writeInt8 (value, offset, noAssert) {
|
|
2481
2481
|
value = +value;
|
|
2482
2482
|
offset = offset >>> 0;
|
|
2483
|
-
if (!noAssert) checkInt(this, value, offset, 1, 0x7f, -
|
|
2483
|
+
if (!noAssert) checkInt(this, value, offset, 1, 0x7f, -128);
|
|
2484
2484
|
if (value < 0) value = 0xff + value + 1;
|
|
2485
2485
|
this[offset] = (value & 0xff);
|
|
2486
2486
|
return offset + 1
|
|
@@ -2489,7 +2489,7 @@ function requireBuffer () {
|
|
|
2489
2489
|
Buffer.prototype.writeInt16LE = function writeInt16LE (value, offset, noAssert) {
|
|
2490
2490
|
value = +value;
|
|
2491
2491
|
offset = offset >>> 0;
|
|
2492
|
-
if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -
|
|
2492
|
+
if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -32768);
|
|
2493
2493
|
this[offset] = (value & 0xff);
|
|
2494
2494
|
this[offset + 1] = (value >>> 8);
|
|
2495
2495
|
return offset + 2
|
|
@@ -2498,7 +2498,7 @@ function requireBuffer () {
|
|
|
2498
2498
|
Buffer.prototype.writeInt16BE = function writeInt16BE (value, offset, noAssert) {
|
|
2499
2499
|
value = +value;
|
|
2500
2500
|
offset = offset >>> 0;
|
|
2501
|
-
if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -
|
|
2501
|
+
if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -32768);
|
|
2502
2502
|
this[offset] = (value >>> 8);
|
|
2503
2503
|
this[offset + 1] = (value & 0xff);
|
|
2504
2504
|
return offset + 2
|
|
@@ -2507,7 +2507,7 @@ function requireBuffer () {
|
|
|
2507
2507
|
Buffer.prototype.writeInt32LE = function writeInt32LE (value, offset, noAssert) {
|
|
2508
2508
|
value = +value;
|
|
2509
2509
|
offset = offset >>> 0;
|
|
2510
|
-
if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -
|
|
2510
|
+
if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -2147483648);
|
|
2511
2511
|
this[offset] = (value & 0xff);
|
|
2512
2512
|
this[offset + 1] = (value >>> 8);
|
|
2513
2513
|
this[offset + 2] = (value >>> 16);
|
|
@@ -2518,7 +2518,7 @@ function requireBuffer () {
|
|
|
2518
2518
|
Buffer.prototype.writeInt32BE = function writeInt32BE (value, offset, noAssert) {
|
|
2519
2519
|
value = +value;
|
|
2520
2520
|
offset = offset >>> 0;
|
|
2521
|
-
if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -
|
|
2521
|
+
if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -2147483648);
|
|
2522
2522
|
if (value < 0) value = 0xffffffff + value + 1;
|
|
2523
2523
|
this[offset] = (value >>> 24);
|
|
2524
2524
|
this[offset + 1] = (value >>> 16);
|
package/dist/jsenv_core.js
CHANGED
|
@@ -1968,7 +1968,7 @@ const comparePathnames = (leftPathame, rightPathname) => {
|
|
|
1968
1968
|
|
|
1969
1969
|
// longer comes first
|
|
1970
1970
|
if (!leftPartExists) {
|
|
1971
|
-
return
|
|
1971
|
+
return 1;
|
|
1972
1972
|
}
|
|
1973
1973
|
if (!rightPartExists) {
|
|
1974
1974
|
return -1;
|
|
@@ -1978,7 +1978,7 @@ const comparePathnames = (leftPathame, rightPathname) => {
|
|
|
1978
1978
|
const rightPartIsLast = i === rightPartArray.length - 1;
|
|
1979
1979
|
// folder comes first
|
|
1980
1980
|
if (leftPartIsLast && !rightPartIsLast) {
|
|
1981
|
-
return
|
|
1981
|
+
return 1;
|
|
1982
1982
|
}
|
|
1983
1983
|
if (!leftPartIsLast && rightPartIsLast) {
|
|
1984
1984
|
return -1;
|
|
@@ -1995,7 +1995,7 @@ const comparePathnames = (leftPathame, rightPathname) => {
|
|
|
1995
1995
|
}
|
|
1996
1996
|
|
|
1997
1997
|
if (leftLength < rightLength) {
|
|
1998
|
-
return
|
|
1998
|
+
return 1;
|
|
1999
1999
|
}
|
|
2000
2000
|
if (leftLength > rightLength) {
|
|
2001
2001
|
return -1;
|
|
@@ -3900,6 +3900,7 @@ const writeDirectorySync = (
|
|
|
3900
3900
|
.slice(0, -1),
|
|
3901
3901
|
),
|
|
3902
3902
|
);
|
|
3903
|
+
destinationStats = null;
|
|
3903
3904
|
} else {
|
|
3904
3905
|
throw new Error(
|
|
3905
3906
|
`cannot write directory at ${destinationPath} because there is a file at ${urlToFileSystemPath(
|
|
@@ -3919,10 +3920,14 @@ const writeDirectorySync = (
|
|
|
3919
3920
|
}
|
|
3920
3921
|
throw new Error(`directory already exists at ${destinationPath}`);
|
|
3921
3922
|
}
|
|
3922
|
-
|
|
3923
|
-
|
|
3924
|
-
|
|
3925
|
-
|
|
3923
|
+
if (force) {
|
|
3924
|
+
unlinkSync(destinationPath);
|
|
3925
|
+
} else {
|
|
3926
|
+
const destinationType = statsToType(destinationStats);
|
|
3927
|
+
throw new Error(
|
|
3928
|
+
`cannot write directory at ${destinationPath} because there is a ${destinationType}`,
|
|
3929
|
+
);
|
|
3930
|
+
}
|
|
3926
3931
|
}
|
|
3927
3932
|
|
|
3928
3933
|
try {
|
|
@@ -13056,7 +13061,7 @@ const createReference = ({
|
|
|
13056
13061
|
isInline = false,
|
|
13057
13062
|
content,
|
|
13058
13063
|
contentType,
|
|
13059
|
-
|
|
13064
|
+
fsStat = null,
|
|
13060
13065
|
debug = false,
|
|
13061
13066
|
original = null,
|
|
13062
13067
|
prev = null,
|
|
@@ -13117,7 +13122,7 @@ const createReference = ({
|
|
|
13117
13122
|
version,
|
|
13118
13123
|
injected,
|
|
13119
13124
|
timing: {},
|
|
13120
|
-
|
|
13125
|
+
fsStat,
|
|
13121
13126
|
debug,
|
|
13122
13127
|
// for inline resources the reference contains the content
|
|
13123
13128
|
isInline,
|
|
@@ -14038,7 +14043,7 @@ const createUrlInfo = (url, context) => {
|
|
|
14038
14043
|
version: reference.version,
|
|
14039
14044
|
content: reference.content,
|
|
14040
14045
|
contentType: reference.contentType,
|
|
14041
|
-
|
|
14046
|
+
fsStat: reference.fsStat,
|
|
14042
14047
|
debug: reference.debug,
|
|
14043
14048
|
importAttributes: reference.importAttributes,
|
|
14044
14049
|
astInfo: reference.astInfo,
|
|
@@ -14501,7 +14506,7 @@ const createUrlInfoTransformer = ({
|
|
|
14501
14506
|
if (
|
|
14502
14507
|
urlInfo.type === "directory" ||
|
|
14503
14508
|
// happens when type is "html" to list directory content for example
|
|
14504
|
-
urlInfo.firstReference?.
|
|
14509
|
+
urlInfo.firstReference?.fsStat?.isDirectory()
|
|
14505
14510
|
) {
|
|
14506
14511
|
// no need to write the directory
|
|
14507
14512
|
return;
|
|
@@ -15585,7 +15590,6 @@ const jsenvPluginDirectoryReferenceEffect = (
|
|
|
15585
15590
|
if (pathname[pathname.length - 1] !== "/") {
|
|
15586
15591
|
return null;
|
|
15587
15592
|
}
|
|
15588
|
-
reference.leadsToADirectory = true;
|
|
15589
15593
|
reference.expectedType = "directory";
|
|
15590
15594
|
if (reference.ownerUrlInfo.type === "directory") {
|
|
15591
15595
|
reference.dirnameHint = reference.ownerUrlInfo.filenameHint;
|
|
@@ -16905,11 +16909,7 @@ const jsenvPluginHtmlReferenceAnalysis = ({
|
|
|
16905
16909
|
} else {
|
|
16906
16910
|
position = getHtmlNodeAttributePosition(node, attributeName);
|
|
16907
16911
|
}
|
|
16908
|
-
const {
|
|
16909
|
-
line,
|
|
16910
|
-
column,
|
|
16911
|
-
// originalLine, originalColumn
|
|
16912
|
-
} = position;
|
|
16912
|
+
const { line, column, originalLine, originalColumn } = position;
|
|
16913
16913
|
const debug =
|
|
16914
16914
|
getHtmlNodeAttribute(node, "jsenv-debug") !== undefined;
|
|
16915
16915
|
|
|
@@ -16942,8 +16942,9 @@ const jsenvPluginHtmlReferenceAnalysis = ({
|
|
|
16942
16942
|
subtype,
|
|
16943
16943
|
expectedType,
|
|
16944
16944
|
specifier: attributeValue,
|
|
16945
|
-
specifierLine: line,
|
|
16946
|
-
specifierColumn:
|
|
16945
|
+
specifierLine: originalLine === undefined ? line : originalLine,
|
|
16946
|
+
specifierColumn:
|
|
16947
|
+
originalColumn === undefined ? column : originalColumn,
|
|
16947
16948
|
specifierStart: attributeValueStart,
|
|
16948
16949
|
specifierEnd: attributeValueEnd,
|
|
16949
16950
|
isResourceHint,
|
|
@@ -18885,11 +18886,6 @@ const createNodeEsmResolver = ({
|
|
|
18885
18886
|
return reference.specifier;
|
|
18886
18887
|
}
|
|
18887
18888
|
const { ownerUrlInfo } = reference;
|
|
18888
|
-
if (reference.specifier === "/") {
|
|
18889
|
-
const { mainFilePath, rootDirectoryUrl } = ownerUrlInfo.context;
|
|
18890
|
-
const url = new URL(mainFilePath, rootDirectoryUrl);
|
|
18891
|
-
return url;
|
|
18892
|
-
}
|
|
18893
18889
|
if (reference.specifier[0] === "/") {
|
|
18894
18890
|
const url = new URL(
|
|
18895
18891
|
reference.specifier.slice(1),
|
|
@@ -19092,11 +19088,6 @@ const jsenvPluginWebResolution = () => {
|
|
|
19092
19088
|
appliesDuring: "*",
|
|
19093
19089
|
resolveReference: (reference) => {
|
|
19094
19090
|
const { ownerUrlInfo } = reference;
|
|
19095
|
-
if (reference.specifier === "/") {
|
|
19096
|
-
const { mainFilePath, rootDirectoryUrl } = ownerUrlInfo.context;
|
|
19097
|
-
const url = new URL(mainFilePath, rootDirectoryUrl);
|
|
19098
|
-
return url;
|
|
19099
|
-
}
|
|
19100
19091
|
if (reference.specifier[0] === "/") {
|
|
19101
19092
|
const url = new URL(
|
|
19102
19093
|
reference.specifier.slice(1),
|
|
@@ -19107,7 +19098,9 @@ const jsenvPluginWebResolution = () => {
|
|
|
19107
19098
|
// baseUrl happens second argument to new URL() is different from
|
|
19108
19099
|
// import.meta.url or document.currentScript.src
|
|
19109
19100
|
const parentUrl =
|
|
19110
|
-
reference.baseUrl || ownerUrlInfo.
|
|
19101
|
+
reference.baseUrl || ownerUrlInfo.context.dev
|
|
19102
|
+
? ownerUrlInfo.url
|
|
19103
|
+
: ownerUrlInfo.originalUrl || ownerUrlInfo.url;
|
|
19111
19104
|
const url = new URL(reference.specifier, parentUrl);
|
|
19112
19105
|
return url;
|
|
19113
19106
|
},
|
|
@@ -19165,7 +19158,6 @@ const jsenvPluginFsRedirection = ({
|
|
|
19165
19158
|
return null;
|
|
19166
19159
|
}
|
|
19167
19160
|
if (reference.url === "file:///" || reference.url === "file://") {
|
|
19168
|
-
reference.leadsToADirectory = true;
|
|
19169
19161
|
return `ignore:file:///`;
|
|
19170
19162
|
}
|
|
19171
19163
|
// ignore all new URL second arg
|
|
@@ -19180,27 +19172,19 @@ const jsenvPluginFsRedirection = ({
|
|
|
19180
19172
|
// return `ignore:${reference.url}`;
|
|
19181
19173
|
// }
|
|
19182
19174
|
const urlObject = new URL(reference.url);
|
|
19183
|
-
let
|
|
19184
|
-
|
|
19185
|
-
stat = readEntryStatSync(urlObject);
|
|
19186
|
-
} catch (e) {
|
|
19187
|
-
if (e.code === "ENOENT") {
|
|
19188
|
-
stat = null;
|
|
19189
|
-
} else {
|
|
19190
|
-
throw e;
|
|
19191
|
-
}
|
|
19192
|
-
}
|
|
19175
|
+
let fsStat = readEntryStatSync(urlObject, { nullIfNotFound: true });
|
|
19176
|
+
reference.fsStat = fsStat;
|
|
19193
19177
|
const { search, hash } = urlObject;
|
|
19194
19178
|
urlObject.search = "";
|
|
19195
19179
|
urlObject.hash = "";
|
|
19196
|
-
|
|
19180
|
+
applyFsStatEffectsOnUrlObject(urlObject, fsStat);
|
|
19197
19181
|
const shouldApplyFilesystemMagicResolution =
|
|
19198
19182
|
reference.type === "js_import";
|
|
19199
19183
|
if (shouldApplyFilesystemMagicResolution) {
|
|
19200
19184
|
const filesystemResolution = applyFileSystemMagicResolution(
|
|
19201
19185
|
urlObject.href,
|
|
19202
19186
|
{
|
|
19203
|
-
fileStat:
|
|
19187
|
+
fileStat: fsStat,
|
|
19204
19188
|
magicDirectoryIndex,
|
|
19205
19189
|
magicExtensions: getExtensionsToTry(
|
|
19206
19190
|
magicExtensions,
|
|
@@ -19209,12 +19193,28 @@ const jsenvPluginFsRedirection = ({
|
|
|
19209
19193
|
},
|
|
19210
19194
|
);
|
|
19211
19195
|
if (filesystemResolution.stat) {
|
|
19212
|
-
|
|
19196
|
+
fsStat = filesystemResolution.stat;
|
|
19197
|
+
reference.fsStat = fsStat;
|
|
19213
19198
|
urlObject.href = filesystemResolution.url;
|
|
19214
|
-
|
|
19199
|
+
applyFsStatEffectsOnUrlObject(urlObject, fsStat);
|
|
19215
19200
|
}
|
|
19216
19201
|
}
|
|
19217
|
-
if (!
|
|
19202
|
+
if (!fsStat) {
|
|
19203
|
+
// for SPA we want to serve the root HTML file only when:
|
|
19204
|
+
// 1. There is no corresponding file on the filesystem
|
|
19205
|
+
// 2. The url pathname does not have an extension
|
|
19206
|
+
// This point assume client is requesting a file when there is an extension
|
|
19207
|
+
// and it assumes all routes will not use extension
|
|
19208
|
+
// 3. The url pathname does not ends with "/"
|
|
19209
|
+
// In that case we assume client explicitely asks to load a directory
|
|
19210
|
+
if (
|
|
19211
|
+
!urlToExtension$1(urlObject) &&
|
|
19212
|
+
!urlToPathname$1(urlObject).endsWith("/")
|
|
19213
|
+
) {
|
|
19214
|
+
const { mainFilePath, rootDirectoryUrl } =
|
|
19215
|
+
reference.ownerUrlInfo.context;
|
|
19216
|
+
return new URL(mainFilePath, rootDirectoryUrl);
|
|
19217
|
+
}
|
|
19218
19218
|
return null;
|
|
19219
19219
|
}
|
|
19220
19220
|
const urlBeforeSymlinkResolution = urlObject.href;
|
|
@@ -19234,15 +19234,19 @@ const jsenvPluginFsRedirection = ({
|
|
|
19234
19234
|
};
|
|
19235
19235
|
};
|
|
19236
19236
|
|
|
19237
|
-
const
|
|
19237
|
+
const applyFsStatEffectsOnUrlObject = (urlObject, fsStat) => {
|
|
19238
|
+
if (!fsStat) {
|
|
19239
|
+
return;
|
|
19240
|
+
}
|
|
19238
19241
|
const { pathname } = urlObject;
|
|
19239
19242
|
const pathnameUsesTrailingSlash = pathname.endsWith("/");
|
|
19240
19243
|
// force trailing slash on directories
|
|
19241
|
-
if (
|
|
19242
|
-
|
|
19243
|
-
|
|
19244
|
-
|
|
19245
|
-
|
|
19244
|
+
if (fsStat.isDirectory()) {
|
|
19245
|
+
if (!pathnameUsesTrailingSlash) {
|
|
19246
|
+
urlObject.pathname = `${pathname}/`;
|
|
19247
|
+
}
|
|
19248
|
+
} else if (pathnameUsesTrailingSlash) {
|
|
19249
|
+
// otherwise remove trailing slash if any
|
|
19246
19250
|
// a warning here? (because it's strange to reference a file with a trailing slash)
|
|
19247
19251
|
urlObject.pathname = pathname.slice(0, -1);
|
|
19248
19252
|
}
|
|
@@ -19327,45 +19331,16 @@ const jsenvPluginProtocolFile = ({
|
|
|
19327
19331
|
if (!urlInfo.url.startsWith("file:")) {
|
|
19328
19332
|
return null;
|
|
19329
19333
|
}
|
|
19330
|
-
const {
|
|
19331
|
-
|
|
19332
|
-
|
|
19333
|
-
|
|
19334
|
-
|
|
19335
|
-
|
|
19336
|
-
|
|
19337
|
-
|
|
19338
|
-
|
|
19339
|
-
|
|
19340
|
-
contentType: "application/json",
|
|
19341
|
-
content,
|
|
19342
|
-
};
|
|
19343
|
-
}
|
|
19344
|
-
const acceptsHtml = urlInfo.context.request
|
|
19345
|
-
? pickContentType(urlInfo.context.request, ["text/html"])
|
|
19346
|
-
: false;
|
|
19347
|
-
if (acceptsHtml) {
|
|
19348
|
-
firstReference.expectedType = "html";
|
|
19349
|
-
const directoryUrl = urlObject.href;
|
|
19350
|
-
const directoryContentItems = generateDirectoryContentItems(
|
|
19351
|
-
directoryUrl,
|
|
19352
|
-
rootDirectoryUrl,
|
|
19353
|
-
);
|
|
19354
|
-
const html = generateHtmlForDirectory(directoryContentItems);
|
|
19355
|
-
return {
|
|
19356
|
-
type: "html",
|
|
19357
|
-
contentType: "text/html",
|
|
19358
|
-
content: html,
|
|
19359
|
-
};
|
|
19360
|
-
}
|
|
19361
|
-
return {
|
|
19362
|
-
type: "directory",
|
|
19363
|
-
contentType: "application/json",
|
|
19364
|
-
content: JSON.stringify(directoryContentArray, null, " "),
|
|
19365
|
-
};
|
|
19366
|
-
}
|
|
19367
|
-
const contentType = CONTENT_TYPE.fromUrlExtension(urlInfo.url);
|
|
19368
|
-
const fileBuffer = readFileSync(urlObject);
|
|
19334
|
+
const { firstReference } = urlInfo;
|
|
19335
|
+
let { fsStat } = firstReference;
|
|
19336
|
+
if (!fsStat) {
|
|
19337
|
+
fsStat = readEntryStatSync(urlInfo.url, { nullIfNotFound: true });
|
|
19338
|
+
}
|
|
19339
|
+
const isDirectory = fsStat?.isDirectory();
|
|
19340
|
+
const { rootDirectoryUrl, request } = urlInfo.context;
|
|
19341
|
+
const serveFile = (url) => {
|
|
19342
|
+
const contentType = CONTENT_TYPE.fromUrlExtension(url);
|
|
19343
|
+
const fileBuffer = readFileSync(new URL(url));
|
|
19369
19344
|
const content = CONTENT_TYPE.isTextual(contentType)
|
|
19370
19345
|
? String(fileBuffer)
|
|
19371
19346
|
: fileBuffer;
|
|
@@ -19376,14 +19351,8 @@ const jsenvPluginProtocolFile = ({
|
|
|
19376
19351
|
};
|
|
19377
19352
|
};
|
|
19378
19353
|
|
|
19379
|
-
|
|
19380
|
-
|
|
19381
|
-
try {
|
|
19382
|
-
return generateContent();
|
|
19383
|
-
} catch (e) {
|
|
19384
|
-
if (e.code !== "ENOENT") {
|
|
19385
|
-
throw e;
|
|
19386
|
-
}
|
|
19354
|
+
if (!fsStat) {
|
|
19355
|
+
if (request && request.headers["sec-fetch-dest"] === "document") {
|
|
19387
19356
|
const directoryContentItems = generateDirectoryContentItems(
|
|
19388
19357
|
urlInfo.url,
|
|
19389
19358
|
rootDirectoryUrl,
|
|
@@ -19403,7 +19372,40 @@ const jsenvPluginProtocolFile = ({
|
|
|
19403
19372
|
};
|
|
19404
19373
|
}
|
|
19405
19374
|
}
|
|
19406
|
-
|
|
19375
|
+
if (isDirectory) {
|
|
19376
|
+
const directoryContentArray = readdirSync(new URL(urlInfo.url));
|
|
19377
|
+
if (firstReference.type === "filesystem") {
|
|
19378
|
+
const content = JSON.stringify(directoryContentArray, null, " ");
|
|
19379
|
+
return {
|
|
19380
|
+
type: "directory",
|
|
19381
|
+
contentType: "application/json",
|
|
19382
|
+
content,
|
|
19383
|
+
};
|
|
19384
|
+
}
|
|
19385
|
+
const acceptsHtml = request
|
|
19386
|
+
? pickContentType(request, ["text/html"])
|
|
19387
|
+
: false;
|
|
19388
|
+
if (acceptsHtml) {
|
|
19389
|
+
firstReference.expectedType = "html";
|
|
19390
|
+
const directoryUrl = urlInfo.url;
|
|
19391
|
+
const directoryContentItems = generateDirectoryContentItems(
|
|
19392
|
+
directoryUrl,
|
|
19393
|
+
rootDirectoryUrl,
|
|
19394
|
+
);
|
|
19395
|
+
const html = generateHtmlForDirectory(directoryContentItems);
|
|
19396
|
+
return {
|
|
19397
|
+
type: "html",
|
|
19398
|
+
contentType: "text/html",
|
|
19399
|
+
content: html,
|
|
19400
|
+
};
|
|
19401
|
+
}
|
|
19402
|
+
return {
|
|
19403
|
+
type: "directory",
|
|
19404
|
+
contentType: "application/json",
|
|
19405
|
+
content: JSON.stringify(directoryContentArray, null, " "),
|
|
19406
|
+
};
|
|
19407
|
+
}
|
|
19408
|
+
return serveFile(urlInfo.url);
|
|
19407
19409
|
},
|
|
19408
19410
|
},
|
|
19409
19411
|
];
|
|
@@ -21122,6 +21124,19 @@ const getCorePlugins = ({
|
|
|
21122
21124
|
directoryListingUrlMocks,
|
|
21123
21125
|
}),
|
|
21124
21126
|
|
|
21127
|
+
{
|
|
21128
|
+
name: "jsenv:resolve_root_as_main",
|
|
21129
|
+
appliesDuring: "*",
|
|
21130
|
+
resolveReference: (reference) => {
|
|
21131
|
+
const { ownerUrlInfo } = reference;
|
|
21132
|
+
if (reference.specifier === "/") {
|
|
21133
|
+
const { mainFilePath, rootDirectoryUrl } = ownerUrlInfo.context;
|
|
21134
|
+
const url = new URL(mainFilePath, rootDirectoryUrl);
|
|
21135
|
+
return url;
|
|
21136
|
+
}
|
|
21137
|
+
return null;
|
|
21138
|
+
},
|
|
21139
|
+
},
|
|
21125
21140
|
...(nodeEsmResolution
|
|
21126
21141
|
? [jsenvPluginNodeEsmResolution(nodeEsmResolution)]
|
|
21127
21142
|
: []),
|
|
@@ -22865,7 +22880,7 @@ const build = async ({
|
|
|
22865
22880
|
if (outDirectoryUrl === undefined) {
|
|
22866
22881
|
if (
|
|
22867
22882
|
process.env.CAPTURING_SIDE_EFFECTS ||
|
|
22868
|
-
(
|
|
22883
|
+
(false)
|
|
22869
22884
|
) {
|
|
22870
22885
|
outDirectoryUrl = new URL("../.jsenv_b/", sourceDirectoryUrl);
|
|
22871
22886
|
} else {
|
|
@@ -23742,7 +23757,7 @@ const startDevServer = async ({
|
|
|
23742
23757
|
if (outDirectoryUrl === undefined) {
|
|
23743
23758
|
if (
|
|
23744
23759
|
process.env.CAPTURING_SIDE_EFFECTS ||
|
|
23745
|
-
(
|
|
23760
|
+
(false)
|
|
23746
23761
|
) {
|
|
23747
23762
|
outDirectoryUrl = new URL("../.jsenv/", sourceDirectoryUrl);
|
|
23748
23763
|
} else {
|
|
@@ -24052,12 +24067,14 @@ const startDevServer = async ({
|
|
|
24052
24067
|
parentUrl,
|
|
24053
24068
|
);
|
|
24054
24069
|
if (!reference) {
|
|
24055
|
-
|
|
24056
|
-
|
|
24057
|
-
|
|
24058
|
-
|
|
24059
|
-
|
|
24060
|
-
|
|
24070
|
+
const rootUrlInfo = kitchen.graph.rootUrlInfo;
|
|
24071
|
+
rootUrlInfo.context.request = request;
|
|
24072
|
+
reference = rootUrlInfo.dependencies.createResolveAndFinalize({
|
|
24073
|
+
trace: { message: parentUrl },
|
|
24074
|
+
type: "http_request",
|
|
24075
|
+
specifier: request.resource,
|
|
24076
|
+
});
|
|
24077
|
+
rootUrlInfo.context.request = null;
|
|
24061
24078
|
}
|
|
24062
24079
|
const urlInfo = reference.urlInfo;
|
|
24063
24080
|
const ifNoneMatch = request.headers["if-none-match"];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jsenv/core",
|
|
3
|
-
"version": "39.9.
|
|
3
|
+
"version": "39.9.5",
|
|
4
4
|
"description": "Tool to develop, test and build js projects",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": {
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"/src/"
|
|
35
35
|
],
|
|
36
36
|
"volta": {
|
|
37
|
-
"node": "22.
|
|
37
|
+
"node": "22.13.1"
|
|
38
38
|
},
|
|
39
39
|
"workspaces": [
|
|
40
40
|
"./packages/independent/*",
|
|
@@ -69,17 +69,17 @@
|
|
|
69
69
|
"dependencies": {
|
|
70
70
|
"@financial-times/polyfill-useragent-normaliser": "1.10.2",
|
|
71
71
|
"@jsenv/abort": "4.3.0",
|
|
72
|
-
"@jsenv/ast": "6.4.
|
|
73
|
-
"@jsenv/filesystem": "4.13.
|
|
72
|
+
"@jsenv/ast": "6.4.3",
|
|
73
|
+
"@jsenv/filesystem": "4.13.1",
|
|
74
74
|
"@jsenv/humanize": "1.2.8",
|
|
75
75
|
"@jsenv/importmap": "1.2.1",
|
|
76
76
|
"@jsenv/integrity": "0.0.2",
|
|
77
|
-
"@jsenv/js-module-fallback": "1.3.
|
|
77
|
+
"@jsenv/js-module-fallback": "1.3.55",
|
|
78
78
|
"@jsenv/node-esm-resolution": "1.0.6",
|
|
79
|
-
"@jsenv/plugin-bundling": "2.7.
|
|
80
|
-
"@jsenv/plugin-minification": "1.5.
|
|
81
|
-
"@jsenv/plugin-supervisor": "1.6.
|
|
82
|
-
"@jsenv/plugin-transpilation": "1.4.
|
|
79
|
+
"@jsenv/plugin-bundling": "2.7.23",
|
|
80
|
+
"@jsenv/plugin-minification": "1.5.13",
|
|
81
|
+
"@jsenv/plugin-supervisor": "1.6.2",
|
|
82
|
+
"@jsenv/plugin-transpilation": "1.4.91",
|
|
83
83
|
"@jsenv/runtime-compat": "1.3.1",
|
|
84
84
|
"@jsenv/server": "15.3.3",
|
|
85
85
|
"@jsenv/sourcemap": "1.2.29",
|
|
@@ -91,7 +91,6 @@
|
|
|
91
91
|
"devDependencies": {
|
|
92
92
|
"@babel/plugin-syntax-import-attributes": "7.26.0",
|
|
93
93
|
"@babel/plugin-syntax-optional-chaining-assign": "7.25.9",
|
|
94
|
-
"@eslint/compat": "1.2.4",
|
|
95
94
|
"@jsenv/assert": "workspace:*",
|
|
96
95
|
"@jsenv/cli": "workspace:*",
|
|
97
96
|
"@jsenv/core": "./",
|
|
@@ -108,7 +107,7 @@
|
|
|
108
107
|
"@playwright/browser-firefox": "1.49.1",
|
|
109
108
|
"@playwright/browser-webkit": "1.49.1",
|
|
110
109
|
"babel-plugin-transform-async-to-promises": "0.8.18",
|
|
111
|
-
"eslint": "9.
|
|
110
|
+
"eslint": "9.18.0",
|
|
112
111
|
"open": "10.1.0",
|
|
113
112
|
"playwright": "1.49.1",
|
|
114
113
|
"prettier": "3.4.2",
|
|
@@ -422,12 +422,14 @@ export const startDevServer = async ({
|
|
|
422
422
|
parentUrl,
|
|
423
423
|
);
|
|
424
424
|
if (!reference) {
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
425
|
+
const rootUrlInfo = kitchen.graph.rootUrlInfo;
|
|
426
|
+
rootUrlInfo.context.request = request;
|
|
427
|
+
reference = rootUrlInfo.dependencies.createResolveAndFinalize({
|
|
428
|
+
trace: { message: parentUrl },
|
|
429
|
+
type: "http_request",
|
|
430
|
+
specifier: request.resource,
|
|
431
|
+
});
|
|
432
|
+
rootUrlInfo.context.request = null;
|
|
431
433
|
}
|
|
432
434
|
const urlInfo = reference.urlInfo;
|
|
433
435
|
const ifNoneMatch = request.headers["if-none-match"];
|
|
@@ -291,7 +291,7 @@ const createReference = ({
|
|
|
291
291
|
isInline = false,
|
|
292
292
|
content,
|
|
293
293
|
contentType,
|
|
294
|
-
|
|
294
|
+
fsStat = null,
|
|
295
295
|
debug = false,
|
|
296
296
|
original = null,
|
|
297
297
|
prev = null,
|
|
@@ -352,7 +352,7 @@ const createReference = ({
|
|
|
352
352
|
version,
|
|
353
353
|
injected,
|
|
354
354
|
timing: {},
|
|
355
|
-
|
|
355
|
+
fsStat,
|
|
356
356
|
debug,
|
|
357
357
|
// for inline resources the reference contains the content
|
|
358
358
|
isInline,
|
|
@@ -336,7 +336,7 @@ const createUrlInfo = (url, context) => {
|
|
|
336
336
|
version: reference.version,
|
|
337
337
|
content: reference.content,
|
|
338
338
|
contentType: reference.contentType,
|
|
339
|
-
|
|
339
|
+
fsStat: reference.fsStat,
|
|
340
340
|
debug: reference.debug,
|
|
341
341
|
importAttributes: reference.importAttributes,
|
|
342
342
|
astInfo: reference.astInfo,
|
|
@@ -254,7 +254,7 @@ export const createUrlInfoTransformer = ({
|
|
|
254
254
|
if (
|
|
255
255
|
urlInfo.type === "directory" ||
|
|
256
256
|
// happens when type is "html" to list directory content for example
|
|
257
|
-
urlInfo.firstReference?.
|
|
257
|
+
urlInfo.firstReference?.fsStat?.isDirectory()
|
|
258
258
|
) {
|
|
259
259
|
// no need to write the directory
|
|
260
260
|
return;
|
|
@@ -65,7 +65,29 @@ export const initAutoreload = ({ mainFilePath }) => {
|
|
|
65
65
|
currentExecution: null,
|
|
66
66
|
reload: () => {
|
|
67
67
|
const someEffectIsFullReload = reloader.changes.value.some(
|
|
68
|
-
(reloadMessage) =>
|
|
68
|
+
(reloadMessage) => {
|
|
69
|
+
if (reloadMessage.type === "full") {
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
if (reloadMessage.type === "hot") {
|
|
73
|
+
for (const reloadInstruction of reloadMessage.hotInstructions) {
|
|
74
|
+
if (reloadInstruction.type === "html") {
|
|
75
|
+
const acceptedByUrl = new URL(
|
|
76
|
+
reloadInstruction.acceptedBy,
|
|
77
|
+
`${window.location.origin}/`,
|
|
78
|
+
).href;
|
|
79
|
+
const isCurrentHtmlFile = compareTwoUrlPaths(
|
|
80
|
+
acceptedByUrl,
|
|
81
|
+
window.location.href,
|
|
82
|
+
);
|
|
83
|
+
if (isCurrentHtmlFile) {
|
|
84
|
+
return true;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return false;
|
|
90
|
+
},
|
|
69
91
|
);
|
|
70
92
|
if (someEffectIsFullReload) {
|
|
71
93
|
dispatchBeforeFullReload();
|
|
@@ -99,7 +121,7 @@ This could be due to syntax errors or importing non-existent modules (see errors
|
|
|
99
121
|
},
|
|
100
122
|
);
|
|
101
123
|
};
|
|
102
|
-
reloader.changes.value
|
|
124
|
+
for (const reloadMessage of reloader.changes.value) {
|
|
103
125
|
if (reloadMessage.type === "hot") {
|
|
104
126
|
const promise = addToHotQueue(() => {
|
|
105
127
|
return applyHotReload(reloadMessage);
|
|
@@ -108,7 +130,7 @@ This could be due to syntax errors or importing non-existent modules (see errors
|
|
|
108
130
|
} else {
|
|
109
131
|
setReloadMessagePromise(reloadMessage, Promise.resolve());
|
|
110
132
|
}
|
|
111
|
-
}
|
|
133
|
+
}
|
|
112
134
|
},
|
|
113
135
|
};
|
|
114
136
|
|
|
@@ -149,33 +171,35 @@ This could be due to syntax errors or importing non-existent modules (see errors
|
|
|
149
171
|
// - code was not executed (code splitting with dynamic import)
|
|
150
172
|
// - import.meta.hot.accept() is not called (happens for HTML and CSS)
|
|
151
173
|
if (type === "prune") {
|
|
152
|
-
if (urlHotMeta) {
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
174
|
+
if (!urlHotMeta) {
|
|
175
|
+
// code not executed for this url, no need to prune
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
dispatchBeforePrune();
|
|
179
|
+
delete urlHotMetas[urlToFetch];
|
|
180
|
+
if (urlHotMeta.disposeCallback) {
|
|
181
|
+
console.log(
|
|
182
|
+
`[jsenv] cleanup ${boundary} (no longer referenced by ${acceptedBy})`,
|
|
183
|
+
);
|
|
184
|
+
if (debug) {
|
|
185
|
+
console.log(`call dispose callback`);
|
|
163
186
|
}
|
|
187
|
+
await urlHotMeta.disposeCallback();
|
|
164
188
|
}
|
|
165
189
|
continue;
|
|
166
190
|
}
|
|
167
|
-
if (acceptedBy === boundary) {
|
|
168
|
-
console.log(`[jsenv] hot reloading ${boundary} (${cause})`);
|
|
169
|
-
} else {
|
|
170
|
-
console.log(
|
|
171
|
-
`[jsenv] hot reloading ${acceptedBy} usage in ${boundary} (${cause})`,
|
|
172
|
-
);
|
|
173
|
-
}
|
|
174
191
|
if (type === "js_module") {
|
|
175
192
|
if (!urlHotMeta) {
|
|
176
|
-
// code
|
|
193
|
+
// code not yet executed for this url, no need to re-execute it
|
|
177
194
|
continue;
|
|
178
195
|
}
|
|
196
|
+
if (acceptedBy === boundary) {
|
|
197
|
+
console.log(`[jsenv] hot reload ${boundary} (${cause})`);
|
|
198
|
+
} else {
|
|
199
|
+
console.log(
|
|
200
|
+
`[jsenv] hot reload ${acceptedBy} usage in ${boundary} (${cause})`,
|
|
201
|
+
);
|
|
202
|
+
}
|
|
179
203
|
if (urlHotMeta.disposeCallback) {
|
|
180
204
|
if (debug) {
|
|
181
205
|
console.log(`call dispose callback`);
|
|
@@ -211,9 +235,21 @@ This could be due to syntax errors or importing non-existent modules (see errors
|
|
|
211
235
|
!isRootHtmlFile &&
|
|
212
236
|
!compareTwoUrlPaths(urlToFetch, window.location.href)
|
|
213
237
|
) {
|
|
238
|
+
if (debug) {
|
|
239
|
+
console.log(
|
|
240
|
+
`[jsenv] skip ${acceptedBy} hot reload because we are not in that html page`,
|
|
241
|
+
);
|
|
242
|
+
}
|
|
214
243
|
// we are not in that HTML page
|
|
215
244
|
continue;
|
|
216
245
|
}
|
|
246
|
+
if (acceptedBy === boundary) {
|
|
247
|
+
console.log(`[jsenv] hot reload ${boundary} (${cause})`);
|
|
248
|
+
} else {
|
|
249
|
+
console.log(
|
|
250
|
+
`[jsenv] hot reload ${acceptedBy} usage in ${boundary} (${cause})`,
|
|
251
|
+
);
|
|
252
|
+
}
|
|
217
253
|
const urlToReload = new URL(acceptedBy, `${window.location.origin}/`)
|
|
218
254
|
.href;
|
|
219
255
|
const domNodesUsingUrl = getDOMNodesUsingUrl(urlToReload);
|
|
@@ -22,7 +22,6 @@ export const jsenvPluginDirectoryReferenceEffect = (
|
|
|
22
22
|
if (pathname[pathname.length - 1] !== "/") {
|
|
23
23
|
return null;
|
|
24
24
|
}
|
|
25
|
-
reference.leadsToADirectory = true;
|
|
26
25
|
reference.expectedType = "directory";
|
|
27
26
|
if (reference.ownerUrlInfo.type === "directory") {
|
|
28
27
|
reference.dirnameHint = reference.ownerUrlInfo.filenameHint;
|
package/src/plugins/plugins.js
CHANGED
|
@@ -81,6 +81,19 @@ export const getCorePlugins = ({
|
|
|
81
81
|
directoryListingUrlMocks,
|
|
82
82
|
}),
|
|
83
83
|
|
|
84
|
+
{
|
|
85
|
+
name: "jsenv:resolve_root_as_main",
|
|
86
|
+
appliesDuring: "*",
|
|
87
|
+
resolveReference: (reference) => {
|
|
88
|
+
const { ownerUrlInfo } = reference;
|
|
89
|
+
if (reference.specifier === "/") {
|
|
90
|
+
const { mainFilePath, rootDirectoryUrl } = ownerUrlInfo.context;
|
|
91
|
+
const url = new URL(mainFilePath, rootDirectoryUrl);
|
|
92
|
+
return url;
|
|
93
|
+
}
|
|
94
|
+
return null;
|
|
95
|
+
},
|
|
96
|
+
},
|
|
84
97
|
...(nodeEsmResolution
|
|
85
98
|
? [jsenvPluginNodeEsmResolution(nodeEsmResolution)]
|
|
86
99
|
: []),
|
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
applyFileSystemMagicResolution,
|
|
4
4
|
getExtensionsToTry,
|
|
5
5
|
} from "@jsenv/node-esm-resolution";
|
|
6
|
+
import { urlToExtension, urlToPathname } from "@jsenv/urls";
|
|
6
7
|
import { realpathSync } from "node:fs";
|
|
7
8
|
import { pathToFileURL } from "node:url";
|
|
8
9
|
|
|
@@ -23,7 +24,6 @@ export const jsenvPluginFsRedirection = ({
|
|
|
23
24
|
return null;
|
|
24
25
|
}
|
|
25
26
|
if (reference.url === "file:///" || reference.url === "file://") {
|
|
26
|
-
reference.leadsToADirectory = true;
|
|
27
27
|
return `ignore:file:///`;
|
|
28
28
|
}
|
|
29
29
|
// ignore all new URL second arg
|
|
@@ -38,27 +38,19 @@ export const jsenvPluginFsRedirection = ({
|
|
|
38
38
|
// return `ignore:${reference.url}`;
|
|
39
39
|
// }
|
|
40
40
|
const urlObject = new URL(reference.url);
|
|
41
|
-
let
|
|
42
|
-
|
|
43
|
-
stat = readEntryStatSync(urlObject);
|
|
44
|
-
} catch (e) {
|
|
45
|
-
if (e.code === "ENOENT") {
|
|
46
|
-
stat = null;
|
|
47
|
-
} else {
|
|
48
|
-
throw e;
|
|
49
|
-
}
|
|
50
|
-
}
|
|
41
|
+
let fsStat = readEntryStatSync(urlObject, { nullIfNotFound: true });
|
|
42
|
+
reference.fsStat = fsStat;
|
|
51
43
|
const { search, hash } = urlObject;
|
|
52
44
|
urlObject.search = "";
|
|
53
45
|
urlObject.hash = "";
|
|
54
|
-
|
|
46
|
+
applyFsStatEffectsOnUrlObject(urlObject, fsStat);
|
|
55
47
|
const shouldApplyFilesystemMagicResolution =
|
|
56
48
|
reference.type === "js_import";
|
|
57
49
|
if (shouldApplyFilesystemMagicResolution) {
|
|
58
50
|
const filesystemResolution = applyFileSystemMagicResolution(
|
|
59
51
|
urlObject.href,
|
|
60
52
|
{
|
|
61
|
-
fileStat:
|
|
53
|
+
fileStat: fsStat,
|
|
62
54
|
magicDirectoryIndex,
|
|
63
55
|
magicExtensions: getExtensionsToTry(
|
|
64
56
|
magicExtensions,
|
|
@@ -67,12 +59,28 @@ export const jsenvPluginFsRedirection = ({
|
|
|
67
59
|
},
|
|
68
60
|
);
|
|
69
61
|
if (filesystemResolution.stat) {
|
|
70
|
-
|
|
62
|
+
fsStat = filesystemResolution.stat;
|
|
63
|
+
reference.fsStat = fsStat;
|
|
71
64
|
urlObject.href = filesystemResolution.url;
|
|
72
|
-
|
|
65
|
+
applyFsStatEffectsOnUrlObject(urlObject, fsStat);
|
|
73
66
|
}
|
|
74
67
|
}
|
|
75
|
-
if (!
|
|
68
|
+
if (!fsStat) {
|
|
69
|
+
// for SPA we want to serve the root HTML file only when:
|
|
70
|
+
// 1. There is no corresponding file on the filesystem
|
|
71
|
+
// 2. The url pathname does not have an extension
|
|
72
|
+
// This point assume client is requesting a file when there is an extension
|
|
73
|
+
// and it assumes all routes will not use extension
|
|
74
|
+
// 3. The url pathname does not ends with "/"
|
|
75
|
+
// In that case we assume client explicitely asks to load a directory
|
|
76
|
+
if (
|
|
77
|
+
!urlToExtension(urlObject) &&
|
|
78
|
+
!urlToPathname(urlObject).endsWith("/")
|
|
79
|
+
) {
|
|
80
|
+
const { mainFilePath, rootDirectoryUrl } =
|
|
81
|
+
reference.ownerUrlInfo.context;
|
|
82
|
+
return new URL(mainFilePath, rootDirectoryUrl);
|
|
83
|
+
}
|
|
76
84
|
return null;
|
|
77
85
|
}
|
|
78
86
|
const urlBeforeSymlinkResolution = urlObject.href;
|
|
@@ -92,15 +100,19 @@ export const jsenvPluginFsRedirection = ({
|
|
|
92
100
|
};
|
|
93
101
|
};
|
|
94
102
|
|
|
95
|
-
const
|
|
103
|
+
const applyFsStatEffectsOnUrlObject = (urlObject, fsStat) => {
|
|
104
|
+
if (!fsStat) {
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
96
107
|
const { pathname } = urlObject;
|
|
97
108
|
const pathnameUsesTrailingSlash = pathname.endsWith("/");
|
|
98
109
|
// force trailing slash on directories
|
|
99
|
-
if (
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
110
|
+
if (fsStat.isDirectory()) {
|
|
111
|
+
if (!pathnameUsesTrailingSlash) {
|
|
112
|
+
urlObject.pathname = `${pathname}/`;
|
|
113
|
+
}
|
|
114
|
+
} else if (pathnameUsesTrailingSlash) {
|
|
115
|
+
// otherwise remove trailing slash if any
|
|
104
116
|
// a warning here? (because it's strange to reference a file with a trailing slash)
|
|
105
117
|
urlObject.pathname = pathname.slice(0, -1);
|
|
106
118
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
assertAndNormalizeDirectoryUrl,
|
|
3
3
|
comparePathnames,
|
|
4
|
+
readEntryStatSync,
|
|
4
5
|
} from "@jsenv/filesystem";
|
|
5
6
|
import { pickContentType } from "@jsenv/server";
|
|
6
7
|
import {
|
|
@@ -84,45 +85,16 @@ export const jsenvPluginProtocolFile = ({
|
|
|
84
85
|
if (!urlInfo.url.startsWith("file:")) {
|
|
85
86
|
return null;
|
|
86
87
|
}
|
|
87
|
-
const {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
contentType: "application/json",
|
|
98
|
-
content,
|
|
99
|
-
};
|
|
100
|
-
}
|
|
101
|
-
const acceptsHtml = urlInfo.context.request
|
|
102
|
-
? pickContentType(urlInfo.context.request, ["text/html"])
|
|
103
|
-
: false;
|
|
104
|
-
if (acceptsHtml) {
|
|
105
|
-
firstReference.expectedType = "html";
|
|
106
|
-
const directoryUrl = urlObject.href;
|
|
107
|
-
const directoryContentItems = generateDirectoryContentItems(
|
|
108
|
-
directoryUrl,
|
|
109
|
-
rootDirectoryUrl,
|
|
110
|
-
);
|
|
111
|
-
const html = generateHtmlForDirectory(directoryContentItems);
|
|
112
|
-
return {
|
|
113
|
-
type: "html",
|
|
114
|
-
contentType: "text/html",
|
|
115
|
-
content: html,
|
|
116
|
-
};
|
|
117
|
-
}
|
|
118
|
-
return {
|
|
119
|
-
type: "directory",
|
|
120
|
-
contentType: "application/json",
|
|
121
|
-
content: JSON.stringify(directoryContentArray, null, " "),
|
|
122
|
-
};
|
|
123
|
-
}
|
|
124
|
-
const contentType = CONTENT_TYPE.fromUrlExtension(urlInfo.url);
|
|
125
|
-
const fileBuffer = readFileSync(urlObject);
|
|
88
|
+
const { firstReference } = urlInfo;
|
|
89
|
+
let { fsStat } = firstReference;
|
|
90
|
+
if (!fsStat) {
|
|
91
|
+
fsStat = readEntryStatSync(urlInfo.url, { nullIfNotFound: true });
|
|
92
|
+
}
|
|
93
|
+
const isDirectory = fsStat?.isDirectory();
|
|
94
|
+
const { rootDirectoryUrl, request } = urlInfo.context;
|
|
95
|
+
const serveFile = (url) => {
|
|
96
|
+
const contentType = CONTENT_TYPE.fromUrlExtension(url);
|
|
97
|
+
const fileBuffer = readFileSync(new URL(url));
|
|
126
98
|
const content = CONTENT_TYPE.isTextual(contentType)
|
|
127
99
|
? String(fileBuffer)
|
|
128
100
|
: fileBuffer;
|
|
@@ -133,14 +105,8 @@ export const jsenvPluginProtocolFile = ({
|
|
|
133
105
|
};
|
|
134
106
|
};
|
|
135
107
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
try {
|
|
139
|
-
return generateContent();
|
|
140
|
-
} catch (e) {
|
|
141
|
-
if (e.code !== "ENOENT") {
|
|
142
|
-
throw e;
|
|
143
|
-
}
|
|
108
|
+
if (!fsStat) {
|
|
109
|
+
if (request && request.headers["sec-fetch-dest"] === "document") {
|
|
144
110
|
const directoryContentItems = generateDirectoryContentItems(
|
|
145
111
|
urlInfo.url,
|
|
146
112
|
rootDirectoryUrl,
|
|
@@ -160,7 +126,40 @@ export const jsenvPluginProtocolFile = ({
|
|
|
160
126
|
};
|
|
161
127
|
}
|
|
162
128
|
}
|
|
163
|
-
|
|
129
|
+
if (isDirectory) {
|
|
130
|
+
const directoryContentArray = readdirSync(new URL(urlInfo.url));
|
|
131
|
+
if (firstReference.type === "filesystem") {
|
|
132
|
+
const content = JSON.stringify(directoryContentArray, null, " ");
|
|
133
|
+
return {
|
|
134
|
+
type: "directory",
|
|
135
|
+
contentType: "application/json",
|
|
136
|
+
content,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
const acceptsHtml = request
|
|
140
|
+
? pickContentType(request, ["text/html"])
|
|
141
|
+
: false;
|
|
142
|
+
if (acceptsHtml) {
|
|
143
|
+
firstReference.expectedType = "html";
|
|
144
|
+
const directoryUrl = urlInfo.url;
|
|
145
|
+
const directoryContentItems = generateDirectoryContentItems(
|
|
146
|
+
directoryUrl,
|
|
147
|
+
rootDirectoryUrl,
|
|
148
|
+
);
|
|
149
|
+
const html = generateHtmlForDirectory(directoryContentItems);
|
|
150
|
+
return {
|
|
151
|
+
type: "html",
|
|
152
|
+
contentType: "text/html",
|
|
153
|
+
content: html,
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
return {
|
|
157
|
+
type: "directory",
|
|
158
|
+
contentType: "application/json",
|
|
159
|
+
content: JSON.stringify(directoryContentArray, null, " "),
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
return serveFile(urlInfo.url);
|
|
164
163
|
},
|
|
165
164
|
},
|
|
166
165
|
];
|
|
@@ -156,11 +156,7 @@ export const jsenvPluginHtmlReferenceAnalysis = ({
|
|
|
156
156
|
} else {
|
|
157
157
|
position = getHtmlNodeAttributePosition(node, attributeName);
|
|
158
158
|
}
|
|
159
|
-
const {
|
|
160
|
-
line,
|
|
161
|
-
column,
|
|
162
|
-
// originalLine, originalColumn
|
|
163
|
-
} = position;
|
|
159
|
+
const { line, column, originalLine, originalColumn } = position;
|
|
164
160
|
const debug =
|
|
165
161
|
getHtmlNodeAttribute(node, "jsenv-debug") !== undefined;
|
|
166
162
|
|
|
@@ -193,8 +189,9 @@ export const jsenvPluginHtmlReferenceAnalysis = ({
|
|
|
193
189
|
subtype,
|
|
194
190
|
expectedType,
|
|
195
191
|
specifier: attributeValue,
|
|
196
|
-
specifierLine: line,
|
|
197
|
-
specifierColumn:
|
|
192
|
+
specifierLine: originalLine === undefined ? line : originalLine,
|
|
193
|
+
specifierColumn:
|
|
194
|
+
originalColumn === undefined ? column : originalColumn,
|
|
198
195
|
specifierStart: attributeValueStart,
|
|
199
196
|
specifierEnd: attributeValueEnd,
|
|
200
197
|
isResourceHint,
|
|
@@ -33,11 +33,6 @@ export const createNodeEsmResolver = ({
|
|
|
33
33
|
return reference.specifier;
|
|
34
34
|
}
|
|
35
35
|
const { ownerUrlInfo } = reference;
|
|
36
|
-
if (reference.specifier === "/") {
|
|
37
|
-
const { mainFilePath, rootDirectoryUrl } = ownerUrlInfo.context;
|
|
38
|
-
const url = new URL(mainFilePath, rootDirectoryUrl);
|
|
39
|
-
return url;
|
|
40
|
-
}
|
|
41
36
|
if (reference.specifier[0] === "/") {
|
|
42
37
|
const url = new URL(
|
|
43
38
|
reference.specifier.slice(1),
|
|
@@ -4,11 +4,6 @@ export const jsenvPluginWebResolution = () => {
|
|
|
4
4
|
appliesDuring: "*",
|
|
5
5
|
resolveReference: (reference) => {
|
|
6
6
|
const { ownerUrlInfo } = reference;
|
|
7
|
-
if (reference.specifier === "/") {
|
|
8
|
-
const { mainFilePath, rootDirectoryUrl } = ownerUrlInfo.context;
|
|
9
|
-
const url = new URL(mainFilePath, rootDirectoryUrl);
|
|
10
|
-
return url;
|
|
11
|
-
}
|
|
12
7
|
if (reference.specifier[0] === "/") {
|
|
13
8
|
const url = new URL(
|
|
14
9
|
reference.specifier.slice(1),
|
|
@@ -19,7 +14,9 @@ export const jsenvPluginWebResolution = () => {
|
|
|
19
14
|
// baseUrl happens second argument to new URL() is different from
|
|
20
15
|
// import.meta.url or document.currentScript.src
|
|
21
16
|
const parentUrl =
|
|
22
|
-
reference.baseUrl || ownerUrlInfo.
|
|
17
|
+
reference.baseUrl || ownerUrlInfo.context.dev
|
|
18
|
+
? ownerUrlInfo.url
|
|
19
|
+
: ownerUrlInfo.originalUrl || ownerUrlInfo.url;
|
|
23
20
|
const url = new URL(reference.specifier, parentUrl);
|
|
24
21
|
return url;
|
|
25
22
|
},
|