@atlaspack/core 2.34.0 → 2.36.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 (66) hide show
  1. package/CHANGELOG.md +70 -0
  2. package/dist/AssetGraph.js +4 -72
  3. package/dist/BundleGraph.js +34 -0
  4. package/dist/PackagerRunner.js +8 -53
  5. package/dist/RequestTracker.js +17 -80
  6. package/dist/TargetDescriptor.schema.js +3 -0
  7. package/dist/UncommittedAsset.js +0 -5
  8. package/dist/atlaspack-v3/AtlaspackV3.js +6 -2
  9. package/dist/requests/AssetGraphRequest.js +6 -15
  10. package/dist/requests/AssetGraphRequestRust.js +51 -7
  11. package/dist/requests/AtlaspackBuildRequest.js +8 -2
  12. package/dist/requests/BundleGraphRequest.js +17 -21
  13. package/dist/requests/BundleGraphRequestRust.js +2 -2
  14. package/dist/requests/BundleGraphRequestUtils.js +133 -2
  15. package/dist/requests/PackageRequest.js +1 -1
  16. package/dist/requests/TargetRequest.js +5 -0
  17. package/dist/requests/WriteBundleRequest.js +169 -24
  18. package/dist/resolveOptions.js +2 -4
  19. package/lib/AssetGraph.js +3 -62
  20. package/lib/BundleGraph.js +38 -0
  21. package/lib/PackagerRunner.js +8 -42
  22. package/lib/RequestTracker.js +15 -69
  23. package/lib/TargetDescriptor.schema.js +3 -0
  24. package/lib/UncommittedAsset.js +0 -11
  25. package/lib/atlaspack-v3/AtlaspackV3.js +6 -2
  26. package/lib/requests/AssetGraphRequest.js +4 -18
  27. package/lib/requests/AssetGraphRequestRust.js +51 -7
  28. package/lib/requests/AtlaspackBuildRequest.js +8 -2
  29. package/lib/requests/BundleGraphRequest.js +20 -22
  30. package/lib/requests/BundleGraphRequestRust.js +3 -3
  31. package/lib/requests/BundleGraphRequestUtils.js +132 -2
  32. package/lib/requests/PackageRequest.js +3 -1
  33. package/lib/requests/TargetRequest.js +5 -0
  34. package/lib/requests/WriteBundleRequest.js +182 -14
  35. package/lib/resolveOptions.js +2 -4
  36. package/lib/types/AssetGraph.d.ts +2 -27
  37. package/lib/types/BundleGraph.d.ts +5 -0
  38. package/lib/types/atlaspack-v3/AtlaspackV3.d.ts +3 -2
  39. package/lib/types/requests/BundleGraphRequest.d.ts +1 -1
  40. package/lib/types/requests/BundleGraphRequestUtils.d.ts +7 -0
  41. package/lib/types/requests/WriteBundleRequest.d.ts +33 -0
  42. package/lib/types/types.d.ts +1 -0
  43. package/package.json +15 -15
  44. package/src/AssetGraph.ts +4 -72
  45. package/src/BundleGraph.ts +39 -0
  46. package/src/PackagerRunner.ts +9 -55
  47. package/src/RequestTracker.ts +24 -110
  48. package/src/TargetDescriptor.schema.ts +3 -0
  49. package/src/UncommittedAsset.ts +1 -11
  50. package/src/atlaspack-v3/AtlaspackV3.ts +19 -3
  51. package/src/requests/AssetGraphRequest.ts +8 -20
  52. package/src/requests/AssetGraphRequestRust.ts +59 -7
  53. package/src/requests/AtlaspackBuildRequest.ts +16 -8
  54. package/src/requests/BundleGraphRequest.ts +22 -36
  55. package/src/requests/BundleGraphRequestRust.ts +4 -2
  56. package/src/requests/BundleGraphRequestUtils.ts +157 -1
  57. package/src/requests/PackageRequest.ts +1 -1
  58. package/src/requests/TargetRequest.ts +5 -0
  59. package/src/requests/WriteBundleRequest.ts +203 -29
  60. package/src/resolveOptions.ts +2 -4
  61. package/src/types.ts +1 -0
  62. package/test/AssetGraph.test.ts +0 -32
  63. package/test/RequestTracker.test.ts +0 -165
  64. package/test/TargetRequest.test.ts +25 -0
  65. package/test/requests/WriteBundleRequest.test.ts +363 -0
  66. package/tsconfig.tsbuildinfo +1 -1
@@ -3,6 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
+ exports.dumpBundleGraphSnapshot = dumpBundleGraphSnapshot;
6
7
  exports.loadPluginConfigWithDevDeps = loadPluginConfigWithDevDeps;
7
8
  exports.nameBundle = nameBundle;
8
9
  exports.runDevDepRequest = runDevDepRequest;
@@ -14,6 +15,13 @@ function _assert() {
14
15
  };
15
16
  return data;
16
17
  }
