@jsenv/core 40.0.9 → 40.1.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.
Files changed (27) hide show
  1. package/dist/build/build.js +1792 -1098
  2. package/dist/client/autoreload/autoreload.js +2 -45
  3. package/dist/client/autoreload/jsenv_core_packages.js +20 -0
  4. package/dist/client/directory_listing/directory_listing.html +2 -2
  5. package/dist/client/directory_listing/js/directory_listing.js +8 -14
  6. package/dist/client/directory_listing/jsenv_core_node_modules.js +9 -0
  7. package/dist/jsenv_core_node_modules.js +2045 -0
  8. package/dist/jsenv_core_packages.js +9397 -5830
  9. package/dist/start_build_server/start_build_server.js +4 -2
  10. package/dist/start_dev_server/start_dev_server.js +228 -70
  11. package/package.json +16 -15
  12. package/src/build/build.js +1084 -559
  13. package/src/build/build_content_report.js +377 -0
  14. package/src/build/build_params.js +1 -4
  15. package/src/build/build_specifier_manager.js +70 -21
  16. package/src/build/build_urls_generator.js +29 -28
  17. package/src/kitchen/fetched_content_compliance.js +2 -2
  18. package/src/kitchen/kitchen.js +1 -1
  19. package/src/plugins/directory_reference_effect/jsenv_plugin_directory_reference_effect.js +20 -5
  20. package/src/plugins/plugins.js +5 -2
  21. package/src/plugins/protocol_file/jsenv_plugin_directory_listing.js +3 -4
  22. package/src/plugins/reference_analysis/jsenv_plugin_reference_analysis.js +1 -4
  23. package/src/plugins/resolution_node_esm/jsenv_plugin_node_esm_resolution.js +56 -34
  24. package/src/plugins/resolution_node_esm/node_esm_resolver.js +132 -11
  25. package/src/build/jsenv_plugin_subbuilds.js +0 -74
  26. package/src/kitchen/url_graph/url_graph_report.js +0 -202
  27. /package/dist/client/{server_events_client → server_events}/server_events_client.js +0 -0
