@depup/webpack-sources 3.3.4-depup.0 → 3.6.0-depup.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 (53) hide show
  1. package/README.md +2 -2
  2. package/changes.json +1 -1
  3. package/lib/CachedSource.js +257 -63
  4. package/lib/CompatSource.js +42 -1
  5. package/lib/ConcatSource.js +100 -28
  6. package/lib/OriginalSource.js +111 -45
  7. package/lib/PrefixSource.js +60 -11
  8. package/lib/RawSource.js +85 -29
  9. package/lib/ReplaceSource.js +269 -73
  10. package/lib/SizeOnlySource.js +10 -1
  11. package/lib/Source.js +39 -0
  12. package/lib/SourceMapSource.js +92 -10
  13. package/lib/helpers/createMappingsSerializer.js +307 -54
  14. package/lib/helpers/getFromStreamChunks.js +165 -73
  15. package/lib/helpers/getGeneratedSourceInfo.js +7 -4
  16. package/lib/helpers/readMappings.js +6 -3
  17. package/lib/helpers/scopes.js +438 -0
  18. package/lib/helpers/splitIntoLines.js +10 -9
  19. package/lib/helpers/splitIntoPotentialTokens.js +99 -26
  20. package/lib/helpers/streamAndGetSourceAndMap.js +61 -22
  21. package/lib/helpers/streamChunks.js +3 -2
  22. package/lib/helpers/streamChunksOfCombinedSourceMap.js +7 -3
  23. package/lib/helpers/streamChunksOfRawSource.js +23 -15
  24. package/lib/helpers/streamChunksOfSourceMap.js +50 -42
  25. package/lib/index.js +3 -0
  26. package/package.json +34 -23
  27. package/types/CachedSource.d.ts +192 -0
  28. package/types/CompatSource.d.ts +87 -0
  29. package/types/ConcatSource.d.ts +75 -0
  30. package/types/OriginalSource.d.ts +87 -0
  31. package/types/PrefixSource.d.ts +59 -0
  32. package/types/RawSource.d.ts +75 -0
  33. package/types/ReplaceSource.d.ts +107 -0
  34. package/types/SizeOnlySource.d.ts +24 -0
  35. package/types/Source.d.ts +189 -0
  36. package/types/SourceMapSource.d.ts +136 -0
  37. package/types/helpers/createMappingsSerializer.d.ts +60 -0
  38. package/types/helpers/getFromStreamChunks.d.ts +16 -0
  39. package/types/helpers/getGeneratedSourceInfo.d.ts +31 -0
  40. package/types/helpers/getName.d.ts +15 -0
  41. package/types/helpers/getSource.d.ts +15 -0
  42. package/types/helpers/readMappings.d.ts +19 -0
  43. package/types/helpers/scopes.d.ts +119 -0
  44. package/types/helpers/splitIntoLines.d.ts +6 -0
  45. package/types/helpers/splitIntoPotentialTokens.d.ts +37 -0
  46. package/types/helpers/streamAndGetSourceAndMap.d.ts +39 -0
  47. package/types/helpers/streamChunks.d.ts +56 -0
  48. package/types/helpers/streamChunksOfCombinedSourceMap.d.ts +42 -0
  49. package/types/helpers/streamChunksOfRawSource.d.ts +16 -0
  50. package/types/helpers/streamChunksOfSourceMap.d.ts +19 -0
  51. package/types/helpers/stringBufferUtils.d.ts +55 -0
  52. package/types/index.d.ts +50 -0
  53. package/types.d.ts +42 -439
package/README.md CHANGED
@@ -13,8 +13,8 @@ npm install @depup/webpack-sources
13
13
 
14
14
  | Field | Value |
15
15
  |-------|-------|
