@jsenv/core 40.2.0 → 40.3.1

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,213 @@
1
+ /**
2
+ * Lorsqu'on bundle un package ayant pas le field sideEffects
3
+ * alors on fini potentiellement par dire
4
+ * sideEffect: false
5
+ * sur le package racine alors qu'on en sait rien
6
+ * on pourrait mettre un package.json dans dist dans ce cas
7
+ * qui ne déclare pas le field side effect afin
8
+ * d'override le package.json du project qui lui dit qu'il ny en a pas
9
+ *
10
+ * On part du principe pour le moment que c'est la respo du package racine de déclarer cela
11
+ *
12
+ */
13
+
14
+ import { updateJsonFileSync } from "@jsenv/filesystem";
15
+ import { isSpecifierForNodeBuiltin } from "@jsenv/node-esm-resolution/src/node_builtin_specifiers.js";
16
+ import { URL_META } from "@jsenv/url-meta";
17
+ import { urlToRelativeUrl } from "@jsenv/urls";
18
+
19
+ export const jsenvPluginPackageSideEffects = ({ packageDirectory }) => {
20
+ if (!packageDirectory.url) {
21
+ return [];
22
+ }
23
+ const packageJson = packageDirectory.read(packageDirectory.url);
24
+ if (!packageJson) {
25
+ return [];
26
+ }
27
+ const { sideEffects } = packageJson;
28
+ if (sideEffects !== false && !Array.isArray(sideEffects)) {
29
+ return [];
30
+ }
31
+
32
+ const sideEffectFileUrlSet = new Set();
33
+ const packageJsonFileUrl = new URL("./package.json", packageDirectory.url)
34
+ .href;
35
+
36
+ const normalizeSideEffectFileUrl = (url) => {
37
+ const urlRelativeToPackage = urlToRelativeUrl(url, packageDirectory.url);
38
+ return urlRelativeToPackage[0] === "."
39
+ ? urlRelativeToPackage
40
+ : `./${urlRelativeToPackage}`;
41
+ };
42
+
43
+ const sideEffectBuildFileUrls = [];
44
+
45
+ const packageSideEffectsCacheMap = new Map();
46
+ const readSideEffectInfoFromClosestPackage = (urlInfo) => {
47
+ const closestPackageDirectoryUrl = urlInfo.packageDirectoryUrl;
48
+ const closestPackageJSON = urlInfo.packageJSON;
49
+ if (!closestPackageJSON) {
50
+ return undefined;
51
+ }
52
+ const fromCache = packageSideEffectsCacheMap.get(
53
+ closestPackageDirectoryUrl,
54
+ );
55
+ if (fromCache) {
56
+ return fromCache.value;
57
+ }
58
+ try {
59
+ return storePackageSideEffect(
60
+ closestPackageDirectoryUrl,
61
+ closestPackageJSON,
62
+ );
63
+ } catch {
64
+ return storePackageSideEffect(closestPackageDirectoryUrl, null);
65
+ }
66
+ };
67
+ const storePackageSideEffect = (packageDirectoryUrl, packageJSON) => {
68
+ if (!packageJSON) {
69
+ packageSideEffectsCacheMap.set(packageDirectoryUrl, { value: undefined });
70
+ return undefined;
71
+ }
72
+ const value = packageJSON.sideEffects;
73
+ if (Array.isArray(value)) {
74
+ const noSideEffect = {
75
+ has: false,
76
+ reason: "not listed in package.json side effects",
77
+ packageDirectoryUrl,
78
+ };
79
+ const hasSideEffect = {
80
+ has: true,
81
+ reason: "listed in package.json side effects",
82
+ packageDirectoryUrl,
83
+ };
84
+ const sideEffectPatterns = {};
85
+ for (const v of value) {
86
+ sideEffectPatterns[v] = v;
87
+ }
88
+ const associations = URL_META.resolveAssociations(
89
+ { sideEffects: sideEffectPatterns },
90
+ packageDirectoryUrl,
91
+ );
92
+ const getSideEffectInfo = (urlInfo) => {
93
+ const meta = URL_META.applyAssociations({
94
+ url: urlInfo.url,
95
+ associations,
96
+ });
97
+ const sideEffectKey = meta.sideEffects;
98
+ if (sideEffectKey) {
99
+ return {
100
+ ...hasSideEffect,
101
+ reason: `"${sideEffectKey}" listed in package.json side effects`,
102
+ };
103
+ }
104
+ return noSideEffect;
105
+ };
106
+ packageSideEffectsCacheMap.set(packageDirectoryUrl, {
107
+ value: getSideEffectInfo,
108
+ });
109
+ return getSideEffectInfo;
110
+ }
111
+ if (value === false) {
112
+ const noSideEffect = {
113
+ has: false,
114
+ reason: "package.json side effects is false",
115
+ packageDirectoryUrl,
116
+ };
117
+ packageSideEffectsCacheMap.set(packageDirectoryUrl, {
118
+ value: noSideEffect,
119
+ });
120
+ return noSideEffect;
121
+ }
122
+ const hasSideEffect = {
123
+ has: true,
124
+ reason: "package.json side effects is true",
125
+ packageDirectoryUrl,
126
+ };
127
+ packageSideEffectsCacheMap.set(packageDirectoryUrl, {
128
+ value: hasSideEffect,
129
+ });
130
+ return hasSideEffect;
131
+ };
132
+ const getSideEffectInfoFromClosestPackage = (urlInfo) => {
133
+ const sideEffectInfoFromClosestPackage =
134
+ readSideEffectInfoFromClosestPackage(urlInfo);
135
+ if (sideEffectInfoFromClosestPackage === undefined) {
136
+ return null;
137
+ }
138
+ if (typeof sideEffectInfoFromClosestPackage === "function") {
139
+ return sideEffectInfoFromClosestPackage(urlInfo);
140
+ }
141
+ return sideEffectInfoFromClosestPackage;
142
+ };
143
+
144
+ return {
145
+ name: "jsenv:package_side_effects",
146
+ appliesDuring: "build",
147
+ urlInfoCreated: (urlInfo) => {
148
+ const url = urlInfo.url;
149
+ if (isSpecifierForNodeBuiltin(url)) {
150
+ urlInfo.contentSideEffects.push({
151
+ sideEffect: "no",
152
+ reason: "node builtin module",
153
+ });
154
+ return;
155
+ }
156
+ if (url.startsWith("file:")) {
157
+ const sideEffectFromClosestPackage =
158
+ getSideEffectInfoFromClosestPackage(urlInfo);
159
+ if (sideEffectFromClosestPackage) {
160
+ // if (sideEffectFromClosestPackage.has) {
161
+ // console.log(`have side effect: ${url}`);
162
+ // } else {
163
+ // console.log(`no side effect: ${url}`);
164
+ // }
165
+ urlInfo.contentSideEffects.push(sideEffectFromClosestPackage);
166
+ }
167
+ return;
168
+ }
169
+ },
170
+ refineBuildUrlContent: (buildUrlInfo, { buildUrl }) => {
171
+ for (const sideEffect of buildUrlInfo.contentSideEffects) {
172
+ if (sideEffect.has) {
173
+ sideEffectBuildFileUrls.push(buildUrl);
174
+ return;
175
+ }
176
+ }
177
+ },
178
+ refineBuild: () => {
179
+ if (sideEffectBuildFileUrls.length === 0) {
180
+ return;
181
+ }
182
+ let sideEffectsToAdd = [];
183
+ if (sideEffects === false) {
184
+ sideEffectsToAdd = sideEffectBuildFileUrls;
185
+ } else if (Array.isArray(sideEffects)) {
186
+ for (const sideEffectFileRelativeUrl of sideEffects) {
187
+ const sideEffectFileUrl = new URL(
188
+ sideEffectFileRelativeUrl,
189
+ packageDirectory.url,
190
+ ).href;
191
+ sideEffectFileUrlSet.add(sideEffectFileUrl);
192
+ }
193
+ for (const url of sideEffectBuildFileUrls) {
194
+ if (sideEffectFileUrlSet.has(url)) {
195
+ continue;
196
+ }
197
+ sideEffectsToAdd.push(url);
198
+ }
199
+ }
200
+ if (sideEffectsToAdd.length === 0) {
201
+ return;
202
+ }
203
+
204
+ const finalSideEffects = Array.isArray(sideEffects) ? sideEffects : [];
205
+ for (const sideEffectBuildUrl of sideEffectBuildFileUrls) {
206
+ finalSideEffects.push(normalizeSideEffectFileUrl(sideEffectBuildUrl));
207
+ }
208
+ updateJsonFileSync(packageJsonFileUrl, {
209
+ sideEffects: finalSideEffects,
210
+ });
211
+ },
212
+ };
213
+ };
@@ -289,15 +289,18 @@ const HOOK_NAMES = [
289
289
  "redirectReference",
290
290
  "transformReferenceSearchParams",
291
291
  "formatReference",
292
+ "urlInfoCreated",
292
293
  "fetchUrlContent",
293
294
  "transformUrlContent",
294
295
  "finalizeUrlContent",
295
296
  "bundle", // is called only during build
296
- "optimizeUrlContent", // is called only during build
297
+ "optimizeBuildUrlContent", // is called only during build
297
298
  "cooked",
298
299
  "augmentResponse", // is called only during dev/tests
299
300
  "destroy",
300
301
  "effect",
302
+ "refineBuildUrlContent", // called only during build
303
+ "refineBuild", // called only during build
301
304
  ];
