@jsenv/core 36.3.1 → 37.0.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.
Files changed (64) hide show
  1. package/dist/js/autoreload.js +6 -5
  2. package/dist/js/import_meta_hot.js +4 -4
  3. package/dist/js/server_events_client.js +422 -304
  4. package/dist/jsenv_core.js +3819 -3256
  5. package/package.json +17 -17
  6. package/src/build/build.js +342 -658
  7. package/src/build/build_urls_generator.js +8 -8
  8. package/src/build/build_versions_manager.js +495 -0
  9. package/src/build/version_mappings_injection.js +27 -16
  10. package/src/dev/file_service.js +80 -91
  11. package/src/dev/start_dev_server.js +5 -3
  12. package/src/kitchen/errors.js +16 -16
  13. package/src/kitchen/fetched_content_compliance.js +4 -8
  14. package/src/kitchen/kitchen.js +367 -939
  15. package/src/kitchen/prepend_content.js +13 -35
  16. package/src/kitchen/url_graph/references.js +713 -0
  17. package/src/kitchen/url_graph/sort_by_dependencies.js +2 -2
  18. package/src/kitchen/url_graph/url_content.js +96 -0
  19. package/src/kitchen/url_graph/url_graph.js +439 -0
  20. package/src/kitchen/url_graph/url_graph_report.js +6 -4
  21. package/src/kitchen/url_graph/url_graph_visitor.js +14 -12
  22. package/src/kitchen/url_graph/url_info_transformations.js +180 -184
  23. package/src/plugins/autoreload/client/autoreload.js +1 -0
  24. package/src/plugins/autoreload/client/reload.js +6 -6
  25. package/src/plugins/autoreload/jsenv_plugin_autoreload.js +2 -2
  26. package/src/plugins/autoreload/jsenv_plugin_autoreload_client.js +2 -2
  27. package/src/plugins/autoreload/jsenv_plugin_autoreload_server.js +84 -78
  28. package/src/plugins/autoreload/jsenv_plugin_hot_search_param.js +52 -0
  29. package/src/plugins/cache_control/jsenv_plugin_cache_control.js +1 -1
  30. package/src/plugins/commonjs_globals/jsenv_plugin_commonjs_globals.js +2 -2
  31. package/src/plugins/global_scenarios/jsenv_plugin_global_scenarios.js +3 -3
  32. package/src/plugins/import_meta_hot/client/import_meta_hot.js +4 -4
  33. package/src/plugins/import_meta_hot/jsenv_plugin_import_meta_hot.js +18 -20
  34. package/src/plugins/import_meta_scenarios/jsenv_plugin_import_meta_scenarios.js +2 -2
  35. package/src/plugins/importmap/jsenv_plugin_importmap.js +35 -37
  36. package/src/plugins/inlining/jsenv_plugin_inlining.js +1 -17
  37. package/src/plugins/inlining/jsenv_plugin_inlining_as_data_url.js +70 -50
  38. package/src/plugins/inlining/jsenv_plugin_inlining_into_html.js +72 -54
  39. package/src/plugins/plugin_controller.js +92 -27
  40. package/src/plugins/protocol_file/jsenv_plugin_protocol_file.js +18 -20
  41. package/src/plugins/reference_analysis/css/jsenv_plugin_css_reference_analysis.js +4 -5
  42. package/src/plugins/reference_analysis/data_urls/jsenv_plugin_data_urls_analysis.js +18 -16
  43. package/src/plugins/reference_analysis/directory/jsenv_plugin_directory_reference_analysis.js +13 -20
  44. package/src/plugins/reference_analysis/html/jsenv_plugin_html_reference_analysis.js +55 -72
  45. package/src/plugins/reference_analysis/js/jsenv_plugin_js_reference_analysis.js +33 -42
  46. package/src/plugins/reference_analysis/jsenv_plugin_reference_analysis.js +16 -7
  47. package/src/plugins/reference_analysis/webmanifest/jsenv_plugin_webmanifest_reference_analysis.js +4 -3
  48. package/src/plugins/resolution_node_esm/jsenv_plugin_node_esm_resolution.js +16 -6
  49. package/src/plugins/resolution_node_esm/node_esm_resolver.js +30 -24
  50. package/src/plugins/resolution_web/jsenv_plugin_web_resolution.js +8 -5
  51. package/src/plugins/ribbon/jsenv_plugin_ribbon.js +3 -3
  52. package/src/plugins/server_events/client/server_events_client.js +460 -15
  53. package/src/plugins/server_events/jsenv_plugin_server_events_client_injection.js +13 -29
  54. package/src/plugins/version_search_param/jsenv_plugin_version_search_param.js +1 -1
  55. package/src/build/version_generator.js +0 -19
  56. package/src/kitchen/url_graph/url_graph_loader.js +0 -77
  57. package/src/kitchen/url_graph.js +0 -322
  58. package/src/plugins/autoreload/jsenv_plugin_hmr.js +0 -42
  59. package/src/plugins/resolution_node_esm/url_type_from_reference.js +0 -13
  60. package/src/plugins/server_events/client/connection_manager.js +0 -170
  61. package/src/plugins/server_events/client/event_source_connection.js +0 -83
  62. package/src/plugins/server_events/client/events_manager.js +0 -75
  63. package/src/plugins/server_events/client/web_socket_connection.js +0 -81
  64. /package/src/kitchen/{url_specifier_encoding.js → url_graph/url_specifier_encoding.js} +0 -0