@@ -0,0 +1,377 @@
1
+ import {
2
+ ANSI,
3
+ distributePercentages,
4
+ humanizeDuration,
5
+ humanizeFileSize,
6
+ humanizeMemory,
7
+ renderBigSection,
8
+ renderDetails,
9
+ } from "@jsenv/humanize";
10
+ import { renderTable } from "@jsenv/terminal-table";
11
+
12
+ export const createBuildContentSummary = (
13
+ buildFileContents,
14
+ { indent, title } = {},
15
+ ) => {
16
+ const buildContentReport = createBuildContentReport(buildFileContents);
17
+ return `--- ${title} ---
18
+ ${createRepartitionMessage(buildContentReport, { indent })}
19
+ --------------------`;
20
+ };
21
+
22
+ const humanizeProcessCpuUsage = (ratio) => {
23
+ const percentageAsNumber = ratio * 100;
24
+ const percentageAsNumberRounded = Math.round(percentageAsNumber);
25
+ const percentage = `${percentageAsNumberRounded}%`;
26
+ return percentage;
27
+ };
28
+ const humanizeProcessMemoryUsage = (value) => {
29
+ return humanizeMemory(value, { short: true, decimals: 0 });
30
+ };
31
+ export const renderBuildDoneLog = ({
32
+ duration,
33
+ buildFileContents,
34
+ processCpuUsage,
35
+ processMemoryUsage,
36
+ }) => {
37
+ const buildContentReport = createBuildContentReport(buildFileContents);
38
+
39
+ let title = "";
40
+ let content = "";
41
+ const lines = [];
42
+
43
+ const filesWrittenCount = buildContentReport.total.count;
44
+ if (filesWrittenCount === 1) {
45
+ title = `1 file written`;
46
+ } else {
47
+ title = `${filesWrittenCount} files written`;
48
+ const keys = Object.keys(buildContentReport);
49
+ const rows = [];
50
+ let y = 0;
51
+ let highestPercentage = 0;
52
+ let highestPercentageY = 0;
53
+ for (const key of keys) {
54
+ if (key === "sourcemaps") {
55
+ continue;
56
+ }
57
+ if (key === "total") {
58
+ continue;
59
+ }
60
+ const { count, size, percentage } = buildContentReport[key];
61
+ if (count === 0) {
62
+ continue;
63
+ }
64
+ const row = [
65
+ {
66
+ value: key,
67
+ borderTop: {},
68
+ borderBottom: {},
69
+ },
70
+ {
71
+ value: count,
72
+ borderTop: {},
73
+ borderBottom: {},
74
+ },
75
+ {
76
+ value: size,
77
+ format: "size",
78
+ borderTop: {},
79
+ borderBottom: {},
80
+ },
81
+ {
82
+ value: percentage,
83
+ format: "percentage",
84
+ unit: "%",
85
+ borderTop: {},
86
+ borderBottom: {},
87
+ },
88
+ ];
89
+ if (percentage > highestPercentage) {
90
+ highestPercentage = percentage;
91
+ highestPercentageY = y;
92
+ }
93
+ rows.push(row);
94
+ y++;
95
+ }
96
+ if (rows.length > 1) {
97
+ const rowWithHighestPercentage = rows[highestPercentageY];
98
+ for (const cell of rowWithHighestPercentage) {
99
+ cell.bold = true;
100
+ }
101
+ const table = renderTable(rows, {
102
+ borderCollapse: true,
103
+ ansi: true,
104
+ });
105
+ content += table;
106
+ content += "\n";
107
+ }
108
+ }
109
+
110
+ let sizeLine = `total size: `;
111
+ sizeLine += humanizeFileSize(buildContentReport.total.size);
112
+ lines.push(sizeLine);
113
+
114
+ let durationLine = `duration: `;
115
+ durationLine += humanizeDuration(duration, { short: true });
116
+ lines.push(durationLine);
117
+
118
+ // cpu usage
119
+ let cpuUsageLine = "cpu: ";
120
+ cpuUsageLine += `${humanizeProcessCpuUsage(processCpuUsage.end)}`;
121
+ cpuUsageLine += renderDetails({
122
+ med: humanizeProcessCpuUsage(processCpuUsage.median),
123
+ min: humanizeProcessCpuUsage(processCpuUsage.min),
124
+ max: humanizeProcessCpuUsage(processCpuUsage.max),
125
+ });
126
+ lines.push(cpuUsageLine);
127
+
128
+ // memory usage
129
+ let memoryUsageLine = "memory: ";
130
+ memoryUsageLine += `${humanizeProcessMemoryUsage(processMemoryUsage.end)}`;
131
+ memoryUsageLine += renderDetails({
132
+ med: humanizeProcessMemoryUsage(processMemoryUsage.median),
133
+ min: humanizeProcessMemoryUsage(processMemoryUsage.min),
134
+ max: humanizeProcessMemoryUsage(processMemoryUsage.max),
135
+ });
136
+ lines.push(memoryUsageLine);
137
+
138
+ content += lines.join("\n");
139
+ return `${renderBigSection({
140
+ title,
141
+ content,
142
+ })}`;
143
+ };
144
+
145
+ export const createBuildContentOneLineSummary = (
146
+ buildFileContents,
147
+ { indent },
148
+ ) => {
149
+ const buildContentReport = createBuildContentReport(buildFileContents);
150
+ const shortSummary = createBuildShortSummary(buildContentReport);
151
+ return `${indent}${shortSummary}`;
152
+ };
153
+
154
+ const createBuildContentReport = (buildFileContents) => {
155
+ const countGroups = {
156
+ sourcemaps: 0,
157
+ html: 0,
158
+ css: 0,
159
+ js: 0,
160
+ json: 0,
161
+ other: 0,
162
+ total: 0,
163
+ };
164
+ const sizeGroups = {
165
+ sourcemaps: 0,
166
+ html: 0,
167
+ css: 0,
168
+ js: 0,
169
+ json: 0,
170
+ other: 0,
171
+ total: 0,
172
+ };
173
+
174
+ for (const buildRelativeUrl of Object.keys(buildFileContents)) {
175
+ const content = buildFileContents[buildRelativeUrl];
176
+ const contentSize = Buffer.byteLength(content);
177
+ const category = determineCategory(buildRelativeUrl);
178
+ if (category === "sourcemap") {
179
+ countGroups.sourcemaps++;
180
+ sizeGroups.sourcemaps += contentSize;
181
+ continue;
182
+ }
183
+ countGroups.total++;
184
+ sizeGroups.total += contentSize;
185
+ if (category === "html") {
186
+ countGroups.html++;
187
+ sizeGroups.html += contentSize;
188
+ continue;
189
+ }
190
+ if (category === "css") {
191
+ countGroups.css++;
192
+ sizeGroups.css += contentSize;
193
+ continue;
194
+ }
195
+ if (category === "js") {
196
+ countGroups.js++;
197
+ sizeGroups.js += contentSize;
198
+ continue;
199
+ }
200
+ if (category === "json") {
201
+ countGroups.json++;
202
+ sizeGroups.json += contentSize;
203
+ continue;
204
+ }
205
+ countGroups.other++;
206
+ sizeGroups.other += contentSize;
207
+ continue;
208
+ }
209
+
210
+ const sizesToDistribute = {};
211
+ for (const groupName of Object.keys(sizeGroups)) {
212
+ if (groupName !== "sourcemaps" && groupName !== "total") {
213
+ sizesToDistribute[groupName] = sizeGroups[groupName];
214
+ }
215
+ }
216
+ const percentageGroups = distributePercentages(sizesToDistribute);
217
+
218
+ return {
219
+ // sourcemaps are special, there size are ignored
220
+ // so there is no "percentage" associated
221
+ sourcemaps: {
222
+ count: countGroups.sourcemaps,
223
+ size: sizeGroups.sourcemaps,
224
+ percentage: undefined,
225
+ },
226
+
227
+ html: {
228
+ count: countGroups.html,
229
+ size: sizeGroups.html,
230
+ percentage: percentageGroups.html,
231
+ },
232
+ css: {
233
+ count: countGroups.css,
234
+ size: sizeGroups.css,
235
+ percentage: percentageGroups.css,
236
+ },
237
+ js: {
238
+ count: countGroups.js,
239
+ size: sizeGroups.js,
240
+ percentage: percentageGroups.js,
241
+ },
242
+ json: {
243
+ count: countGroups.json,
244
+ size: sizeGroups.json,
245
+ percentage: percentageGroups.json,
246
+ },
247
+ other: {
248
+ count: countGroups.other,
249
+ size: sizeGroups.other,
250
+ percentage: percentageGroups.other,
251
+ },
252
+ total: {
253
+ count: countGroups.total,
254
+ size: sizeGroups.total,
255
+ percentage: 100,
256
+ },
257
+ };
258
+ };
259
+
260
+ const determineCategory = (buildRelativeUrl) => {
261
+ if (buildRelativeUrl.endsWith(".map")) {
262
+ return "sourcemap";
263
+ }
264
+ if (buildRelativeUrl.endsWith(".html")) {
265
+ return "html";
266
+ }
267
+ if (buildRelativeUrl.endsWith(".css")) {
268
+ return "css";
269
+ }
270
+ if (
271
+ buildRelativeUrl.endsWith(".js") ||
272
+ buildRelativeUrl.endsWith(".mjs") ||
273
+ buildRelativeUrl.endsWith(".cjs")
274
+ ) {
275
+ return "js";
276
+ }
277
+ if (buildRelativeUrl.endsWith(".json")) {
278
+ return "json";
279
+ }
280
+ return "other";
281
+ };
282
+
283
+ const createBuildShortSummary = ({ html, css, js, json, other, total }) => {
284
+ let shortSummary = "";
285
+
286
+ const tag =
287
+ html.count === total.count
288
+ ? "html"
289
+ : css.count === total.count
290
+ ? "css"
291
+ : js.count === total.count
292
+ ? "js"
293
+ : json.count === total.count
294
+ ? "json"
295
+ : "";
296
+
297
+ if (total.count === 1) {
298
+ if (tag) {
299
+ shortSummary += `1 ${tag} file`;
300
+ } else {
301
+ shortSummary += "1 file";
302
+ }
303
+ } else if (tag) {
304
+ shortSummary += `${total.count} ${tag} files`;
305
+ } else {
306
+ shortSummary += `${total.count} files`;
307
+ }
308
+
309
+ shortSummary += " (";
310
+ shortSummary += humanizeFileSize(total.size);
311
+ const repart = [];
312
+ if (html.count) {
313
+ repart.push(`html: ${html.percentage}%`);
314
+ }
315
+ if (css.count) {
316
+ repart.push(`css: ${css.percentage}%`);
317
+ }
318
+ if (js.count) {
319
+ repart.push(`js: ${js.percentage}%`);
320
+ }
321
+ if (json.count) {
322
+ repart.push(`json: ${js.percentage}%`);
323
+ }
324
+ if (other.count) {
325
+ repart.push(`other: ${js.percentage}%`);
326
+ }
327
+ if (repart.length > 1) {
328
+ shortSummary += ` / ${repart.join(" ")}`;
329
+ }
330
+ shortSummary += ")";
331
+ return shortSummary;
332
+ };
333
+
334
+ const createRepartitionMessage = (
335
+ { html, css, js, json, other, total },
336
+ { indent },
337
+ ) => {
338
+ const addPart = (name, { count, size, percentage }) => {
339
+ let part = "";
340
+ part += ANSI.color(`${name}:`, ANSI.GREY);
341
+ part += " ";
342
+ part += count;
343
+ part += " ";
344
+ part += ANSI.color(
345
+ `(${humanizeFileSize(size)} / ${percentage} %)`,
346
+ ANSI.GREY,
347
+ );
348
+ parts.push(part);
349
+ };
350
+
351
+ const parts = [];
352
+ // if (sourcemaps.count) {
353
+ // parts.push(
354
+ // `${ANSI.color(`sourcemaps:`, ANSI.GREY)} ${
355
+ // sourcemaps.count
356
+ // } (${humanizeFileSize(sourcemaps.size)})`,
357
+ // )
358
+ // }
359
+ if (html.count) {
360
+ addPart("html ", html);
361
+ }
362
+ if (css.count) {
363
+ addPart("css ", css);
364
+ }
365
+ if (js.count) {
366
+ addPart("js ", js);
367
+ }
368
+ if (json.count) {
369
+ addPart("json ", json);
370
+ }
371
+ if (other.count) {
372
+ addPart("other", other);
373
+ }
374
+ addPart("total", total);
375
+ return `${indent}${ANSI.color("-", ANSI.GREY)} ${parts.join(`
376
+ ${indent}${ANSI.color("-", ANSI.GREY)} `)}`;
377
+ };
@@ -13,8 +13,5 @@ export const defaultRuntimeCompat = {
13
13
  };