302
305
 
303
306
  const testAppliesDuring = (plugin, kitchen) => {
@@ -408,7 +411,7 @@ const returnValueAssertions = [
408
411
  "fetchUrlContent",
409
412
  "transformUrlContent",
410
413
  "finalizeUrlContent",
411
- "optimizeUrlContent",
414
+ "optimizeBuildUrlContent",
412
415
  ],
413
416
  assertion: (valueReturned, urlInfo, { hook }) => {
414
417
  if (typeof valueReturned === "string" || Buffer.isBuffer(valueReturned)) {
@@ -25,11 +25,13 @@ import { jsenvPluginRibbon } from "./ribbon/jsenv_plugin_ribbon.js";
25
25
  import { jsenvPluginCleanHTML } from "./clean_html/jsenv_plugin_clean_html.js";
26
26
  import { jsenvPluginChromeDevtoolsJson } from "./chrome_devtools_json/jsenv_plugin_chrome_devtools_json.js";
27
27
  import { jsenvPluginAutoreloadOnServerRestart } from "./autoreload_on_server_restart/jsenv_plugin_autoreload_on_server_restart.js";
28
+ import { jsenvPluginPackageSideEffects } from "./package_side_effects/jsenv_plugin_package_side_effects.js";
28
29
 
29
30
  export const getCorePlugins = ({
30
31
  rootDirectoryUrl,
31
32
  mainFilePath,
32
33
  runtimeCompat,
34
+ packageDirectory,
33
35
  sourceFilesConfig,
34
36
 
35
37
  referenceAnalysis = {},
@@ -50,6 +52,7 @@ export const getCorePlugins = ({
50
52
  cacheControl,
51
53
  scenarioPlaceholders = true,
52
54
  ribbon = true,
55
+ packageSideEffects = false,
53
56
  } = {}) => {
54
57
  if (cacheControl === true) {
55
58
  cacheControl = {};
@@ -90,6 +93,7 @@ export const getCorePlugins = ({
90
93
  directoryListing,
91
94
  rootDirectoryUrl,
92
95
  mainFilePath,
96
+ packageDirectory,
93
97
  sourceFilesConfig,
94
98
  }),
95
99
  {
@@ -133,5 +137,8 @@ export const getCorePlugins = ({
133
137
  ...(ribbon ? [jsenvPluginRibbon({ rootDirectoryUrl, ...ribbon })] : []),
134
138
  jsenvPluginCleanHTML(),
135
139
  jsenvPluginChromeDevtoolsJson(),
140
+ ...(packageSideEffects
141
+ ? [jsenvPluginPackageSideEffects({ rootDirectoryUrl, packageDirectory })]
142
+ : []),
136
143
  ];
137
144
  };
@@ -24,7 +24,6 @@
24
24
 
25
25
  import {
26
26
  compareFileUrls,
27
- lookupPackageDirectory,
28
27
  readEntryStatSync,
29
28
  registerDirectoryLifecycle,
30
29
  } from "@jsenv/filesystem";
@@ -49,6 +48,7 @@ export const jsenvPluginDirectoryListing = ({
49
48
  urlMocks = false,
50
49
  autoreload = true,
51
50
  directoryContentMagicName,
51
+ packageDirectory,
52
52
  rootDirectoryUrl,
53
53
  mainFilePath,
54
54
  sourceFilesConfig,
@@ -134,6 +134,7 @@ export const jsenvPluginDirectoryListing = ({
134
134
  directoryContentMagicName,
135
135
  rootDirectoryUrl,
136
136
  mainFilePath,
137
+ packageDirectory,
137
138
  enoent,
138
139
  }),
139
140
  },
@@ -221,6 +222,7 @@ const generateDirectoryListingInjection = (
221
222
  {
222
223
  rootDirectoryUrl,
223
224
  mainFilePath,
225
+ packageDirectory,
224
226
  request,
225
227
  urlMocks,
226
228
  directoryContentMagicName,
@@ -240,14 +242,13 @@ const generateDirectoryListingInjection = (
240
242
  firstExistingDirectoryUrl,
241
243
  });
242
244
  package_workspaces: {
243
- const packageDirectoryUrl = lookupPackageDirectory(serverRootDirectoryUrl);
244
- if (!packageDirectoryUrl) {
245
+ if (!packageDirectory.url) {
245
246
  break package_workspaces;
246
247
  }
247
- if (String(packageDirectoryUrl) === String(serverRootDirectoryUrl)) {
248
+ if (String(packageDirectory.url) === String(serverRootDirectoryUrl)) {
248
249
  break package_workspaces;
249
250
  }
250
- rootDirectoryUrl = packageDirectoryUrl;
251
+ rootDirectoryUrl = packageDirectory.url;
251
252
  // if (String(firstExistingDirectoryUrl) === String(serverRootDirectoryUrl)) {
252
253
  // let packageContent;
253
254
  // try {
@@ -15,6 +15,7 @@ export const jsenvPluginProtocolFile = ({
15
15
  directoryListing,
16
16
  rootDirectoryUrl,
17
17
  mainFilePath,
18
+ packageDirectory,
18
19
  sourceFilesConfig,
19
20
  }) => {
20
21
  return [
@@ -78,6 +79,7 @@ export const jsenvPluginProtocolFile = ({
78
79
  directoryContentMagicName,
79
80
  rootDirectoryUrl,
80
81
  mainFilePath,
82
+ packageDirectory,
81
83
  sourceFilesConfig,
82
84
  }),
83
85
  ]