@jsenv/core 28.3.0 → 28.3.2

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/main.js CHANGED
@@ -11940,7 +11940,7 @@ const jsenvPluginImportmap = () => {
11940
11940
  // We must precook the importmap to know its content and inline it into the HTML
11941
11941
  // In this situation the ref to the importmap was already discovered
11942
11942
  // when parsing the HTML
11943
- const importmapReference = context.referenceUtils.findByGeneratedSpecifier(src);
11943
+ const importmapReference = context.referenceUtils.find(ref => ref.generatedSpecifier === src);
11944
11944
  const importmapUrlInfo = context.urlGraph.getUrlInfo(importmapReference.url);
11945
11945
  await context.cook(importmapUrlInfo, {
11946
11946
  reference: importmapReference
@@ -17800,7 +17800,7 @@ const createUrlInfoTransformer = ({
17800
17800
  // jsenv won't emit a warning and use the following strategy:
17801
17801
  // "no sourcemap is better than wrong sourcemap"
17802
17802
 
17803
- urlInfo.sourcemapIsWrong = sourcemapIsWrong;
17803
+ urlInfo.sourcemapIsWrong = urlInfo.sourcemapIsWrong || sourcemapIsWrong;
17804
17804
  }
17805
17805
  };
17806
17806
 
@@ -17809,52 +17809,54 @@ const createUrlInfoTransformer = ({
17809
17809
  applyIntermediateTransformations(urlInfo, transformations);
17810
17810
  }
17811
17811
 
17812
- if (sourcemapsEnabled && urlInfo.sourcemap && !urlInfo.generatedUrl.startsWith("data:")) {
17813
- // during build this function can be called after the file is cooked
17814
- // - to update content and sourcemap after "optimize" hook
17815
- // - to inject versioning into the entry point content
17816
- // in this scenarion we don't want to call injectSourcemap
17817
- // just update the content and the
17818
- const sourcemapReference = urlInfo.sourcemapReference;
17819
- const sourcemapUrlInfo = urlGraph.getUrlInfo(sourcemapReference.url);
17820
- sourcemapUrlInfo.contentType = "application/json";
17821
- const sourcemap = urlInfo.sourcemap;
17822
-
17823
- if (sourcemapsRelativeSources) {
17824
- sourcemap.sources = sourcemap.sources.map(source => {
17825
- const sourceRelative = urlToRelativeUrl(source, urlInfo.url);
17826
- return sourceRelative || ".";
17827
- });
17828
- }
17812
+ if (urlInfo.sourcemapReference) {
17813
+ if (sourcemapsEnabled && urlInfo.sourcemap && !urlInfo.generatedUrl.startsWith("data:")) {
17814
+ // during build this function can be called after the file is cooked
17815
+ // - to update content and sourcemap after "optimize" hook
17816
+ // - to inject versioning into the entry point content
17817
+ // in this scenarion we don't want to call injectSourcemap
17818
+ // just update the content and the
17819
+ const sourcemapReference = urlInfo.sourcemapReference;
17820
+ const sourcemapUrlInfo = urlGraph.getUrlInfo(sourcemapReference.url);
17821
+ sourcemapUrlInfo.contentType = "application/json";
17822
+ const sourcemap = urlInfo.sourcemap;
17823
+
17824
+ if (sourcemapsRelativeSources) {
17825
+ sourcemap.sources = sourcemap.sources.map(source => {
17826
+ const sourceRelative = urlToRelativeUrl(source, urlInfo.url);
17827
+ return sourceRelative || ".";
17828
+ });
17829
+ }
17829
17830
 
17830
- if (sourcemapsSourcesProtocol !== "file:///") {
17831
- sourcemap.sources = sourcemap.sources.map(source => {
17832
- if (source.startsWith("file:///")) {
17833
- return `${sourcemapsSourcesProtocol}${source.slice("file:///".length)}`;
17834
- }
17831
+ if (sourcemapsSourcesProtocol !== "file:///") {
17832
+ sourcemap.sources = sourcemap.sources.map(source => {
17833
+ if (source.startsWith("file:///")) {
17834
+ return `${sourcemapsSourcesProtocol}${source.slice("file:///".length)}`;
17835
+ }
17835
17836
 
17836
- return source;
17837
- });
17838
- }
17837
+ return source;
17838
+ });
17839
+ }
17839
17840
 
17840
- sourcemapUrlInfo.content = JSON.stringify(sourcemap, null, " ");
17841
+ sourcemapUrlInfo.content = JSON.stringify(sourcemap, null, " ");
17841
17842
 
17842
- if (!urlInfo.sourcemapIsWrong) {
17843
- if (sourcemaps === "inline") {
17844
- sourcemapReference.generatedSpecifier = generateSourcemapDataUrl(sourcemap);
17845
- }
17843
+ if (!urlInfo.sourcemapIsWrong) {
17844
+ if (sourcemaps === "inline") {
17845
+ sourcemapReference.generatedSpecifier = generateSourcemapDataUrl(sourcemap);
17846
+ }
17846
17847
 
17847
- if (sourcemaps === "file" || sourcemaps === "inline") {
17848
- urlInfo.content = SOURCEMAP.writeComment({
17849
- contentType: urlInfo.contentType,
17850
- content: urlInfo.content,
17851
- specifier: sourcemaps === "file" && sourcemapsRelativeSources ? urlToRelativeUrl(sourcemapReference.url, urlInfo.url) : sourcemapReference.generatedSpecifier
17852
- });
17848
+ if (sourcemaps === "file" || sourcemaps === "inline") {
17849
+ urlInfo.content = SOURCEMAP.writeComment({
17850
+ contentType: urlInfo.contentType,
17851
+ content: urlInfo.content,
17852
+ specifier: sourcemaps === "file" && sourcemapsRelativeSources ? urlToRelativeUrl(sourcemapReference.url, urlInfo.url) : sourcemapReference.generatedSpecifier
17853
+ });
17854
+ }
17853
17855
  }
17856
+ } else {
17857
+ // in the end we don't use the sourcemap placeholder
17858
+ urlGraph.deleteUrlInfo(urlInfo.sourcemapReference.url);
17854
17859
  }
17855
- } else if (urlInfo.sourcemapReference) {
17856
- // in the end we don't use the sourcemap placeholder
17857
- urlGraph.deleteUrlInfo(urlInfo.sourcemapReference.url);
17858
17860
  }
17859
17861
 
17860
17862
  urlInfo.contentEtag = urlInfo.content === urlInfo.originalContent ? urlInfo.originalContentEtag : bufferToEtag$1(Buffer.from(urlInfo.content));
@@ -18632,6 +18634,8 @@ ${ANSI.color(normalizedReturnValue, ANSI.YELLOW)}
18632
18634
  const references = [];
18633
18635
  context.referenceUtils = {
18634
18636
  _references: references,
18637
+ find: predicate => references.find(predicate),
18638
+ readGeneratedSpecifier,
18635
18639
  add: props => {
18636
18640
  const [reference, referencedUrlInfo] = resolveReference(createReference({
18637
18641
  parentUrl: urlInfo.url,
@@ -18640,8 +18644,6 @@ ${ANSI.color(normalizedReturnValue, ANSI.YELLOW)}
18640
18644
  references.push(reference);
18641
18645
  return [reference, referencedUrlInfo];
18642
18646
  },
18643
- find: predicate => references.find(predicate),
18644
- readGeneratedSpecifier,
18645
18647
  found: ({
18646
18648
  trace,
18647
18649
  ...rest
@@ -18703,6 +18705,29 @@ ${ANSI.color(normalizedReturnValue, ANSI.YELLOW)}
18703
18705
 
18704
18706
  return [newReference, newUrlInfo];
18705
18707
  },
18708
+ inject: ({
18709
+ trace,
18710
+ ...rest
18711
+ }) => {
18712
+ if (trace === undefined) {
18713
+ const {
18714
+ url,
18715
+ line,
18716
+ column
18717
+ } = getCallerPosition();
18718
+ trace = traceFromUrlSite({
18719
+ url,
18720
+ line,
18721
+ column
18722
+ });
18723
+ }
18724
+
18725
+ return context.referenceUtils.add({
18726
+ trace,
18727
+ injected: true,
18728
+ ...rest
18729
+ });
18730
+ },
18706
18731
  becomesInline: (reference, {
18707
18732
  isOriginalPosition,
18708
18733
  specifier,
@@ -18729,37 +18754,8 @@ ${ANSI.color(normalizedReturnValue, ANSI.YELLOW)}
18729
18754
  content
18730
18755
  });
18731
18756
  },
18732
- inject: ({
18733
- trace,
18734
- ...rest
18735
- }) => {
18736
- if (trace === undefined) {
18737
- const {
18738
- url,
18739
- line,
18740
- column
18741
- } = getCallerPosition();
18742
- trace = traceFromUrlSite({
18743
- url,
18744
- line,
18745
- column
18746
- });
18747
- }
18748
-
18749
- return context.referenceUtils.add({
18750
- trace,
18751
- injected: true,
18752
- ...rest
18753
- });
18754
- },
18755
- findByGeneratedSpecifier: generatedSpecifier => {
18756
- const reference = references.find(ref => ref.generatedSpecifier === generatedSpecifier);
18757
-
18758
- if (!reference) {
18759
- throw new Error(`No reference found using the following generatedSpecifier: "${generatedSpecifier}"`);
18760
- }
18761
-
18762
- return reference;
18757
+ becomesExternal: () => {
18758
+ throw new Error("not implemented yet");
18763
18759
  }
18764
18760
  }; // "fetchUrlContent" hook
18765
18761
 
@@ -25486,22 +25482,30 @@ const createFileService = ({
25486
25482
  const urlInfoTargetedByCache = urlGraph.getParentIfInline(urlInfo);
25487
25483
 
25488
25484
  if (ifNoneMatch) {
25489
- if (urlInfoTargetedByCache.contentEtag === ifNoneMatch && urlInfoTargetedByCache.isValid()) {
25485
+ const [clientOriginalContentEtag, clientContentEtag] = ifNoneMatch.split("_");
25486
+
25487
+ if (urlInfoTargetedByCache.originalContentEtag === clientOriginalContentEtag && urlInfoTargetedByCache.contentEtag === clientContentEtag && urlInfoTargetedByCache.isValid()) {
25488
+ const headers = {
25489
+ "cache-control": `private,max-age=0,must-revalidate`
25490
+ };
25491
+ Object.keys(urlInfo.headers).forEach(key => {
25492
+ if (key !== "content-length") {
25493
+ headers[key] = urlInfo.headers[key];
25494
+ }
25495
+ });
25490
25496
  return {
25491
25497
  status: 304,
25492
- headers: {
25493
- "cache-control": `private,max-age=0,must-revalidate`,
25494
- ...urlInfo.headers
25495
- }
25498
+ headers
25496
25499
  };
25497
25500
  }
25498
25501
  }
25499
25502
 
25500
25503
  try {
25501
25504
  // urlInfo objects are reused, they must be "reset" before cooking them again
25502
- if (urlInfo.contentEtag && !urlInfo.isInline && urlInfo.type !== "sourcemap") {
25505
+ if ((urlInfo.error || urlInfo.contentEtag) && !urlInfo.isInline && urlInfo.type !== "sourcemap") {
25503
25506
  urlInfo.error = null;
25504
25507
  urlInfo.sourcemap = null;
25508
+ urlInfo.sourcemapIsWrong = null;
25505
25509
  urlInfo.sourcemapReference = null;
25506
25510
  urlInfo.content = null;
25507
25511
  urlInfo.originalContent = null;
@@ -25526,11 +25530,12 @@ const createFileService = ({
25526
25530
  url: reference.url,
25527
25531
  status: 200,
25528
25532
  headers: {
25529
- "content-length": Buffer.byteLength(urlInfo.content),
25530
25533
  "cache-control": `private,max-age=0,must-revalidate`,
25531
- "eTag": urlInfoTargetedByCache.contentEtag,
25534
+ // it's safe to use "_" separator because etag is encoded with base64 (see https://stackoverflow.com/a/13195197)
25535
+ "eTag": `${urlInfoTargetedByCache.originalContentEtag}_${urlInfoTargetedByCache.contentEtag}`,
25532
25536
  ...urlInfo.headers,
25533
- "content-type": urlInfo.contentType
25537
+ "content-type": urlInfo.contentType,
25538
+ "content-length": Buffer.byteLength(urlInfo.content)
25534
25539
  },
25535
25540
  body: urlInfo.content,
25536
25541
  timing: urlInfo.timing
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jsenv/core",
3
- "version": "28.3.0",
3
+ "version": "28.3.2",
4
4
  "description": "Tool to develop, test and build js projects",
5
5
  "license": "MIT",
6
6
  "author": {
@@ -429,6 +429,8 @@ ${ANSI.color(normalizedReturnValue, ANSI.YELLOW)}
429
429
  const references = []
430
430
  context.referenceUtils = {
431
431
  _references: references,
432
+ find: (predicate) => references.find(predicate),
433
+ readGeneratedSpecifier,
432
434
  add: (props) => {
433
435
  const [reference, referencedUrlInfo] = resolveReference(
434
436
  createReference({
@@ -440,8 +442,6 @@ ${ANSI.color(normalizedReturnValue, ANSI.YELLOW)}
440
442
  references.push(reference)
441
443
  return [reference, referencedUrlInfo]
442
444
  },
443
- find: (predicate) => references.find(predicate),
444
- readGeneratedSpecifier,
445
445
  found: ({ trace, ...rest }) => {
446
446
  if (trace === undefined) {
447
447
  trace = traceFromUrlSite(
@@ -511,6 +511,21 @@ ${ANSI.color(normalizedReturnValue, ANSI.YELLOW)}
511
511
  }
512
512
  return [newReference, newUrlInfo]
513
513
  },
514
+ inject: ({ trace, ...rest }) => {
515
+ if (trace === undefined) {
516
+ const { url, line, column } = getCallerPosition()
517
+ trace = traceFromUrlSite({
518
+ url,
519
+ line,
520
+ column,
521
+ })
522
+ }
523
+ return context.referenceUtils.add({
524
+ trace,
525
+ injected: true,
526
+ ...rest,
527
+ })
528
+ },
514
529
  becomesInline: (
515
530
  reference,
516
531
  {
@@ -544,31 +559,8 @@ ${ANSI.color(normalizedReturnValue, ANSI.YELLOW)}
544
559
  content,
545
560
  })
546
561
  },
547
- inject: ({ trace, ...rest }) => {
548
- if (trace === undefined) {
549
- const { url, line, column } = getCallerPosition()
550
- trace = traceFromUrlSite({
551
- url,
552
- line,
553
- column,
554
- })
555
- }
556
- return context.referenceUtils.add({
557
- trace,
558
- injected: true,
559
- ...rest,
560
- })
561
- },
562
- findByGeneratedSpecifier: (generatedSpecifier) => {
563
- const reference = references.find(
564
- (ref) => ref.generatedSpecifier === generatedSpecifier,
565
- )
566
- if (!reference) {
567
- throw new Error(
568
- `No reference found using the following generatedSpecifier: "${generatedSpecifier}"`,
569
- )
570
- }
571
- return reference
562
+ becomesExternal: () => {
563
+ throw new Error("not implemented yet")
572
564
  },
573
565
  }
574
566
 
@@ -264,28 +264,38 @@ export const createFileService = ({
264
264
  const urlInfoTargetedByCache = urlGraph.getParentIfInline(urlInfo)
265
265
 
266
266
  if (ifNoneMatch) {
267
+ const [clientOriginalContentEtag, clientContentEtag] =
268
+ ifNoneMatch.split("_")
267
269
  if (
268
- urlInfoTargetedByCache.contentEtag === ifNoneMatch &&
270
+ urlInfoTargetedByCache.originalContentEtag ===
271
+ clientOriginalContentEtag &&
272
+ urlInfoTargetedByCache.contentEtag === clientContentEtag &&
269
273
  urlInfoTargetedByCache.isValid()
270
274
  ) {
275
+ const headers = {
276
+ "cache-control": `private,max-age=0,must-revalidate`,
277
+ }
278
+ Object.keys(urlInfo.headers).forEach((key) => {
279
+ if (key !== "content-length") {
280
+ headers[key] = urlInfo.headers[key]
281
+ }
282
+ })
271
283
  return {
272
284
  status: 304,
273
- headers: {
274
- "cache-control": `private,max-age=0,must-revalidate`,
275
- ...urlInfo.headers,
276
- },
285
+ headers,
277
286
  }
278
287
  }
279
288
  }
280
289
  try {
281
290
  // urlInfo objects are reused, they must be "reset" before cooking them again
282
291
  if (
283
- urlInfo.contentEtag &&
292
+ (urlInfo.error || urlInfo.contentEtag) &&
284
293
  !urlInfo.isInline &&
285
294
  urlInfo.type !== "sourcemap"
286
295
  ) {
287
296
  urlInfo.error = null
288
297
  urlInfo.sourcemap = null
298
+ urlInfo.sourcemapIsWrong = null
289
299
  urlInfo.sourcemapReference = null
290
300
  urlInfo.content = null
291
301
  urlInfo.originalContent = null
@@ -305,11 +315,12 @@ export const createFileService = ({
305
315
  url: reference.url,
306
316
  status: 200,
307
317
  headers: {
308
- "content-length": Buffer.byteLength(urlInfo.content),
309
318
  "cache-control": `private,max-age=0,must-revalidate`,
310
- "eTag": urlInfoTargetedByCache.contentEtag,
319
+ // it's safe to use "_" separator because etag is encoded with base64 (see https://stackoverflow.com/a/13195197)
320
+ "eTag": `${urlInfoTargetedByCache.originalContentEtag}_${urlInfoTargetedByCache.contentEtag}`,
311
321
  ...urlInfo.headers,
312
322
  "content-type": urlInfo.contentType,
323
+ "content-length": Buffer.byteLength(urlInfo.content),
313
324
  },
314
325
  body: urlInfo.content,
315
326
  timing: urlInfo.timing,
@@ -164,7 +164,7 @@ export const createUrlInfoTransformer = ({
164
164
  // is a nightmare no-one could solve in years so
165
165
  // jsenv won't emit a warning and use the following strategy:
166
166
  // "no sourcemap is better than wrong sourcemap"
167
- urlInfo.sourcemapIsWrong = sourcemapIsWrong
167
+ urlInfo.sourcemapIsWrong = urlInfo.sourcemapIsWrong || sourcemapIsWrong
168
168
  }
169
169
  }
170
170
 
@@ -172,57 +172,60 @@ export const createUrlInfoTransformer = ({
172
172
  if (transformations) {
173
173
  applyIntermediateTransformations(urlInfo, transformations)
174
174
  }
175
- if (
176
- sourcemapsEnabled &&
177
- urlInfo.sourcemap &&
178
- !urlInfo.generatedUrl.startsWith("data:")
179
- ) {
180
- // during build this function can be called after the file is cooked
181
- // - to update content and sourcemap after "optimize" hook
182
- // - to inject versioning into the entry point content
183
- // in this scenarion we don't want to call injectSourcemap
184
- // just update the content and the
185
- const sourcemapReference = urlInfo.sourcemapReference
186
- const sourcemapUrlInfo = urlGraph.getUrlInfo(sourcemapReference.url)
187
- sourcemapUrlInfo.contentType = "application/json"
188
- const sourcemap = urlInfo.sourcemap
189
- if (sourcemapsRelativeSources) {
190
- sourcemap.sources = sourcemap.sources.map((source) => {
191
- const sourceRelative = urlToRelativeUrl(source, urlInfo.url)
192
- return sourceRelative || "."
193
- })
194
- }
195
- if (sourcemapsSourcesProtocol !== "file:///") {
196
- sourcemap.sources = sourcemap.sources.map((source) => {
197
- if (source.startsWith("file:///")) {
198
- return `${sourcemapsSourcesProtocol}${source.slice(
199
- "file:///".length,
200
- )}`
201
- }
202
- return source
203
- })
204
- }
205
- sourcemapUrlInfo.content = JSON.stringify(sourcemap, null, " ")
206
- if (!urlInfo.sourcemapIsWrong) {
207
- if (sourcemaps === "inline") {
208
- sourcemapReference.generatedSpecifier =
209
- generateSourcemapDataUrl(sourcemap)
175
+ if (urlInfo.sourcemapReference) {
176
+ if (
177
+ sourcemapsEnabled &&
178
+ urlInfo.sourcemap &&
179
+ !urlInfo.generatedUrl.startsWith("data:")
180
+ ) {
181
+ // during build this function can be called after the file is cooked
182
+ // - to update content and sourcemap after "optimize" hook
183
+ // - to inject versioning into the entry point content
184
+ // in this scenarion we don't want to call injectSourcemap
185
+ // just update the content and the
186
+ const sourcemapReference = urlInfo.sourcemapReference
187
+ const sourcemapUrlInfo = urlGraph.getUrlInfo(sourcemapReference.url)
188
+ sourcemapUrlInfo.contentType = "application/json"
189
+ const sourcemap = urlInfo.sourcemap
190
+ if (sourcemapsRelativeSources) {
191
+ sourcemap.sources = sourcemap.sources.map((source) => {
192
+ const sourceRelative = urlToRelativeUrl(source, urlInfo.url)
193
+ return sourceRelative || "."
194
+ })
210
195
  }
211
- if (sourcemaps === "file" || sourcemaps === "inline") {
212
- urlInfo.content = SOURCEMAP.writeComment({
213
- contentType: urlInfo.contentType,
214
- content: urlInfo.content,
215
- specifier:
216
- sourcemaps === "file" && sourcemapsRelativeSources
217
- ? urlToRelativeUrl(sourcemapReference.url, urlInfo.url)
218
- : sourcemapReference.generatedSpecifier,
196
+ if (sourcemapsSourcesProtocol !== "file:///") {
197
+ sourcemap.sources = sourcemap.sources.map((source) => {
198
+ if (source.startsWith("file:///")) {
199
+ return `${sourcemapsSourcesProtocol}${source.slice(
200
+ "file:///".length,
201
+ )}`
202
+ }
203
+ return source
219
204
  })
220
205
  }
206
+ sourcemapUrlInfo.content = JSON.stringify(sourcemap, null, " ")
207
+ if (!urlInfo.sourcemapIsWrong) {
208
+ if (sourcemaps === "inline") {
209
+ sourcemapReference.generatedSpecifier =
210
+ generateSourcemapDataUrl(sourcemap)
211
+ }
212
+ if (sourcemaps === "file" || sourcemaps === "inline") {
213
+ urlInfo.content = SOURCEMAP.writeComment({
214
+ contentType: urlInfo.contentType,
215
+ content: urlInfo.content,
216
+ specifier:
217
+ sourcemaps === "file" && sourcemapsRelativeSources
218
+ ? urlToRelativeUrl(sourcemapReference.url, urlInfo.url)
219
+ : sourcemapReference.generatedSpecifier,
220
+ })
221
+ }
222
+ }
223
+ } else {
224
+ // in the end we don't use the sourcemap placeholder
225
+ urlGraph.deleteUrlInfo(urlInfo.sourcemapReference.url)
221
226
  }
222
- } else if (urlInfo.sourcemapReference) {
223
- // in the end we don't use the sourcemap placeholder
224
- urlGraph.deleteUrlInfo(urlInfo.sourcemapReference.url)
225
227
  }
228
+
226
229
  urlInfo.contentEtag =
227
230
  urlInfo.content === urlInfo.originalContent
228
231
  ? urlInfo.originalContentEtag
@@ -148,8 +148,9 @@ export const jsenvPluginImportmap = () => {
148
148
  // We must precook the importmap to know its content and inline it into the HTML
149
149
  // In this situation the ref to the importmap was already discovered
150
150
  // when parsing the HTML
151
- const importmapReference =
152
- context.referenceUtils.findByGeneratedSpecifier(src)
151
+ const importmapReference = context.referenceUtils.find(
152
+ (ref) => ref.generatedSpecifier === src,
153
+ )
153
154
  const importmapUrlInfo = context.urlGraph.getUrlInfo(
154
155
  importmapReference.url,
155
156
  )