@jsenv/core 39.2.18 → 39.3.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/jsenv_core.js +319 -211
- package/package.json +7 -7
- package/src/build/build.js +9 -4
- package/src/build/build_specifier_manager.js +50 -6
- package/src/build/build_urls_generator.js +7 -2
- package/src/dev/start_dev_server.js +6 -2
- package/src/jsenv_core_directory_url.js +1 -0
- package/src/kitchen/url_graph/references.js +3 -0
- package/src/kitchen/url_graph/url_graph_visitor.js +14 -4
- package/src/plugins/directory_reference_effect/jsenv_plugin_directory_reference_effect.js +63 -0
- package/src/plugins/plugin_controller.js +4 -4
- package/src/plugins/plugins.js +2 -1
- package/src/plugins/protocol_file/jsenv_plugin_fs_redirection.js +108 -0
- package/src/plugins/protocol_file/jsenv_plugin_protocol_file.js +13 -153
- package/src/plugins/reference_analysis/directory/jsenv_plugin_directory_reference_analysis.js +14 -13
- package/src/plugins/reference_analysis/jsenv_plugin_reference_analysis.js +4 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jsenv/core",
|
|
3
|
-
"version": "39.
|
|
3
|
+
"version": "39.3.0",
|
|
4
4
|
"description": "Tool to develop, test and build js projects",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": {
|
|
@@ -68,20 +68,20 @@
|
|
|
68
68
|
"dependencies": {
|
|
69
69
|
"@financial-times/polyfill-useragent-normaliser": "1.10.2",
|
|
70
70
|
"@jsenv/abort": "4.3.0",
|
|
71
|
-
"@jsenv/ast": "6.2.
|
|
71
|
+
"@jsenv/ast": "6.2.15",
|
|
72
72
|
"@jsenv/filesystem": "4.9.10",
|
|
73
73
|
"@jsenv/humanize": "1.2.8",
|
|
74
74
|
"@jsenv/importmap": "1.2.1",
|
|
75
75
|
"@jsenv/integrity": "0.0.2",
|
|
76
|
-
"@jsenv/js-module-fallback": "1.3.
|
|
76
|
+
"@jsenv/js-module-fallback": "1.3.36",
|
|
77
77
|
"@jsenv/node-esm-resolution": "1.0.2",
|
|
78
|
-
"@jsenv/plugin-bundling": "2.7.
|
|
78
|
+
"@jsenv/plugin-bundling": "2.7.7",
|
|
79
79
|
"@jsenv/plugin-minification": "1.5.5",
|
|
80
|
-
"@jsenv/plugin-supervisor": "1.5.
|
|
81
|
-
"@jsenv/plugin-transpilation": "1.4.
|
|
80
|
+
"@jsenv/plugin-supervisor": "1.5.16",
|
|
81
|
+
"@jsenv/plugin-transpilation": "1.4.20",
|
|
82
82
|
"@jsenv/runtime-compat": "1.3.1",
|
|
83
83
|
"@jsenv/server": "15.2.19",
|
|
84
|
-
"@jsenv/sourcemap": "1.2.
|
|
84
|
+
"@jsenv/sourcemap": "1.2.23",
|
|
85
85
|
"@jsenv/url-meta": "8.5.1",
|
|
86
86
|
"@jsenv/urls": "2.5.2",
|
|
87
87
|
"@jsenv/utils": "2.1.2",
|
package/src/build/build.js
CHANGED
|
@@ -27,18 +27,19 @@ import { createLogger, createTaskLog } from "@jsenv/humanize";
|
|
|
27
27
|
import { jsenvPluginBundling } from "@jsenv/plugin-bundling";
|
|
28
28
|
import { jsenvPluginMinification } from "@jsenv/plugin-minification";
|
|
29
29
|
import { jsenvPluginJsModuleFallback } from "@jsenv/plugin-transpilation";
|
|
30
|
-
|
|
30
|
+
import { urlIsInsideOf } from "@jsenv/urls";
|
|
31
31
|
import { lookupPackageDirectory } from "../helpers/lookup_package_directory.js";
|
|
32
32
|
import { watchSourceFiles } from "../helpers/watch_source_files.js";
|
|
33
|
+
import { jsenvCoreDirectoryUrl } from "../jsenv_core_directory_url.js";
|
|
33
34
|
import { createKitchen } from "../kitchen/kitchen.js";
|
|
34
35
|
import { createUrlGraphSummary } from "../kitchen/url_graph/url_graph_report.js";
|
|
35
36
|
import { GRAPH_VISITOR } from "../kitchen/url_graph/url_graph_visitor.js";
|
|
37
|
+
import { jsenvPluginDirectoryReferenceEffect } from "../plugins/directory_reference_effect/jsenv_plugin_directory_reference_effect.js";
|
|
36
38
|
import { jsenvPluginInlining } from "../plugins/inlining/jsenv_plugin_inlining.js";
|
|
37
39
|
import { getCorePlugins } from "../plugins/plugins.js";
|
|
38
40
|
import { jsenvPluginReferenceAnalysis } from "../plugins/reference_analysis/jsenv_plugin_reference_analysis.js";
|
|
39
|
-
import { jsenvPluginLineBreakNormalization } from "./jsenv_plugin_line_break_normalization.js";
|
|
40
|
-
|
|
41
41
|
import { createBuildSpecifierManager } from "./build_specifier_manager.js";
|
|
42
|
+
import { jsenvPluginLineBreakNormalization } from "./jsenv_plugin_line_break_normalization.js";
|
|
42
43
|
|
|
43
44
|
// default runtimeCompat corresponds to
|
|
44
45
|
// "we can keep <script type="module"> intact":
|
|
@@ -149,7 +150,10 @@ export const build = async ({
|
|
|
149
150
|
"buildDirectoryUrl",
|
|
150
151
|
);
|
|
151
152
|
if (outDirectoryUrl === undefined) {
|
|
152
|
-
if (
|
|
153
|
+
if (
|
|
154
|
+
process.env.CAPTURING_SIDE_EFFECTS ||
|
|
155
|
+
urlIsInsideOf(sourceDirectoryUrl, jsenvCoreDirectoryUrl)
|
|
156
|
+
) {
|
|
153
157
|
outDirectoryUrl = new URL("../.jsenv/", sourceDirectoryUrl);
|
|
154
158
|
} else {
|
|
155
159
|
const packageDirectoryUrl = lookupPackageDirectory(sourceDirectoryUrl);
|
|
@@ -363,6 +367,7 @@ build ${entryPointKeys.length} entry points`);
|
|
|
363
367
|
fetchInlineUrls: false,
|
|
364
368
|
// inlineContent: false,
|
|
365
369
|
}),
|
|
370
|
+
jsenvPluginDirectoryReferenceEffect(directoryReferenceEffect),
|
|
366
371
|
...(lineBreakNormalization
|
|
367
372
|
? [jsenvPluginLineBreakNormalization()]
|
|
368
373
|
: []),
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
ensurePathnameTrailingSlash,
|
|
17
17
|
injectQueryParamIntoSpecifierWithoutEncoding,
|
|
18
18
|
renderUrlOrRelativeUrlFilename,
|
|
19
|
+
urlIsInsideOf,
|
|
19
20
|
urlToRelativeUrl,
|
|
20
21
|
} from "@jsenv/urls";
|
|
21
22
|
import { CONTENT_TYPE } from "@jsenv/utils/src/content_type/content_type.js";
|
|
@@ -203,7 +204,7 @@ export const createBuildSpecifierManager = ({
|
|
|
203
204
|
if (!generatedUrl.startsWith("file:")) {
|
|
204
205
|
return null;
|
|
205
206
|
}
|
|
206
|
-
if (reference.isWeak) {
|
|
207
|
+
if (reference.isWeak && reference.expectedType !== "directory") {
|
|
207
208
|
return null;
|
|
208
209
|
}
|
|
209
210
|
if (reference.type === "sourcemap_comment") {
|
|
@@ -468,6 +469,9 @@ export const createBuildSpecifierManager = ({
|
|
|
468
469
|
if (reference.type === "sourcemap_comment") {
|
|
469
470
|
return false;
|
|
470
471
|
}
|
|
472
|
+
if (reference.expectedType === "directory") {
|
|
473
|
+
return true;
|
|
474
|
+
}
|
|
471
475
|
// specifier comes from "normalize" hook done a bit earlier in this file
|
|
472
476
|
// we want to get back their build url to access their infos
|
|
473
477
|
const referencedUrlInfo = reference.urlInfo;
|
|
@@ -480,6 +484,7 @@ export const createBuildSpecifierManager = ({
|
|
|
480
484
|
const prepareVersioning = () => {
|
|
481
485
|
const contentOnlyVersionMap = new Map();
|
|
482
486
|
const urlInfoToContainedPlaceholderSetMap = new Map();
|
|
487
|
+
const directoryUrlInfoSet = new Set();
|
|
483
488
|
generate_content_only_versions: {
|
|
484
489
|
GRAPH_VISITOR.forEachUrlInfoStronglyReferenced(
|
|
485
490
|
finalKitchen.graph.rootUrlInfo,
|
|
@@ -536,6 +541,9 @@ export const createBuildSpecifierManager = ({
|
|
|
536
541
|
const contentVersion = generateVersion([content], versionLength);
|
|
537
542
|
contentOnlyVersionMap.set(urlInfo, contentVersion);
|
|
538
543
|
},
|
|
544
|
+
{
|
|
545
|
+
directoryUrlInfoSet,
|
|
546
|
+
},
|
|
539
547
|
);
|
|
540
548
|
}
|
|
541
549
|
|
|
@@ -582,9 +590,13 @@ export const createBuildSpecifierManager = ({
|
|
|
582
590
|
}
|
|
583
591
|
return setOfUrlInfluencingVersion;
|
|
584
592
|
};
|
|
585
|
-
|
|
593
|
+
|
|
594
|
+
for (const [
|
|
595
|
+
contentOnlyUrlInfo,
|
|
596
|
+
contentOnlyVersion,
|
|
597
|
+
] of contentOnlyVersionMap) {
|
|
586
598
|
const setOfUrlInfoInfluencingVersion =
|
|
587
|
-
getSetOfUrlInfoInfluencingVersion(
|
|
599
|
+
getSetOfUrlInfoInfluencingVersion(contentOnlyUrlInfo);
|
|
588
600
|
const versionPartSet = new Set();
|
|
589
601
|
versionPartSet.add(contentOnlyVersion);
|
|
590
602
|
for (const urlInfoInfluencingVersion of setOfUrlInfoInfluencingVersion) {
|
|
@@ -593,13 +605,42 @@ export const createBuildSpecifierManager = ({
|
|
|
593
605
|
);
|
|
594
606
|
if (!otherUrlInfoContentVersion) {
|
|
595
607
|
throw new Error(
|
|
596
|
-
`cannot find content version for ${urlInfoInfluencingVersion.url} (used by ${
|
|
608
|
+
`cannot find content version for ${urlInfoInfluencingVersion.url} (used by ${contentOnlyUrlInfo.url})`,
|
|
597
609
|
);
|
|
598
610
|
}
|
|
599
611
|
versionPartSet.add(otherUrlInfoContentVersion);
|
|
600
612
|
}
|
|
601
613
|
const version = generateVersion(versionPartSet, versionLength);
|
|
602
|
-
versionMap.set(
|
|
614
|
+
versionMap.set(contentOnlyUrlInfo, version);
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
generate_directory_versions: {
|
|
619
|
+
// we should grab all the files inside this directory
|
|
620
|
+
// they will influence his versioning
|
|
621
|
+
for (const directoryUrlInfo of directoryUrlInfoSet) {
|
|
622
|
+
const directoryUrl = directoryUrlInfo.url;
|
|
623
|
+
// const urlInfoInsideThisDirectorySet = new Set();
|
|
624
|
+
const versionsInfluencingThisDirectorySet = new Set();
|
|
625
|
+
for (const [url, urlInfo] of finalKitchen.graph.urlInfoMap) {
|
|
626
|
+
if (!urlIsInsideOf(url, directoryUrl)) {
|
|
627
|
+
continue;
|
|
628
|
+
}
|
|
629
|
+
// ideally we should exclude eventual directories as the are redundant
|
|
630
|
+
// with the file they contains
|
|
631
|
+
const version = versionMap.get(urlInfo);
|
|
632
|
+
if (version !== undefined) {
|
|
633
|
+
versionsInfluencingThisDirectorySet.add(version);
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
const contentVersion =
|
|
637
|
+
versionsInfluencingThisDirectorySet.size === 0
|
|
638
|
+
? "empty"
|
|
639
|
+
: generateVersion(
|
|
640
|
+
versionsInfluencingThisDirectorySet,
|
|
641
|
+
versionLength,
|
|
642
|
+
);
|
|
643
|
+
versionMap.set(directoryUrlInfo, contentVersion);
|
|
603
644
|
}
|
|
604
645
|
}
|
|
605
646
|
};
|
|
@@ -613,6 +654,9 @@ export const createBuildSpecifierManager = ({
|
|
|
613
654
|
return buildSpecifier;
|
|
614
655
|
}
|
|
615
656
|
const version = versionMap.get(reference.urlInfo);
|
|
657
|
+
if (version === undefined) {
|
|
658
|
+
return buildSpecifier;
|
|
659
|
+
}
|
|
616
660
|
const buildSpecifierVersioned = injectVersionIntoBuildSpecifier({
|
|
617
661
|
buildSpecifier,
|
|
618
662
|
versioningMethod,
|
|
@@ -722,9 +766,9 @@ export const createBuildSpecifierManager = ({
|
|
|
722
766
|
generateReplacement(urlInfo.firstReference);
|
|
723
767
|
}
|
|
724
768
|
if (urlInfo.firstReference.type === "side_effect_file") {
|
|
769
|
+
// side effect stuff must be generated too
|
|
725
770
|
generateReplacement(urlInfo.firstReference);
|
|
726
771
|
}
|
|
727
|
-
// side effect stuff must be generated too
|
|
728
772
|
if (mayUsePlaceholder(urlInfo)) {
|
|
729
773
|
const contentBeforeReplace = urlInfo.content;
|
|
730
774
|
const { content, sourcemap } = placeholderAPI.replaceAll(
|
|
@@ -33,9 +33,14 @@ ${ANSI.color(buildUrl, ANSI.MAGENTA)}
|
|
|
33
33
|
if (buildUrlFromCache) {
|
|
34
34
|
return buildUrlFromCache;
|
|
35
35
|
}
|
|
36
|
-
if (
|
|
36
|
+
if (
|
|
37
|
+
urlInfo.type === "directory" ||
|
|
38
|
+
(urlInfo.type === undefined && urlInfo.typeHint === "directory")
|
|
39
|
+
) {
|
|
37
40
|
let directoryPath;
|
|
38
|
-
if (
|
|
41
|
+
if (url === sourceDirectoryUrl) {
|
|
42
|
+
directoryPath = "";
|
|
43
|
+
} else if (urlInfo.filenameHint) {
|
|
39
44
|
directoryPath = urlInfo.filenameHint;
|
|
40
45
|
} else {
|
|
41
46
|
directoryPath = urlToRelativeUrl(url, sourceDirectoryUrl);
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
} from "@jsenv/server";
|
|
14
14
|
import { convertFileSystemErrorToResponseProperties } from "@jsenv/server/src/internal/convertFileSystemErrorToResponseProperties.js";
|
|
15
15
|
import { URL_META } from "@jsenv/url-meta";
|
|
16
|
-
import { urlToRelativeUrl } from "@jsenv/urls";
|
|
16
|
+
import { urlIsInsideOf, urlToRelativeUrl } from "@jsenv/urls";
|
|
17
17
|
import { existsSync, readFileSync } from "node:fs";
|
|
18
18
|
|
|
19
19
|
import { defaultRuntimeCompat } from "../build/build.js";
|
|
@@ -21,6 +21,7 @@ import { createEventEmitter } from "../helpers/event_emitter.js";
|
|
|
21
21
|
import { lookupPackageDirectory } from "../helpers/lookup_package_directory.js";
|
|
22
22
|
import { watchSourceFiles } from "../helpers/watch_source_files.js";
|
|
23
23
|
import { WEB_URL_CONVERTER } from "../helpers/web_url_converter.js";
|
|
24
|
+
import { jsenvCoreDirectoryUrl } from "../jsenv_core_directory_url.js";
|
|
24
25
|
import { createKitchen } from "../kitchen/kitchen.js";
|
|
25
26
|
import { getCorePlugins } from "../plugins/plugins.js";
|
|
26
27
|
import { jsenvPluginServerEventsClientInjection } from "../plugins/server_events/jsenv_plugin_server_events_client_injection.js";
|
|
@@ -105,7 +106,10 @@ export const startDevServer = async ({
|
|
|
105
106
|
sourceDirectoryUrl,
|
|
106
107
|
);
|
|
107
108
|
if (outDirectoryUrl === undefined) {
|
|
108
|
-
if (
|
|
109
|
+
if (
|
|
110
|
+
process.env.CAPTURING_SIDE_EFFECTS ||
|
|
111
|
+
urlIsInsideOf(sourceDirectoryUrl, jsenvCoreDirectoryUrl)
|
|
112
|
+
) {
|
|
109
113
|
outDirectoryUrl = new URL("../.jsenv/", sourceDirectoryUrl);
|
|
110
114
|
} else {
|
|
111
115
|
const packageDirectoryUrl = lookupPackageDirectory(sourceDirectoryUrl);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const jsenvCoreDirectoryUrl = new URL("../", import.meta.url);
|
|
@@ -728,6 +728,9 @@ const applyReferenceEffectsOnUrlInfo = (reference) => {
|
|
|
728
728
|
if (reference.filenameHint && !referencedUrlInfo.filenameHint) {
|
|
729
729
|
referencedUrlInfo.filenameHint = reference.filenameHint;
|
|
730
730
|
}
|
|
731
|
+
if (reference.dirnameHint && !referencedUrlInfo.dirnameHint) {
|
|
732
|
+
referencedUrlInfo.dirnameHint = reference.dirnameHint;
|
|
733
|
+
}
|
|
731
734
|
if (reference.debug) {
|
|
732
735
|
referencedUrlInfo.debug = true;
|
|
733
736
|
}
|
|
@@ -106,18 +106,28 @@ GRAPH_VISITOR.findDependency = (urlInfo, visitor) => {
|
|
|
106
106
|
// because we start from root and ignore weak ref
|
|
107
107
|
// The alternative would be to iterate on urlInfoMap
|
|
108
108
|
// and call urlInfo.isUsed() but that would be more expensive
|
|
109
|
-
GRAPH_VISITOR.forEachUrlInfoStronglyReferenced = (
|
|
109
|
+
GRAPH_VISITOR.forEachUrlInfoStronglyReferenced = (
|
|
110
|
+
initialUrlInfo,
|
|
111
|
+
callback,
|
|
112
|
+
{ directoryUrlInfoSet } = {},
|
|
113
|
+
) => {
|
|
110
114
|
const seen = new Set();
|
|
111
115
|
seen.add(initialUrlInfo);
|
|
112
116
|
const iterateOnReferences = (urlInfo) => {
|
|
113
117
|
for (const referenceToOther of urlInfo.referenceToOthersSet) {
|
|
114
|
-
if (referenceToOther.isWeak) {
|
|
115
|
-
continue;
|
|
116
|
-
}
|
|
117
118
|
if (referenceToOther.gotInlined()) {
|
|
118
119
|
continue;
|
|
119
120
|
}
|
|
120
121
|
const referencedUrlInfo = referenceToOther.urlInfo;
|
|
122
|
+
if (
|
|
123
|
+
directoryUrlInfoSet &&
|
|
124
|
+
referenceToOther.expectedType === "directory"
|
|
125
|
+
) {
|
|
126
|
+
directoryUrlInfoSet.add(referencedUrlInfo);
|
|
127
|
+
}
|
|
128
|
+
if (referenceToOther.isWeak) {
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
121
131
|
if (seen.has(referencedUrlInfo)) {
|
|
122
132
|
continue;
|
|
123
133
|
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { urlToFilename } from "@jsenv/urls";
|
|
2
|
+
|
|
3
|
+
export const jsenvPluginDirectoryReferenceEffect = (
|
|
4
|
+
directoryReferenceEffect = "error",
|
|
5
|
+
) => {
|
|
6
|
+
return {
|
|
7
|
+
name: "jsenv:directory_reference_effect",
|
|
8
|
+
appliesDuring: "*",
|
|
9
|
+
redirectReference: (reference) => {
|
|
10
|
+
// http, https, data, about, ...
|
|
11
|
+
if (!reference.url.startsWith("file:")) {
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
if (reference.isInline) {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
if (reference.ownerUrlInfo.type === "directory") {
|
|
18
|
+
reference.dirnameHint = reference.ownerUrlInfo.filenameHint;
|
|
19
|
+
}
|
|
20
|
+
const { pathname } = new URL(reference.url);
|
|
21
|
+
if (pathname[pathname.length - 1] !== "/") {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
reference.leadsToADirectory = true;
|
|
25
|
+
reference.expectedType = "directory";
|
|
26
|
+
if (reference.ownerUrlInfo.type === "directory") {
|
|
27
|
+
reference.dirnameHint = reference.ownerUrlInfo.filenameHint;
|
|
28
|
+
}
|
|
29
|
+
if (reference.type === "filesystem") {
|
|
30
|
+
reference.filenameHint = `${
|
|
31
|
+
reference.ownerUrlInfo.filenameHint
|
|
32
|
+
}${urlToFilename(reference.url)}/`;
|
|
33
|
+
} else {
|
|
34
|
+
reference.filenameHint = `${urlToFilename(reference.url)}/`;
|
|
35
|
+
}
|
|
36
|
+
let actionForDirectory;
|
|
37
|
+
if (reference.type === "a_href") {
|
|
38
|
+
actionForDirectory = "copy";
|
|
39
|
+
} else if (reference.type === "filesystem") {
|
|
40
|
+
actionForDirectory = "copy";
|
|
41
|
+
} else if (typeof directoryReferenceEffect === "string") {
|
|
42
|
+
actionForDirectory = directoryReferenceEffect;
|
|
43
|
+
} else if (typeof directoryReferenceEffect === "function") {
|
|
44
|
+
actionForDirectory = directoryReferenceEffect(reference);
|
|
45
|
+
} else {
|
|
46
|
+
actionForDirectory = "error";
|
|
47
|
+
}
|
|
48
|
+
reference.actionForDirectory = actionForDirectory;
|
|
49
|
+
if (actionForDirectory !== "copy") {
|
|
50
|
+
reference.isWeak = true;
|
|
51
|
+
}
|
|
52
|
+
if (actionForDirectory === "error") {
|
|
53
|
+
const error = new Error("Reference leads to a directory");
|
|
54
|
+
error.code = "DIRECTORY_REFERENCE_NOT_ALLOWED";
|
|
55
|
+
throw error;
|
|
56
|
+
}
|
|
57
|
+
if (actionForDirectory === "preserve") {
|
|
58
|
+
return `ignore:${reference.specifier}`;
|
|
59
|
+
}
|
|
60
|
+
return null;
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
};
|
|
@@ -181,13 +181,13 @@ export const createPluginController = (
|
|
|
181
181
|
currentPlugin = hook.plugin;
|
|
182
182
|
currentHookName = hook.name;
|
|
183
183
|
let valueReturned = hookFn(info);
|
|
184
|
-
currentPlugin = null;
|
|
185
|
-
currentHookName = null;
|
|
186
184
|
if (info.timing) {
|
|
187
185
|
info.timing[`${hook.name}-${hook.plugin.name.replace("jsenv:", "")}`] =
|
|
188
186
|
performance.now() - startTimestamp;
|
|
189
187
|
}
|
|
190
188
|
valueReturned = assertAndNormalizeReturnValue(hook, valueReturned, info);
|
|
189
|
+
currentPlugin = null;
|
|
190
|
+
currentHookName = null;
|
|
191
191
|
return valueReturned;
|
|
192
192
|
};
|
|
193
193
|
const callAsyncHook = async (hook, info) => {
|
|
@@ -204,13 +204,13 @@ export const createPluginController = (
|
|
|
204
204
|
currentPlugin = hook.plugin;
|
|
205
205
|
currentHookName = hook.name;
|
|
206
206
|
let valueReturned = await hookFn(info);
|
|
207
|
-
currentPlugin = null;
|
|
208
|
-
currentHookName = null;
|
|
209
207
|
if (info.timing) {
|
|
210
208
|
info.timing[`${hook.name}-${hook.plugin.name.replace("jsenv:", "")}`] =
|
|
211
209
|
performance.now() - startTimestamp;
|
|
212
210
|
}
|
|
213
211
|
valueReturned = assertAndNormalizeReturnValue(hook, valueReturned, info);
|
|
212
|
+
currentPlugin = null;
|
|
213
|
+
currentHookName = null;
|
|
214
214
|
return valueReturned;
|
|
215
215
|
};
|
|
216
216
|
|
package/src/plugins/plugins.js
CHANGED
|
@@ -9,6 +9,7 @@ import { jsenvPluginWebResolution } from "./resolution_web/jsenv_plugin_web_reso
|
|
|
9
9
|
import { jsenvPluginVersionSearchParam } from "./version_search_param/jsenv_plugin_version_search_param.js";
|
|
10
10
|
import { jsenvPluginProtocolFile } from "./protocol_file/jsenv_plugin_protocol_file.js";
|
|
11
11
|
import { jsenvPluginProtocolHttp } from "./protocol_http/jsenv_plugin_protocol_http.js";
|
|
12
|
+
import { jsenvPluginDirectoryReferenceEffect } from "./directory_reference_effect/jsenv_plugin_directory_reference_effect.js";
|
|
12
13
|
import { jsenvPluginInjections } from "./injections/jsenv_plugin_injections.js";
|
|
13
14
|
import { jsenvPluginInlining } from "./inlining/jsenv_plugin_inlining.js";
|
|
14
15
|
import { jsenvPluginCommonJsGlobals } from "./commonjs_globals/jsenv_plugin_commonjs_globals.js";
|
|
@@ -66,7 +67,6 @@ export const getCorePlugins = ({
|
|
|
66
67
|
- All the rest uses web standard url resolution
|
|
67
68
|
*/
|
|
68
69
|
jsenvPluginProtocolFile({
|
|
69
|
-
directoryReferenceEffect,
|
|
70
70
|
magicExtensions,
|
|
71
71
|
magicDirectoryIndex,
|
|
72
72
|
}),
|
|
@@ -75,6 +75,7 @@ export const getCorePlugins = ({
|
|
|
75
75
|
? [jsenvPluginNodeEsmResolution(nodeEsmResolution)]
|
|
76
76
|
: []),
|
|
77
77
|
jsenvPluginWebResolution(),
|
|
78
|
+
jsenvPluginDirectoryReferenceEffect(directoryReferenceEffect),
|
|
78
79
|
|
|
79
80
|
jsenvPluginVersionSearchParam(),
|
|
80
81
|
jsenvPluginCommonJsGlobals(),
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import {
|
|
2
|
+
applyFileSystemMagicResolution,
|
|
3
|
+
getExtensionsToTry,
|
|
4
|
+
} from "@jsenv/node-esm-resolution";
|
|
5
|
+
import { realpathSync, statSync } from "node:fs";
|
|
6
|
+
import { pathToFileURL } from "node:url";
|
|
7
|
+
|
|
8
|
+
export const jsenvPluginFsRedirection = ({
|
|
9
|
+
magicExtensions = ["inherit", ".js"],
|
|
10
|
+
magicDirectoryIndex = true,
|
|
11
|
+
preserveSymlinks = false,
|
|
12
|
+
}) => {
|
|
13
|
+
return {
|
|
14
|
+
name: "jsenv:fs_redirection",
|
|
15
|
+
appliesDuring: "*",
|
|
16
|
+
redirectReference: (reference) => {
|
|
17
|
+
// http, https, data, about, ...
|
|
18
|
+
if (!reference.url.startsWith("file:")) {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
if (reference.isInline) {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
if (reference.url === "file:///" || reference.url === "file://") {
|
|
25
|
+
reference.leadsToADirectory = true;
|
|
26
|
+
return `ignore:file:///`;
|
|
27
|
+
}
|
|
28
|
+
// ignore all new URL second arg
|
|
29
|
+
if (reference.subtype === "new_url_second_arg") {
|
|
30
|
+
return `ignore:${reference.url}`;
|
|
31
|
+
}
|
|
32
|
+
// ignore "./" on new URL("./")
|
|
33
|
+
// if (
|
|
34
|
+
// reference.subtype === "new_url_first_arg" &&
|
|
35
|
+
// reference.specifier === "./"
|
|
36
|
+
// ) {
|
|
37
|
+
// return `ignore:${reference.url}`;
|
|
38
|
+
// }
|
|
39
|
+
const urlObject = new URL(reference.url);
|
|
40
|
+
let stat;
|
|
41
|
+
try {
|
|
42
|
+
stat = statSync(urlObject);
|
|
43
|
+
} catch (e) {
|
|
44
|
+
if (e.code === "ENOENT") {
|
|
45
|
+
stat = null;
|
|
46
|
+
} else {
|
|
47
|
+
throw e;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
const { search, hash } = urlObject;
|
|
51
|
+
urlObject.search = "";
|
|
52
|
+
urlObject.hash = "";
|
|
53
|
+
applyStatEffectsOnUrlObject(urlObject, stat);
|
|
54
|
+
const shouldApplyFilesystemMagicResolution =
|
|
55
|
+
reference.type === "js_import";
|
|
56
|
+
if (shouldApplyFilesystemMagicResolution) {
|
|
57
|
+
const filesystemResolution = applyFileSystemMagicResolution(
|
|
58
|
+
urlObject.href,
|
|
59
|
+
{
|
|
60
|
+
fileStat: stat,
|
|
61
|
+
magicDirectoryIndex,
|
|
62
|
+
magicExtensions: getExtensionsToTry(
|
|
63
|
+
magicExtensions,
|
|
64
|
+
reference.ownerUrlInfo.url,
|
|
65
|
+
),
|
|
66
|
+
},
|
|
67
|
+
);
|
|
68
|
+
if (filesystemResolution.stat) {
|
|
69
|
+
stat = filesystemResolution.stat;
|
|
70
|
+
urlObject.href = filesystemResolution.url;
|
|
71
|
+
applyStatEffectsOnUrlObject(urlObject, stat);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
if (!stat) {
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
const urlRaw = preserveSymlinks
|
|
78
|
+
? urlObject.href
|
|
79
|
+
: resolveSymlink(urlObject.href);
|
|
80
|
+
const resolvedUrl = `${urlRaw}${search}${hash}`;
|
|
81
|
+
return resolvedUrl;
|
|
82
|
+
},
|
|
83
|
+
};
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
const applyStatEffectsOnUrlObject = (urlObject, stat) => {
|
|
87
|
+
const { pathname } = urlObject;
|
|
88
|
+
const pathnameUsesTrailingSlash = pathname.endsWith("/");
|
|
89
|
+
// force trailing slash on directories
|
|
90
|
+
if (stat && stat.isDirectory() && !pathnameUsesTrailingSlash) {
|
|
91
|
+
urlObject.pathname = `${pathname}/`;
|
|
92
|
+
}
|
|
93
|
+
// otherwise remove trailing slash if any
|
|
94
|
+
if (stat && !stat.isDirectory() && pathnameUsesTrailingSlash) {
|
|
95
|
+
// a warning here? (because it's strange to reference a file with a trailing slash)
|
|
96
|
+
urlObject.pathname = pathname.slice(0, -1);
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
const resolveSymlink = (fileUrl) => {
|
|
101
|
+
const urlObject = new URL(fileUrl);
|
|
102
|
+
const realpath = realpathSync(urlObject);
|
|
103
|
+
const realUrlObject = pathToFileURL(realpath);
|
|
104
|
+
if (urlObject.pathname.endsWith("/")) {
|
|
105
|
+
realUrlObject.pathname += `/`;
|
|
106
|
+
}
|
|
107
|
+
return realUrlObject.href;
|
|
108
|
+
};
|