UNPKG

@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
"use strict"; 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