@@ -0,0 +1,96 @@
1
+ import { parseJsWithAcorn } from "@jsenv/ast";
2
+ import { bufferToEtag } from "@jsenv/filesystem";
3
+
4
+ export const defineGettersOnPropertiesDerivedFromOriginalContent = (
5
+ urlInfo,
6
+ ) => {
7
+ const originalContentAstDescriptor = Object.getOwnPropertyDescriptor(
8
+ urlInfo,
9
+ "originalContentAst",
10
+ );
11
+ if (originalContentAstDescriptor.value === undefined) {
12
+ defineVolatileGetter(urlInfo, "originalContentAst", () => {
13
+ return getContentAst(urlInfo.originalContent, urlInfo.type, urlInfo.url);
14
+ });
15
+ }
16
+ const originalContentEtagDescriptor = Object.getOwnPropertyDescriptor(
17
+ urlInfo,
18
+ "originalContentEtag",
19
+ );
20
+ if (originalContentEtagDescriptor.value === undefined) {
21
+ defineVolatileGetter(urlInfo, "originalContentEtag", () => {
22
+ return bufferToEtag(Buffer.from(urlInfo.originalContent));
23
+ });
24
+ }
25
+ };
26
+
27
+ export const defineGettersOnPropertiesDerivedFromContent = (urlInfo) => {
28
+ const contentAstDescriptor = Object.getOwnPropertyDescriptor(
29
+ urlInfo,
30
+ "contentAst",
31
+ );
32
+ if (contentAstDescriptor.value === undefined) {
33
+ defineVolatileGetter(urlInfo, "contentAst", () => {
34
+ if (urlInfo.content === urlInfo.originalContent) {
35
+ return urlInfo.originalContentAst;
36
+ }
37
+ const ast = getContentAst(urlInfo.content, urlInfo.type, urlInfo.url);
38
+ return ast;
39
+ });
40
+ }
41
+ const contentEtagDescriptor = Object.getOwnPropertyDescriptor(
42
+ urlInfo,
43
+ "contentEtag",
44
+ );
45
+ if (contentEtagDescriptor.value === undefined) {
46
+ defineVolatileGetter(urlInfo, "contentEtag", () => {
47
+ if (urlInfo.content === urlInfo.originalContent) {
48
+ return urlInfo.originalContentEtag;
49
+ }
50
+ return getContentEtag(urlInfo.content);
51
+ });
52
+ }
53
+ };
54
+
55
+ const defineVolatileGetter = (object, property, getter) => {
56
+ const restore = (value) => {
57
+ Object.defineProperty(object, property, {
58
+ enumerable: true,
59
+ configurable: true,
60
+ writable: true,
61
+ value,
62
+ });
63
+ };
64
+
65
+ Object.defineProperty(object, property, {
66
+ enumerable: true,
67
+ configurable: true,
68
+ get: () => {
69
+ const value = getter();
70
+ restore(value);
71
+ return value;
72
+ },
73
+ set: restore,
74
+ });
75
+ };
76
+
77
+ const getContentAst = (content, type, url) => {
78
+ if (type === "js_module") {
79
+ return parseJsWithAcorn({
80
+ js: content,
81
+ url,
82
+ isJsModule: true,
83
+ });
84
+ }
85
+ if (type === "js_classic") {
86
+ return parseJsWithAcorn({
87
+ js: content,
88
+ url,
89
+ });
90
+ }
91
+ return null;
92
+ };
93
+
94
+ const getContentEtag = (content) => {
95
+ return bufferToEtag(Buffer.from(content));
96
+ };
@@ -0,0 +1,439 @@
1
+ import {
2
+ urlToRelativeUrl,
3
+ asUrlWithoutSearch,
4
+ injectQueryParamsIntoSpecifier,
5
+ } from "@jsenv/urls";
6
+
7
+ import { urlSpecifierEncoding } from "./url_specifier_encoding.js";
8
+ import { createDependencies } from "./references.js";
9
+
10
+ export const createUrlGraph = ({
11
+ rootDirectoryUrl,
12
+ kitchen,
13
+ name = "anonymous",
14
+ }) => {
15
+ const urlGraph = {};
16
+ const createUrlInfoCallbackRef = { current: () => {} };
17
+ const pruneUrlInfoCallbackRef = { current: () => {} };
18
+
19
+ const urlInfoMap = new Map();
20
+ const hasUrlInfo = (key) => {
21
+ if (typeof key === "string") {
22
+ return urlInfoMap.has(key);
23
+ }
24
+ if (typeof key === "object" && key && key.url) {
25
+ return urlInfoMap.has(key.url);
26
+ }
27
+ return null;
28
+ };
29
+ const getUrlInfo = (key) => {
30
+ if (typeof key === "string") {
31
+ return urlInfoMap.get(key);
32
+ }
33
+ if (typeof key === "object" && key && key.url) {
34
+ return urlInfoMap.get(key.url);
35
+ }
36
+ return null;
37
+ };
38
+ const deleteUrlInfo = (url, lastReferenceFromOther) => {
39
+ const urlInfo = urlInfoMap.get(url);
40
+ if (urlInfo) {
41
+ urlInfo.kitchen.urlInfoTransformer.resetContent(urlInfo);
42
+ urlInfoMap.delete(url);
43
+ urlInfo.modifiedTimestamp = Date.now();
44
+ if (lastReferenceFromOther && !urlInfo.isInline) {
45
+ pruneUrlInfoCallbackRef.current(urlInfo, lastReferenceFromOther);
46
+ }
47
+ urlInfo.referenceToOthersSet.forEach((referenceToOther) => {
48
+ referenceToOther.remove();
49
+ });
50
+ if (urlInfo.searchParams.size > 0) {
51
+ const urlWithoutSearch = asUrlWithoutSearch(urlInfo.url);
52
+ const urlInfoWithoutSearch = getUrlInfo(urlWithoutSearch);
53
+ if (urlInfoWithoutSearch) {
54
+ urlInfoWithoutSearch.searchParamVariantSet.delete(urlInfo);
55
+ }
56
+ }
57
+ }
58
+ };
59
+ const addUrlInfo = (urlInfo) => {
60
+ urlInfo.graph = urlGraph;
61
+ urlInfo.kitchen = kitchen;
62
+ urlInfoMap.set(urlInfo.url, urlInfo);
63
+ };
64
+ const reuseOrCreateUrlInfo = (reference, useGeneratedUrl) => {
65
+ const referencedUrl = useGeneratedUrl
66
+ ? reference.generatedUrl
67
+ : reference.url;
68
+ const existingUrlInfo = getUrlInfo(referencedUrl);
69
+ if (existingUrlInfo) return existingUrlInfo;
70
+ const ownerUrlInfo = reference.ownerUrlInfo;
71
+ const ownerContext = ownerUrlInfo.context;
72
+ const context = Object.create(ownerContext);
73
+ const referencedUrlInfo = createUrlInfo(referencedUrl, context);
74
+ addUrlInfo(referencedUrlInfo);
75
+ createUrlInfoCallbackRef.current(referencedUrlInfo);
76
+ if (referencedUrlInfo.searchParams.size > 0 && !kitchen.context.shape) {
77
+ // A resource is represented by a url.
78
+ // Variations of a resource are represented by url search params
79
+ // Each representation of the resource is given a dedicated url info
80
+ // object (one url -> one url info)
81
+ // It's because search params often influence the final content returned for that url
82
+ // When a reference contains url search params it must create 2 url infos:
83
+ // 1. The url info corresponding to the url with search params
84
+ // 2. The url info corresponding to url without search params
85
+ // Because the underlying content without search params is used to generate
86
+ // the content modified according to search params
87
+ // This way when a file like "style.css" is considered as modified
88
+ // references like "style.css?as_css_module" are also affected
89
+ const urlWithoutSearch = asUrlWithoutSearch(reference.url);
90
+ // a reference with a search param creates an implicit reference
91
+ // to the file without search param
92
+ const referenceWithoutSearch = reference.addImplicit({
93
+ specifier: urlWithoutSearch,
94
+ url: urlWithoutSearch,
95
+ searchParams: new URLSearchParams(),
96
+ isWeak: true,
97
+ });
98
+ const urlInfoWithoutSearch = referenceWithoutSearch.urlInfo;
99
+ urlInfoWithoutSearch.searchParamVariantSet.add(referencedUrlInfo);
100
+ }
101
+ return referencedUrlInfo;
102
+ };
103
+
104
+ const inferReference = (specifier, parentUrl) => {
105
+ const parentUrlInfo = getUrlInfo(parentUrl);
106
+ if (!parentUrlInfo) {
107
+ return null;
108
+ }
109
+ const seen = [];
110
+ const search = (urlInfo) => {
111
+ for (const referenceToOther of urlInfo.referenceToOthersSet) {
112
+ if (urlSpecifierEncoding.decode(referenceToOther) === specifier) {
113
+ return referenceToOther;
114
+ }
115
+ }
116
+ for (const referenceToOther of parentUrlInfo.referenceToOthersSet) {
117
+ if (seen.includes(referenceToOther.url)) {
118
+ continue;
119
+ }
120
+ seen.push(referenceToOther.url);
121
+ const referencedUrlInfo = referenceToOther.urlInfo;
122
+ if (referencedUrlInfo.isInline) {
123
+ const firstRef = search(referencedUrlInfo);
124
+ if (firstRef) {
125
+ return firstRef;
126
+ }
127
+ }
128
+ }
129
+ return null;
130
+ };
131
+ return search(parentUrlInfo);
132
+ };
133
+
134
+ const getEntryPoints = () => {
135
+ const entryPoints = [];
136
+ urlInfoMap.forEach((urlInfo) => {
137
+ if (urlInfo.isEntryPoint && urlInfo.isUsed()) {
138
+ entryPoints.push(urlInfo);
139
+ }
140
+ });
141
+ return entryPoints;
142
+ };
143
+
144
+ const rootUrlInfo = createUrlInfo(rootDirectoryUrl, kitchen.context);
145
+ rootUrlInfo.isRoot = true;
146
+ addUrlInfo(rootUrlInfo);
147
+
148
+ Object.assign(urlGraph, {
149
+ name,
150
+ rootUrlInfo,
151
+ createUrlInfoCallbackRef,
152
+ pruneUrlInfoCallbackRef,
153
+
154
+ urlInfoMap,
155
+ reuseOrCreateUrlInfo,
156
+ hasUrlInfo,
157
+ getUrlInfo,
158
+ deleteUrlInfo,
159
+ getEntryPoints,
160
+
161
+ inferReference,
162
+
163
+ toObject: () => {
164
+ const data = {};
165
+ urlInfoMap.forEach((urlInfo) => {
166
+ data[urlInfo.url] = urlInfo;
167
+ });
168
+ return data;
169
+ },
170
+ toJSON: (rootDirectoryUrl) => {
171
+ const data = {};
172
+ urlInfoMap.forEach((urlInfo) => {
173
+ if (urlInfo.referenceToOthersSet.size) {
174
+ const relativeUrl = urlToRelativeUrl(urlInfo.url, rootDirectoryUrl);
175
+ const referencedUrlSet = new Set();
176
+ for (const referenceToOther of urlInfo.referenceToOthersSet) {
177
+ data[relativeUrl] = referencedUrlSet.add(referenceToOther.url);
178
+ }
179
+ data[relativeUrl] = Array.from(referencedUrlSet).map(
180
+ (referencedUrl) =>
181
+ urlToRelativeUrl(referencedUrl, rootDirectoryUrl),
182
+ );
183
+ }
184
+ });
185
+ return data;
186
+ },
187
+ });
188
+ return urlGraph;
189
+ };
190
+
191
+ const createUrlInfo = (url, context) => {
192
+ const urlInfo = {
193
+ isRoot: false,
194
+ graph: null,
195
+ kitchen: null,
196
+ context,
197
+ error: null,
198
+ modifiedTimestamp: 0,
199
+ originalContentEtag: null,
200
+ contentEtag: null,
201
+ isWatched: false,
202
+ isValid: () => false,
203
+ data: {}, // plugins can put whatever they want here
204
+ referenceToOthersSet: new Set(),
205
+ referenceFromOthersSet: new Set(),
206
+ firstReference: null, // first reference from an other url to this one
207
+ implicitUrlSet: new Set(),
208
+ searchParamVariantSet: new Set(),
209
+
210
+ type: undefined, // "html", "css", "js_classic", "js_module", "importmap", "sourcemap", "json", "webmanifest", ...
211
+ subtype: undefined, // "worker", "service_worker", "shared_worker" for js, otherwise undefined
212
+ typeHint: undefined,
213
+ subtypeHint: undefined,
214
+ contentType: "", // "text/html", "text/css", "text/javascript", "application/json", ...
215
+ url: null,
216
+ originalUrl: undefined,
217
+ filename: "",
218
+ isEntryPoint: false,
219
+ originalContent: undefined,
220
+ originalContentAst: undefined,
221
+ content: undefined,
222
+ contentAst: undefined,
223
+ contentFinalized: false,
224
+
225
+ sourcemap: null,
226
+ sourcemapIsWrong: false,
227
+
228
+ generatedUrl: null,
229
+ sourcemapGeneratedUrl: null,
230
+ injected: false,
231
+
232
+ isInline: false,
233
+ inlineUrlSite: null,
234
+ jsQuote: null, // maybe move to inlineUrlSite?
235
+
236
+ timing: {},
237
+ headers: {},
238
+ debug: false,
239
+ };
240
+ Object.defineProperty(urlInfo, "url", {
241
+ enumerable: true,
242
+ configurable: false,
243
+ writable: false,
244
+ value: url,
245
+ });
246
+ urlInfo.searchParams = new URL(url).searchParams;
247
+
248
+ urlInfo.dependencies = createDependencies(urlInfo);
249
+ urlInfo.getFirstReferenceFromOther = ({ ignoreWeak } = {}) => {
250
+ for (const referenceFromOther of urlInfo.referenceFromOthersSet) {
251
+ if (referenceFromOther.url === urlInfo.url) {
252
+ if (
253
+ !referenceFromOther.isInline &&
254
+ referenceFromOther.next &&
255
+ referenceFromOther.next.isInline
256
+ ) {
257
+ // the url info was inlined, an other reference is required
258
+ // to consider the non-inlined urlInfo as used
259
+ continue;
260
+ }
261
+ if (ignoreWeak && referenceFromOther.isWeak) {
262
+ // weak reference don't count as using the url
263
+ continue;
264
+ }
265
+ return referenceFromOther;
266
+ }
267
+ }
268
+ return null;
269
+ };
270
+ urlInfo.isUsed = () => {
271
+ if (urlInfo.isRoot) {
272
+ return true;
273
+ }
274
+ // if (urlInfo.type === "sourcemap") {
275
+ // return true;
276
+ // }
277
+ // check if there is a strong reference to this urlInfo
278
+ if (urlInfo.getFirstReferenceFromOther({ ignoreWeak: true })) {
279
+ return true;
280
+ }
281
+ // nothing uses this url anymore
282
+ // - versioning update inline content
283
+ // - file converted for import assertion or js_classic conversion
284
+ // - urlInfo for a file that is now inlined
285
+ return false;
286
+ };
287
+ urlInfo.findParentIfInline = () => {
288
+ let currentUrlInfo = urlInfo;
289
+ const graph = urlInfo.graph;
290
+ while (currentUrlInfo.isInline) {
291
+ const parentUrlInfo = graph.getUrlInfo(currentUrlInfo.inlineUrlSite.url);
292
+ if (!parentUrlInfo.isInline) {
293
+ return parentUrlInfo;
294
+ }
295
+ currentUrlInfo = parentUrlInfo;
296
+ }
297
+ return null;
298
+ };
299
+ urlInfo.isSearchParamVariantOf = (otherUrlInfo) => {
300
+ if (urlInfo.searchParams.size === 0) {
301
+ return false;
302
+ }
303
+ if (otherUrlInfo.searchParams.size > 0) {
304
+ return false;
305
+ }
306
+ const withoutSearch = asUrlWithoutSearch(urlInfo.url);
307
+ if (withoutSearch === otherUrlInfo.url) {
308
+ return true;
309
+ }
310
+ return false;
311
+ };
312
+ urlInfo.getWithoutSearchParam = (searchParam, { expectedType } = {}) => {
313
+ // The search param can be
314
+ // 1. injected by a plugin during "redirectReference"
315
+ // - import assertions
316
+ // - js module fallback to systemjs
317
+ // 2. already inside source files
318
+ // - turn js module into js classic for convenience ?as_js_classic
319
+ // - turn js classic to js module for to make it importable
320
+ if (!urlInfo.searchParams.has(searchParam)) {
321
+ return null;
322
+ }
323
+ const reference = urlInfo.firstReference;
324
+ const newSpecifier = injectQueryParamsIntoSpecifier(reference.specifier, {
325
+ [searchParam]: undefined,
326
+ });
327
+ const referenceWithoutSearchParam = reference.addImplicit({
328
+ type: reference.type,
329
+ subtype: reference.subtype,
330
+ expectedContentType: reference.expectedContentType,
331
+ expectedType: expectedType || reference.expectedType,
332
+ expectedSubtype: reference.expectedSubtype,
333
+ integrity: reference.integrity,
334
+ crossorigin: reference.crossorigin,
335
+ specifierStart: reference.specifierStart,
336
+ specifierEnd: reference.specifierEnd,
337
+ specifierLine: reference.specifierLine,
338
+ specifierColumn: reference.specifierColumn,
339
+ baseUrl: reference.baseUrl,
340
+ isOriginalPosition: reference.isOriginalPosition,
341
+ // ok mais cet ref est implicite + weak
342
+ // donc ne devrait pas etre retournée par getEntryPoints()
343
+ isEntryPoint: reference.isEntryPoint,
344
+ isResourceHint: reference.isResourceHint,
345
+ hasVersioningEffect: reference.hasVersioningEffect,
346
+ version: reference.version,
347
+ content: reference.content,
348
+ contentType: reference.contentType,
349
+ leadsToADirectory: reference.leadsToADirectory,
350
+ debug: reference.debug,
351
+ importAttributes: reference.importAttributes,
352
+ astInfo: reference.astInfo,
353
+ mutation: reference.mutation,
354
+ data: { ...reference.data },
355
+ specifier: newSpecifier,
356
+ isWeak: true,
357
+ isInline: false,
358
+ original: reference.original || reference,
359
+ prev: reference,
360
+ // urlInfo: null,
361
+ // url: null,
362
+ // generatedUrl: null,
363
+ // generatedSpecifier: null,
364
+ // filename: null,
365
+ });
366
+ reference.next = referenceWithoutSearchParam;
367
+ return referenceWithoutSearchParam.urlInfo;
368
+ };
369
+ urlInfo.considerModified = ({ modifiedTimestamp = Date.now() } = {}) => {
370
+ const visitedSet = new Set();
371
+ const iterate = (urlInfo) => {
372
+ if (visitedSet.has(urlInfo)) {
373
+ return;
374
+ }
375
+ visitedSet.add(urlInfo);
376
+ urlInfo.modifiedTimestamp = modifiedTimestamp;
377
+ urlInfo.kitchen.urlInfoTransformer.resetContent(urlInfo);
378
+ for (const referenceToOther of urlInfo.referenceToOthersSet) {
379
+ const referencedUrlInfo = referenceToOther.urlInfo;
380
+ if (referencedUrlInfo.isInline) {
381
+ iterate(referencedUrlInfo);
382
+ }
383
+ }
384
+ for (const searchParamVariant of urlInfo.searchParamVariantSet) {
385
+ iterate(searchParamVariant);
386
+ }
387
+ };
388
+ iterate(urlInfo);
389
+ };
390
+ urlInfo.deleteFromGraph = (reference) => {
391
+ urlInfo.graph.deleteUrlInfo(urlInfo.url, reference);
392
+ };
393
+ urlInfo.cook = (customContext) => {
394
+ return urlInfo.context.cook(urlInfo, customContext);
395
+ };
396
+ urlInfo.cookDependencies = (options) => {
397
+ return urlInfo.context.cookDependencies(urlInfo, options);
398
+ };
399
+ urlInfo.fetchContent = () => {
400
+ return urlInfo.context.fetchUrlContent(urlInfo);
401
+ };
402
+ urlInfo.transformContent = () => {
403
+ return urlInfo.context.transformUrlContent(urlInfo);
404
+ };
405
+ urlInfo.finalizeContent = () => {
406
+ return urlInfo.context.finalizeUrlContent(urlInfo);
407
+ };
408
+ urlInfo.mutateContent = (transformations) => {
409
+ return urlInfo.kitchen.urlInfoTransformer.applyTransformations(
410
+ urlInfo,
411
+ transformations,
412
+ );
413
+ };
414
+
415
+ const contentTransformationCallbackSet = new Set();
416
+ urlInfo.addContentTransformationCallback = (callback) => {
417
+ if (urlInfo.contentFinalized) {
418
+ if (urlInfo.context.dev) {
419
+ throw new Error(
420
+ `cannot add a transform callback on content already sent to the browser.
421
+ --- content url ---
422
+ ${urlInfo.url}`,
423
+ );
424
+ }
425
+ urlInfo.context.addLastTransformationCallback(callback);
426
+ } else {
427
+ contentTransformationCallbackSet.add(callback);
428
+ }
429
+ };
430
+ urlInfo.applyContentTransformationCallbacks = async () => {
431
+ for (const contentTransformationCallback of contentTransformationCallbackSet) {
432
+ await contentTransformationCallback();
433
+ }
434
+ contentTransformationCallbackSet.clear();
435
+ };
436
+
437
+ // Object.preventExtensions(urlInfo) // useful to ensure all properties are declared here
438
+ return urlInfo;
439
+ };
@@ -30,6 +30,9 @@ const createUrlGraphReport = (urlGraph) => {
30
30
  total: 0,
31
31
  };