16
- | Original | [webpack-sources](https://www.npmjs.com/package/webpack-sources) @ 3.3.4 |
17
- | Processed | 2026-03-17 |
16
+ | Original | [webpack-sources](https://www.npmjs.com/package/webpack-sources) @ 3.6.0 |
17
+ | Processed | 2026-09-27 |
18
18
  | Smoke test | passed |
19
19
  | Deps updated | 0 |
20
20
 
package/changes.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "bumped": {},
3
- "timestamp": "2026-03-17T16:39:35.097Z",
3
+ "timestamp": "2026-09-27T01:03:15.009Z",
4
4
  "totalUpdated": 0
5
5
  }
@@ -13,6 +13,7 @@ const {
13
13
  isDualStringBufferCachingEnabled,
14
14
  } = require("./helpers/stringBufferUtils");
15
15
 
16
+ /** @typedef {import("./Source").ClearCacheOptions} ClearCacheOptions */
16
17
  /** @typedef {import("./Source").HashLike} HashLike */
17
18
  /** @typedef {import("./Source").MapOptions} MapOptions */
18
19
  /** @typedef {import("./Source").RawSourceMap} RawSourceMap */
@@ -23,6 +24,7 @@ const {
23
24
  /** @typedef {import("./helpers/streamChunks").OnName} OnName */
24
25
  /** @typedef {import("./helpers/streamChunks").OnSource} OnSource */
25
26
  /** @typedef {import("./helpers/streamChunks").Options} Options */
27
+ /** @typedef {import("./helpers/streamChunks").ScopeBindings} ScopeBindings */
26
28
 
27
29
  /**
28
30
  * @typedef {object} BufferedMap
@@ -55,6 +57,25 @@ const mapToBufferedMap = (map) => {
55
57
  return bufferedMap;
56
58
  };
57
59
 
60
+ /**
61
+ * Encodes every string a recorded hash update holds as a buffer, so cached data
62
+ * handed to a caller carries no big string: a string goes into the serialized
63
+ * payload, where it is copied in and rebuilt on every deserialization, while a
64
+ * buffer is carried alongside it. Hashing reads a string as utf8, so the
65
+ * encoded update hashes the same. It encodes in place, so a source handed out
66
+ * repeatedly is encoded once, and one that never is keeps its string uncopied.
67
+ * @param {(string | Buffer)[]=} update recorded hash update
68
+ * @returns {(string | Buffer)[]=} the update, holding no string
69
+ */
70
+ const bufferHashUpdate = (update) => {
71
+ if (update === undefined) return undefined;
72
+ for (let index = 0; index < update.length; index++) {
73
+ const item = update[index];
74
+ if (typeof item === "string") update[index] = Buffer.from(item, "utf8");
75
+ }
76
+ return update;
77
+ };
78
+
58
79
  /**
59
80
  * @param {null | BufferedMap} bufferedMap buffered map
60
81
  * @returns {null | RawSourceMap} map
@@ -75,9 +96,51 @@ const bufferedMapToMap = (bufferedMap) => {
75
96
  return map;
76
97
  };
77
98
 
78
- /** @typedef {{ map?: null | RawSourceMap, bufferedMap?: null | BufferedMap }} BufferEntry */
99
+ /**
100
+ * What replaying an entry streamed for a `scopes` request needs besides its
101
+ * map. The map only keeps the encoded `scopes` field, so `bindings` holds, by
102
+ * source index, the bindings each source reported. The field also appended
103
+ * names to the map, and `names` counts the ones the stream itself reported,
104
+ * so a replay reports the same names a fresh stream would.
105
+ * @typedef {object} ScopesReplay
106
+ * @property {(ScopeBindings | undefined)[]} bindings bindings by source index
107
+ * @property {number} names number of names the stream reported
108
+ */
109
+
110
+ /**
111
+ * @typedef {{ map?: null | RawSourceMap, bufferedMap?: null | BufferedMap, scopes?: ScopesReplay }} BufferEntry
112
+ */
79
113
  /** @typedef {Map<string, BufferEntry>} BufferedMaps */
80
114
 
115
+ const CACHE_KEY_EMPTY = "{}";
116
+ const CACHE_KEY_COLUMNS_FALSE = '{"columns":false}';
117
+ const CACHE_KEY_COLUMNS_TRUE = '{"columns":true}';
118
+
119
+ /**
120
+ * Fast-path replacement for `JSON.stringify(options)` when used as a cache
121
+ * key. MapOptions / streamChunks Options are both small boolean-only shapes
122
+ * and the overwhelmingly common shapes (`undefined`, `{}`, `{columns}`) can
123
+ * be keyed without calling `JSON.stringify`, which dominates short-circuit
124
+ * cache lookups. Falls back to `JSON.stringify` for any other shape so keys
125
+ * remain compatible with previously cached `BufferedMaps` entries.
126
+ * @param {undefined | MapOptions | Options} options options
127
+ * @returns {string} cache key
128
+ */
129
+ const getCacheKey = (options) => {
130
+ if (!options) return CACHE_KEY_EMPTY;
131
+ const { columns } = options;
132
+ if (
133
+ /** @type {Options} */ (options).source === undefined &&
134
+ /** @type {Options} */ (options).finalSource === undefined &&
135
+ /** @type {MapOptions} */ (options).module === undefined &&
136
+ /** @type {MapOptions} */ (options).scopes === undefined
137
+ ) {
138
+ if (columns === undefined) return CACHE_KEY_EMPTY;
139
+ return columns ? CACHE_KEY_COLUMNS_TRUE : CACHE_KEY_COLUMNS_FALSE;
140
+ }
141
+ return JSON.stringify(options);
142
+ };
143
+
81
144
  /**
82
145
  * @typedef {object} CachedData
83
146
  * @property {boolean=} source source
@@ -95,40 +158,56 @@ class CachedSource extends Source {
95
158
  constructor(source, cachedData) {
96
159
  super();
97
160
  /**
98
- * @private
99
161
  * @type {Source | (() => Source)}
100
162
  */
101
163
  this._source = source;
102
164
  /**
103
- * @private
104
- * @type {boolean | undefined}
105
- */
106
- this._cachedSourceType = cachedData ? cachedData.source : undefined;
107
- /**
108
- * @private
109
165
  * @type {undefined | string}
110
166
  */
111
167
  this._cachedSource = undefined;
112
- /**
113
- * @private
114
- * @type {Buffer | undefined}
115
- */
116
- this._cachedBuffer = cachedData ? cachedData.buffer : undefined;
117
- /**
118
- * @private
119
- * @type {number | undefined}
120
- */
121
- this._cachedSize = cachedData ? cachedData.size : undefined;
122
- /**
123
- * @private
124
- * @type {BufferedMaps}
125
- */
126
- this._cachedMaps = cachedData ? cachedData.maps : new Map();
127
- /**
128
- * @private
129
- * @type {(string | Buffer)[] | undefined}
130
- */
131
- this._cachedHashUpdate = cachedData ? cachedData.hash : undefined;
168
+ // Split on `cachedData` once instead of re-evaluating the ternary for
169
+ // every field. Under the interpreter (and CodSpeed's simulation) each
170
+ // ternary is a separate branch; consolidating cuts the per-instance
171
+ // branch count roughly in half.
172
+ if (cachedData) {
173
+ /**
174
+ * @type {boolean | undefined}
175
+ */
176
+ this._cachedSourceType = cachedData.source;
177
+ /**
178
+ * @type {Buffer | undefined}
179
+ */
180
+ this._cachedBuffer = cachedData.buffer;
181
+ /**
182
+ * @type {number | undefined}
183
+ */
184
+ this._cachedSize = cachedData.size;
185
+ /**
186
+ * @type {BufferedMaps | undefined}
187
+ */
188
+ this._cachedMaps = cachedData.maps;
189
+ /**
190
+ * @type {(string | Buffer)[] | undefined}
191
+ */
192
+ this._cachedHashUpdate = cachedData.hash;
193
+ } else {
194
+ this._cachedSourceType = undefined;
195
+ this._cachedBuffer = undefined;
196
+ this._cachedSize = undefined;
197
+ this._cachedMaps = undefined;
198
+ this._cachedHashUpdate = undefined;
199
+ }
200
+ }
201
+
202
+ /**
203
+ * The map cache, created on first use: a source nobody asks a map of holds
204
+ * none, since V8 allocates a Map's hash table whether or not it is filled.
205
+ * @returns {BufferedMaps} map cache
206
+ */
207
+ _getOrCreateCachedMaps() {
208
+ const cachedMaps = this._cachedMaps;
209
+ if (cachedMaps !== undefined) return cachedMaps;
210
+ return (this._cachedMaps = new Map());
132
211
  }
133
212
 
134
213
  /**
@@ -137,26 +216,36 @@ class CachedSource extends Source {
137
216
  getCachedData() {
138
217
  /** @type {BufferedMaps} */
139
218
  const bufferedMaps = new Map();
140
- for (const pair of this._cachedMaps) {
141
- const [, cacheEntry] = pair;
142
- if (cacheEntry.bufferedMap === undefined) {
143
- cacheEntry.bufferedMap = mapToBufferedMap(
144
- this._getMapFromCacheEntry(cacheEntry),
145
- );
219
+ if (this._cachedMaps !== undefined) {
220
+ for (const pair of this._cachedMaps) {
221
+ const [, cacheEntry] = pair;
222
+ if (cacheEntry.bufferedMap === undefined) {
223
+ cacheEntry.bufferedMap = mapToBufferedMap(
224
+ this._getMapFromCacheEntry(cacheEntry),
225
+ );
226
+ }
227
+ /** @type {BufferEntry} */
228
+ const bufferEntry = {
229
+ map: undefined,
230
+ bufferedMap: cacheEntry.bufferedMap,
231
+ };
232
+ // Keep the bindings a `scopes` request recorded, so a source
233
+ // restored from this data replays them without its original.
234
+ if (cacheEntry.scopes !== undefined) {
235
+ bufferEntry.scopes = cacheEntry.scopes;
236
+ }
237
+ bufferedMaps.set(pair[0], bufferEntry);
146
238
  }
147
- bufferedMaps.set(pair[0], {
148
- map: undefined,
149
- bufferedMap: cacheEntry.bufferedMap,
150
- });
151
239
  }
152
240
  return {
153
- // We don't want to cache strings
154
- // So if we have a caches sources
155
- // create a buffer from it and only store
156
- // if it was a Buffer or string
157
- buffer: this._cachedSource
158
- ? this.buffer()
159
- : /** @type {Buffer} */ (this._cachedBuffer),
241
+ // `CachedData.buffer` is required (it is the on-disk
242
+ // serialization format consumed by the
243
+ // `new CachedSource(source, cachedData)` constructor).
244
+ // `_cachedBuffer` is populated by `buffer()` calls but a
245
+ // caller may invoke `getCachedData()` after `clearCache()`
246
+ // has dropped it; `this.buffer()` rehydrates via the
247
+ // wrapped source so the contract holds in every state.
248
+ buffer: this.buffer(),
160
249
  source:
161
250
  this._cachedSourceType !== undefined
162
251
  ? this._cachedSourceType
@@ -167,7 +256,7 @@ class CachedSource extends Source {
167
256
  : undefined,
168
257
  size: this._cachedSize,
169
258
  maps: bufferedMaps,
170
- hash: this._cachedHashUpdate,
259
+ hash: bufferHashUpdate(this._cachedHashUpdate),
171
260
  };
172
261
  }
173
262
 
@@ -184,15 +273,27 @@ class CachedSource extends Source {
184
273
  * @returns {SourceValue} source
185
274
  */
186
275
  source() {
187
- const source = this._getCachedSource();
188
- if (source !== undefined) return source;
276
+ // Fully inlined _getCachedSource: both warm- and cold-cache paths skip
277
+ // the prototype method lookup / stack frame the interpreter would
278
+ // otherwise pay on every call.
279
+ if (this._cachedSource !== undefined) return this._cachedSource;
280
+ const cachedBuffer = this._cachedBuffer;
281
+ const cachedSourceType = this._cachedSourceType;
282
+ if (cachedBuffer !== undefined && cachedSourceType !== undefined) {
283
+ const value = cachedSourceType
284
+ ? cachedBuffer.toString("utf8")
285
+ : cachedBuffer;
286
+ if (isDualStringBufferCachingEnabled()) {
287
+ this._cachedSource = /** @type {string} */ (value);
288
+ }
289
+ return /** @type {string} */ (value);
290
+ }
189
291
  return (this._cachedSource =
190
292
  /** @type {string} */
191
293
  (this.original().source()));
192
294
  }
193
295
 
194
296
  /**
195
- * @private
196
297
  * @param {BufferEntry} cacheEntry cache entry
197
298
  * @returns {null | RawSourceMap} raw source map
198
299
  */
@@ -207,7 +308,6 @@ class CachedSource extends Source {
207
308
  }
208
309
 
209
310
  /**
210
- * @private
211
311
  * @returns {undefined | string} cached source
212
312
  */
213
313
  _getCachedSource() {
@@ -228,6 +328,9 @@ class CachedSource extends Source {
228
328
  */
229
329
  buffer() {
230
330
  if (this._cachedBuffer !== undefined) return this._cachedBuffer;
331
+ if (this._cachedBuffers !== undefined) {
332
+ return (this._cachedBuffer = Buffer.concat(this._cachedBuffers));
333
+ }
231
334
  if (this._cachedSource !== undefined) {
232
335
  const value = Buffer.isBuffer(this._cachedSource)
233
336
  ? this._cachedSource
@@ -251,6 +354,21 @@ class CachedSource extends Source {
251
354
  return value;
252
355
  }
253
356
 
357
+ /**
358
+ * @returns {Buffer[]} buffers
359
+ */
360
+ buffers() {
361
+ if (this._cachedBuffers !== undefined) return this._cachedBuffers;
362
+ if (this._cachedBuffer !== undefined) {
363
+ return (this._cachedBuffers = [this._cachedBuffer]);
364
+ }
365
+ const original = this.original();
366
+ if (typeof original.buffers === "function") {
367
+ return (this._cachedBuffers = original.buffers());
368
+ }
369
+ return (this._cachedBuffers = [this.buffer()]);
370
+ }
371
+
254
372
  /**
255
373
  * @returns {number} size
256
374
  */
@@ -271,8 +389,10 @@ class CachedSource extends Source {
271
389
  * @returns {SourceAndMap} source and map
272
390
  */
273
391
  sourceAndMap(options) {
274
- const key = options ? JSON.stringify(options) : "{}";
275
- const cacheEntry = this._cachedMaps.get(key);
392
+ const key = getCacheKey(options);
393
+ const cachedMaps = this._cachedMaps;
394
+ const cacheEntry =
395
+ cachedMaps === undefined ? undefined : cachedMaps.get(key);
276
396
  // Look for a cached map
277
397
  if (cacheEntry !== undefined) {
278
398
  // We have a cached map in some representation
@@ -294,7 +414,7 @@ class CachedSource extends Source {
294
414
  map = sourceAndMap.map;
295
415
  this._cachedSource = source;
296
416
  }
297
- this._cachedMaps.set(key, {
417
+ this._getOrCreateCachedMaps().set(key, {
298
418
  map,
299
419
  bufferedMap: undefined,
300
420
  });
@@ -309,19 +429,39 @@ class CachedSource extends Source {
309
429
  * @returns {GeneratedSourceInfo} generated source info
310
430
  */
311
431
  streamChunks(options, onChunk, onSource, onName) {
312
- const key = options ? JSON.stringify(options) : "{}";
432
+ const key = getCacheKey(options);
433
+ const scopes = Boolean(
434
+ options && /** @type {MapOptions} */ (options).scopes,
435
+ );
436
+ const cachedMaps = this._cachedMaps;
437
+ const cacheEntry =
438
+ cachedMaps === undefined ? undefined : cachedMaps.get(key);
313
439
  if (
314
- this._cachedMaps.has(key) &&
440
+ cacheEntry !== undefined &&
441
+ // An entry filled without streaming never saw the bindings, so a
442
+ // scopes request streams the original once to record them.
443
+ (!scopes || cacheEntry.scopes !== undefined) &&
315
444
  (this._cachedBuffer !== undefined || this._cachedSource !== undefined)
316
445
  ) {
317
446
  const { source, map } = this.sourceAndMap(options);
318
447
  if (map) {
448
+ const replay = scopes ? cacheEntry.scopes : undefined;
319
449
  return streamChunksOfSourceMap(
320
450
  /** @type {string} */
321
451
  (source),
322
- map,
452
+ replay !== undefined && map.names.length > replay.names
453
+ ? { ...map, names: map.names.slice(0, replay.names) }
454
+ : map,
323
455
  onChunk,
324
- onSource,
456
+ replay !== undefined
457
+ ? (sourceIndex, source, sourceContent) =>
458
+ onSource(
459
+ sourceIndex,
460
+ source,
461
+ sourceContent,
462
+ replay.bindings[sourceIndex],
463
+ )
464
+ : onSource,
325
465
  onName,
326
466
  Boolean(options && options.finalSource),
327
467
  true,
@@ -336,17 +476,30 @@ class CachedSource extends Source {
336
476
  Boolean(options && options.finalSource),
337
477
  );
338
478
  }
479
+ /** @type {ScopesReplay | undefined} */
480
+ const replay = scopes ? { bindings: [], names: 0 } : undefined;
339
481
  const sourceAndMap = streamAndGetSourceAndMap(
340
482
  this.original(),
341
483
  options,
342
484
  onChunk,
343
- onSource,
344
- onName,
485
+ replay !== undefined
486
+ ? (sourceIndex, source, sourceContent, bindings) => {
487
+ replay.bindings[sourceIndex] = bindings;
488
+ onSource(sourceIndex, source, sourceContent, bindings);
489
+ }
490
+ : onSource,
491
+ replay !== undefined
492
+ ? (nameIndex, name) => {
493
+ if (nameIndex >= replay.names) replay.names = nameIndex + 1;
494
+ onName(nameIndex, name);
495
+ }
496
+ : onName,
345
497
  );
346
498
  this._cachedSource = sourceAndMap.source;
347
- this._cachedMaps.set(key, {
499
+ this._getOrCreateCachedMaps().set(key, {
348
500
  map: /** @type {RawSourceMap} */ (sourceAndMap.map),
349
501
  bufferedMap: undefined,
502
+ scopes: replay,
350
503
  });
351
504
  return sourceAndMap.result;
352
505
  }
@@ -356,19 +509,60 @@ class CachedSource extends Source {
356
509
  * @returns {RawSourceMap | null} map
357
510
  */
358
511
  map(options) {
359
- const key = options ? JSON.stringify(options) : "{}";
360
- const cacheEntry = this._cachedMaps.get(key);
512
+ const key = getCacheKey(options);
513
+ const cachedMaps = this._cachedMaps;
514
+ const cacheEntry =
515
+ cachedMaps === undefined ? undefined : cachedMaps.get(key);
361
516
  if (cacheEntry !== undefined) {
362
517
  return this._getMapFromCacheEntry(cacheEntry);
363
518
  }
364
519
  const map = this.original().map(options);
365
- this._cachedMaps.set(key, {
520
+ this._getOrCreateCachedMaps().set(key, {
366
521
  map,
367
522
  bufferedMap: undefined,
368
523
  });
369
524
  return map;
370
525
  }
371
526
 
527
+ /**
528
+ * Release cached data held by this source. clearCache is a memory
529
+ * hint: it never affects correctness or output, only how expensive
530
+ * the next read is. Subclasses override; the base is a no-op so
531
+ * every Source supports the call. Composite sources always recurse
532
+ * into wrapped sources. When the same child is reachable via several
533
+ * parents (e.g. modules shared across webpack chunks), pass a shared
534
+ * `visited` WeakSet so each subtree is walked at most once.
535
+ * Not safe to call concurrently with source/map/sourceAndMap/
536
+ * streamChunks/updateHash on the same instance.
537
+ * @param {ClearCacheOptions=} options selectors
538
+ * @param {WeakSet<Source>=} visited de-duplication set shared across calls
539
+ * @returns {void}
540
+ */
541
+ clearCache(options, visited) {
542
+ if (visited !== undefined && visited.has(this)) return;
543
+ const clearSource = !options || options.source !== false;
544
+ const clearMaps = !options || options.maps !== false;
545
+ if (clearSource) {
546
+ this._cachedSource = undefined;
547
+ this._cachedSourceType = undefined;
548
+ this._cachedBuffer = undefined;
549
+ this._cachedBuffers = undefined;
550
+ }
551
+ if (clearMaps && this._cachedMaps !== undefined) {
552
+ // Reusing the Map avoids per-call allocation churn when builds
553
+ // call clearCache thousands of times.
554
+ this._cachedMaps.clear();
555
+ }
556
+ if (typeof this._source !== "function") {
557
+ let v = visited;
558
+ if (v === undefined) v = new WeakSet();
559
+ v.add(this);
560
+ this._source.clearCache(options, v);
561
+ } else if (visited !== undefined) {
562
+ visited.add(this);
563
+ }
564
+ }
565
+
372
566
  /**
373
567
  * @param {HashLike} hash hash
374
568
  * @returns {void}
@@ -7,6 +7,7 @@
7
7
 
8
8
  const Source = require("./Source");
9
9
 
10
+ /** @typedef {import("./Source").ClearCacheOptions} ClearCacheOptions */
10
11
  /** @typedef {import("./Source").HashLike} HashLike */
11
12
  /** @typedef {import("./Source").MapOptions} MapOptions */
12
13
  /** @typedef {import("./Source").RawSourceMap} RawSourceMap */
@@ -17,10 +18,12 @@ const Source = require("./Source");
17
18
  * @typedef {object} SourceLike
18
19
  * @property {() => SourceValue} source source
19
20
  * @property {(() => Buffer)=} buffer buffer
21
+ * @property {(() => Buffer[])=} buffers buffers
20
22
  * @property {(() => number)=} size size
21
23
  * @property {((options?: MapOptions) => RawSourceMap | null)=} map map
22
24
  * @property {((options?: MapOptions) => SourceAndMap)=} sourceAndMap source and map
23
25
  * @property {((hash: HashLike) => void)=} updateHash hash updater
26
+ * @property {((options?: ClearCacheOptions, visited?: WeakSet<Source>) => void)=} clearCache clear cache
24
27
  */
25
28
 
26
29
  class CompatSource extends Source {
@@ -40,7 +43,6 @@ class CompatSource extends Source {
40
43
  constructor(sourceLike) {
41
44
  super();
42
45
  /**
43
- * @private
44
46
  * @type {SourceLike}
45
47
  */
46
48
  this._sourceLike = sourceLike;
@@ -53,6 +55,9 @@ class CompatSource extends Source {
53
55
  return this._sourceLike.source();
54
56
  }
55
57
 
58
+ /**
59
+ * @returns {Buffer} buffer
60
+ */
56
61
  buffer() {
57
62
  if (typeof this._sourceLike.buffer === "function") {
58
63
  return this._sourceLike.buffer();
@@ -60,6 +65,19 @@ class CompatSource extends Source {
60
65
  return super.buffer();
61
66
  }
62
67
 
68
+ /**
69
+ * @returns {Buffer[]} buffers
70
+ */
71
+ buffers() {
72
+ if (typeof this._sourceLike.buffers === "function") {
73
+ return this._sourceLike.buffers();
74
+ }
75
+ return super.buffers();
76
+ }
77
+
78
+ /**
79
+ * @returns {number} size
80
+ */
63
81
  size() {
64
82
  if (typeof this._sourceLike.size === "function") {
65
83
  return this._sourceLike.size();
@@ -89,6 +107,29 @@ class CompatSource extends Source {
89
107
  return super.sourceAndMap(options);
90
108
  }
91
109
 
110
+ /**
111
+ * Release cached data held by this source. clearCache is a memory
112
+ * hint: it never affects correctness or output, only how expensive
113
+ * the next read is. Subclasses override; the base is a no-op so
114
+ * every Source supports the call. Composite sources always recurse
115
+ * into wrapped sources. When the same child is reachable via several
116
+ * parents (e.g. modules shared across webpack chunks), pass a shared
117
+ * `visited` WeakSet so each subtree is walked at most once.
118
+ * Not safe to call concurrently with source/map/sourceAndMap/
119
+ * streamChunks/updateHash on the same instance.
120
+ * @param {ClearCacheOptions=} options selectors
121
+ * @param {WeakSet<Source>=} visited de-duplication set shared across calls
122
+ * @returns {void}
123
+ */
124
+ clearCache(options, visited) {
125
+ if (visited !== undefined && visited.has(this)) return;
126
+ if (visited !== undefined) visited.add(this);
127
+ const sourceLike = this._sourceLike;
128
+ if (typeof sourceLike.clearCache === "function") {
129
+ sourceLike.clearCache(options, visited);
130
+ }
131
+ }
132
+
92
133
  /**
93
134
  * @param {HashLike} hash hash
94
135
  * @returns {void}