@ttsc/metro 0.30.4 → 0.31.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/README.md +11 -6
  2. package/lib/core/SnapshotReadOperations.d.ts +119 -0
  3. package/lib/core/SnapshotReadOperations.js +3 -0
  4. package/lib/core/SnapshotReadOperations.js.map +1 -0
  5. package/lib/core/SnapshotReadOperations.mjs +2 -0
  6. package/lib/core/SnapshotReadOperations.mjs.map +1 -0
  7. package/lib/core/TtscMetroOptions.d.ts +119 -0
  8. package/lib/core/TtscMetroOptions.js +3 -0
  9. package/lib/core/TtscMetroOptions.js.map +1 -0
  10. package/lib/core/TtscMetroOptions.mjs +2 -0
  11. package/lib/core/TtscMetroOptions.mjs.map +1 -0
  12. package/lib/core/TtscMetroProjectView.d.ts +64 -0
  13. package/lib/core/TtscMetroProjectView.js +3 -0
  14. package/lib/core/TtscMetroProjectView.js.map +1 -0
  15. package/lib/core/TtscMetroProjectView.mjs +2 -0
  16. package/lib/core/TtscMetroProjectView.mjs.map +1 -0
  17. package/lib/core/UpstreamTransformer.d.ts +127 -0
  18. package/lib/core/UpstreamTransformer.js +3 -0
  19. package/lib/core/UpstreamTransformer.js.map +1 -0
  20. package/lib/core/UpstreamTransformer.mjs +2 -0
  21. package/lib/core/UpstreamTransformer.mjs.map +1 -0
  22. package/lib/core/fingerprint.d.ts +442 -97
  23. package/lib/core/fingerprint.js +838 -83
  24. package/lib/core/fingerprint.js.map +1 -1
  25. package/lib/core/fingerprint.mjs +839 -84
  26. package/lib/core/fingerprint.mjs.map +1 -1
  27. package/lib/core/options.d.ts +81 -58
  28. package/lib/core/options.js +81 -4
  29. package/lib/core/options.js.map +1 -1
  30. package/lib/core/options.mjs +81 -4
  31. package/lib/core/options.mjs.map +1 -1
  32. package/lib/core/remapAstLocations.d.ts +76 -0
  33. package/lib/core/remapAstLocations.js +205 -0
  34. package/lib/core/remapAstLocations.js.map +1 -0
  35. package/lib/core/remapAstLocations.mjs +203 -0
  36. package/lib/core/remapAstLocations.mjs.map +1 -0
  37. package/lib/core/upstream.d.ts +97 -27
  38. package/lib/core/upstream.js +109 -8
  39. package/lib/core/upstream.js.map +1 -1
  40. package/lib/core/upstream.mjs +109 -9
  41. package/lib/core/upstream.mjs.map +1 -1
  42. package/lib/index.d.ts +50 -2
  43. package/lib/index.js +88 -24
  44. package/lib/index.js.map +1 -1
  45. package/lib/index.mjs +89 -25
  46. package/lib/index.mjs.map +1 -1
  47. package/lib/transformer.d.ts +183 -6
  48. package/lib/transformer.js +209 -14
  49. package/lib/transformer.js.map +1 -1
  50. package/lib/transformer.mjs +211 -16
  51. package/lib/transformer.mjs.map +1 -1
  52. package/package.json +7 -18
  53. package/src/core/SnapshotReadOperations.ts +121 -0
  54. package/src/core/TtscMetroOptions.ts +127 -0
  55. package/src/core/TtscMetroProjectView.ts +74 -0
  56. package/src/core/UpstreamTransformer.ts +126 -0
  57. package/src/core/fingerprint.ts +987 -109
  58. package/src/core/options.ts +85 -62
  59. package/src/core/remapAstLocations.ts +219 -0
  60. package/src/core/upstream.ts +110 -26
  61. package/src/index.ts +99 -28
  62. package/src/transformer.ts +214 -17
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Move every source location in an upstream transformer's AST from the ttsc
3
+ * transformed text back to the text the module's author wrote
4
+ * (samchon/ttsc#1392).
5
+ *
6
+ * Metro's Babel transformer contract returns an AST, never a map, and Metro
7
+ * builds the module's source map from that AST's `loc` positions against the
8
+ * file it read. The upstream transformer parsed the ttsc transformed text, so
9
+ * without this pass every position after the first change points at the
10
+ * reprinted lines: breakpoints, stack traces, and the error overlay would all
11
+ * be off. Each node's `loc` start and end are looked up in `map` with the usual
12
+ * greatest-lower-bound rule. A node whose start has no mapping into `file`,
13
+ * such as generated code, loses its `loc`, which Babel treats as a synthesized
14
+ * node, so it takes the mapping of the code around it.
15
+ *
16
+ * Babel locations have one-based lines and zero-based UTF-16 columns; source
17
+ * map segments have zero-based lines and columns. The map points from generated
18
+ * text to the authored file. Missing or reversed mapped ends clamp to the
19
+ * mapped start. Traversal tracks visited objects and mutates only AST
20
+ * locations. Absolute sources are compared by filesystem identity within this
21
+ * call, so links and actual directory case capabilities determine the owning
22
+ * source.
23
+ *
24
+ * @param ast The upstream transformer's AST, rewritten in place.
25
+ * @param map The adapter's map from the transformed text to `file`, with
26
+ * absolute `sources`.
27
+ * @param file Absolute path of the module.
28
+ * @evidence contracts/common.md#principled-implementation
29
+ * The adapter consumes its own source-map VLQ segments using
30
+ * greatest-lower-bound lookup, then updates the upstream-owned AST through
31
+ * Metro's returned-AST extension boundary. Iterative traversal tracks
32
+ * visited objects to handle shared/cyclic AST references. Unmapped starts
33
+ * lose loc and invalid ends clamp to the mapped start rather than
34
+ * manufacturing authored positions.
35
+ *
36
+ * @evidence contracts/common.md#clear-and-simple-design
37
+ * Mapping decoding, position lookup and object traversal remain distinct
38
+ * steps; the traversal owns AST mutation and the local lookup owns coordinate
39
+ * conversion without adding a second Babel parser.
40
+ *
41
+ * @evidence contracts/performance.md#efficient-algorithms
42
+ * Mapping decoding is linear in encoded bytes. A visited Set walks each
43
+ * AST object once; each endpoint uses binary search on its generated line's
44
+ * segments. Temporary storage follows decoded segments and reachable AST
45
+ * objects, and the iterative stack avoids call-depth dependence on the AST.
46
+ * Source identity resolution is shared within this call; missing sources can
47
+ * additionally require ancestor and directory-capability observations.
48
+ *
49
+ * @evidenceExclude contracts/performance.md#reuse-equivalent-work
50
+ * This call mutates one returned AST using that delivery's map; it owns no
51
+ * shared cache and repeated calls would remap already moved coordinates.
52
+ *
53
+ * @evidenceExclude contracts/performance.md#bound-retention-and-release-resources
54
+ * The caller owns the AST. Local decoded lines and traversal state end with
55
+ * the call; no handle or cross-delivery state is retained.
56
+ *
57
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts
58
+ * No Babel methods or compiler internals are patched.
59
+ *
60
+ * @evidence contracts/portability.md#os-neutral-implementation
61
+ * The shared filesystem-identity context compares absolute map sources with
62
+ * the delivered file using physical spelling and actual directory case
63
+ * capabilities. Source coordinates remain line/column values independent
64
+ * of native newline spelling; OS names do not fold distinct filenames.
65
+ *
66
+ * @evidence contracts/common.md#meaningful-documentation
67
+ * The native JSDoc explains map direction, in-place mutation, coordinate
68
+ * indexing and generated/unmapped locations. Checked against the
69
+ * documentation skill: separate paragraphs state the contract and why its
70
+ * nonobvious boundary matters; field comments retain their own useful
71
+ * facts.
72
+ */
73
+ export declare function remapAstLocations(ast: unknown, map: {
74
+ mappings: string;
75
+ sources: readonly string[];
76
+ }, file: string): void;
@@ -0,0 +1,205 @@
1
+ 'use strict';
2
+
3
+ var pathIdentity = require('ttsc/path-identity');
4
+
5
+ /**
6
+ * Move every source location in an upstream transformer's AST from the ttsc
7
+ * transformed text back to the text the module's author wrote
8
+ * (samchon/ttsc#1392).
9
+ *
10
+ * Metro's Babel transformer contract returns an AST, never a map, and Metro
11
+ * builds the module's source map from that AST's `loc` positions against the
12
+ * file it read. The upstream transformer parsed the ttsc transformed text, so
13
+ * without this pass every position after the first change points at the
14
+ * reprinted lines: breakpoints, stack traces, and the error overlay would all
15
+ * be off. Each node's `loc` start and end are looked up in `map` with the usual
16
+ * greatest-lower-bound rule. A node whose start has no mapping into `file`,
17
+ * such as generated code, loses its `loc`, which Babel treats as a synthesized
18
+ * node, so it takes the mapping of the code around it.
19
+ *
20
+ * Babel locations have one-based lines and zero-based UTF-16 columns; source
21
+ * map segments have zero-based lines and columns. The map points from generated
22
+ * text to the authored file. Missing or reversed mapped ends clamp to the
23
+ * mapped start. Traversal tracks visited objects and mutates only AST
24
+ * locations. Absolute sources are compared by filesystem identity within this
25
+ * call, so links and actual directory case capabilities determine the owning
26
+ * source.
27
+ *
28
+ * @param ast The upstream transformer's AST, rewritten in place.
29
+ * @param map The adapter's map from the transformed text to `file`, with
30
+ * absolute `sources`.
31
+ * @param file Absolute path of the module.
32
+ * @evidence contracts/common.md#principled-implementation
33
+ * The adapter consumes its own source-map VLQ segments using
34
+ * greatest-lower-bound lookup, then updates the upstream-owned AST through
35
+ * Metro's returned-AST extension boundary. Iterative traversal tracks
36
+ * visited objects to handle shared/cyclic AST references. Unmapped starts
37
+ * lose loc and invalid ends clamp to the mapped start rather than
38
+ * manufacturing authored positions.
39
+ *
40
+ * @evidence contracts/common.md#clear-and-simple-design
41
+ * Mapping decoding, position lookup and object traversal remain distinct
42
+ * steps; the traversal owns AST mutation and the local lookup owns coordinate
43
+ * conversion without adding a second Babel parser.
44
+ *
45
+ * @evidence contracts/performance.md#efficient-algorithms
46
+ * Mapping decoding is linear in encoded bytes. A visited Set walks each
47
+ * AST object once; each endpoint uses binary search on its generated line's
48
+ * segments. Temporary storage follows decoded segments and reachable AST
49
+ * objects, and the iterative stack avoids call-depth dependence on the AST.
50
+ * Source identity resolution is shared within this call; missing sources can
51
+ * additionally require ancestor and directory-capability observations.
52
+ *
53
+ * @evidenceExclude contracts/performance.md#reuse-equivalent-work
54
+ * This call mutates one returned AST using that delivery's map; it owns no
55
+ * shared cache and repeated calls would remap already moved coordinates.
56
+ *
57
+ * @evidenceExclude contracts/performance.md#bound-retention-and-release-resources
58
+ * The caller owns the AST. Local decoded lines and traversal state end with
59
+ * the call; no handle or cross-delivery state is retained.
60
+ *
61
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts
62
+ * No Babel methods or compiler internals are patched.
63
+ *
64
+ * @evidence contracts/portability.md#os-neutral-implementation
65
+ * The shared filesystem-identity context compares absolute map sources with
66
+ * the delivered file using physical spelling and actual directory case
67
+ * capabilities. Source coordinates remain line/column values independent
68
+ * of native newline spelling; OS names do not fold distinct filenames.
69
+ *
70
+ * @evidence contracts/common.md#meaningful-documentation
71
+ * The native JSDoc explains map direction, in-place mutation, coordinate
72
+ * indexing and generated/unmapped locations. Checked against the
73
+ * documentation skill: separate paragraphs state the contract and why its
74
+ * nonobvious boundary matters; field comments retain their own useful
75
+ * facts.
76
+ */
77
+ function remapAstLocations(ast, map, file) {
78
+ const identities = pathIdentity.createFilesystemPathIdentityContext({
79
+ throwOnRealpathError: false,
80
+ });
81
+ const fileKey = identities.resolve(file).key;
82
+ const own = map.sources.findIndex((source) => identities.resolve(source).key === fileKey);
83
+ if (own < 0) {
84
+ return;
85
+ }
86
+ const lines = decodeSegments(map.mappings);
87
+ const locate = (position) => {
88
+ if (typeof position !== "object" || position === null)
89
+ return undefined;
90
+ const { column, line } = position;
91
+ if (typeof line !== "number" || typeof column !== "number") {
92
+ return undefined;
93
+ }
94
+ const segments = lines[line - 1];
95
+ if (segments === undefined)
96
+ return undefined;
97
+ let low = 0;
98
+ let high = segments.length - 1;
99
+ let found;
100
+ while (low <= high) {
101
+ const middle = (low + high) >> 1;
102
+ const segment = segments[middle];
103
+ if (segment.generatedColumn <= column) {
104
+ found = segment;
105
+ low = middle + 1;
106
+ }
107
+ else {
108
+ high = middle - 1;
109
+ }
110
+ }
111
+ return found === undefined || found.source !== own
112
+ ? undefined
113
+ : { column: found.column, line: found.line + 1 };
114
+ };
115
+ const visited = new Set();
116
+ const pending = [ast];
117
+ while (pending.length !== 0) {
118
+ const value = pending.pop();
119
+ if (typeof value !== "object" || value === null || visited.has(value)) {
120
+ continue;
121
+ }
122
+ visited.add(value);
123
+ if (Array.isArray(value)) {
124
+ for (const entryToAppend of value)
125
+ pending.push(entryToAppend);
126
+ continue;
127
+ }
128
+ const node = value;
129
+ for (const [key, child] of Object.entries(node)) {
130
+ if (key !== "loc")
131
+ pending.push(child);
132
+ }
133
+ const loc = node.loc;
134
+ if (typeof loc !== "object" || loc === null)
135
+ continue;
136
+ const { end, start } = loc;
137
+ const mappedStart = locate(start);
138
+ if (mappedStart === undefined) {
139
+ node.loc = null;
140
+ continue;
141
+ }
142
+ const mappedEnd = locate(end);
143
+ node.loc = {
144
+ ...loc,
145
+ end: mappedEnd === undefined ||
146
+ mappedEnd.line < mappedStart.line ||
147
+ (mappedEnd.line === mappedStart.line &&
148
+ mappedEnd.column < mappedStart.column)
149
+ ? mappedStart
150
+ : mappedEnd,
151
+ start: mappedStart,
152
+ };
153
+ }
154
+ }
155
+ /**
156
+ * Decode `mappings` into its segments per generated line, in column order.
157
+ * Segments of every source are kept, and a segment with no source position is
158
+ * kept with source `-1`, so a lookup that lands on either reports no position
159
+ * instead of reaching past it to an earlier mapping.
160
+ */
161
+ function decodeSegments(mappings) {
162
+ const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
163
+ const lines = [];
164
+ let source = 0;
165
+ let line = 0;
166
+ let column = 0;
167
+ for (const text of mappings.split(";")) {
168
+ const segments = [];
169
+ let generatedColumn = 0;
170
+ for (const encoded of text.split(",")) {
171
+ if (encoded === "")
172
+ continue;
173
+ const fields = [];
174
+ let value = 0;
175
+ let shift = 0;
176
+ for (const char of encoded) {
177
+ const digit = alphabet.indexOf(char);
178
+ if (digit < 0)
179
+ return lines;
180
+ value += (digit & 31) << shift;
181
+ if ((digit & 32) !== 0) {
182
+ shift += 5;
183
+ continue;
184
+ }
185
+ fields.push((value & 1) !== 0 ? -(value >>> 1) : value >>> 1);
186
+ value = 0;
187
+ shift = 0;
188
+ }
189
+ generatedColumn += fields[0] ?? 0;
190
+ if (fields.length < 4) {
191
+ segments.push({ column: 0, generatedColumn, line: 0, source: -1 });
192
+ continue;
193
+ }
194
+ source += fields[1];
195
+ line += fields[2];
196
+ column += fields[3];
197
+ segments.push({ column, generatedColumn, line, source });
198
+ }
199
+ lines.push(segments);
200
+ }
201
+ return lines;
202
+ }
203
+
204
+ exports.remapAstLocations = remapAstLocations;
205
+ //# sourceMappingURL=remapAstLocations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remapAstLocations.js","sources":["../../src/core/remapAstLocations.ts"],"sourcesContent":[null],"names":["createFilesystemPathIdentityContext"],"mappings":"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"}
@@ -0,0 +1,203 @@
1
+ import { createFilesystemPathIdentityContext } from 'ttsc/path-identity';
2
+
3
+ /**
4
+ * Move every source location in an upstream transformer's AST from the ttsc
5
+ * transformed text back to the text the module's author wrote
6
+ * (samchon/ttsc#1392).
7
+ *
8
+ * Metro's Babel transformer contract returns an AST, never a map, and Metro
9
+ * builds the module's source map from that AST's `loc` positions against the
10
+ * file it read. The upstream transformer parsed the ttsc transformed text, so
11
+ * without this pass every position after the first change points at the
12
+ * reprinted lines: breakpoints, stack traces, and the error overlay would all
13
+ * be off. Each node's `loc` start and end are looked up in `map` with the usual
14
+ * greatest-lower-bound rule. A node whose start has no mapping into `file`,
15
+ * such as generated code, loses its `loc`, which Babel treats as a synthesized
16
+ * node, so it takes the mapping of the code around it.
17
+ *
18
+ * Babel locations have one-based lines and zero-based UTF-16 columns; source
19
+ * map segments have zero-based lines and columns. The map points from generated
20
+ * text to the authored file. Missing or reversed mapped ends clamp to the
21
+ * mapped start. Traversal tracks visited objects and mutates only AST
22
+ * locations. Absolute sources are compared by filesystem identity within this
23
+ * call, so links and actual directory case capabilities determine the owning
24
+ * source.
25
+ *
26
+ * @param ast The upstream transformer's AST, rewritten in place.
27
+ * @param map The adapter's map from the transformed text to `file`, with
28
+ * absolute `sources`.
29
+ * @param file Absolute path of the module.
30
+ * @evidence contracts/common.md#principled-implementation
31
+ * The adapter consumes its own source-map VLQ segments using
32
+ * greatest-lower-bound lookup, then updates the upstream-owned AST through
33
+ * Metro's returned-AST extension boundary. Iterative traversal tracks
34
+ * visited objects to handle shared/cyclic AST references. Unmapped starts
35
+ * lose loc and invalid ends clamp to the mapped start rather than
36
+ * manufacturing authored positions.
37
+ *
38
+ * @evidence contracts/common.md#clear-and-simple-design
39
+ * Mapping decoding, position lookup and object traversal remain distinct
40
+ * steps; the traversal owns AST mutation and the local lookup owns coordinate
41
+ * conversion without adding a second Babel parser.
42
+ *
43
+ * @evidence contracts/performance.md#efficient-algorithms
44
+ * Mapping decoding is linear in encoded bytes. A visited Set walks each
45
+ * AST object once; each endpoint uses binary search on its generated line's
46
+ * segments. Temporary storage follows decoded segments and reachable AST
47
+ * objects, and the iterative stack avoids call-depth dependence on the AST.
48
+ * Source identity resolution is shared within this call; missing sources can
49
+ * additionally require ancestor and directory-capability observations.
50
+ *
51
+ * @evidenceExclude contracts/performance.md#reuse-equivalent-work
52
+ * This call mutates one returned AST using that delivery's map; it owns no
53
+ * shared cache and repeated calls would remap already moved coordinates.
54
+ *
55
+ * @evidenceExclude contracts/performance.md#bound-retention-and-release-resources
56
+ * The caller owns the AST. Local decoded lines and traversal state end with
57
+ * the call; no handle or cross-delivery state is retained.
58
+ *
59
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts
60
+ * No Babel methods or compiler internals are patched.
61
+ *
62
+ * @evidence contracts/portability.md#os-neutral-implementation
63
+ * The shared filesystem-identity context compares absolute map sources with
64
+ * the delivered file using physical spelling and actual directory case
65
+ * capabilities. Source coordinates remain line/column values independent
66
+ * of native newline spelling; OS names do not fold distinct filenames.
67
+ *
68
+ * @evidence contracts/common.md#meaningful-documentation
69
+ * The native JSDoc explains map direction, in-place mutation, coordinate
70
+ * indexing and generated/unmapped locations. Checked against the
71
+ * documentation skill: separate paragraphs state the contract and why its
72
+ * nonobvious boundary matters; field comments retain their own useful
73
+ * facts.
74
+ */
75
+ function remapAstLocations(ast, map, file) {
76
+ const identities = createFilesystemPathIdentityContext({
77
+ throwOnRealpathError: false,
78
+ });
79
+ const fileKey = identities.resolve(file).key;
80
+ const own = map.sources.findIndex((source) => identities.resolve(source).key === fileKey);
81
+ if (own < 0) {
82
+ return;
83
+ }
84
+ const lines = decodeSegments(map.mappings);
85
+ const locate = (position) => {
86
+ if (typeof position !== "object" || position === null)
87
+ return undefined;
88
+ const { column, line } = position;
89
+ if (typeof line !== "number" || typeof column !== "number") {
90
+ return undefined;
91
+ }
92
+ const segments = lines[line - 1];
93
+ if (segments === undefined)
94
+ return undefined;
95
+ let low = 0;
96
+ let high = segments.length - 1;
97
+ let found;
98
+ while (low <= high) {
99
+ const middle = (low + high) >> 1;
100
+ const segment = segments[middle];
101
+ if (segment.generatedColumn <= column) {
102
+ found = segment;
103
+ low = middle + 1;
104
+ }
105
+ else {
106
+ high = middle - 1;
107
+ }
108
+ }
109
+ return found === undefined || found.source !== own
110
+ ? undefined
111
+ : { column: found.column, line: found.line + 1 };
112
+ };
113
+ const visited = new Set();
114
+ const pending = [ast];
115
+ while (pending.length !== 0) {
116
+ const value = pending.pop();
117
+ if (typeof value !== "object" || value === null || visited.has(value)) {
118
+ continue;
119
+ }
120
+ visited.add(value);
121
+ if (Array.isArray(value)) {
122
+ for (const entryToAppend of value)
123
+ pending.push(entryToAppend);
124
+ continue;
125
+ }
126
+ const node = value;
127
+ for (const [key, child] of Object.entries(node)) {
128
+ if (key !== "loc")
129
+ pending.push(child);
130
+ }
131
+ const loc = node.loc;
132
+ if (typeof loc !== "object" || loc === null)
133
+ continue;
134
+ const { end, start } = loc;
135
+ const mappedStart = locate(start);
136
+ if (mappedStart === undefined) {
137
+ node.loc = null;
138
+ continue;
139
+ }
140
+ const mappedEnd = locate(end);
141
+ node.loc = {
142
+ ...loc,
143
+ end: mappedEnd === undefined ||
144
+ mappedEnd.line < mappedStart.line ||
145
+ (mappedEnd.line === mappedStart.line &&
146
+ mappedEnd.column < mappedStart.column)
147
+ ? mappedStart
148
+ : mappedEnd,
149
+ start: mappedStart,
150
+ };
151
+ }
152
+ }
153
+ /**
154
+ * Decode `mappings` into its segments per generated line, in column order.
155
+ * Segments of every source are kept, and a segment with no source position is
156
+ * kept with source `-1`, so a lookup that lands on either reports no position
157
+ * instead of reaching past it to an earlier mapping.
158
+ */
159
+ function decodeSegments(mappings) {
160
+ const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
161
+ const lines = [];
162
+ let source = 0;
163
+ let line = 0;
164
+ let column = 0;
165
+ for (const text of mappings.split(";")) {
166
+ const segments = [];
167
+ let generatedColumn = 0;
168
+ for (const encoded of text.split(",")) {
169
+ if (encoded === "")
170
+ continue;
171
+ const fields = [];
172
+ let value = 0;
173
+ let shift = 0;
174
+ for (const char of encoded) {
175
+ const digit = alphabet.indexOf(char);
176
+ if (digit < 0)
177
+ return lines;
178
+ value += (digit & 31) << shift;
179
+ if ((digit & 32) !== 0) {
180
+ shift += 5;
181
+ continue;
182
+ }
183
+ fields.push((value & 1) !== 0 ? -(value >>> 1) : value >>> 1);
184
+ value = 0;
185
+ shift = 0;
186
+ }
187
+ generatedColumn += fields[0] ?? 0;
188
+ if (fields.length < 4) {
189
+ segments.push({ column: 0, generatedColumn, line: 0, source: -1 });
190
+ continue;
191
+ }
192
+ source += fields[1];
193
+ line += fields[2];
194
+ column += fields[3];
195
+ segments.push({ column, generatedColumn, line, source });
196
+ }
197
+ lines.push(segments);
198
+ }
199
+ return lines;
200
+ }
201
+
202
+ export { remapAstLocations };
203
+ //# sourceMappingURL=remapAstLocations.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remapAstLocations.mjs","sources":["../../src/core/remapAstLocations.ts"],"sourcesContent":[null],"names":[],"mappings":"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"}
@@ -1,23 +1,4 @@
1
- /**
2
- * The subset of the Metro Babel-transformer contract this adapter relies on.
3
- *
4
- * Metro loads the module named by `transformer.babelTransformerPath` and calls
5
- * its `transform` once per file, expecting a Babel AST back. `getCacheKey` is
6
- * an optional export Metro folds into its transform-cache key; Metro invokes it
7
- * with arguments (e.g. `{ projectRoot, enableBabelRCLookup }`), so it is typed
8
- * variadic.
9
- */
10
- export interface UpstreamTransformer {
11
- transform(params: {
12
- src: string;
13
- filename: string;
14
- options: Record<string, unknown>;
15
- [key: string]: unknown;
16
- }): Promise<{
17
- ast: object;
18
- }>;
19
- getCacheKey?: (...args: unknown[]) => string;
20
- }
1
+ import type { UpstreamTransformer } from "./UpstreamTransformer";
21
2
  /**
22
3
  * Upstream transformer module specifiers tried (in order) when no explicit
23
4
  * `upstreamTransformer` is configured: Expo first, then modern bare React
@@ -32,13 +13,102 @@ export declare const UPSTREAM_CANDIDATES: readonly ["@expo/metro-config/babel-tr
32
13
  * 1. An explicit `customPath` (the `upstreamTransformer` option);
33
14
  * 2. Each of {@link UPSTREAM_CANDIDATES} in turn.
34
15
  *
35
- * These are declared as optional peers and resolved at runtime against the
36
- * consumer project, so the adapter carries no Metro/Expo dependency itself.
37
- * Resolution is not memoised: Node's own module cache already makes the
38
- * repeated `require` a cheap lookup, and keeping no module-level state lets a
39
- * changed `upstreamTransformer` always take effect.
16
+ * `withTtsc` resolves an explicit specifier and the automatic candidates from
17
+ * the consuming project in the Metro config process, and publishes the absolute
18
+ * path it found (see {@link locateProjectUpstreamTransformer}). This worker-side
19
+ * lookup, rooted in the adapter's own location, is what remains for a specifier
20
+ * the project could not resolve, so the adapter carries no Metro/Expo
21
+ * dependency itself. Resolution is not memoised: Node's own module cache
22
+ * already makes the repeated `require` a cheap lookup, and keeping no
23
+ * module-level state lets a changed `upstreamTransformer` always take effect.
24
+ *
25
+ * `load` is the explicit module-loading boundary. Its default uses Node's real
26
+ * `require`; an injected loader must preserve absence versus failure
27
+ * semantics.
28
+ *
29
+ * @evidence contracts/common.md#principled-implementation
30
+ * Node createRequire loads the configured module or documented
31
+ * Expo/React-Native candidates. Resolution is separated from execution: only
32
+ * known entry-absence codes permit another automatic candidate;
33
+ * installed-module initialization failures preserve their cause.
34
+ *
35
+ * @evidence contracts/common.md#clear-and-simple-design
36
+ * Explicit selection and ordered detection share the loading boundary.
37
+ * tryRequire owns absence classification, leaving this function to choose
38
+ * the transformer and attach contextual errors.
39
+ *
40
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts
41
+ * The loader argument is an explicit dependency-injection boundary, not a
42
+ * test-only runtime branch or a patched require.
43
+ *
44
+ * @evidence contracts/portability.md#os-neutral-implementation
45
+ * Node resolution accepts project-resolved absolute paths on Windows and
46
+ * POSIX. createRequire is rooted at this module via import.meta.url; no
47
+ * path is turned into a shell command. Runtime errors propagate through the
48
+ * same policy on every OS.
49
+ *
50
+ * @evidence contracts/common.md#meaningful-documentation
51
+ * The native JSDoc explains candidate order, project versus worker
52
+ * resolution and absence versus initialization failures. Checked against
53
+ * the documentation skill: separate paragraphs state the contract and why
54
+ * its nonobvious boundary matters; field comments retain their own useful
55
+ * facts.
56
+ *
57
+ * @evidenceExclude contracts/performance.md#bound-retention-and-release-resources
58
+ * Keeps no state between calls; loaded modules belong to Node's module cache.
59
+ *
60
+ * @evidenceExclude contracts/performance.md#efficient-algorithms
61
+ * At most three candidate probes per call, each a require.resolve followed by one require.
40
62
  *
41
- * `load` is injectable purely so the resolution order and the not-found path
42
- * can be tested deterministically; production always uses the real `require`.
63
+ * @evidenceExclude contracts/performance.md#reuse-equivalent-work
64
+ * Deliberately unmemoised: Node's module cache makes a repeated require cheap and a changed option must take effect.
43
65
  */
44
66
  export declare function resolveUpstreamTransformer(customPath?: string, load?: (modulePath: string) => UpstreamTransformer | undefined): UpstreamTransformer;
67
+ /**
68
+ * Locate the automatic upstream transformer the consuming project installed,
69
+ * without executing it.
70
+ *
71
+ * The candidates belong to the app, not to this adapter: under pnpm or a linked
72
+ * workspace the adapter sits outside the app's `node_modules` ancestry, so a
73
+ * lookup rooted in the adapter cannot see a transformer only the app installed.
74
+ * `resolve` is rooted in the project; each candidate is tried in
75
+ * {@link UPSTREAM_CANDIDATES} order and an absent one is skipped, exactly as the
76
+ * worker's probe skips it. Only resolution runs here, so a broken installation
77
+ * still fails where the worker loads it, with its own error.
78
+ *
79
+ * @param resolve Resolves a module specifier from the project.
80
+ * @returns The absolute path of the first installed candidate, or `undefined`.
81
+ * @evidence contracts/common.md#principled-implementation
82
+ * The supplied project resolver uses Node module resolution without
83
+ * executing candidate code. Only recognized entry-absence errors continue
84
+ * probing; other resolver failures propagate.
85
+ *
86
+ * @evidence contracts/common.md#clear-and-simple-design
87
+ * Project discovery resolves only the shared candidate list; execution is
88
+ * deferred to the worker loader that owns initialization failures.
89
+ *
90
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts
91
+ * The documented optional-peer order is a product default, not a
92
+ * fixture-specific answer. No module methods are replaced.
93
+ *
94
+ * @evidence contracts/portability.md#os-neutral-implementation
95
+ * The injected resolver owns project filesystem resolution on the host OS.
96
+ * This operation compares module specifiers and returns its absolute result
97
+ * without inventing separators or quoting a command.
98
+ *
99
+ * @evidence contracts/common.md#meaningful-documentation
100
+ * The native JSDoc explains project ownership, ordered probing,
101
+ * nonexecution and the absent result. Checked against the documentation
102
+ * skill: separate paragraphs state the contract and why its nonobvious
103
+ * boundary matters; field comments retain their own useful facts.
104
+ *
105
+ * @evidenceExclude contracts/performance.md#bound-retention-and-release-resources
106
+ * Resolves paths without executing a candidate and retains nothing.
107
+ *
108
+ * @evidenceExclude contracts/performance.md#efficient-algorithms
109
+ * At most three resolutions, stopping at the first one that succeeds.
110
+ *
111
+ * @evidenceExclude contracts/performance.md#reuse-equivalent-work
112
+ * Runs once per withTtsc call, in the config process only.
113
+ */
114
+ export declare function locateProjectUpstreamTransformer(resolve: (specifier: string) => string): string | undefined;