18
+ function _fs() {
19
+ const data = _interopRequireDefault(require("fs"));
20
+ _fs = function () {
21
+ return data;
22
+ };
23
+ return data;
24
+ }
17
25
  function _nullthrows() {
18
26
  const data = _interopRequireDefault(require("nullthrows"));
19
27
  _nullthrows = function () {
@@ -21,6 +29,13 @@ function _nullthrows() {
21
29
  };
22
30
  return data;
23
31
  }
32
+ function _path() {
33
+ const data = _interopRequireDefault(require("path"));
34
+ _path = function () {
35
+ return data;
36
+ };
37
+ return data;
38
+ }
24
39
  function _logger() {
25
40
  const data = require("@atlaspack/logger");
26
41
  _logger = function () {
@@ -42,7 +57,8 @@ function _utils() {
42
57
  };
43
58
  return data;
44
59
  }
45
- var _BundleGraph = _interopRequireDefault(require("../public/BundleGraph"));
60
+ var _BundleGraph = require("../BundleGraph");
61
+ var _BundleGraph2 = _interopRequireDefault(require("../public/BundleGraph"));
46
62
  var _Bundle = require("../public/Bundle");
47
63
  var _InternalConfig = require("../InternalConfig");
48
64
  var _DevDepRequest = require("./DevDepRequest");
@@ -75,12 +91,126 @@ function validateBundles(bundleGraph) {
75
91
  _assert().default.deepEqual(bundleNames, (0, _utils().unique)(bundleNames), 'Bundles must have unique name. Conflicting names: ' + [...(0, _utils().setSymmetricDifference)(new Set(bundleNames), new Set((0, _utils().unique)(bundleNames)))].join());
76
92
  }
77
93
 
94
+ /**
95
+ * Dump a canonical JSON snapshot of the bundle graph for parity comparison.
96
+ * Gated by ATLASPACK_DUMP_BUNDLE_GRAPH environment variable which specifies the output directory.
97
+ * The snapshot captures bundle identity, type, contained assets, and bundle group structure
98
+ * in a deterministic, sorted format suitable for diffing.
99
+ */
100
+ function dumpBundleGraphSnapshot(bundleGraph, variant) {
101
+ let outDir = process.env.ATLASPACK_DUMP_BUNDLE_GRAPH;
102
+ if (!outDir) return;
103
+ let filename = variant === 'js' ? 'bundle-graph-js.json' : 'bundle-graph-rust.json';
104
+ let outPath = _path().default.join(outDir, filename);
105
+ _fs().default.mkdirSync(outDir, {
106
+ recursive: true
107
+ });
108
+ let bundles = bundleGraph.getBundles();
109
+ let bundlesSnapshot = bundles.map(bundle => {
110
+ let bundleNodeId = bundleGraph._graph.getNodeIdByContentKey(bundle.id);
111
+ let containedAssetNodeIds = bundleGraph._graph.getNodeIdsConnectedFrom(bundleNodeId, _BundleGraph.bundleGraphEdgeTypes.contains);
112
+ let containedAssets = containedAssetNodeIds.map(nodeId => bundleGraph._graph.getNode(nodeId)).flatMap(node => {
113
+ if ((node === null || node === void 0 ? void 0 : node.type) !== 'asset') return [];
114
+ return [{
115
+ id: node.value.id,
116
+ filePath: (0, _projectPath.fromProjectPathRelative)(node.value.filePath)
117
+ }];
118
+ }).sort((a, b) => a.filePath.localeCompare(b.filePath));
119
+
120
+ // Resolve mainEntry and entry asset file paths
121
+ let mainEntryPath = null;
122
+ let entryAssetPaths = [];
123
+ if (bundle.mainEntryId) {
124
+ let mainEntryNodeId = bundleGraph._graph.getNodeIdByContentKey(bundle.mainEntryId);
125
+ let mainEntryNode = bundleGraph._graph.getNode(mainEntryNodeId);
126
+ if ((mainEntryNode === null || mainEntryNode === void 0 ? void 0 : mainEntryNode.type) === 'asset') {
127
+ mainEntryPath = (0, _projectPath.fromProjectPathRelative)(mainEntryNode.value.filePath);
128
+ }
129
+ }
130
+ for (let entryId of bundle.entryAssetIds) {
131
+ let entryNodeId = bundleGraph._graph.getNodeIdByContentKey(entryId);
132
+ let entryNode = bundleGraph._graph.getNode(entryNodeId);
133
+ if ((entryNode === null || entryNode === void 0 ? void 0 : entryNode.type) === 'asset') {
134
+ entryAssetPaths.push((0, _projectPath.fromProjectPathRelative)(entryNode.value.filePath));
135
+ }
136
+ }
137
+ entryAssetPaths.sort();
138
+ return {
139
+ id: bundle.id,
140
+ type: bundle.type,
141
+ bundleBehavior: bundle.bundleBehavior ?? null,
142
+ needsStableName: bundle.needsStableName,
143
+ isSplittable: bundle.isSplittable,
144
+ isPlaceholder: bundle.isPlaceholder,
145
+ mainEntryPath,
146
+ entryAssetPaths,
147
+ assets: containedAssets.map(a => a.filePath)
148
+ };
149
+ }).sort((a, b) => {
150
+ // Sort by mainEntryPath first, then by sorted assets as tiebreaker
151
+ let aKey = a.mainEntryPath || a.assets.join(',');
152
+ let bKey = b.mainEntryPath || b.assets.join(',');
153
+ return aKey.localeCompare(bKey);
154
+ });
155
+ let bundleGroupsSnapshot = bundleGraph._graph.nodes.flatMap(node => {
156
+ if ((node === null || node === void 0 ? void 0 : node.type) !== 'bundle_group') return [];
157
+ let bundleGroup = node.value;
158
+
159
+ // Resolve entry asset file path
160
+ let entryAssetPath = null;
161
+ try {
162
+ let entryNodeId = bundleGraph._graph.getNodeIdByContentKey(bundleGroup.entryAssetId);
163
+ let entryNode = bundleGraph._graph.getNode(entryNodeId);
164
+ if ((entryNode === null || entryNode === void 0 ? void 0 : entryNode.type) === 'asset') {
165
+ entryAssetPath = (0, _projectPath.fromProjectPathRelative)(entryNode.value.filePath);
166
+ }
167
+ } catch {
168
+ // Content key not found
169
+ }
170
+ let bundlesInGroup = bundleGraph.getBundlesInBundleGroup(bundleGroup);
171
+ let bundlePaths = bundlesInGroup.map(b => {
172
+ // Use mainEntry file path if available, otherwise bundle id as fallback
173
+ if (b.mainEntryId) {
174
+ try {
175
+ let nodeId = bundleGraph._graph.getNodeIdByContentKey(b.mainEntryId);
176
+ let node = bundleGraph._graph.getNode(nodeId);
177
+ if ((node === null || node === void 0 ? void 0 : node.type) === 'asset') {
178
+ return (0, _projectPath.fromProjectPathRelative)(node.value.filePath);
179
+ }
180
+ } catch {
181
+ // fallback
182
+ }
183
+ }
184
+ return `[bundle:${b.id}]`;
185
+ }).sort();
186
+ return [{
187
+ entryAssetPath: entryAssetPath ?? `[unknown:${bundleGroup.entryAssetId}]`,
188
+ bundlePaths
189
+ }];
190
+ }).sort((a, b) => a.entryAssetPath.localeCompare(b.entryAssetPath));
191
+ let totalAssets = bundleGraph._graph.nodes.filter(node => (node === null || node === void 0 ? void 0 : node.type) === 'asset').length;
192
+ let snapshot = {
193
+ version: 1,
194
+ variant,
195
+ stats: {
196
+ totalBundles: bundlesSnapshot.length,
197
+ totalBundleGroups: bundleGroupsSnapshot.length,
198
+ totalAssets
199
+ },
200
+ bundles: bundlesSnapshot,
201
+ bundleGroups: bundleGroupsSnapshot
202
+ };
203
+ _fs().default.writeFileSync(outPath, JSON.stringify(snapshot, null, 2), 'utf8');
204
+ // eslint-disable-next-line no-console
205
+ console.log(`[BundleGraphSnapshot] Wrote ${variant} snapshot to ${outPath}`);
206
+ }
207
+
78
208
  /**
79
209
  * Names a bundle by running through the configured namers until one returns a name.
80
210
  */
81
211
  async function nameBundle(namers, internalBundle, internalBundleGraph, options, pluginOptions, configs) {
82
212
  const bundle = _Bundle.Bundle.get(internalBundle, internalBundleGraph, options);
83
- const bundleGraph = new _BundleGraph.default(internalBundleGraph, _Bundle.NamedBundle.get.bind(_Bundle.NamedBundle), options);
213
+ const bundleGraph = new _BundleGraph2.default(internalBundleGraph, _Bundle.NamedBundle.get.bind(_Bundle.NamedBundle), options);
84
214
  for (const namer of namers) {
85
215
  let measurement;
86
216
  try {
@@ -70,7 +70,9 @@ async function run({
70
70
  let packagingResult;
71
71
  if ((0, _featureFlags().getFeatureFlag)('nativePackager') && (0, _featureFlags().getFeatureFlag)('nativePackagerSSRDev') && rustAtlaspack && (0, _EnvironmentManager.fromEnvironmentId)(bundle.env).context === 'tesseract' && bundle.type === 'js') {
72
72
  // Once this actually does something, the code below will be in an `else` block (i.e. we'll only run one or the other)
73
- let result = await rustAtlaspack.package(bundle.id);
73
+ let result = await rustAtlaspack.package(bundle.id, {
74
+ inlineRequires: true
75
+ });
74
76
  let error = null;
75
77
  [packagingResult, error] = result;
76
78
  if (error) {
@@ -247,6 +247,7 @@ class TargetResolver {
247
247
  name,
248
248
  distDir: (0, _projectPath.toProjectPath)(this.options.projectRoot, _path().default.resolve(this.fs.cwd(), distDir)),
249
249
  publicUrl: descriptor.publicUrl ?? this.options.defaultTargetOptions.publicUrl,
250
+ inlineRequires: descriptor.inlineRequires ?? false,
250
251
  env: (0, _Environment.createEnvironment)({
251
252
  engines: descriptor.engines,
252
253
  context: descriptor.context,
@@ -311,6 +312,7 @@ class TargetResolver {
311
312
  name: 'default',
312
313
  distDir: (0, _projectPath.toProjectPath)(this.options.projectRoot, this.options.serveOptions.distDir),
313
314
  publicUrl: this.options.defaultTargetOptions.publicUrl ?? '/',
315
+ inlineRequires: false,
314
316
  env: (0, _Environment.createEnvironment)({
315
317
  context: 'browser',
316
318
  engines: {
@@ -670,6 +672,7 @@ class TargetResolver {
670
672
  distDir,
671
673
  distEntry,
672
674
  publicUrl: descriptor.publicUrl ?? this.options.defaultTargetOptions.publicUrl,
675
+ inlineRequires: descriptor.inlineRequires ?? false,
673
676
  env: (0, _Environment.createEnvironment)({
674
677
  engines: descriptor.engines ?? pkgEngines,
675
678
  // @ts-expect-error TS2322
@@ -819,6 +822,7 @@ class TargetResolver {
819
822
  distDir: (0, _projectPath.toProjectPath)(this.options.projectRoot, descriptor.distDir != null ? _path().default.resolve(pkgDir, descriptor.distDir) : distDir),
820
823
  distEntry,
821
824
  publicUrl: descriptor.publicUrl ?? this.options.defaultTargetOptions.publicUrl,
825
+ inlineRequires: descriptor.inlineRequires ?? false,
822
826
  env: (0, _Environment.createEnvironment)({
823
827
  engines: descriptor.engines ?? pkgEngines,
824
828
  context: descriptor.context,
@@ -889,6 +893,7 @@ class TargetResolver {
889
893
  name: 'default',
890
894
  distDir: this.options.defaultTargetOptions.distDir ?? (0, _projectPath.toProjectPath)(this.options.projectRoot, _path().default.join(pkgDir, DEFAULT_DIST_DIRNAME)),
891
895
  publicUrl: this.options.defaultTargetOptions.publicUrl,
896
+ inlineRequires: false,
892
897
  env: (0, _Environment.createEnvironment)({
893
898
  engines: pkgEngines,
894
899
  // @ts-expect-error TS2322
@@ -3,7 +3,9 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
+ exports.SourceMapHashRefRewriteStream = void 0;
6
7
  exports.applyReplacementsToSourceMap = applyReplacementsToSourceMap;
8
+ exports.applyReplacementsToVLQMappings = applyReplacementsToVLQMappings;
7
9
  exports.computeSourceMapRoot = computeSourceMapRoot;
8
10
  exports.default = createWriteBundleRequest;
9
11
  var _constants = require("../constants");
@@ -78,7 +80,7 @@ function _featureFlags() {
78
80
  }
79
81
  var _EnvironmentManager = require("../EnvironmentManager");
80
82
  function _sourceMap() {
81
- const data = _interopRequireDefault(require("@atlaspack/source-map"));
83
+ const data = require("@atlaspack/source-map");
82
84
  _sourceMap = function () {
83
85
  return data;
84
86
  };
@@ -90,6 +92,9 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
90
92
  const HASH_REF_PREFIX_LEN = _constants.HASH_REF_PREFIX.length;
91
93
  const BOUNDARY_LENGTH = _constants.HASH_REF_PREFIX.length + 32 - 1;
92
94
  const HASH_REF_PLACEHOLDER_LEN = HASH_REF_PREFIX_LEN + _constants.HASH_REF_HASH_LEN;
95
+
96
+ // The JSON key prefix we scan for in the source map stream.
97
+ const MAPPINGS_KEY_BUF = Buffer.from('"mappings":"');
93
98
  /**
94
99
  * Writes a bundle to the dist directory, replacing hash references with the final content hashes.
95
100
  */
@@ -177,23 +182,13 @@ async function run({
177
182
  (0, _DevDepRequest.invalidateDevDeps)(invalidDevDeps, options, config);
178
183
  const bundleReplacements = (0, _featureFlags().getFeatureFlag)('fixSourceMapHashRefs') ? [] : undefined;
179
184
  await writeFiles(contentStream, info, hashRefToNameHash, options, config, outputFS, filePath, writeOptions, devDeps, api, bundleReplacements);
180
- const hasSourceMap = (0, _featureFlags().getFeatureFlag)('cachePerformanceImprovements') ? await options.cache.hasLargeBlob(mapKey) : await options.cache.has(mapKey);
185
+ const hasSourceMap = await options.cache.has(mapKey);
181
186
  if (mapKey && env.sourceMap && !env.sourceMap.inline && hasSourceMap) {
187
+ const mapEntry = await options.cache.getBlob(mapKey);
182
188
  let mapStream;
183
189
  if ((0, _featureFlags().getFeatureFlag)('fixSourceMapHashRefs') && bundleReplacements && bundleReplacements.length > 0) {
184
- const mapEntry = (0, _featureFlags().getFeatureFlag)('cachePerformanceImprovements') ? await options.cache.getLargeBlob(mapKey) : await options.cache.getBlob(mapKey);
185
- const mapBuffer = Buffer.isBuffer(mapEntry) ? mapEntry : Buffer.from(mapEntry);
186
- const projectRoot = typeof options.projectRoot === 'string' ? options.projectRoot : String(options.projectRoot);
187
- const sourceMap = new (_sourceMap().default)(projectRoot, mapBuffer);
188
- applyReplacementsToSourceMap(sourceMap, bundleReplacements);
189
- const mapJson = await sourceMap.stringify({
190
- format: 'string',
191
- file: name,
192
- sourceRoot: computeSourceMapRoot(bundle, options)
193
- });
194
- mapStream = (0, _utils().blobToStream)(Buffer.from(typeof mapJson === 'string' ? mapJson : JSON.stringify(mapJson), 'utf8'));
190
+ mapStream = (0, _utils().blobToStream)(mapEntry).pipe(new SourceMapHashRefRewriteStream(bundleReplacements));
195
191
  } else {
196
- const mapEntry = (0, _featureFlags().getFeatureFlag)('cachePerformanceImprovements') ? await options.cache.getLargeBlob(mapKey) : await options.cache.getBlob(mapKey);
197
192
  mapStream = (0, _utils().blobToStream)(mapEntry);
198
193
  }
199
194
  await writeFiles(mapStream, info, hashRefToNameHash, options, config, outputFS, (0, _projectPath.toProjectPathUnsafe)((0, _projectPath.fromProjectPathRelative)(filePath) + '.map'), writeOptions, devDeps, api);
@@ -228,6 +223,178 @@ function applyReplacementsToSourceMap(sourceMap, replacements) {
228
223
  }
229
224
  }
230
225
 
226
+ /**
227
+ * Applies hash-ref replacement column offsets directly to a VLQ mappings
228
+ * string without deserializing the full source map into a native struct.
229
+ *
230
+ * Each replacement r describes a hash-ref that was substituted in the output
231
+ * file. r.column is in the progressively-shifted post-replacement coordinate
232
+ * space (matching the already-shifted source map state after all previous
233
+ * offsetColumns calls), so thresholds are applied sequentially against the
234
+ * running absCol values exactly as the native offsetColumns implementation does.
235
+ */
236
+ function applyReplacementsToVLQMappings(mappings, replacements) {
237
+ if (replacements.length === 0) return mappings;
238
+
239
+ // Group replacements by line (0-indexed), sorted by column ascending.
240
+ const byLine = new Map();
241
+ for (const r of replacements) {
242
+ let arr = byLine.get(r.line);
243
+ if (!arr) {
244
+ arr = [];
245
+ byLine.set(r.line, arr);
246
+ }
247
+ arr.push(r);
248
+ }
249
+ for (const arr of byLine.values()) {
250
+ arr.sort((a, b) => a.column - b.column);
251
+ }
252
+ const lines = mappings.split(';');
253
+ const resultLines = [];
254
+ for (let lineIdx = 0; lineIdx < lines.length; lineIdx++) {
255
+ const lineReps = byLine.get(lineIdx);
256
+ if (!lineReps || lineReps.length === 0) {
257
+ resultLines.push(lines[lineIdx]);
258
+ continue;
259
+ }
260
+ const line = lines[lineIdx];
261
+ if (!line) {
262
+ resultLines.push('');
263
+ continue;
264
+ }
265
+
266
+ // Decode segment column deltas to absolute columns.
267
+ const segments = line.split(',');
268
+ const colVlqEnds = [];
269
+ const absCols = [];
270
+ let absCol = 0;
271
+ for (const seg of segments) {
272
+ const {
273
+ value: colDelta,
274
+ nextPos
275
+ } = (0, _sourceMap().decodeVLQ)(seg, 0);
276
+ absCol += colDelta;
277
+ colVlqEnds.push(nextPos);
278
+ absCols.push(absCol);
279
+ }
280
+
281
+ // Apply each replacement's column shift sequentially against the
282
+ // current absCol values (which have already been adjusted by previous
283
+ // replacements on this line), mirroring the sequential offsetColumns calls.
284
+ for (const r of lineReps) {
285
+ const delta = r.newLength - r.originalLength;
286
+ if (delta === 0) continue;
287
+ const threshold = r.column + r.originalLength;
288
+ for (let i = 0; i < absCols.length; i++) {
289
+ if (absCols[i] >= threshold) {
290
+ absCols[i] += delta;
291
+ }
292
+ }
293
+ }
294
+
295
+ // Re-encode with updated absolute columns; only the leading column VLQ
296
+ // field of each segment changes – the tail bytes are sliced unchanged.
297
+ const resultSegments = [];
298
+ let prevAbsCol = 0;
299
+ for (let i = 0; i < segments.length; i++) {
300
+ const newDelta = absCols[i] - prevAbsCol;
301
+ prevAbsCol = absCols[i];
302
+ resultSegments.push((0, _sourceMap().encodeVLQ)(newDelta) + segments[i].slice(colVlqEnds[i]));
303
+ }
304
+ resultLines.push(resultSegments.join(','));
305
+ }
306
+ return resultLines.join(';');
307
+ }
308
+ /**
309
+ * A Transform stream that rewrites the "mappings" VLQ field of a source map
310
+ * JSON to account for hash-ref replacements, without ever loading the full
311
+ * JSON object or the native Rust SourceMapInner into memory.
312
+ *
313
+ * Field order in cached source maps (from partialVlqMapToSourceMap / toVLQ):
314
+ * mappings → sources → sourcesContent → names → version → file → sourceRoot
315
+ *
316
+ * "mappings" is the very first field, so we scan only a tiny header before
317
+ * switching to zero-copy passthrough for the bulk sourcesContent bytes.
318
+ */
319
+ class SourceMapHashRefRewriteStream extends _stream().Transform {
320
+ constructor(replacements) {
321
+ super();
322
+ this.replacements = replacements;
323
+ this.state = 'scanning';
324
+ this.scanBuf = Buffer.alloc(0);
325
+ this.mappingsBufs = [];
326
+ }
327
+
328
+ // @ts-expect-error TS7006
329
+ _transform(chunk, _encoding, cb) {
330
+ if (this.state === 'passthrough') {
331
+ this.push(chunk);
332
+ cb();
333
+ return;
334
+ }
335
+ if (this.state === 'scanning') {
336
+ const combined = Buffer.concat([this.scanBuf, chunk]);
337
+ const idx = combined.indexOf(MAPPINGS_KEY_BUF);
338
+ if (idx === -1) {
339
+ // Key not yet found – hold back enough bytes to handle a split key.
340
+ const keepLen = Math.min(combined.length, MAPPINGS_KEY_BUF.length - 1);
341
+ if (combined.length > keepLen) {
342
+ this.push(combined.slice(0, combined.length - keepLen));
343
+ }
344
+ this.scanBuf = combined.slice(combined.length - keepLen);
345
+ cb();
346
+ return;
347
+ }
348
+
349
+ // Emit everything up to and including the key.
350
+ const keyEnd = idx + MAPPINGS_KEY_BUF.length;
351
+ this.push(combined.slice(0, keyEnd));
352
+ this.scanBuf = Buffer.alloc(0);
353
+ this.state = 'buffering';
354
+ this._bufferingTransform(combined.slice(keyEnd), cb);
355
+ return;
356
+ }
357
+
358
+ // state === 'buffering'
359
+ this._bufferingTransform(chunk, cb);
360
+ }
361
+
362
+ // @ts-expect-error TS7006
363
+ _bufferingTransform(chunk, cb) {
364
+ // Mappings values contain only base64 chars, ';', and ',' – no escaping –
365
+ // so scanning for the closing '"' (0x22) is safe.
366
+ const closeIdx = chunk.indexOf(0x22);
367
+ if (closeIdx === -1) {
368
+ this.mappingsBufs.push(chunk);
369
+ cb();
370
+ return;
371
+ }
372
+ this.mappingsBufs.push(chunk.slice(0, closeIdx));
373
+
374
+ // VLQ chars are all ASCII (<128), so latin1 round-trips without loss.
375
+ const mappingsStr = Buffer.concat(this.mappingsBufs).toString('latin1');
376
+ const rewritten = applyReplacementsToVLQMappings(mappingsStr, this.replacements);
377
+ this.push(Buffer.from(rewritten, 'latin1'));
378
+
379
+ // Emit the closing '"' and everything remaining in one push.
380
+ this.push(chunk.slice(closeIdx));
381
+ this.state = 'passthrough';
382
+ this.mappingsBufs = [];
383
+ cb();
384
+ }
385
+
386
+ // @ts-expect-error TS7006
387
+ _flush(cb) {
388
+ if (this.state === 'scanning' && this.scanBuf.length > 0) {
389
+ this.push(this.scanBuf);
390
+ } else if (this.state === 'buffering') {
391
+ // Malformed JSON – flush whatever we buffered as-is.
392
+ this.push(Buffer.concat(this.mappingsBufs));
393
+ }
394
+ cb();
395
+ }
396
+ }
397
+
231
398
  /**
232
399
  * Computes the sourceRoot for a source map file. This is the relative path from
233
400
  * the output directory back to the project root, so that source paths (stored
@@ -238,6 +405,7 @@ function applyReplacementsToSourceMap(sourceMap, replacements) {
238
405
  *
239
406
  * This logic must stay in sync with PackagerRunner.generateSourceMap.
240
407
  */
408
+ exports.SourceMapHashRefRewriteStream = SourceMapHashRefRewriteStream;
241
409
  function computeSourceMapRoot(bundle, options) {
242
410
  let name = (0, _nullthrows().default)(bundle.name);
243
411
  let filePath = (0, _projectPath.joinProjectPath)(bundle.target.distDir, name);
@@ -167,10 +167,8 @@ async function resolveOptions(initialOptions) {
167
167
  return initialOptions.cache;
168
168
  }
169
169
  const needsRustLmdbCache = (0, _featureFlags().getFeatureFlag)('atlaspackV3') || (0, _featureFlags().getFeatureFlag)('nativePackager');
170
- if (!(0, _featureFlags().getFeatureFlag)('cachePerformanceImprovements')) {
171
- if (!needsRustLmdbCache && !(outputFS instanceof _fs().NodeFS)) {
172
- return new (_cache().FSCache)(outputFS, cacheDir);
173
- }
170
+ if (!needsRustLmdbCache && !(outputFS instanceof _fs().NodeFS)) {
171
+ return new (_cache().FSCache)(outputFS, cacheDir);
174
172
  }
175
173
  return new (_cache().LMDBLiteCache)(cacheDir);
176
174
  }
@@ -9,13 +9,9 @@ type InitOpts = {
9
9
  assetGroups?: Array<AssetGroup>;
10
10
  };
11
11
  type AssetGraphOpts = ContentGraphOpts<AssetGraphNode> & {
12
- bundlingVersion?: number;
13
- disableIncrementalBundling?: boolean;
14
12
  hash?: string | null | undefined;
15
13
  };
16
14
  type SerializedAssetGraph = SerializedContentGraph<AssetGraphNode> & {
17
- bundlingVersion: number;
18
- disableIncrementalBundling: boolean;
19
15
  hash?: string | null | undefined;
20
16
  };
21
17
  export declare function nodeFromDep(dep: Dependency): DependencyNode;
@@ -24,40 +20,19 @@ export declare function nodeFromAsset(asset: Asset): AssetNode;
24
20
  export declare function nodeFromEntrySpecifier(entry: ProjectPath): EntrySpecifierNode;
25
21
  export declare function nodeFromEntryFile(entry: Entry): EntryFileNode;
26
22
  export default class AssetGraph extends ContentGraph<AssetGraphNode> {
27
- #private;
28
23
  onNodeRemoved: ((nodeId: NodeId) => unknown) | null | undefined;
29
24
  hash: string | null | undefined;
30
25
  envCache: Map<string, Environment>;
31
- /**
32
- * @deprecated
33
- */
34
26
  safeToIncrementallyBundle: boolean;
35
27
  undeferredDependencies: Set<Dependency>;
36
28
  constructor(opts?: AssetGraphOpts | null);
37
29
  static deserialize(opts: AssetGraphOpts): AssetGraph;
38
30
  serialize(): SerializedAssetGraph;
39
31
  /**
40
- * Force incremental bundling to be disabled.
41
- */
42
- setDisableIncrementalBundling(disable: boolean): void;
43
- testing_getDisableIncrementalBundling(): boolean;
44
- /**
45
- * Make sure this asset graph is marked as needing a full bundling pass.
46
- */
47
- setNeedsBundling(): void;
48
- /**
49
- * Get the current bundling version.
50
- *
51
- * Each bundle pass should keep this version around. Whenever an asset graph has a new version,
52
- * bundling should be re-run.
53
- */
54
- getBundlingVersion(): number;
55
- /**
56
- * If the `bundlingVersion` has not changed since the last bundling pass,
57
- * we can incrementally bundle, which will not require a full bundling pass
32
+ * Determine if we can incrementally bundle, which will not require a full bundling pass
58
33
  * but just update assets into the bundle graph output.
59
34
  */
60
- canIncrementallyBundle(lastVersion: number): boolean;
35
+ canIncrementallyBundle(): boolean;
61
36
  normalizeEnvironment(input: Asset | Dependency | AssetGroup): void;
62
37
  setRootConnections({ entries, assetGroups }: InitOpts): void;
63
38
  addNode(node: AssetGraphNode): NodeId;
@@ -87,6 +87,11 @@ export default class BundleGraph {
87
87
  publicIdByAssetId: Record<string, string>;
88
88
  environmentsJson: string;
89
89
  };
90
+ /**
91
+ * Serialize only the given asset nodes for native incremental update.
92
+ * Same node shape and env/omit logic as serializeForNative.
93
+ */
94
+ serializeAssetNodesForNative(assetIds: Array<string>): string;
90
95
  /**
91
96
  * Remove null and undefined values from an object to reduce JSON size.
92
97
  * Preserves false, 0, empty strings, and arrays.
@@ -1,4 +1,4 @@
1
- import { AtlaspackNapi, Lmdb, AtlaspackNapiOptions, CacheStats } from '@atlaspack/rust';
1
+ import { AtlaspackNapi, Lmdb, AtlaspackNapiOptions, CacheStats, PackageOptions } from '@atlaspack/rust';
2
2
  import { Diagnostic } from '@atlaspack/diagnostic';
3
3
  import type { Event } from '@parcel/watcher';
4
4
  import type { NapiWorkerPool as INapiWorkerPool } from '@atlaspack/types';
@@ -27,7 +27,8 @@ export declare class AtlaspackV3 {
27
27
  buildAssetGraph(): Promise<any>;
28
28
  buildBundleGraph(): Promise<any>;
29
29
  loadBundleGraph(bundleGraph: BundleGraph): Promise<void>;
30
- package(bundleId: string): Promise<[RunPackagerRunnerResult, Diagnostic | null]>;
30
+ updateBundleGraph(bundleGraph: BundleGraph, changedAssetIds: string[]): Promise<void>;
31
+ package(bundleId: string, options?: PackageOptions): Promise<[RunPackagerRunnerResult, Diagnostic | null]>;
31
32
  respondToFsEvents(events: Array<Event>): Promise<boolean>;
32
33
  completeCacheSession(): Promise<CacheStats>;
33
34
  }
@@ -14,9 +14,9 @@ type RunInput = {
14
14
  } & StaticRunOpts<BundleGraphResult>;
15
15
  export type BundleGraphResult = {
16
16
  bundleGraph: InternalBundleGraph;
17
- assetGraphBundlingVersion: number;
18
17
  changedAssets: Map<string, Asset>;
19
18
  assetRequests: Array<AssetGroup>;
19
+ didIncrementallyBundle: boolean;
20
20
  };
21
21
  type BundleGraphRequest = {
22
22
  id: string;
@@ -17,6 +17,13 @@ import type { BundleGraphResult } from './BundleGraphRequest';
17
17
  * Throws an assertion error if duplicate bundle names are found.
18
18
  */
19
19
  export declare function validateBundles(bundleGraph: InternalBundleGraph): void;
20
+ /**
21
+ * Dump a canonical JSON snapshot of the bundle graph for parity comparison.
22
+ * Gated by ATLASPACK_DUMP_BUNDLE_GRAPH environment variable which specifies the output directory.
23
+ * The snapshot captures bundle identity, type, contained assets, and bundle group structure
24
+ * in a deterministic, sorted format suitable for diffing.
25
+ */
26
+ export declare function dumpBundleGraphSnapshot(bundleGraph: InternalBundleGraph, variant: 'js' | 'rust'): void;
20
27
  /**
21
28
  * Names a bundle by running through the configured namers until one returns a name.
22
29
  */
@@ -4,6 +4,7 @@ import type { StaticRunOpts } from '../RequestTracker';
4
4
  import type { Bundle, PackagedBundleInfo, AtlaspackOptions } from '../types';
5
5
  import type BundleGraph from '../BundleGraph';
6
6
  import type { BundleInfo } from '../PackagerRunner';
7
+ import { Transform } from 'stream';
7
8
  import { requestTypes } from '../RequestTracker';
8
9
  import SourceMap from '@atlaspack/source-map';
9
10
  export type HashRefReplacement = {
@@ -33,6 +34,38 @@ export type WriteBundleRequest = {
33
34
  */
34
35
  export default function createWriteBundleRequest(input: WriteBundleRequestInput): WriteBundleRequest;
35
36
  export declare function applyReplacementsToSourceMap(sourceMap: SourceMap, replacements: HashRefReplacement[]): void;
37
+ /**
38
+ * Applies hash-ref replacement column offsets directly to a VLQ mappings
39
+ * string without deserializing the full source map into a native struct.
40
+ *
41
+ * Each replacement r describes a hash-ref that was substituted in the output
42
+ * file. r.column is in the progressively-shifted post-replacement coordinate
43
+ * space (matching the already-shifted source map state after all previous
44
+ * offsetColumns calls), so thresholds are applied sequentially against the
45
+ * running absCol values exactly as the native offsetColumns implementation does.
46
+ */
47
+ export declare function applyReplacementsToVLQMappings(mappings: string, replacements: HashRefReplacement[]): string;
48
+ /**
49
+ * A Transform stream that rewrites the "mappings" VLQ field of a source map
50
+ * JSON to account for hash-ref replacements, without ever loading the full
51
+ * JSON object or the native Rust SourceMapInner into memory.
52
+ *
53
+ * Field order in cached source maps (from partialVlqMapToSourceMap / toVLQ):
54
+ * mappings → sources → sourcesContent → names → version → file → sourceRoot
55
+ *
56
+ * "mappings" is the very first field, so we scan only a tiny header before
57
+ * switching to zero-copy passthrough for the bulk sourcesContent bytes.
58
+ */
59
+ export declare class SourceMapHashRefRewriteStream extends Transform {
60
+ private replacements;
61
+ private state;
62
+ private scanBuf;
63
+ private mappingsBufs;
64
+ constructor(replacements: HashRefReplacement[]);
65
+ _transform(chunk: Buffer, _encoding: string, cb: any): void;
66
+ private _bufferingTransform;
67
+ _flush(cb: any): void;
68
+ }
36
69
  /**
37
70
  * Computes the sourceRoot for a source map file. This is the relative path from
38
71
  * the output directory back to the project root, so that source paths (stored
@@ -70,6 +70,7 @@ export type Target = {
70
70
  loc?: InternalSourceLocation | null | undefined;
71
71
  pipeline?: string;
72
72
  source?: FilePath | Array<FilePath>;
73
+ inlineRequires?: boolean;
73
74
  };
74
75
  export declare const SpecifierType: {
75
76
  readonly esm: 0;