@jsenv/core 38.4.16 → 38.4.18
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/html/directory.html +18 -0
- package/dist/html/html_404_and_parent_dir.html +19 -0
- package/dist/html/html_404_and_parent_dir_is_empty.html +16 -0
- package/dist/html/html_syntax_error.html +14 -0
- package/dist/js/autoreload.js +135 -132
- package/dist/jsenv_core.js +708 -406
- package/package.json +6 -7
- package/src/dev/start_dev_server.js +9 -1
- package/src/kitchen/errors.js +8 -5
- package/src/kitchen/url_graph/references.js +7 -6
- package/src/plugins/autoreload/client/autoreload.js +138 -137
- package/src/plugins/autoreload/jsenv_plugin_autoreload_client.js +10 -1
- package/src/plugins/autoreload/jsenv_plugin_autoreload_server.js +4 -1
- package/src/plugins/protocol_file/directory.html +20 -0
- package/src/plugins/protocol_file/html_404_and_parent_dir.html +21 -0
- package/src/plugins/protocol_file/html_404_and_parent_dir_is_empty.html +18 -0
- package/src/plugins/protocol_file/jsenv_plugin_protocol_file.js +173 -13
- package/src/plugins/reference_analysis/html/html_syntax_error.html +14 -0
- package/src/plugins/reference_analysis/html/jsenv_plugin_html_reference_analysis.js +480 -369
- package/src/plugins/ribbon/jsenv_plugin_ribbon.js +1 -1
|
@@ -1,5 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import {
|
|
2
|
+
existsSync,
|
|
3
|
+
readFileSync,
|
|
4
|
+
realpathSync,
|
|
5
|
+
statSync,
|
|
6
|
+
lstatSync,
|
|
7
|
+
readdirSync,
|
|
8
|
+
} from "node:fs";
|
|
3
9
|
import { pathToFileURL } from "node:url";
|
|
4
10
|
import {
|
|
5
11
|
urlIsInsideOf,
|
|
@@ -11,7 +17,19 @@ import {
|
|
|
11
17
|
applyFileSystemMagicResolution,
|
|
12
18
|
getExtensionsToTry,
|
|
13
19
|
} from "@jsenv/node-esm-resolution";
|
|
20
|
+
import { pickContentType } from "@jsenv/server";
|
|
14
21
|
import { CONTENT_TYPE } from "@jsenv/utils/src/content_type/content_type.js";
|
|
22
|
+
import { assertAndNormalizeDirectoryUrl } from "@jsenv/filesystem";
|
|
23
|
+
|
|
24
|
+
const html404AndParentDirIsEmptyFileUrl = new URL(
|
|
25
|
+
"./html_404_and_parent_dir_is_empty.html",
|
|
26
|
+
import.meta.url,
|
|
27
|
+
);
|
|
28
|
+
const html404AndParentDirFileUrl = new URL(
|
|
29
|
+
"./html_404_and_parent_dir.html",
|
|
30
|
+
import.meta.url,
|
|
31
|
+
);
|
|
32
|
+
const htmlFileUrlForDirectory = new URL("./directory.html", import.meta.url);
|
|
15
33
|
|
|
16
34
|
export const jsenvPluginProtocolFile = ({
|
|
17
35
|
magicExtensions = ["inherit", ".js"],
|
|
@@ -99,7 +117,9 @@ export const jsenvPluginProtocolFile = ({
|
|
|
99
117
|
reference.leadsToADirectory = stat && stat.isDirectory();
|
|
100
118
|
if (reference.leadsToADirectory) {
|
|
101
119
|
let actionForDirectory;
|
|
102
|
-
if (
|
|
120
|
+
if (reference.type === "a_href") {
|
|
121
|
+
actionForDirectory = "ignore";
|
|
122
|
+
} else if (
|
|
103
123
|
reference.type === "http_request" ||
|
|
104
124
|
reference.type === "filesystem"
|
|
105
125
|
) {
|
|
@@ -184,17 +204,33 @@ export const jsenvPluginProtocolFile = ({
|
|
|
184
204
|
urlInfo.filenameHint = `${urlToFilename(urlInfo.url)}/`;
|
|
185
205
|
}
|
|
186
206
|
}
|
|
187
|
-
const
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
207
|
+
const directoryContentArray = readdirSync(urlObject);
|
|
208
|
+
if (urlInfo.firstReference.type === "filesystem") {
|
|
209
|
+
const content = JSON.stringify(directoryContentArray, null, " ");
|
|
210
|
+
return {
|
|
211
|
+
type: "directory",
|
|
212
|
+
contentType: "application/json",
|
|
213
|
+
content,
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
const acceptsHtml = urlInfo.context.request
|
|
217
|
+
? pickContentType(urlInfo.context.request, ["text/html"])
|
|
218
|
+
: false;
|
|
219
|
+
if (acceptsHtml) {
|
|
220
|
+
const html = generateHtmlForDirectory(
|
|
221
|
+
urlObject.href,
|
|
222
|
+
directoryContentArray,
|
|
223
|
+
urlInfo.context.rootDirectoryUrl,
|
|
224
|
+
);
|
|
225
|
+
return {
|
|
226
|
+
contentType: "text/html",
|
|
227
|
+
content: html,
|
|
228
|
+
};
|
|
229
|
+
}
|
|
193
230
|
return {
|
|
194
231
|
type: "directory",
|
|
195
|
-
contentType:
|
|
196
|
-
|
|
197
|
-
content: body,
|
|
232
|
+
contentType: "application/json",
|
|
233
|
+
content: JSON.stringify(directoryContentArray, null, " "),
|
|
198
234
|
};
|
|
199
235
|
}
|
|
200
236
|
if (
|
|
@@ -204,20 +240,144 @@ export const jsenvPluginProtocolFile = ({
|
|
|
204
240
|
urlInfo.dirnameHint =
|
|
205
241
|
urlInfo.firstReference.ownerUrlInfo.filenameHint;
|
|
206
242
|
}
|
|
207
|
-
const fileBuffer = readFileSync(urlObject);
|
|
208
243
|
const contentType = CONTENT_TYPE.fromUrlExtension(urlInfo.url);
|
|
244
|
+
if (contentType === "text/html") {
|
|
245
|
+
try {
|
|
246
|
+
const fileBuffer = readFileSync(urlObject);
|
|
247
|
+
const content = String(fileBuffer);
|
|
248
|
+
return {
|
|
249
|
+
content,
|
|
250
|
+
contentType,
|
|
251
|
+
contentLength: fileBuffer.length,
|
|
252
|
+
};
|
|
253
|
+
} catch (e) {
|
|
254
|
+
if (e.code !== "ENOENT") {
|
|
255
|
+
throw e;
|
|
256
|
+
}
|
|
257
|
+
const parentDirectoryUrl = new URL("./", urlInfo.url);
|
|
258
|
+
if (!existsSync(parentDirectoryUrl)) {
|
|
259
|
+
throw e;
|
|
260
|
+
}
|
|
261
|
+
const parentDirectoryContentArray = readdirSync(
|
|
262
|
+
new URL(parentDirectoryUrl),
|
|
263
|
+
);
|
|
264
|
+
const html = generateHtmlForENOENTOnHtmlFile(
|
|
265
|
+
urlInfo.url,
|
|
266
|
+
parentDirectoryContentArray,
|
|
267
|
+
parentDirectoryUrl,
|
|
268
|
+
urlInfo.context.rootDirectoryUrl,
|
|
269
|
+
);
|
|
270
|
+
return {
|
|
271
|
+
contentType: "text/html",
|
|
272
|
+
content: html,
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
const fileBuffer = readFileSync(urlObject);
|
|
209
277
|
const content = CONTENT_TYPE.isTextual(contentType)
|
|
210
278
|
? String(fileBuffer)
|
|
211
279
|
: fileBuffer;
|
|
212
280
|
return {
|
|
213
281
|
content,
|
|
214
282
|
contentType,
|
|
283
|
+
contentLength: fileBuffer.length,
|
|
215
284
|
};
|
|
216
285
|
},
|
|
217
286
|
},
|
|
218
287
|
];
|
|
219
288
|
};
|
|
220
289
|
|
|
290
|
+
const generateHtmlForDirectory = (
|
|
291
|
+
directoryUrl,
|
|
292
|
+
directoryContentArray,
|
|
293
|
+
rootDirectoryUrl,
|
|
294
|
+
) => {
|
|
295
|
+
directoryUrl = assertAndNormalizeDirectoryUrl(directoryUrl);
|
|
296
|
+
const htmlForDirectory = String(readFileSync(htmlFileUrlForDirectory));
|
|
297
|
+
const replacers = {
|
|
298
|
+
directoryRelativeUrl: urlToRelativeUrl(directoryUrl, rootDirectoryUrl),
|
|
299
|
+
directoryUrl,
|
|
300
|
+
directoryContent: () =>
|
|
301
|
+
generateDirectoryContent(
|
|
302
|
+
directoryContentArray,
|
|
303
|
+
directoryUrl,
|
|
304
|
+
rootDirectoryUrl,
|
|
305
|
+
),
|
|
306
|
+
};
|
|
307
|
+
const html = replacePlaceholders(htmlForDirectory, replacers);
|
|
308
|
+
return html;
|
|
309
|
+
};
|
|
310
|
+
const generateHtmlForENOENTOnHtmlFile = (
|
|
311
|
+
url,
|
|
312
|
+
parentDirectoryContentArray,
|
|
313
|
+
parentDirectoryUrl,
|
|
314
|
+
rootDirectoryUrl,
|
|
315
|
+
) => {
|
|
316
|
+
if (parentDirectoryContentArray.length === 0) {
|
|
317
|
+
const htmlFor404AndParentDirIsEmpty = String(
|
|
318
|
+
readFileSync(html404AndParentDirIsEmptyFileUrl),
|
|
319
|
+
);
|
|
320
|
+
return replacePlaceholders(htmlFor404AndParentDirIsEmpty, {
|
|
321
|
+
fileRelativeUrl: urlToRelativeUrl(url, rootDirectoryUrl),
|
|
322
|
+
parentDirectoryRelativeUrl: urlToRelativeUrl(
|
|
323
|
+
parentDirectoryUrl,
|
|
324
|
+
rootDirectoryUrl,
|
|
325
|
+
),
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
const htmlFor404AndParentDir = String(
|
|
329
|
+
readFileSync(html404AndParentDirFileUrl),
|
|
330
|
+
);
|
|
331
|
+
|
|
332
|
+
const replacers = {
|
|
333
|
+
fileUrl: url,
|
|
334
|
+
fileRelativeUrl: urlToRelativeUrl(url, rootDirectoryUrl),
|
|
335
|
+
parentDirectoryUrl,
|
|
336
|
+
parentDirectoryRelativeUrl: urlToRelativeUrl(
|
|
337
|
+
parentDirectoryUrl,
|
|
338
|
+
rootDirectoryUrl,
|
|
339
|
+
),
|
|
340
|
+
parentDirectoryContent: () =>
|
|
341
|
+
generateDirectoryContent(
|
|
342
|
+
parentDirectoryContentArray,
|
|
343
|
+
parentDirectoryUrl,
|
|
344
|
+
rootDirectoryUrl,
|
|
345
|
+
),
|
|
346
|
+
};
|
|
347
|
+
const html = replacePlaceholders(htmlFor404AndParentDir, replacers);
|
|
348
|
+
return html;
|
|
349
|
+
};
|
|
350
|
+
const generateDirectoryContent = (
|
|
351
|
+
directoryContentArray,
|
|
352
|
+
directoryUrl,
|
|
353
|
+
rootDirectoryUrl,
|
|
354
|
+
) => {
|
|
355
|
+
return directoryContentArray.map((filename) => {
|
|
356
|
+
const fileUrlObject = new URL(filename, directoryUrl);
|
|
357
|
+
const fileUrl = String(fileUrlObject);
|
|
358
|
+
let fileUrlRelative = urlToRelativeUrl(fileUrl, rootDirectoryUrl);
|
|
359
|
+
if (lstatSync(fileUrlObject).isDirectory()) {
|
|
360
|
+
fileUrlRelative += "/";
|
|
361
|
+
}
|
|
362
|
+
return `<li>
|
|
363
|
+
<a href="/${fileUrlRelative}">/${fileUrlRelative}</a>
|
|
364
|
+
</li>`;
|
|
365
|
+
}).join(`
|
|
366
|
+
`);
|
|
367
|
+
};
|
|
368
|
+
const replacePlaceholders = (html, replacers) => {
|
|
369
|
+
return html.replace(/\${([\w]+)}/g, (match, name) => {
|
|
370
|
+
const replacer = replacers[name];
|
|
371
|
+
if (replacer === undefined) {
|
|
372
|
+
return match;
|
|
373
|
+
}
|
|
374
|
+
if (typeof replacer === "function") {
|
|
375
|
+
return replacer();
|
|
376
|
+
}
|
|
377
|
+
return replacer;
|
|
378
|
+
});
|
|
379
|
+
};
|
|
380
|
+
|
|
221
381
|
const resolveSymlink = (fileUrl) => {
|
|
222
382
|
const urlObject = new URL(fileUrl);
|
|
223
383
|
const realpath = realpathSync(urlObject);
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<title>Syntax error in HTML</title>
|
|
5
|
+
<meta charset="utf-8" />
|
|
6
|
+
<link rel="icon" href="data:," />
|
|
7
|
+
</head>
|
|
8
|
+
|
|
9
|
+
<body>
|
|
10
|
+
<p>Syntax error: <strong>${reasonCode}</strong></p>
|
|
11
|
+
<a jsenv-ignore href="${errorLinkHref}">${errorLinkText}</a>
|
|
12
|
+
<pre>${syntaxError}</pre>
|
|
13
|
+
</body>
|
|
14
|
+
</html>
|