@remotex-labs/xmap
Version:
A library with a sourcemap parser and TypeScript code formatter for the CLI
1,254 lines (1,245 loc) • 36.3 kB
JavaScript
;
var W = Object.create;
var S = Object.defineProperty;
var F = Object.getOwnPropertyDescriptor;
var Q = Object.getOwnPropertyNames;
var T = Object.getPrototypeOf, V = Object.prototype.hasOwnProperty;
var K = (n, e) => {
for (var t in e)
S(n, t, { get: e[t], enumerable: !0 });
}, k = (n, e, t, r) => {
if (e && typeof e == "object" || typeof e == "function")
for (let o of Q(e))
!V.call(n, o) && o !== t && S(n, o, { get: () => e[o], enumerable: !(r = F(e, o)) || r.enumerable });
return n;
};
var B = (n, e, t) => (t = n != null ? W(T(n)) : {}, k(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
e || !n || !n.__esModule ? S(t, "default", { value: n, enumerable: !0 }) : t,
n
)), q = (n) => k(S({}, "__esModule", { value: !0 }), n);
// src/index.ts
var ne = {};
K(ne, {
Bias: () => C,
SourceService: () => R,
basename: () => J,
createOffset: () => y,
decodeSegment: () => v,
decodeSegmentRaw: () => Y,
decodeVLQ: () => I,
dirname: () => L,
encodeArrayVLQ: () => w,
encodeSegment: () => M,
encodeVLQ: () => $,
formatStackLine: () => P,
join: () => H,
normalize: () => G,
relative: () => A,
resolve: () => x,
resolveError: () => ee,
stackEntry: () => j,
stackSourceEntry: () => D,
toPosix: () => g,
validateSegment: () => E
});
module.exports = q(ne);
// src/components/path.component.ts
var p = B(require("path"), 1), h = B(require("path/posix"), 1), _ = /\\/g, z = /\/+/g;
function g(n) {
if (!n) return "";
let e = String(n);
return e = e.replace(_, "/"), e = e.replace(z, "/"), e;
}
function G(n) {
return h.normalize(g(n));
}
function H(...n) {
return h.join(...n.map(g));
}
function x(...n) {
return g(p.resolve(...n));
}
function L(n) {
return g(p.dirname(n));
}
function A(n, e) {
return h.relative(g(n), g(e)) || ".";
}
function J(n, e) {
return g(p.basename(n, e));
}
// src/components/base64.component.ts
var Z = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", X = /* @__PURE__ */ new Uint8Array([
255,
255,
255,
255,
255,
255,
255,
255,
255,
255,
255,
255,
255,
255,
255,
255,
255,
255,
255,
255,
255,
255,
255,
255,
255,
255,
255,
255,
255,
255,
255,
255,
255,
255,
255,
255,
255,
255,
255,
255,
255,
255,
255,
62,
255,
255,
255,
63,
// + /
52,
53,
54,
55,
56,
57,
58,
59,
60,
61,
255,
255,
255,
255,
255,
255,
// 0-9
255,
0,
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
// A-O
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25,
255,
255,
255,
255,
255,
// P-Z
255,
26,
27,
28,
29,
30,
31,
32,
33,
34,
35,
36,
37,
38,
39,
40,
// a-o
41,
42,
43,
44,
45,
46,
47,
48,
49,
50,
51,
255,
255,
255,
255,
255
// p-z
]);
function $(n) {
let e = n < 0 ? -n * 2 | 1 : n * 2, t = "";
do {
let r = e & 31;
e >>>= 5, t += Z[e > 0 ? r | 32 : r];
} while (e > 0);
return t;
}
function w(n) {
return n.map($).join("");
}
function I(n) {
let e = [], t = 0, r = 0;
for (let o = 0; o < n.length; o++) {
let s = n.charCodeAt(o), i = s < 128 ? X[s] : 255;
if (i === 255)
throw new Error(`Invalid Base64 character: '${n[o]}' at index ${o}`);
r += (i & 31) << t, i & 32 ? t += 5 : (e.push(r & 1 ? -(r >> 1) : r >> 1), r = t = 0);
}
if (t > 0)
throw new Error("Unexpected end of VLQ input: incomplete sequence");
return e;
}
// src/components/segment.component.ts
var C = /* @__PURE__ */ ((r) => (r[r.BOUND = 0] = "BOUND", r[r.LOWER_BOUND = 1] = "LOWER_BOUND", r[r.UPPER_BOUND = 2] = "UPPER_BOUND", r))(C || {});
function y(n = 0, e = 0) {
return {
line: 0,
column: 0,
nameIndex: n,
sourceIndex: e,
generatedLine: 0,
generatedColumn: 0
};
}
function v(n, e) {
let t = e[0], r = e[1], o = e[2], s = e[3], i = e[4];
return n.line += o ?? 0, n.column += s ?? 0, n.sourceIndex += r ?? 0, n.generatedColumn += t, i !== void 0 && (n.nameIndex += i), {
// +1 converts 0-based VLQ accumulator → 1-based public API
line: n.line + 1,
column: n.column + 1,
generatedLine: n.generatedLine + 1,
generatedColumn: n.generatedColumn + 1,
sourceIndex: n.sourceIndex,
nameIndex: i !== void 0 ? n.nameIndex : null
};
}
function Y(n, e) {
return v(n, I(e));
}
function M(n, e) {
let t = e.line - 1, r = e.column - 1, o = e.generatedColumn - 1, s = [
o - n.generatedColumn,
// Δ generatedColumn
e.sourceIndex - n.sourceIndex,
// Δ sourceIndex
t - n.line,
// Δ sourceLine
r - n.column
// Δ sourceColumn
];
return e.nameIndex !== null && e.nameIndex !== void 0 && (s[4] = e.nameIndex - n.nameIndex, n.nameIndex = e.nameIndex), n.generatedColumn = o, n.sourceIndex = e.sourceIndex, n.line = t, n.column = r, w(s);
}
function E(n) {
let e = ["line", "column", "generatedLine", "generatedColumn"];
for (let t of e) {
let r = n[t];
if (!Number.isFinite(r) || r < 1)
throw new Error(`Invalid segment: '${t}' must be a finite number \u2265 1, received ${r}`);
}
if (!Number.isFinite(n.sourceIndex))
throw new Error(`Invalid segment: 'sourceIndex' must be a finite number, received ${n.sourceIndex}`);
if (n.nameIndex !== null && !Number.isFinite(n.nameIndex))
throw new Error(`Invalid segment: 'nameIndex' must be a finite number or null, received ${n.nameIndex}`);
}
// src/services/source.service.ts
var U = require("process");
// src/services/mapping.service.ts
var O = class n {
/**
* The generated file this source map is associated with.
*
* @remarks
* Optional field specifying the filename of the generated code that this
* source map describes. This is typically a relative path.
*
* Can be `null` or omitted if the filename is not relevant or is provided
* through other means (e.g., HTTP headers, file naming conventions).
*
* @example
* ```ts
* file: 'bundle.min.js'
* ```
*
* @since 5.0.0
*/
lines = [];
/**
* List of identifier names referenced in the mappings.
*
* @remarks
* Optional array containing all identifier names (variables, functions, etc.)
* that are referenced by segments with a `nameIndex`. These names correspond
* to their positions in the original source code.
*
* Segments can reference these names by index to indicate which identifier
* in the original code corresponds to a position in the generated code.
*
* Omit this field if no names need to be tracked, or provide an empty array.
*
* @example
* ```ts
* names: ['myFunction', 'result', 'value']
* ```
*
* @since 5.0.0
*/
offsets = {
line: 0,
name: 0,
sources: 0
};
/**
* Gets the current line offset used for coordinate adjustments.
*
* @returns The line offset value
*
* @remarks
* This offset is applied when decoding mappings to shift generated line numbers.
* Useful when merging multiple source maps where line numbers need adjustment.
*
* @since 5.0.0
*/
get lineOffset() {
return this.offsets.line;
}
/**
* Gets the current name index offset used for coordinate adjustments.
*
* @returns The name index offset value
*
* @remarks
* This offset is applied when decoding mappings to shift name indices.
* Necessary when concatenating source maps with different name arrays.
*
* @since 5.0.0
*/
get namesOffset() {
return this.offsets.name;
}
/**
* Gets the current source file index offset used for coordinate adjustments.
*
* @returns The source index offset value
*
* @remarks
* This offset is applied when decoding mappings to shift source file indices.
* Required when merging source maps with different source file arrays.
*
* @since 5.0.0
*/
get sourcesOffset() {
return this.offsets.sources;
}
/**
* Encodes all stored mappings to a Source Map v3 VLQ string.
*
* @returns A Base64 VLQ-encoded mappings string
*
* @remarks
* Converts the internal 1-based segment representation to 0-based VLQ deltas
* and encodes them as a semicolon-separated string where:
* - Semicolons (`;`) separate lines
* - Commas (`,`) separate segments within a line
* - Empty frames are represented as empty strings between semicolons
*
* The encoding process:
* 1. Resets column offset at each line boundary
* 2. Computes deltas relative to a previous segment
* 3. Encodes deltas using Base64 VLQ
*
* @example Encoding mappings
* ```ts
* const service = new MappingService();
* service.decode(mappingArray);
* const vlqString = service.encode();
* // Returns: "AAAA;AACA,AADA;AAGA;"
* ```
*
* @since 5.0.0
*/
encode() {
return this.encodeSourceMapping(this.lines);
}
/**
* Decodes and stores source map data from various input formats.
*
* @param mapping - Source map data (VLQ string, array, or MappingService instance)
* @param namesOffset - Offset to apply to name indices (default: 0)
* @param sourcesOffset - Offset to apply to source file indices (default: 0)
* @param lineOffset - Offset to apply to generated line numbers (default: 0)
*
* @throws Error - If the mapping format is invalid or contains malformed data
*
* @remarks
* Accepts three input formats:
* - **VLQ string**: Standard Source Map v3 encoded mappings
* - **Array**: Structured {@link SourceMappingType} with segments
* - **MappingService**: Another service instance (copies its lines)
*
* Offsets are useful when merging multiple source maps, allowing index
* adjustment to prevent conflicts in name and source arrays.
*
* The method appends to existing mappings, so calling it multiple times
* will accumulate all decoded segments.
*
* @example Decoding from string
* ```ts
* const service = new MappingService();
* service.decode('AAAA;AACA;AADA;');
* ```
*
* @example Decoding with offsets
* ```ts
* const service = new MappingService();
* service.decode(mappingArray, 5, 3, 10);
* // All name indices += 5, source indices += 3, generated lines += 10
* ```
*
* @example Decoding from another service
* ```ts
* const source = new MappingService();
* source.decode('AAAA;');
* const target = new MappingService();
* target.decode(source);
* ```
*
* @since 5.0.0
*/
decode(e, t = 0, r = 0, o = 0) {
this.offsets.line = o, this.offsets.name = t, this.offsets.sources = r;
let s = e instanceof n ? e.lines : e;
Array.isArray(s) ? this.decodeSourceMappingArray(s) : this.decodeSourceMappingString(s);
}
/**
* Finds a segment at the specified generated position using binary search.
*
* @param generatedLine - 1-based generated line number
* @param generatedColumn - 1-based generated column number
* @param bias - Search behavior when no exact match exists (default: {@link Bias.BOUND})
*
* @returns The matching segment, or `null` if no suitable segment exists
*
* @remarks
* Uses binary search for O(log n) performance on sorted segment arrays.
*
* Bias behavior:
* - **`BOUND`**: Returns exact matches only
* - **`LOWER_BOUND`**: Returns the largest segment ≤ target column
* - **`UPPER_BOUND`**: Returns the smallest segment ≥ target column
*
* The line index is adjusted by the current {@link lineOffset} to support
* merged source maps with shifted line numbers.
*
* @example Finding exact segment
* ```ts
* const service = new MappingService();
* service.decode(mappings);
* const segment = service.getSegment(1, 5);
* // Returns a segment at line 1, column 5, or null
* ```
*
* @example Finding nearest lower bound
* ```ts
* const segment = service.getSegment(1, 7, Bias.LOWER_BOUND);
* // Returns the closest segment at or before column 7
* ```
*
* @see {@link Bias} for bias options
* @see {@link getOriginalSegment} for reverse lookups
*
* @since 5.0.0
*/
getSegment(e, t, r = 0) {
let o = e - this.offsets.line - 1, s = this.lines[o];
if (!s || s.length === 0) return null;
let i = 0, c = s.length - 1, l = null;
for (; i <= c; ) {
let a = i + c >>> 1, u = s[a];
if (u.generatedColumn < t)
i = a + 1, r === 1 && (l = u);
else if (u.generatedColumn > t)
c = a - 1, r === 2 && (l = u);
else
return u;
}
return l;
}
/**
* Finds a segment at the specified original source position using linear search.
*
* @param sourceLine - 1-based original source line number
* @param sourceColumn - 1-based original source column number
* @param sourceIndex - Source file index
* @param bias - Search behavior when no exact match exists (default: {@link Bias.BOUND})
*
* @returns The matching segment, or `null` if no suitable segment exists
*
* @remarks
* Performs exhaustive linear search across all segments to find matches
* by original position. For frequent lookups, consider building an index
* first using {@link buildOriginalPositionIndex}.
*
* Returns immediately on the exact column match. For bias modes, tracks the
* closest segment by computing column distance.
*
* Bias behavior:
* - **`BOUND`**: Returns exact matches only
* - **`LOWER_BOUND`**: Returns the closest segment with column ≤ target
* - **`UPPER_BOUND`**: Returns the closest segment with column ≥ target
*
* @example Finding original segment
* ```ts
* const service = new MappingService();
* service.decode(mappings);
* const segment = service.getOriginalSegment(10, 25, 0);
* // Returns segment mapping to source file 0, line 10, column 25
* ```
*
* @example Finding the nearest original position
* ```ts
* const segment = service.getOriginalSegment(10, 25, 0, Bias.LOWER_BOUND);
* // Returns the closest segment at or before column 25
* ```
*
* @see {@link Bias} for bias options
* @see {@link getSegment} for generated position lookups
* @see {@link buildOriginalPositionIndex} for optimized repeated lookups
*
* @since 5.0.0
*/
getOriginalSegment(e, t, r, o = 0) {
let s = null, i = 1 / 0;
for (let c = 0; c < this.lines.length; c++) {
let l = this.lines[c];
if (l)
for (let a = 0; a < l.length; a++) {
let u = l[a];
if (u.sourceIndex !== r || u.line !== e) continue;
let f = u.column;
if (f === t) return u;
if (o === 1) {
if (f < t) {
let m = t - f;
m < i && (i = m, s = u);
}
} else if (o === 2 && f > t) {
let m = f - t;
m < i && (i = m, s = u);
}
}
}
return s;
}
/**
* Builds an indexed map of segments grouped by original source position.
*
* @returns A map keyed by `"sourceIndex:line"` with sorted segment arrays
*
* @remarks
* Creates a lookup structure for efficient reverse mapping from original
* to generated positions. Each bucket contains all segments that map to
* the same source file and line, sorted by column in ascending order.
*
* The index structure:
* - **Keys**: Formatted as `"sourceIndex:line"` (e.g., `"0:1"`, `"2:15"`)
* - **Values**: Arrays of {@link SegmentInterface} sorted by `column`
*
* This is useful when performing many original position lookups, as it
* avoids the O(n) linear search of {@link getOriginalSegment}.
*
* Null/empty lines are safely skipped during index construction.
*
* @example Building and using index
* ```ts
* const service = new MappingService();
* service.decode(mappings);
* const index = service.buildOriginalPositionIndex();
*
* const segments = index.get('0:10');
* // Returns all segments mapping to source file 0, line 10
* ```
*
* @example Binary search on indexed bucket
* ```ts
* const index = service.buildOriginalPositionIndex();
* const bucket = index.get('0:10') || [];
* // Perform binary search on bucket for specific column
* ```
*
* @see {@link getOriginalSegment} for single lookups
*
* @since 5.0.0
*/
buildOriginalPositionIndex() {
let e = /* @__PURE__ */ new Map();
for (let t = 0; t < this.lines.length; t++) {
let r = this.lines[t];
if (r)
for (let o = 0; o < r.length; o++) {
let s = r[o], i = `${s.sourceIndex}:${s.line}`, c = e.get(i);
c || (c = [], e.set(i, c)), c.push(s);
}
}
for (let t of e.values())
t.sort((r, o) => r.column - o.column);
return e;
}
/**
* Encodes a structured source mapping array to a VLQ string.
*
* @param sourceMapping - Array of segment lines to encode
*
* @returns A Base64 VLQ-encoded mappings string
*
* @remarks
* Converts 1-based segment positions to 0-based VLQ deltas and encodes
* them according to Source Map v3 specification.
*
* The encoding process:
* 1. Pre-allocates arrays for optimal performance
* 2. Resets `generatedColumn` offset to 0 at each line boundary
* 3. Encodes each segment as deltas from the previous segment
* 4. Joins segments with commas (`,`) and lines with semicolons (`;`)
*
* Null lines are encoded as empty strings (represented by consecutive
* semicolons in the output).
*
* This method never reads the `generatedLine` field from segments, as
* line boundaries are encoded structurally via semicolons.
*
* @example Internal encoding
* ```ts
* const encoded = this.encodeSourceMapping([
* [{ generatedColumn: 1, sourceIndex: 0, line: 1, column: 1, nameIndex: null, generatedLine: 1 }],
* null,
* [{ generatedColumn: 5, sourceIndex: 0, line: 2, column: 5, nameIndex: null, generatedLine: 3 }]
* ]);
* // Returns: "AAAA;;IAIA"
* ```
*
* @see {@link encode} for public API
* @see {@link encodeSegment} for single segment encoding
*
* @since 5.0.0
*/
encodeSourceMapping(e) {
let t = y(), r = new Array(e.length);
for (let o = 0; o < e.length; o++) {
let s = e[o];
if (t.generatedColumn = 0, !s) {
r[o] = "";
continue;
}
let i = new Array(s.length);
for (let c = 0; c < s.length; c++)
i[c] = M(t, s[c]);
r[o] = i.join(",");
}
return r.join(";");
}
/**
* Validates that a string contains only valid VLQ characters.
*
* @param raw - String to validate
*
* @returns `true` if the string is valid, `false` otherwise
*
* @remarks
* Checks that the input contains only characters from the Source Map v3
* VLQ alphabet plus structural separators:
* - Base64 VLQ characters: `A-Z`, `a-z`, `0-9`, `+`, `/`
* - Separators: `,` (segments), `;` (lines)
*
* Empty strings are considered invalid.
*
* @example Valid mapping string
* ```ts
* this.validateSourceMappingString('AAAA;AACA,AADA;')
* // Returns: true
* ```
*
* @example Invalid mapping string
* ```ts
* this.validateSourceMappingString('AAAA;A#A;')
* // Returns: false (contains '#')
* ```
*
* @since 5.0.0
*/
validateSourceMappingString(e) {
return /^[a-zA-Z0-9+/,;]+$/.test(e);
}
/**
* Decodes a structured source mapping array and appends segments to internal state.
*
* @param sourceMapping - Array of segment lines or null
*
* @throws Error - If the array structure is invalid or segments fail validation
*
* @remarks
* Processes a pre-parsed {@link SourceMappingType} array, applying configured
* offsets to all indices and positions.
*
* The decoding process:
* 1. Validates that input is an array
* 2. Pre-computes combined line shift for performance
* 3. Validates each segment using {@link validateSegment}
* 4. Applies name, source, and line offsets to all coordinates
* 5. Appends decoded segments to an internal lines array
*
* Null lines are preserved as-is. Each segment is validated before the offset
* application to ensure data integrity.
*
* Error messages include 1-based line numbers for easier debugging.
*
* @example Internal array decoding
* ```ts
* this.decodeSourceMappingArray([
* [{ line: 1, column: 1, nameIndex: null, sourceIndex: 0, generatedLine: 1, generatedColumn: 1 }],
* null,
* [{ line: 2, column: 5, nameIndex: 0, sourceIndex: 0, generatedLine: 3, generatedColumn: 3 }]
* ]);
* ```
*
* @see {@link decode} for public API
* @see {@link validateSegment} for validation rules
*
* @since 5.0.0
*/
decodeSourceMappingArray(e) {
if (!Array.isArray(e))
throw new Error("Invalid source mapping: expected an array of lines.");
let t = this.lines.length, { name: r, sources: o, line: s } = this.offsets, i = t + s;
for (let c = 0; c < e.length; c++) {
let l = e[c];
if (!l) {
this.lines.push(l);
continue;
}
if (!Array.isArray(l))
throw new Error(`Invalid source mapping at line ${c + 1}: expected an array of segments, got ${typeof l}.`);
try {
let a = new Array(l.length);
for (let u = 0; u < l.length; u++) {
let f = l[u];
E(f), a[u] = {
...f,
nameIndex: typeof f.nameIndex == "number" ? f.nameIndex + r : null,
sourceIndex: f.sourceIndex + o,
generatedLine: f.generatedLine + i
};
}
this.lines.push(a);
} catch (a) {
throw new Error(`Error decoding mappings at line ${c + 1}: ${a instanceof Error ? a.message : String(a)}`);
}
}
}
/**
* Decodes a VLQ-encoded mapping string and appends segments to internal state.
*
* @param encodedMapping - Base64 VLQ-encoded mappings string
*
* @throws Error - If the string format is invalid or decoding fails
*
* @remarks
* Parses a Source Map v3 VLQ string into structured segments with 1-based
* positions, applying configured offsets.
*
* The decoding process:
* 1. Validates a character set using {@link validateSourceMappingString}
* 2. Splits string by semicolons (`;`) to separate lines
* 3. Pre-computes offset flags to minimize branching in hot loop
* 4. For each line:
* - Resets `generatedColumn` offset to 0
* - Splits by commas (`,`) to separate segments
* - Decodes VLQ deltas using {@link decodeVLQ}
* - Applies offsets (only allocating new objects when needed)
* 5. Appends decoded segments to an internal lines array
*
* Empty lines (consecutive semicolons) are stored as `null`.
*
* Line offset is only applied when non-zero, avoiding unnecessary object
* allocations for the common case.
*
* Error messages include 1-based line numbers for debugging.
*
* @example Internal string decoding
* ```ts
* this.decodeSourceMappingString('AAAA;AACA,AADA;AAGA;');
* ```
*
* @see {@link decode} for public API
* @see {@link decodeVLQ} for VLQ decoding
* @see {@link decodeSegment} for delta application
*
* @since 5.0.0
*/
decodeSourceMappingString(e) {
if (!this.validateSourceMappingString(e))
throw new Error("Invalid mappings string: contains characters outside the VLQ alphabet.");
let t = e.split(";"), r = this.lines.length, { name: o, sources: s, line: i } = this.offsets, c = y(o, s), l = i !== 0;
for (let a = 0; a < t.length; a++) {
let u = t[a];
if (!u) {
this.lines.push(null);
continue;
}
c.generatedColumn = 0, c.generatedLine = r + a;
let f = u.split(","), m = new Array(f.length);
try {
for (let d = 0; d < f.length; d++) {
let b = v(c, I(f[d]));
m[d] = l ? { ...b, generatedLine: b.generatedLine + i } : b;
}
} catch (d) {
throw new Error(`Error decoding mappings at line ${a + 1}: ${d.message}`);
}
this.lines.push(m);
}
}
};
// src/services/source.service.ts
var R = class n {
/**
* Normalized generated file path associated with this source map.
* @since 5.0.0
*/
file = "";
/**
* Identifier names referenced by mapped segments.
* @since 5.0.0
*/
names = [];
/**
* Resolved source file paths used by the map.
* @since 5.0.0
*/
sources = [];
/**
* Optional source root from the source map payload.
* @since 5.0.0
*/
sourceRoot = "";
/**
* Inline source contents aligned with {@link sources} by index.
* @since 5.0.0
*/
sourcesContent = [];
/**
* Internal mappings handler for encode/decode and lookups.
* @since 5.0.0
*/
mappings = new O();
/**
* Creates a new SourceService from a source map object or JSON string.
*
* @param source - Source map payload as object or JSON string
* @param fileOrOffset - Generated file path override, or generated line offset when numeric
* @param offset - Generated line offset when `fileOrOffset` is a file path
*
* @throws Error - If file path is missing after normalization
* @throws Error - If source map input is invalid or unsupported
*
* @since 5.0.0
*/
constructor(e, t, r) {
if (!e) return;
let o = n.parseSourceMap(e), s = typeof t == "string" ? t : o.file;
if (!s)
throw new Error("File Path not set for the sourcemap");
this.file = x(s);
let i = typeof t == "number" ? t : r ?? 0;
this.mappings.decode(o.mappings, 0, 0, i), this.sources.push(...this.resolveSources(o.sources)), o.names && this.names.push(...o.names), o.sourceRoot && (this.sourceRoot = o.sourceRoot), o.sourcesContent && this.sourcesContent.push(...o.sourcesContent);
}
/**
* Concatenates multiple source maps into one service instance.
*
* @param sources - Source services to merge in order
*
* @returns A new service containing merged mappings, names, sources, and contents
*
* @throws Error - If no source services are provided
*
* @remarks
* Name and source indices are offset during decode to preserve index
* correctness across all merged source maps.
*
* @example
* ```ts
* const merged = SourceService.assign(sourceA, sourceB, ...);
* ```
*
* @since 5.0.0
*/
static assign(...e) {
if (e.length < 1)
throw new Error("At least one source-map must be provided for assign.");
let t = new n();
for (let r of e)
t.mappings.decode(r.mappings, t.names.length, t.sources.length), t.names.push(...r.names), t.sources.push(...r.sources.map((o) => this.isURL(o) ? o : r.sourceRoot + o)), t.sourcesContent.push(...r.sourcesContent);
return t;
}
/**
* Serializes current data to a Source Map v3 object.
*
* @returns A source map object with encoded mappings
*
* @remarks
* Includes optional `file` and `sourceRoot` only when they are set.
*
* @example
* ```ts
* const map = source.getSourceObject();
* ```
*
* @since 5.0.0
*/
getSourceObject() {
let e = {
version: 3,
file: this.file,
names: this.names,
sources: this.sources,
mappings: this.mappings.encode(),
sourcesContent: this.sourcesContent
};
return this.sourceRoot && (e.sourceRoot = this.sourceRoot), e;
}
/**
* Resolves an original position from a generated position.
*
* @param line - 1-based generated line number
* @param column - 1-based generated column number
* @param bias - Search behavior when no exact match exists (default: {@link Bias.BOUND})
*
* @returns Position details, or `null` when no segment matches
*
* @remarks
* The returned `name` can be `null` when the mapped segment has no
* associated name index.
*
* @example
* ```ts
* const pos = source.getPosition(12, 8);
* ```
*
* @since 5.0.0
*/
getPosition(e, t, r = 0) {
let o = this.mappings.getSegment(e, t, r);
return o ? {
name: this.names[o.nameIndex ?? -1] ?? null,
line: o.line,
column: o.column,
source: this.sources[o.sourceIndex],
sourceRoot: this.sourceRoot,
sourceIndex: o.sourceIndex,
generatedLine: o.generatedLine,
generatedColumn: o.generatedColumn
} : null;
}
/**
* Resolves an original position and includes full source content for that file.
*
* @param line - 1-based generated line number
* @param column - 1-based generated column number
* @param bias - Search behavior when no exact match exists (default: {@link Bias.BOUND})
*
* @returns Position details with source content, or `null` when unavailable
*
* @remarks
* Returns `null` if no mapped segment is found for the generated position.
*
* @example
* ```ts
* const pos = source.getPositionWithContent(12, 8);
* ```
*
* @since 5.0.0
*/
getPositionWithContent(e, t, r = 0) {
let o = this.getPosition(e, t, r);
return o ? {
...o,
sourcesContent: this.sourcesContent[o.sourceIndex]
} : null;
}
/**
* Resolves an original position and includes surrounding code context.
*
* @param line - 1-based generated line number
* @param column - 1-based generated column number
* @param bias - Search behavior when no exact match exists (default: {@link Bias.BOUND})
* @param options - Optional line window configuration
*
* @returns Position details with extracted code context, or `null` when unavailable
*
* @remarks
* Default window uses `3` lines before and `4` lines after the target line.
*
* @example
* ```ts
* const pos = source.getPositionWithCode(12, 8, Bias.BOUND, {
* linesBefore: 2,
* linesAfter: 2
* });
* ```
*
* @since 5.0.0
*/
getPositionWithCode(e, t, r = 0, o) {
let s = this.getPosition(e, t, r);
if (!s || !this.sourcesContent[s.sourceIndex])
return null;
let i = Object.assign({
linesAfter: 4,
linesBefore: 3
}, o), c = this.sourcesContent[s.sourceIndex].split(`
`), l = (s.line ?? 1) - 1, a = Math.max(l - i.linesBefore, 0), u = Math.min(l + i.linesAfter, c.length - 1), f = c.slice(a, u + 1).join(`
`);
return {
...s,
code: f,
endLine: u,
startLine: a
};
}
/**
* Resolves a generated position from an original source position.
*
* @param line - 1-based original source line number
* @param column - 1-based original source column number
* @param sourceIndex - Source index or a partial source path to locate the index
* @param bias - Search behavior when no exact match exists (default: {@link Bias.BOUND})
*
* @returns Position details, or `null` when no segment/source matches
*
* @remarks
* String `sourceIndex` is matched using substring search against resolved
* source paths in {@link sources}.
*
* @example
* ```ts
* const pos = source.getPositionByOriginal(40, 3, 'src/main.ts');
* ```
*
* @since 5.0.0
*/
getPositionByOriginal(e, t, r, o = 0) {
let s = r;
if (typeof r == "string" && (s = this.sources.findIndex((c) => c.includes(r))), s < 0)
return null;
let i = this.mappings.getOriginalSegment(e, t, s, o);
return i ? {
name: this.names[i.nameIndex ?? -1] ?? null,
line: i.line,
column: i.column,
source: this.sources[i.sourceIndex],
sourceRoot: this.sourceRoot,
sourceIndex: i.sourceIndex,
generatedLine: i.generatedLine,
generatedColumn: i.generatedColumn
} : null;
}
/**
* Serializes the current source map object as JSON.
*
* @returns JSON string representation of {@link getSourceObject}
*
* @remarks
* Output is suitable for writing a `.map` file or transport over APIs.
*
* @example
* ```ts
* const json = source.toString();
* ```
*
* @since 5.0.0
*/
toString() {
return JSON.stringify(this.getSourceObject());
}
/**
* Parses and validates Source Map v3 input.
*
* @param input - Source map object or JSON string
*
* @returns Parsed and validated source map object
*
* @throws Error - If source map version is not `3`
* @throws Error - If required keys are missing
*
* @remarks
* Accepts JSON input for convenience and validates required structural keys
* before decode operations are attempted.
*
* @example
* ```ts
* const map = SourceService['parseSourceMap'](raw);
* ```
*
* @since 5.0.0
*/
static parseSourceMap(e) {
if (typeof e == "string" && (e = JSON.parse(e)), e.version !== 3)
throw new Error(`Unsupported SourceMap version: ${e.version}. Expected version 3.`);
let r = ["sources", "mappings"].filter((o) => !(o in e));
if (r.length > 0)
throw new Error(
`Invalid SourceMap: missing required ${r.length === 1 ? "key" : "keys"}: ${r.join(", ")}.`
);
return e;
}
/**
* Checks whether a source path is an HTTP(S) URL.
*
* @param path - Path or URL candidate to evaluate
*
* @returns `true` when the value starts with `http` or `https`, otherwise `false`
*
* @remarks
* This helper is used to preserve absolute URL sources and avoid filesystem
* path normalization for remote resources.
*
* @example
* ```ts
* SourceService['isURL']('https://cdn.example.com/app.ts'); // true
* SourceService['isURL']('src/app.ts'); // false
* ```
*
* @since 5.0.0
*/
static isURL(e) {
return e.startsWith("http") || e.startsWith("https");
}
/**
* Resolves source paths relative to the current working directory.
*
* @param sources - Raw source entries from source map payload
*
* @returns Normalized relative source file paths
*
* @remarks
* Each path is resolved from the generated file location, then converted to
* a path relative to `process.cwd()`.
*
* @example
* ```ts
* // internal utility used during construction
* ```
*
* @since 5.0.0
*/
resolveSources(e) {
return e?.map((t) => n.isURL(t) ? t : t.startsWith("..") ? A((0, U.cwd)(), x(L(this.file), t)) : t) ?? [];
}
};
// src/services/resolve.service.ts
var N = require("@remotex-labs/xansi/xterm.component");
function P(n) {
let e = n.fileName ?? n.source ?? "", t = n.functionName ? `${n.functionName} ` : "";
e.startsWith("http") && (e += `#L${n.line}`);
let r = n.line && n.column ? N.xterm.gray(`[${n.line}:${n.column}]`) : "";
return `at ${t}${N.xterm.darkGray(e)} ${r}`.trim();
}
function D(n, e) {
return e.line = n.line, e.column = n.column, n.name && (e.functionName = n.name), n.sourceRoot && !n.source.startsWith("http") && (e.fileName = `${n.sourceRoot}${n.source}`), {
...e,
code: n.code,
format: P(e),
stratLine: n.startLine,
sourceRoot: n.sourceRoot
};
}
function j(n, e) {
if (!e?.withNativeFrames && n.native || !n.line && !n.column && !n.fileName && !n.functionName) return;
let t = e?.getSource?.(n.fileName ?? "");
if (t && n.line && n.column) {
let r = t.getPositionWithCode(n.line, n.column, e?.bias ?? 0, {
linesAfter: e?.linesAfter ?? 4,
linesBefore: e?.linesBefore ?? 3
});
return r ? (r.line += e?.lineOffset ?? 0, r.endLine += e?.lineOffset ?? 0, r.startLine += e?.lineOffset ?? 0, D(r, n)) : void 0;
}
return {
...n,
format: P(n)
};
}
function ee(n, e = {}) {
let t = n.stack.map((r) => j(r, e)).filter(Boolean);
return {
name: n.name,
stack: t,
message: n.message
};
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
Bias,
SourceService,
basename,
createOffset,
decodeSegment,
decodeSegmentRaw,
decodeVLQ,
dirname,
encodeArrayVLQ,
encodeSegment,
encodeVLQ,
formatStackLine,
join,
normalize,
relative,
resolve,
resolveError,
stackEntry,
stackSourceEntry,
toPosix,
validateSegment
});
//# sourceMappingURL=index.js.map