@jsenv/core 28.6.0 → 29.0.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.
@@ -0,0 +1,110 @@
1
+ /*
2
+ * - should I restore eventual search params lost during node esm resolution
3
+ * - what about symlinks?
4
+ * It feels like I should apply symlink (when we don't want to preserve them)
5
+ * once a file:/// url is found, regardless
6
+ * if that comes from node resolution or anything else (not even magic resolution)
7
+ * it should likely be an other plugin happening after the others
8
+ */
9
+
10
+ import { readFileSync } from "node:fs"
11
+ import { bufferToEtag } from "@jsenv/filesystem"
12
+ import {
13
+ applyNodeEsmResolution,
14
+ readCustomConditionsFromProcessArgs,
15
+ defaultLookupPackageScope,
16
+ defaultReadPackageJson,
17
+ } from "@jsenv/node-esm-resolution"
18
+
19
+ export const createNodeEsmResolver = ({ runtimeCompat, packageConditions }) => {
20
+ const nodeRuntimeEnabled = Object.keys(runtimeCompat).includes("node")
21
+ // https://nodejs.org/api/esm.html#resolver-algorithm-specification
22
+ packageConditions = packageConditions || [
23
+ ...readCustomConditionsFromProcessArgs(),
24
+ nodeRuntimeEnabled ? "node" : "browser",
25
+ "import",
26
+ ]
27
+
28
+ return (reference, context) => {
29
+ const { parentUrl, specifier } = reference
30
+ const { url, type, packageUrl } = applyNodeEsmResolution({
31
+ conditions: packageConditions,
32
+ parentUrl,
33
+ specifier,
34
+ })
35
+ if (context.scenarios.dev) {
36
+ const dependsOnPackageJson =
37
+ type !== "relative_specifier" &&
38
+ type !== "absolute_specifier" &&
39
+ type !== "node_builtin_specifier"
40
+ if (dependsOnPackageJson) {
41
+ // this reference depends on package.json and node_modules
42
+ // to be resolved. Each file using this specifier
43
+ // must be invalidated when corresponding package.json changes
44
+ addRelationshipWithPackageJson({
45
+ reference,
46
+ context,
47
+ packageJsonUrl: `${packageUrl}package.json`,
48
+ field: type.startsWith("field:")
49
+ ? `#${type.slice("field:".length)}`
50
+ : "",
51
+ })
52
+ }
53
+ }
54
+ if (context.scenarios.dev) {
55
+ // without this check a file inside a project without package.json
56
+ // could be considered as a node module if there is a ancestor package.json
57
+ // but we want to version only node modules
58
+ if (url.includes("/node_modules/")) {
59
+ const packageDirectoryUrl = defaultLookupPackageScope(url)
60
+ if (
61
+ packageDirectoryUrl &&
62
+ packageDirectoryUrl !== context.rootDirectoryUrl
63
+ ) {
64
+ const packageVersion =
65
+ defaultReadPackageJson(packageDirectoryUrl).version
66
+ // package version can be null, see https://github.com/babel/babel/blob/2ce56e832c2dd7a7ed92c89028ba929f874c2f5c/packages/babel-runtime/helpers/esm/package.json#L2
67
+ if (packageVersion) {
68
+ addRelationshipWithPackageJson({
69
+ reference,
70
+ context,
71
+ packageJsonUrl: `${packageDirectoryUrl}package.json`,
72
+ field: "version",
73
+ hasVersioningEffect: true,
74
+ })
75
+ }
76
+ reference.version = packageVersion
77
+ }
78
+ }
79
+ }
80
+ return url
81
+ }
82
+ }
83
+
84
+ const addRelationshipWithPackageJson = ({
85
+ context,
86
+ packageJsonUrl,
87
+ field,
88
+ hasVersioningEffect = false,
89
+ }) => {
90
+ const referenceFound = context.referenceUtils.find(
91
+ (ref) => ref.type === "package_json" && ref.subtype === field,
92
+ )
93
+ if (referenceFound) {
94
+ return
95
+ }
96
+ const [, packageJsonUrlInfo] = context.referenceUtils.inject({
97
+ type: "package_json",
98
+ subtype: field,
99
+ specifier: packageJsonUrl,
100
+ isImplicit: true,
101
+ hasVersioningEffect,
102
+ })
103
+ if (packageJsonUrlInfo.type === undefined) {
104
+ const packageJsonContentAsBuffer = readFileSync(new URL(packageJsonUrl))
105
+ packageJsonUrlInfo.type = "json"
106
+ packageJsonUrlInfo.content = String(packageJsonContentAsBuffer)
107
+ packageJsonUrlInfo.originalContentEtag = packageJsonUrlInfo.contentEtag =
108
+ bufferToEtag(packageJsonContentAsBuffer)
109
+ }
110
+ }
@@ -9,19 +9,24 @@ export const jsenvPluginUrlVersion = () => {
9
9
  // this goal is achieved when we reach this part of the code
10
10
  // We get rid of this params so that urlGraph and other parts of the code
11
11
  // recognize the url (it is not considered as a different url)
12
- const urlObject = new URL(reference.url)
13
- urlObject.searchParams.delete("v")
14
- return urlObject.href
12
+ const version = reference.searchParams.get("v")
13
+ if (version) {
14
+ const urlObject = new URL(reference.url)
15
+ urlObject.searchParams.delete("v")
16
+ reference.version = version
17
+ return urlObject.href
18
+ }
19
+ return null
15
20
  },