14
14
  export const logsDefault = {
15
15
  level: "info",
16
- disabled: false,
17
- animation: true,
16
+ animated: true,
18
17
  };
19
- export const getDefaultBase = (runtimeCompat) =>
20
- runtimeCompat.node ? "./" : "/";
@@ -26,7 +26,6 @@ import { escapeRegexpSpecialChars } from "@jsenv/utils/src/string/escape_regexp_
26
26
  import { prependContent } from "../kitchen/prepend_content.js";
27
27
  import { GRAPH_VISITOR } from "../kitchen/url_graph/url_graph_visitor.js";
28
28
  import { isWebWorkerUrlInfo } from "../kitchen/web_workers.js";
29
- import { createBuildUrlsGenerator } from "./build_urls_generator.js";
30
29
  import {
31
30
  injectGlobalMappings,
32
31
  injectImportmapMappings,
@@ -38,8 +37,9 @@ export const createBuildSpecifierManager = ({
38
37
  logger,
39
38
  sourceDirectoryUrl,
40
39
  buildDirectoryUrl,
41
- base,
42
40
  assetsDirectory,
41
+ buildUrlsGenerator,
42
+ base,
43
43
  length = 8,
44
44
 
45
45
  versioning,
@@ -47,12 +47,6 @@ export const createBuildSpecifierManager = ({
47
47
  versionLength,
48
48
  canUseImportmap,
49
49
  }) => {
50
- const buildUrlsGenerator = createBuildUrlsGenerator({
51
- logger,
52
- sourceDirectoryUrl,
53
- buildDirectoryUrl,
54
- assetsDirectory,
55
- });
56
50
  const placeholderAPI = createPlaceholderAPI({
57
51
  length,
58
52
  });
@@ -82,6 +76,7 @@ export const createBuildSpecifierManager = ({
82
76
  buildUrl = buildUrlsGenerator.generate(url, {
83
77
  urlInfo,
84
78
  ownerUrlInfo: reference.ownerUrlInfo,
79
+ assetsDirectory,
85
80
  });
86
81
  }
87
82
 
@@ -156,6 +151,12 @@ export const createBuildSpecifierManager = ({
156
151
  resolveReference: (reference) => {
157
152
  const { ownerUrlInfo } = reference;
158
153
  if (ownerUrlInfo.remapReference && !reference.isInline) {
154
+ if (reference.specifier.startsWith("file:")) {
155
+ const rawUrlInfo = rawKitchen.graph.getUrlInfo(reference.specifier);
156
+ if (rawUrlInfo && rawUrlInfo.type === "entry_build") {
157
+ return reference.specifier; // we want to ignore it
158
+ }
159
+ }
159
160
  const newSpecifier = ownerUrlInfo.remapReference(reference);
160
161
  reference.specifier = newSpecifier;
161
162
  }
@@ -188,6 +189,14 @@ export const createBuildSpecifierManager = ({
188
189
  return url;
189
190
  },
190
191
  redirectReference: (reference) => {
192
+ // don't think this is needed because we'll find the rawUrlInfo
193
+ // which contains the filenameHint
194
+ // const otherEntryBuildInfo = getOtherEntryBuildInfo(reference.url);
195
+ // if (otherEntryBuildInfo) {
196
+ // reference.filenameHint = otherEntryBuildInfo.entryUrlInfo.filenameHint;
197
+ // return null;
198
+ // }
199
+
191
200
  let referenceBeforeInlining = reference;
192
201
  if (
193
202
  referenceBeforeInlining.isInline &&
@@ -273,7 +282,6 @@ export const createBuildSpecifierManager = ({
273
282
  firstReference = firstReference.prev;
274
283
  }
275
284
  const rawUrl = firstReference.rawUrl || firstReference.url;
276
- const rawUrlInfo = rawKitchen.graph.getUrlInfo(rawUrl);
277
285
  const bundleInfo = bundleInfoMap.get(rawUrl);
278
286
  if (bundleInfo) {
279
287
  finalUrlInfo.remapReference = bundleInfo.remapReference;
@@ -290,7 +298,21 @@ export const createBuildSpecifierManager = ({
290
298
  data: bundleInfo.data,
291
299
  };
292
300
  }
301
+ const rawUrlInfo = rawKitchen.graph.getUrlInfo(rawUrl);
293
302
  if (rawUrlInfo) {
303
+ if (rawUrlInfo.type === "entry_build") {
304
+ const otherEntryBuildInfo = rawUrlInfo.otherEntryBuildInfo;
305
+ if (
306
+ // we need to wait ONLY if we are versioning
307
+ // and only IF the reference can't be remapped globally or by importmap
308
+ // otherwise we can reference the file right away
309
+ versioning &&
310
+ getReferenceVersioningInfo(firstReference).type === "inline"
311
+ ) {
312
+ await otherEntryBuildInfo.promise;
313
+ }
314
+ finalUrlInfo.otherEntryBuildInfo = otherEntryBuildInfo;
315
+ }
294
316
  return rawUrlInfo;
295
317
  }
296
318
  // reference injected during "shape":
@@ -521,6 +543,15 @@ export const createBuildSpecifierManager = ({
521
543
  if (urlInfo.url.startsWith("ignore:")) {
522
544
  return;
523
545
  }
546
+ if (urlInfo.type === "entry_build") {
547
+ const otherEntryBuildInfo = urlInfo.otherEntryBuildInfo;
548
+ const entryUrlInfoVersion =
549
+ otherEntryBuildInfo.buildFileVersions[
550
+ otherEntryBuildInfo.buildRelativeUrl
551
+ ];
552
+ contentOnlyVersionMap.set(urlInfo, entryUrlInfoVersion);
553
+ return;
554
+ }
524
555
  let content = urlInfo.content;
525
556
  if (urlInfo.type === "html") {
526
557
  content = stringifyHtmlAst(
@@ -560,6 +591,9 @@ export const createBuildSpecifierManager = ({
560
591
  const getSetOfUrlInfoInfluencingVersion = (urlInfo) => {
561
592
  const placeholderInfluencingVersionSet = new Set();
562
593
  const visitContainedPlaceholders = (urlInfo) => {
594
+ if (urlInfo.type === "entry_build") {
595
+ return;
596
+ }
563
597
  const referencedContentVersion = contentOnlyVersionMap.get(urlInfo);
564
598
  if (!referencedContentVersion) {
565
599
  // ignored while traversing graph (not used anymore, inline, ...)
@@ -604,20 +638,24 @@ export const createBuildSpecifierManager = ({
604
638
  contentOnlyUrlInfo,
605
639
  contentOnlyVersion,
606
640
  ] of contentOnlyVersionMap) {
607
- const setOfUrlInfoInfluencingVersion =
608
- getSetOfUrlInfoInfluencingVersion(contentOnlyUrlInfo);
609
641
  const versionPartSet = new Set();
610
- versionPartSet.add(contentOnlyVersion);
611
- for (const urlInfoInfluencingVersion of setOfUrlInfoInfluencingVersion) {
612
- const otherUrlInfoContentVersion = contentOnlyVersionMap.get(
613
- urlInfoInfluencingVersion,
614
- );
615
- if (!otherUrlInfoContentVersion) {
616
- throw new Error(
617
- `cannot find content version for ${urlInfoInfluencingVersion.url} (used by ${contentOnlyUrlInfo.url})`,
642
+ if (contentOnlyUrlInfo.type === "entry_build") {
643
+ versionPartSet.add(contentOnlyVersion);
644
+ } else {
645
+ const setOfUrlInfoInfluencingVersion =
646
+ getSetOfUrlInfoInfluencingVersion(contentOnlyUrlInfo);
647
+ versionPartSet.add(contentOnlyVersion);
648
+ for (const urlInfoInfluencingVersion of setOfUrlInfoInfluencingVersion) {
649
+ const otherUrlInfoContentVersion = contentOnlyVersionMap.get(
650
+ urlInfoInfluencingVersion,
618
651
  );
652
+ if (!otherUrlInfoContentVersion) {
653
+ throw new Error(
654
+ `cannot find content version for ${urlInfoInfluencingVersion.url} (used by ${contentOnlyUrlInfo.url})`,
655
+ );
656
+ }
657
+ versionPartSet.add(otherUrlInfoContentVersion);
619
658
  }
620
- versionPartSet.add(otherUrlInfoContentVersion);
621
659
  }
622
660
  const version = generateVersion(versionPartSet, versionLength);
623
661
  versionMap.set(contentOnlyUrlInfo, version);
@@ -1019,6 +1057,7 @@ export const createBuildSpecifierManager = ({
1019
1057
  const buildManifest = {};
1020
1058
  const buildContents = {};
1021
1059
  const buildInlineRelativeUrlSet = new Set();
1060
+ const buildFileVersions = {};
1022
1061
  GRAPH_VISITOR.forEachUrlInfoStronglyReferenced(
1023
1062
  finalKitchen.graph.rootUrlInfo,
1024
1063
  (urlInfo) => {
@@ -1032,6 +1071,9 @@ export const createBuildSpecifierManager = ({
1032
1071
  ) {
1033
1072
  return;
1034
1073
  }
1074
+ if (urlInfo.type === "entry_build") {
1075
+ return;
1076
+ }
1035
1077
  const buildSpecifier = buildUrlToBuildSpecifierMap.get(buildUrl);
1036
1078
  const buildSpecifierVersioned = versioning
1037
1079
  ? buildSpecifierToBuildSpecifierVersionedMap.get(buildSpecifier)
@@ -1040,6 +1082,8 @@ export const createBuildSpecifierManager = ({
1040
1082
  buildUrl,
1041
1083
  buildDirectoryUrl,
1042
1084
  );
1085
+ buildFileVersions[buildRelativeUrl] = versionMap.get(urlInfo);
1086
+
1043
1087
  let contentKey;
1044
1088
  // if to guard for html where versioned build specifier is not generated
1045
1089
  if (buildSpecifierVersioned) {
@@ -1078,7 +1122,12 @@ export const createBuildSpecifierManager = ({
1078
1122
  }
1079
1123
  });
1080
1124
 
1081
- return { buildFileContents, buildInlineContents, buildManifest };
1125
+ return {
1126
+ buildFileContents,
1127
+ buildInlineContents,
1128
+ buildManifest,
1129
+ buildFileVersions,
1130
+ };
1082
1131
  },
1083
1132
  };
1084
1133
  };
@@ -1,13 +1,11 @@
1
- import { ANSI } from "@jsenv/humanize";
1
+ // import { ANSI } from "@jsenv/humanize";
2
2
  import { urlIsInsideOf, urlToFilename, urlToRelativeUrl } from "@jsenv/urls";
3
3
 
4
4
  export const createBuildUrlsGenerator = ({
5
- logger,
5
+ // logger,
6
6
  sourceDirectoryUrl,
7
7
  buildDirectoryUrl,
8
- assetsDirectory,
9
8
  }) => {
10
- const cache = {};
11
9
  const getUrlName = (url, urlInfo) => {
12
10
  if (!urlInfo) {
13
11
  return urlToFilename(url);
@@ -18,25 +16,30 @@ export const createBuildUrlsGenerator = ({
18
16
  return urlToFilename(url);
19
17
  };
20
18
 
21
- const buildUrlCache = new Map();
22
-
19
+ const buildUrlMap = new Map();
23
20
  const associateBuildUrl = (url, buildUrl) => {
24
- buildUrlCache.set(url, buildUrl);
25
- logger.debug(`associate a build url
26
- ${ANSI.color(url, ANSI.GREY)} ->
27
- ${ANSI.color(buildUrl, ANSI.MAGENTA)}
28
- `);
21
+ buildUrlMap.set(url, buildUrl);
22
+ // logger.debug(`associate a build url
23
+ // ${ANSI.color(url, ANSI.GREY)} ->
24
+ // ${ANSI.color(buildUrl, ANSI.MAGENTA)}
25
+ // `);
29
26
  };
30
27
 
31
- const generate = (url, { urlInfo, ownerUrlInfo }) => {
32
- const buildUrlFromCache = buildUrlCache.get(url);
33
- if (buildUrlFromCache) {
34
- return buildUrlFromCache;
28
+ const nameSetPerDirectoryMap = new Map();
29
+ const generate = (url, { urlInfo, ownerUrlInfo, assetsDirectory }) => {
30
+ const buildUrlFromMap = buildUrlMap.get(url);
31
+ if (buildUrlFromMap) {
32
+ return buildUrlFromMap;
35
33
  }
36
34
  if (urlIsInsideOf(url, buildDirectoryUrl)) {
37
- buildUrlCache.set(url, url);
35
+ associateBuildUrl(url, url);
38
36
  return url;
39
37
  }
38
+ if (urlInfo.type === "entry_build") {
39
+ const buildUrl = new URL(urlInfo.filenameHint, buildDirectoryUrl).href;
40
+ associateBuildUrl(url, buildUrl);
41
+ return buildUrl;
42
+ }
40
43
  if (
41
44
  urlInfo.type === "directory" ||
42
45
  (urlInfo.type === undefined && urlInfo.typeHint === "directory")
@@ -61,27 +64,25 @@ ${ANSI.color(buildUrl, ANSI.MAGENTA)}
61
64
  urlInfo,
62
65
  ownerUrlInfo,
63
66
  });
64
- let names = cache[directoryPath];
65
- if (!names) {
66
- names = [];
67
- cache[directoryPath] = names;
67
+ let nameSet = nameSetPerDirectoryMap.get(directoryPath);
68
+ if (!nameSet) {
69
+ nameSet = new Set();
70
+ nameSetPerDirectoryMap.set(directoryPath, nameSet);
68
71
  }
69
72
  const urlObject = new URL(url);
70
73
  let { search, hash } = urlObject;
71
- let name = getUrlName(url, urlInfo);
72
- let [basename, extension] = splitFileExtension(name);
74
+ let urlName = getUrlName(url, urlInfo);
75
+ let [basename, extension] = splitFileExtension(urlName);
73
76
  extension = extensionMappings[extension] || extension;
74
77
  let nameCandidate = `${basename}${extension}`; // reconstruct name in case extension was normalized
75
78
  let integer = 1;
76
- while (true) {
77
- if (!names.includes(nameCandidate)) {
78
- names.push(nameCandidate);
79
- break;
80
- }
79
+ while (nameSet.has(nameCandidate)) {
81
80
  integer++;
82
81
  nameCandidate = `${basename}${integer}${extension}`;
83
82
  }
84
- const buildUrl = `${buildDirectoryUrl}${directoryPath}${nameCandidate}${search}${hash}`;
83
+ const name = nameCandidate;
84
+ nameSet.add(name);
85
+ const buildUrl = `${buildDirectoryUrl}${directoryPath}${name}${search}${hash}`;
85
86
  associateBuildUrl(url, buildUrl);
86
87
  return buildUrl;
87
88
  };
@@ -12,8 +12,8 @@ export const assertFetchedContentCompliance = ({ urlInfo, content }) => {
12
12
  }
13
13
  const { expectedType } = urlInfo.firstReference;
14
14
  if (expectedType && urlInfo.type !== expectedType) {
15
- if (urlInfo.type === "asset" && urlInfo.context.build) {
16
- // asset is a valid type during build
15
+ if (urlInfo.type === "entry_build" && urlInfo.context.build) {
16
+ // entry_build is a valid type during build
17
17
  } else {
18
18
  throw new Error(
19
19
  `type must be "${expectedType}", got "${urlInfo.type}" on ${urlInfo.url}`,
@@ -74,7 +74,7 @@ export const createKitchen = ({
74
74
  sourcemaps,
75
75
  outDirectoryUrl,
76
76
  },
77
- resolve: (specifier, importer) => {
77
+ resolve: (specifier, importer = rootDirectoryUrl) => {
78
78
  const { url, packageDirectoryUrl, packageJson } = applyNodeEsmResolution({
79
79
  conditions: packageConditions,
80
80
  parentUrl: importer,