32
32
  urlGraph.urlInfoMap.forEach((urlInfo) => {
33
+ if (urlInfo.isRoot) {
34
+ return;
35
+ }
33
36
  // ignore:
34
37
  // - ignored files: we don't know their content
35
38
  // - inline files and data files: they are already taken into account in the file where they appear
@@ -47,11 +50,10 @@ const createUrlGraphReport = (urlGraph) => {
47
50
  // their js module equivalent are ignored to avoid counting it twice
48
51
  // in the build graph the file targeted by import assertion will likely be gone
49
52
  // and only the js module remain (likely bundled)
50
- const urlObject = new URL(urlInfo.url);
51
53
  if (
52
- urlObject.searchParams.has("as_json_module") ||
53
- urlObject.searchParams.has("as_css_module") ||
54
- urlObject.searchParams.has("as_text_module")
54
+ urlInfo.searchParams.has("as_json_module") ||
55
+ urlInfo.searchParams.has("as_css_module") ||
56
+ urlInfo.searchParams.has("as_text_module")
55
57
  ) {
56
58
  return;
57
59
  }
@@ -29,7 +29,8 @@ GRAPH_VISITOR.find = (graph, callback) => {
29
29
  }
30
30
  return found;
31
31
  };
32
- GRAPH_VISITOR.findDependent = (graph, urlInfo, visitor) => {
32
+ GRAPH_VISITOR.findDependent = (urlInfo, visitor) => {
33
+ const graph = urlInfo.graph;
33
34
  const seen = new Set();
34
35
  seen.add(urlInfo.url);
35
36
  let found = null;
@@ -44,9 +45,9 @@ GRAPH_VISITOR.findDependent = (graph, urlInfo, visitor) => {
44
45
  return true;
45
46
  };
46
47
  const iterate = (currentUrlInfo) => {
47
- // When cookin html inline content, html references are not yet updated
48
+ // When cookin html inline content, html dependencies are not yet updated
48
49
  // consequently htmlUrlInfo.dependencies is empty
49
- // and inlineContentUrlInfo.dependents is empty as well
50
+ // and inlineContentUrlInfo.referenceFromOthersSet is empty as well
50
51
  // in that case we resort to isInline + inlineUrlSite to establish the dependency
51
52
  if (currentUrlInfo.isInline) {
52
53
  const parentUrl = currentUrlInfo.inlineUrlSite.url;
@@ -56,20 +57,21 @@ GRAPH_VISITOR.findDependent = (graph, urlInfo, visitor) => {
56
57
  return;
57
58
  }
58
59
  }
59
- for (const dependentUrl of currentUrlInfo.dependents) {
60
- const dependentUrlInfo = graph.getUrlInfo(dependentUrl);
61
- if (visit(dependentUrlInfo)) {
60
+ for (const referenceFromOther of currentUrlInfo.referenceFromOthersSet) {
61
+ const urlInfoReferencingThisOne = referenceFromOther.ownerUrlInfo;
62
+ if (visit(urlInfoReferencingThisOne)) {
62
63
  if (found) {
63
64
  break;
64
65
  }
65
- iterate(dependentUrlInfo);
66
+ iterate(urlInfoReferencingThisOne);
66
67
  }
67
68
  }
68
69
  };
69
70
  iterate(urlInfo);
70
71
  return found;
71
72
  };
72
- GRAPH_VISITOR.findDependency = (graph, urlInfo, visitor) => {
73
+ GRAPH_VISITOR.findDependency = (urlInfo, visitor) => {
74
+ const graph = urlInfo.graph;
73
75
  const seen = new Set();
74
76
  seen.add(urlInfo.url);
75
77
  let found = null;
@@ -84,13 +86,13 @@ GRAPH_VISITOR.findDependency = (graph, urlInfo, visitor) => {
84
86
  return true;
85
87
  };
86
88
  const iterate = (currentUrlInfo) => {
87
- for (const dependencyUrl of currentUrlInfo.dependencies) {
88
- const dependencyUrlInfo = graph.getUrlInfo(dependencyUrl);
89
- if (visit(dependencyUrlInfo)) {
89
+ for (const referenceToOther of currentUrlInfo.referenceToOthersSet) {
90
+ const referencedUrlInfo = graph.getUrlInfo(referenceToOther);
91
+ if (visit(referencedUrlInfo)) {
90
92
  if (found) {
91
93
  break;
92
94
  }
93
- iterate(dependencyUrlInfo);
95
+ iterate(referencedUrlInfo);
94
96
  }
95
97
  }
96
98
  };