16
21
  transformUrlSearchParams: (reference) => {
17
- if (!reference.data.version) {
22
+ if (!reference.version) {
18
23
  return null
19
24
  }
20
25
  if (reference.searchParams.has("v")) {
21
26
  return null
22
27
  }
23
28
  return {
24
- v: reference.data.version,
29
+ v: reference.version,
25
30
  }
26
31
  },
27
32
  }
@@ -1,13 +0,0 @@
1
- export const jsenvPluginLeadingSlash = () => {
2
- return {
3
- name: "jsenv:leading_slash",
4
- appliesDuring: "*",
5
- resolveUrl: (reference, context) => {
6
- if (reference.specifier[0] !== "/") {
7
- return null
8
- }
9
- return new URL(reference.specifier.slice(1), context.rootDirectoryUrl)
10
- .href
11
- },
12
- }
13
- }
@@ -1,148 +0,0 @@
1
- /*
2
- * - should I restore eventual search params lost during node esm resolution
3
- * - what about symlinks?
4
- * It feels like I should apply symlink (when we don't want to preserve them)
5
- * once a file:/// url is found, regardless
6
- * if that comes from node resolution or anything else (not even magic resolution)
7
- * it should likely be an other plugin happening after the others
8
- */
9
-
10
- import { readFileSync } from "node:fs"
11
- import { bufferToEtag } from "@jsenv/filesystem"
12
- import {
13
- applyNodeEsmResolution,
14
- defaultLookupPackageScope,
15
- defaultReadPackageJson,
16
- readCustomConditionsFromProcessArgs,
17
- } from "@jsenv/node-esm-resolution"
18
-
19
- export const jsenvPluginNodeEsmResolution = ({ packageConditions }) => {
20
- const addRelationshipWithPackageJson = ({
21
- context,
22
- packageJsonUrl,
23
- field,
24
- hasVersioningEffect = false,
25
- }) => {
26
- const referenceFound = context.referenceUtils.find(
27
- (ref) => ref.type === "package_json" && ref.subtype === field,
28
- )
29
- if (referenceFound) {
30
- return
31
- }
32
- const [, packageJsonUrlInfo] = context.referenceUtils.inject({
33
- type: "package_json",
34
- subtype: field,
35
- specifier: packageJsonUrl,
36
- isImplicit: true,
37
- hasVersioningEffect,
38
- })
39
- if (packageJsonUrlInfo.type === undefined) {
40
- const packageJsonContentAsBuffer = readFileSync(new URL(packageJsonUrl))
41
- packageJsonUrlInfo.type = "json"
42
- packageJsonUrlInfo.content = String(packageJsonContentAsBuffer)
43
- packageJsonUrlInfo.originalContentEtag = packageJsonUrlInfo.contentEtag =
44
- bufferToEtag(packageJsonContentAsBuffer)
45
- }
46
- }
47
-
48
- return {
49
- name: "jsenv:node_esm_resolution",
50
- appliesDuring: "*",
51
- init: (context) => {
52
- const nodeRuntimeEnabled = Object.keys(context.runtimeCompat).includes(
53
- "node",
54
- )
55
- // https://nodejs.org/api/esm.html#resolver-algorithm-specification
56
- packageConditions = packageConditions || [
57
- ...readCustomConditionsFromProcessArgs(),
58
- nodeRuntimeEnabled ? "node" : "browser",
59
- "import",
60
- ]
61
- },
62
- resolveUrl: {
63
- js_import_export: (reference, context) => {
64
- const { parentUrl, specifier } = reference
65
- const { url, type, packageUrl } = applyNodeEsmResolution({
66
- conditions: packageConditions,
67
- parentUrl,
68
- specifier,
69
- })
70
- if (context.scenarios.dev) {
71
- const dependsOnPackageJson =
72
- type !== "relative_specifier" &&
73
- type !== "absolute_specifier" &&
74
- type !== "node_builtin_specifier"
75
- if (dependsOnPackageJson) {
76
- // this reference depends on package.json and node_modules
77
- // to be resolved. Each file using this specifier
78
- // must be invalidated when corresponding package.json changes
79
- addRelationshipWithPackageJson({
80
- reference,
81
- context,
82
- packageJsonUrl: `${packageUrl}package.json`,
83
- field: type.startsWith("field:")
84
- ? `#${type.slice("field:".length)}`
85
- : "",
86
- })
87
- }
88
- }
89
- return url
90
- },
91
- },
92
- transformUrlSearchParams: (reference, context) => {
93
- if (reference.type === "package_json") {
94
- return null
95
- }
96
- if (context.scenarios.build) {
97
- return null
98
- }
99
- if (!reference.url.startsWith("file:")) {
100
- return null
101
- }
102
- // without this check a file inside a project without package.json
103
- // could be considered as a node module if there is a ancestor package.json
104
- // but we want to version only node modules
105
- if (!reference.url.includes("/node_modules/")) {
106
- return null
107
- }
108
- if (reference.searchParams.has("v")) {
109
- return null
110
- }
111
- const packageDirectoryUrl = defaultLookupPackageScope(reference.url)
112
- if (!packageDirectoryUrl) {
113
- return null
114
- }
115
- if (packageDirectoryUrl === context.rootDirectoryUrl) {
116
- return null
117
- }
118
- // there is a dependency between this file and the package.json version field
119
- const packageVersion = defaultReadPackageJson(packageDirectoryUrl).version
120
- if (!packageVersion) {
121
- // example where it happens: https://github.com/babel/babel/blob/2ce56e832c2dd7a7ed92c89028ba929f874c2f5c/packages/babel-runtime/helpers/esm/package.json#L2
122
- return null
123
- }
124
- if (reference.type === "js_import_export") {
125
- addRelationshipWithPackageJson({
126
- reference,
127
- context,
128
- packageJsonUrl: `${packageDirectoryUrl}package.json`,
129
- field: "version",
130
- hasVersioningEffect: true,
131
- })
132
- }
133
- return {
134
- v: packageVersion,
135
- }
136
- },
137
- fetchUrlContent: (urlInfo) => {
138
- if (urlInfo.url.startsWith("file:///@ignore/")) {
139
- return {
140
- content: "export default {}",
141
- contentType: "text/javascript",
142
- type: "js_module",
143
- }
144
- }
145
- return null
146
- },
147
- }
148
- }