@vitest/utils 0.33.0 → 0.34.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +2 -6
- package/dist/index.js +2 -161
- package/dist/source-map.d.ts +110 -0
- package/dist/source-map.js +874 -0
- package/package.json +8 -1
package/dist/index.d.ts
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
export { assertTypes, clone, createDefer, deepClone, getCallLastIndex, getOwnProperties, getType, isObject, isPrimitive, noop, notNullish, objectAttr, parseRegexp, slash, toArray } from './helpers.js';
|
2
|
-
|
3
|
-
export { ArgumentsType, Arrayable, Awaitable, Constructable, DeepMerge, MergeInsertions, MutableArray, Nullable } from './types.js';
|
2
|
+
export { ArgumentsType, Arrayable, Awaitable, Constructable, DeepMerge, ErrorWithDiff, MergeInsertions, MutableArray, Nullable, ParsedStack } from './types.js';
|
4
3
|
import { PrettyFormatOptions } from 'pretty-format';
|
5
4
|
|
6
5
|
declare function stringify(object: unknown, maxDepth?: number, { maxLength, ...options }?: PrettyFormatOptions & {
|
@@ -97,10 +96,7 @@ interface ErrorOptions {
|
|
97
96
|
declare function createSimpleStackTrace(options?: ErrorOptions): string;
|
98
97
|
|
99
98
|
declare const lineSplitRE: RegExp;
|
100
|
-
declare function parseSingleStack(raw: string): ParsedStack | null;
|
101
|
-
declare function parseStacktrace(stack: string, ignore?: (string | RegExp)[]): ParsedStack[];
|
102
|
-
declare function parseErrorStacktrace(e: ErrorWithDiff, ignore?: (string | RegExp)[]): ParsedStack[];
|
103
99
|
declare function positionToOffset(source: string, lineNumber: number, columnNumber: number): number;
|
104
100
|
declare function offsetToLineNumber(source: string, offset: number): number;
|
105
101
|
|
106
|
-
export {
|
102
|
+
export { SAFE_COLORS_SYMBOL, SAFE_TIMERS_SYMBOL, createColors, createSimpleStackTrace, format, getColors, getDefaultColors, getSafeTimers, inspect, lineSplitRE, objDisplay, offsetToLineNumber, positionToOffset, setSafeTimers, setupColors, shuffle, stringify };
|
package/dist/index.js
CHANGED
@@ -1,5 +1,4 @@
|
|
1
|
-
|
2
|
-
export { assertTypes, clone, createDefer, deepClone, getCallLastIndex, getOwnProperties, getType, isObject, noop, objectAttr, parseRegexp, slash, toArray } from './helpers.js';
|
1
|
+
export { assertTypes, clone, createDefer, deepClone, getCallLastIndex, getOwnProperties, getType, isObject, isPrimitive, noop, notNullish, objectAttr, parseRegexp, slash, toArray } from './helpers.js';
|
3
2
|
export { f as format, i as inspect, o as objDisplay, s as stringify } from './chunk-display.js';
|
4
3
|
import { S as SAFE_TIMERS_SYMBOL } from './chunk-colors.js';
|
5
4
|
export { a as SAFE_COLORS_SYMBOL, c as createColors, b as getColors, g as getDefaultColors, s as setupColors } from './chunk-colors.js';
|
@@ -82,165 +81,7 @@ function createSimpleStackTrace(options) {
|
|
82
81
|
return stackTrace;
|
83
82
|
}
|
84
83
|
|
85
|
-
function normalizeWindowsPath(input = "") {
|
86
|
-
if (!input || !input.includes("\\")) {
|
87
|
-
return input;
|
88
|
-
}
|
89
|
-
return input.replace(/\\/g, "/");
|
90
|
-
}
|
91
|
-
const _IS_ABSOLUTE_RE = /^[/\\](?![/\\])|^[/\\]{2}(?!\.)|^[A-Za-z]:[/\\]/;
|
92
|
-
function cwd() {
|
93
|
-
if (typeof process !== "undefined") {
|
94
|
-
return process.cwd().replace(/\\/g, "/");
|
95
|
-
}
|
96
|
-
return "/";
|
97
|
-
}
|
98
|
-
const resolve = function(...arguments_) {
|
99
|
-
arguments_ = arguments_.map((argument) => normalizeWindowsPath(argument));
|
100
|
-
let resolvedPath = "";
|
101
|
-
let resolvedAbsolute = false;
|
102
|
-
for (let index = arguments_.length - 1; index >= -1 && !resolvedAbsolute; index--) {
|
103
|
-
const path = index >= 0 ? arguments_[index] : cwd();
|
104
|
-
if (!path || path.length === 0) {
|
105
|
-
continue;
|
106
|
-
}
|
107
|
-
resolvedPath = `${path}/${resolvedPath}`;
|
108
|
-
resolvedAbsolute = isAbsolute(path);
|
109
|
-
}
|
110
|
-
resolvedPath = normalizeString(resolvedPath, !resolvedAbsolute);
|
111
|
-
if (resolvedAbsolute && !isAbsolute(resolvedPath)) {
|
112
|
-
return `/${resolvedPath}`;
|
113
|
-
}
|
114
|
-
return resolvedPath.length > 0 ? resolvedPath : ".";
|
115
|
-
};
|
116
|
-
function normalizeString(path, allowAboveRoot) {
|
117
|
-
let res = "";
|
118
|
-
let lastSegmentLength = 0;
|
119
|
-
let lastSlash = -1;
|
120
|
-
let dots = 0;
|
121
|
-
let char = null;
|
122
|
-
for (let index = 0; index <= path.length; ++index) {
|
123
|
-
if (index < path.length) {
|
124
|
-
char = path[index];
|
125
|
-
} else if (char === "/") {
|
126
|
-
break;
|
127
|
-
} else {
|
128
|
-
char = "/";
|
129
|
-
}
|
130
|
-
if (char === "/") {
|
131
|
-
if (lastSlash === index - 1 || dots === 1) ; else if (dots === 2) {
|
132
|
-
if (res.length < 2 || lastSegmentLength !== 2 || res[res.length - 1] !== "." || res[res.length - 2] !== ".") {
|
133
|
-
if (res.length > 2) {
|
134
|
-
const lastSlashIndex = res.lastIndexOf("/");
|
135
|
-
if (lastSlashIndex === -1) {
|
136
|
-
res = "";
|
137
|
-
lastSegmentLength = 0;
|
138
|
-
} else {
|
139
|
-
res = res.slice(0, lastSlashIndex);
|
140
|
-
lastSegmentLength = res.length - 1 - res.lastIndexOf("/");
|
141
|
-
}
|
142
|
-
lastSlash = index;
|
143
|
-
dots = 0;
|
144
|
-
continue;
|
145
|
-
} else if (res.length > 0) {
|
146
|
-
res = "";
|
147
|
-
lastSegmentLength = 0;
|
148
|
-
lastSlash = index;
|
149
|
-
dots = 0;
|
150
|
-
continue;
|
151
|
-
}
|
152
|
-
}
|
153
|
-
if (allowAboveRoot) {
|
154
|
-
res += res.length > 0 ? "/.." : "..";
|
155
|
-
lastSegmentLength = 2;
|
156
|
-
}
|
157
|
-
} else {
|
158
|
-
if (res.length > 0) {
|
159
|
-
res += `/${path.slice(lastSlash + 1, index)}`;
|
160
|
-
} else {
|
161
|
-
res = path.slice(lastSlash + 1, index);
|
162
|
-
}
|
163
|
-
lastSegmentLength = index - lastSlash - 1;
|
164
|
-
}
|
165
|
-
lastSlash = index;
|
166
|
-
dots = 0;
|
167
|
-
} else if (char === "." && dots !== -1) {
|
168
|
-
++dots;
|
169
|
-
} else {
|
170
|
-
dots = -1;
|
171
|
-
}
|
172
|
-
}
|
173
|
-
return res;
|
174
|
-
}
|
175
|
-
const isAbsolute = function(p) {
|
176
|
-
return _IS_ABSOLUTE_RE.test(p);
|
177
|
-
};
|
178
|
-
|
179
84
|
const lineSplitRE = /\r?\n/;
|
180
|
-
const stackIgnorePatterns = [
|
181
|
-
"node:internal",
|
182
|
-
/\/packages\/\w+\/dist\//,
|
183
|
-
/\/@vitest\/\w+\/dist\//,
|
184
|
-
"/vitest/dist/",
|
185
|
-
"/vitest/src/",
|
186
|
-
"/vite-node/dist/",
|
187
|
-
"/vite-node/src/",
|
188
|
-
"/node_modules/chai/",
|
189
|
-
"/node_modules/tinypool/",
|
190
|
-
"/node_modules/tinyspy/"
|
191
|
-
];
|
192
|
-
function extractLocation(urlLike) {
|
193
|
-
if (!urlLike.includes(":"))
|
194
|
-
return [urlLike];
|
195
|
-
const regExp = /(.+?)(?::(\d+))?(?::(\d+))?$/;
|
196
|
-
const parts = regExp.exec(urlLike.replace(/^\(|\)$/g, ""));
|
197
|
-
if (!parts)
|
198
|
-
return [urlLike];
|
199
|
-
return [parts[1], parts[2] || void 0, parts[3] || void 0];
|
200
|
-
}
|
201
|
-
function parseSingleStack(raw) {
|
202
|
-
let line = raw.trim();
|
203
|
-
if (line.includes("(eval "))
|
204
|
-
line = line.replace(/eval code/g, "eval").replace(/(\(eval at [^()]*)|(,.*$)/g, "");
|
205
|
-
let sanitizedLine = line.replace(/^\s+/, "").replace(/\(eval code/g, "(").replace(/^.*?\s+/, "");
|
206
|
-
const location = sanitizedLine.match(/ (\(.+\)$)/);
|
207
|
-
sanitizedLine = location ? sanitizedLine.replace(location[0], "") : sanitizedLine;
|
208
|
-
const [url, lineNumber, columnNumber] = extractLocation(location ? location[1] : sanitizedLine);
|
209
|
-
let method = location && sanitizedLine || "";
|
210
|
-
let file = url && ["eval", "<anonymous>"].includes(url) ? void 0 : url;
|
211
|
-
if (!file || !lineNumber || !columnNumber)
|
212
|
-
return null;
|
213
|
-
if (method.startsWith("async "))
|
214
|
-
method = method.slice(6);
|
215
|
-
if (file.startsWith("file://"))
|
216
|
-
file = file.slice(7);
|
217
|
-
file = resolve(file);
|
218
|
-
return {
|
219
|
-
method,
|
220
|
-
file,
|
221
|
-
line: Number.parseInt(lineNumber),
|
222
|
-
column: Number.parseInt(columnNumber)
|
223
|
-
};
|
224
|
-
}
|
225
|
-
function parseStacktrace(stack, ignore = stackIgnorePatterns) {
|
226
|
-
const stackFrames = stack.split("\n").map((raw) => {
|
227
|
-
const stack2 = parseSingleStack(raw);
|
228
|
-
if (!stack2 || ignore.length && ignore.some((p) => stack2.file.match(p)))
|
229
|
-
return null;
|
230
|
-
return stack2;
|
231
|
-
}).filter(notNullish);
|
232
|
-
return stackFrames;
|
233
|
-
}
|
234
|
-
function parseErrorStacktrace(e, ignore = stackIgnorePatterns) {
|
235
|
-
if (!e || isPrimitive(e))
|
236
|
-
return [];
|
237
|
-
if (e.stacks)
|
238
|
-
return e.stacks;
|
239
|
-
const stackStr = e.stack || e.stackStr || "";
|
240
|
-
const stackFrames = parseStacktrace(stackStr, ignore);
|
241
|
-
e.stacks = stackFrames;
|
242
|
-
return stackFrames;
|
243
|
-
}
|
244
85
|
function positionToOffset(source, lineNumber, columnNumber) {
|
245
86
|
const lines = source.split(lineSplitRE);
|
246
87
|
const nl = /\r\n/.test(source) ? 2 : 1;
|
@@ -270,4 +111,4 @@ function offsetToLineNumber(source, offset) {
|
|
270
111
|
return line + 1;
|
271
112
|
}
|
272
113
|
|
273
|
-
export { SAFE_TIMERS_SYMBOL, createSimpleStackTrace, getSafeTimers,
|
114
|
+
export { SAFE_TIMERS_SYMBOL, createSimpleStackTrace, getSafeTimers, lineSplitRE, offsetToLineNumber, positionToOffset, setSafeTimers, shuffle };
|
@@ -0,0 +1,110 @@
|
|
1
|
+
import { ParsedStack, ErrorWithDiff } from './types.js';
|
2
|
+
|
3
|
+
declare type GeneratedColumn = number;
|
4
|
+
declare type SourcesIndex = number;
|
5
|
+
declare type SourceLine = number;
|
6
|
+
declare type SourceColumn = number;
|
7
|
+
declare type NamesIndex = number;
|
8
|
+
declare type SourceMapSegment = [GeneratedColumn] | [GeneratedColumn, SourcesIndex, SourceLine, SourceColumn] | [GeneratedColumn, SourcesIndex, SourceLine, SourceColumn, NamesIndex];
|
9
|
+
|
10
|
+
interface SourceMapV3 {
|
11
|
+
file?: string | null;
|
12
|
+
names: string[];
|
13
|
+
sourceRoot?: string;
|
14
|
+
sources: (string | null)[];
|
15
|
+
sourcesContent?: (string | null)[];
|
16
|
+
version: 3;
|
17
|
+
}
|
18
|
+
interface EncodedSourceMap extends SourceMapV3 {
|
19
|
+
mappings: string;
|
20
|
+
}
|
21
|
+
interface DecodedSourceMap extends SourceMapV3 {
|
22
|
+
mappings: SourceMapSegment[][];
|
23
|
+
}
|
24
|
+
declare type OriginalMapping = {
|
25
|
+
source: string | null;
|
26
|
+
line: number;
|
27
|
+
column: number;
|
28
|
+
name: string | null;
|
29
|
+
};
|
30
|
+
declare type InvalidOriginalMapping = {
|
31
|
+
source: null;
|
32
|
+
line: null;
|
33
|
+
column: null;
|
34
|
+
name: null;
|
35
|
+
};
|
36
|
+
declare type GeneratedMapping = {
|
37
|
+
line: number;
|
38
|
+
column: number;
|
39
|
+
};
|
40
|
+
declare type InvalidGeneratedMapping = {
|
41
|
+
line: null;
|
42
|
+
column: null;
|
43
|
+
};
|
44
|
+
declare type Bias = typeof GREATEST_LOWER_BOUND | typeof LEAST_UPPER_BOUND;
|
45
|
+
declare type SourceMapInput = string | Ro<EncodedSourceMap> | Ro<DecodedSourceMap> | TraceMap;
|
46
|
+
declare type Needle = {
|
47
|
+
line: number;
|
48
|
+
column: number;
|
49
|
+
bias?: Bias;
|
50
|
+
};
|
51
|
+
declare type SourceNeedle = {
|
52
|
+
source: string;
|
53
|
+
line: number;
|
54
|
+
column: number;
|
55
|
+
bias?: Bias;
|
56
|
+
};
|
57
|
+
declare abstract class SourceMap {
|
58
|
+
version: SourceMapV3['version'];
|
59
|
+
file: SourceMapV3['file'];
|
60
|
+
names: SourceMapV3['names'];
|
61
|
+
sourceRoot: SourceMapV3['sourceRoot'];
|
62
|
+
sources: SourceMapV3['sources'];
|
63
|
+
sourcesContent: SourceMapV3['sourcesContent'];
|
64
|
+
resolvedSources: SourceMapV3['sources'];
|
65
|
+
}
|
66
|
+
declare type Ro<T> = T extends Array<infer V> ? V[] | Readonly<V[]> | RoArray<V> | Readonly<RoArray<V>> : T extends object ? T | Readonly<T> | RoObject<T> | Readonly<RoObject<T>> : T;
|
67
|
+
declare type RoArray<T> = Ro<T>[];
|
68
|
+
declare type RoObject<T> = {
|
69
|
+
[K in keyof T]: T[K] | Ro<T[K]>;
|
70
|
+
};
|
71
|
+
|
72
|
+
declare const LEAST_UPPER_BOUND = -1;
|
73
|
+
declare const GREATEST_LOWER_BOUND = 1;
|
74
|
+
/**
|
75
|
+
* A higher-level API to find the source/line/column associated with a generated line/column
|
76
|
+
* (think, from a stack trace). Line is 1-based, but column is 0-based, due to legacy behavior in
|
77
|
+
* `source-map` library.
|
78
|
+
*/
|
79
|
+
declare let originalPositionFor: (map: TraceMap, needle: Needle) => OriginalMapping | InvalidOriginalMapping;
|
80
|
+
/**
|
81
|
+
* Finds the generated line/column position of the provided source/line/column source position.
|
82
|
+
*/
|
83
|
+
declare let generatedPositionFor: (map: TraceMap, needle: SourceNeedle) => GeneratedMapping | InvalidGeneratedMapping;
|
84
|
+
declare class TraceMap implements SourceMap {
|
85
|
+
version: SourceMapV3['version'];
|
86
|
+
file: SourceMapV3['file'];
|
87
|
+
names: SourceMapV3['names'];
|
88
|
+
sourceRoot: SourceMapV3['sourceRoot'];
|
89
|
+
sources: SourceMapV3['sources'];
|
90
|
+
sourcesContent: SourceMapV3['sourcesContent'];
|
91
|
+
resolvedSources: string[];
|
92
|
+
private _encoded;
|
93
|
+
private _decoded;
|
94
|
+
private _decodedMemo;
|
95
|
+
private _bySources;
|
96
|
+
private _bySourceMemos;
|
97
|
+
constructor(map: SourceMapInput, mapUrl?: string | null);
|
98
|
+
}
|
99
|
+
|
100
|
+
interface StackTraceParserOptions {
|
101
|
+
ignoreStackEntries?: (RegExp | string)[];
|
102
|
+
getSourceMap?: (file: string) => unknown;
|
103
|
+
}
|
104
|
+
declare function parseSingleFFOrSafariStack(raw: string): ParsedStack | null;
|
105
|
+
declare function parseSingleStack(raw: string): ParsedStack | null;
|
106
|
+
declare function parseSingleV8Stack(raw: string): ParsedStack | null;
|
107
|
+
declare function parseStacktrace(stack: string, options?: StackTraceParserOptions): ParsedStack[];
|
108
|
+
declare function parseErrorStacktrace(e: ErrorWithDiff, options?: StackTraceParserOptions): ParsedStack[];
|
109
|
+
|
110
|
+
export { SourceMapInput, StackTraceParserOptions, TraceMap, generatedPositionFor, originalPositionFor, parseErrorStacktrace, parseSingleFFOrSafariStack, parseSingleStack, parseSingleV8Stack, parseStacktrace };
|
@@ -0,0 +1,874 @@
|
|
1
|
+
import { notNullish, isPrimitive } from './helpers.js';
|
2
|
+
|
3
|
+
function normalizeWindowsPath(input = "") {
|
4
|
+
if (!input || !input.includes("\\")) {
|
5
|
+
return input;
|
6
|
+
}
|
7
|
+
return input.replace(/\\/g, "/");
|
8
|
+
}
|
9
|
+
const _IS_ABSOLUTE_RE = /^[/\\](?![/\\])|^[/\\]{2}(?!\.)|^[A-Za-z]:[/\\]/;
|
10
|
+
function cwd() {
|
11
|
+
if (typeof process !== "undefined") {
|
12
|
+
return process.cwd().replace(/\\/g, "/");
|
13
|
+
}
|
14
|
+
return "/";
|
15
|
+
}
|
16
|
+
const resolve$2 = function(...arguments_) {
|
17
|
+
arguments_ = arguments_.map((argument) => normalizeWindowsPath(argument));
|
18
|
+
let resolvedPath = "";
|
19
|
+
let resolvedAbsolute = false;
|
20
|
+
for (let index = arguments_.length - 1; index >= -1 && !resolvedAbsolute; index--) {
|
21
|
+
const path = index >= 0 ? arguments_[index] : cwd();
|
22
|
+
if (!path || path.length === 0) {
|
23
|
+
continue;
|
24
|
+
}
|
25
|
+
resolvedPath = `${path}/${resolvedPath}`;
|
26
|
+
resolvedAbsolute = isAbsolute(path);
|
27
|
+
}
|
28
|
+
resolvedPath = normalizeString(resolvedPath, !resolvedAbsolute);
|
29
|
+
if (resolvedAbsolute && !isAbsolute(resolvedPath)) {
|
30
|
+
return `/${resolvedPath}`;
|
31
|
+
}
|
32
|
+
return resolvedPath.length > 0 ? resolvedPath : ".";
|
33
|
+
};
|
34
|
+
function normalizeString(path, allowAboveRoot) {
|
35
|
+
let res = "";
|
36
|
+
let lastSegmentLength = 0;
|
37
|
+
let lastSlash = -1;
|
38
|
+
let dots = 0;
|
39
|
+
let char = null;
|
40
|
+
for (let index = 0; index <= path.length; ++index) {
|
41
|
+
if (index < path.length) {
|
42
|
+
char = path[index];
|
43
|
+
} else if (char === "/") {
|
44
|
+
break;
|
45
|
+
} else {
|
46
|
+
char = "/";
|
47
|
+
}
|
48
|
+
if (char === "/") {
|
49
|
+
if (lastSlash === index - 1 || dots === 1) ; else if (dots === 2) {
|
50
|
+
if (res.length < 2 || lastSegmentLength !== 2 || res[res.length - 1] !== "." || res[res.length - 2] !== ".") {
|
51
|
+
if (res.length > 2) {
|
52
|
+
const lastSlashIndex = res.lastIndexOf("/");
|
53
|
+
if (lastSlashIndex === -1) {
|
54
|
+
res = "";
|
55
|
+
lastSegmentLength = 0;
|
56
|
+
} else {
|
57
|
+
res = res.slice(0, lastSlashIndex);
|
58
|
+
lastSegmentLength = res.length - 1 - res.lastIndexOf("/");
|
59
|
+
}
|
60
|
+
lastSlash = index;
|
61
|
+
dots = 0;
|
62
|
+
continue;
|
63
|
+
} else if (res.length > 0) {
|
64
|
+
res = "";
|
65
|
+
lastSegmentLength = 0;
|
66
|
+
lastSlash = index;
|
67
|
+
dots = 0;
|
68
|
+
continue;
|
69
|
+
}
|
70
|
+
}
|
71
|
+
if (allowAboveRoot) {
|
72
|
+
res += res.length > 0 ? "/.." : "..";
|
73
|
+
lastSegmentLength = 2;
|
74
|
+
}
|
75
|
+
} else {
|
76
|
+
if (res.length > 0) {
|
77
|
+
res += `/${path.slice(lastSlash + 1, index)}`;
|
78
|
+
} else {
|
79
|
+
res = path.slice(lastSlash + 1, index);
|
80
|
+
}
|
81
|
+
lastSegmentLength = index - lastSlash - 1;
|
82
|
+
}
|
83
|
+
lastSlash = index;
|
84
|
+
dots = 0;
|
85
|
+
} else if (char === "." && dots !== -1) {
|
86
|
+
++dots;
|
87
|
+
} else {
|
88
|
+
dots = -1;
|
89
|
+
}
|
90
|
+
}
|
91
|
+
return res;
|
92
|
+
}
|
93
|
+
const isAbsolute = function(p) {
|
94
|
+
return _IS_ABSOLUTE_RE.test(p);
|
95
|
+
};
|
96
|
+
|
97
|
+
const comma = ','.charCodeAt(0);
|
98
|
+
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
|
99
|
+
const intToChar = new Uint8Array(64); // 64 possible chars.
|
100
|
+
const charToInt = new Uint8Array(128); // z is 122 in ASCII
|
101
|
+
for (let i = 0; i < chars.length; i++) {
|
102
|
+
const c = chars.charCodeAt(i);
|
103
|
+
intToChar[i] = c;
|
104
|
+
charToInt[c] = i;
|
105
|
+
}
|
106
|
+
function decode(mappings) {
|
107
|
+
const state = new Int32Array(5);
|
108
|
+
const decoded = [];
|
109
|
+
let index = 0;
|
110
|
+
do {
|
111
|
+
const semi = indexOf(mappings, index);
|
112
|
+
const line = [];
|
113
|
+
let sorted = true;
|
114
|
+
let lastCol = 0;
|
115
|
+
state[0] = 0;
|
116
|
+
for (let i = index; i < semi; i++) {
|
117
|
+
let seg;
|
118
|
+
i = decodeInteger(mappings, i, state, 0); // genColumn
|
119
|
+
const col = state[0];
|
120
|
+
if (col < lastCol)
|
121
|
+
sorted = false;
|
122
|
+
lastCol = col;
|
123
|
+
if (hasMoreVlq(mappings, i, semi)) {
|
124
|
+
i = decodeInteger(mappings, i, state, 1); // sourcesIndex
|
125
|
+
i = decodeInteger(mappings, i, state, 2); // sourceLine
|
126
|
+
i = decodeInteger(mappings, i, state, 3); // sourceColumn
|
127
|
+
if (hasMoreVlq(mappings, i, semi)) {
|
128
|
+
i = decodeInteger(mappings, i, state, 4); // namesIndex
|
129
|
+
seg = [col, state[1], state[2], state[3], state[4]];
|
130
|
+
}
|
131
|
+
else {
|
132
|
+
seg = [col, state[1], state[2], state[3]];
|
133
|
+
}
|
134
|
+
}
|
135
|
+
else {
|
136
|
+
seg = [col];
|
137
|
+
}
|
138
|
+
line.push(seg);
|
139
|
+
}
|
140
|
+
if (!sorted)
|
141
|
+
sort(line);
|
142
|
+
decoded.push(line);
|
143
|
+
index = semi + 1;
|
144
|
+
} while (index <= mappings.length);
|
145
|
+
return decoded;
|
146
|
+
}
|
147
|
+
function indexOf(mappings, index) {
|
148
|
+
const idx = mappings.indexOf(';', index);
|
149
|
+
return idx === -1 ? mappings.length : idx;
|
150
|
+
}
|
151
|
+
function decodeInteger(mappings, pos, state, j) {
|
152
|
+
let value = 0;
|
153
|
+
let shift = 0;
|
154
|
+
let integer = 0;
|
155
|
+
do {
|
156
|
+
const c = mappings.charCodeAt(pos++);
|
157
|
+
integer = charToInt[c];
|
158
|
+
value |= (integer & 31) << shift;
|
159
|
+
shift += 5;
|
160
|
+
} while (integer & 32);
|
161
|
+
const shouldNegate = value & 1;
|
162
|
+
value >>>= 1;
|
163
|
+
if (shouldNegate) {
|
164
|
+
value = -0x80000000 | -value;
|
165
|
+
}
|
166
|
+
state[j] += value;
|
167
|
+
return pos;
|
168
|
+
}
|
169
|
+
function hasMoreVlq(mappings, i, length) {
|
170
|
+
if (i >= length)
|
171
|
+
return false;
|
172
|
+
return mappings.charCodeAt(i) !== comma;
|
173
|
+
}
|
174
|
+
function sort(line) {
|
175
|
+
line.sort(sortComparator$1);
|
176
|
+
}
|
177
|
+
function sortComparator$1(a, b) {
|
178
|
+
return a[0] - b[0];
|
179
|
+
}
|
180
|
+
|
181
|
+
// Matches the scheme of a URL, eg "http://"
|
182
|
+
const schemeRegex = /^[\w+.-]+:\/\//;
|
183
|
+
/**
|
184
|
+
* Matches the parts of a URL:
|
185
|
+
* 1. Scheme, including ":", guaranteed.
|
186
|
+
* 2. User/password, including "@", optional.
|
187
|
+
* 3. Host, guaranteed.
|
188
|
+
* 4. Port, including ":", optional.
|
189
|
+
* 5. Path, including "/", optional.
|
190
|
+
* 6. Query, including "?", optional.
|
191
|
+
* 7. Hash, including "#", optional.
|
192
|
+
*/
|
193
|
+
const urlRegex = /^([\w+.-]+:)\/\/([^@/#?]*@)?([^:/#?]*)(:\d+)?(\/[^#?]*)?(\?[^#]*)?(#.*)?/;
|
194
|
+
/**
|
195
|
+
* File URLs are weird. They dont' need the regular `//` in the scheme, they may or may not start
|
196
|
+
* with a leading `/`, they can have a domain (but only if they don't start with a Windows drive).
|
197
|
+
*
|
198
|
+
* 1. Host, optional.
|
199
|
+
* 2. Path, which may include "/", guaranteed.
|
200
|
+
* 3. Query, including "?", optional.
|
201
|
+
* 4. Hash, including "#", optional.
|
202
|
+
*/
|
203
|
+
const fileRegex = /^file:(?:\/\/((?![a-z]:)[^/#?]*)?)?(\/?[^#?]*)(\?[^#]*)?(#.*)?/i;
|
204
|
+
var UrlType;
|
205
|
+
(function (UrlType) {
|
206
|
+
UrlType[UrlType["Empty"] = 1] = "Empty";
|
207
|
+
UrlType[UrlType["Hash"] = 2] = "Hash";
|
208
|
+
UrlType[UrlType["Query"] = 3] = "Query";
|
209
|
+
UrlType[UrlType["RelativePath"] = 4] = "RelativePath";
|
210
|
+
UrlType[UrlType["AbsolutePath"] = 5] = "AbsolutePath";
|
211
|
+
UrlType[UrlType["SchemeRelative"] = 6] = "SchemeRelative";
|
212
|
+
UrlType[UrlType["Absolute"] = 7] = "Absolute";
|
213
|
+
})(UrlType || (UrlType = {}));
|
214
|
+
function isAbsoluteUrl(input) {
|
215
|
+
return schemeRegex.test(input);
|
216
|
+
}
|
217
|
+
function isSchemeRelativeUrl(input) {
|
218
|
+
return input.startsWith('//');
|
219
|
+
}
|
220
|
+
function isAbsolutePath(input) {
|
221
|
+
return input.startsWith('/');
|
222
|
+
}
|
223
|
+
function isFileUrl(input) {
|
224
|
+
return input.startsWith('file:');
|
225
|
+
}
|
226
|
+
function isRelative(input) {
|
227
|
+
return /^[.?#]/.test(input);
|
228
|
+
}
|
229
|
+
function parseAbsoluteUrl(input) {
|
230
|
+
const match = urlRegex.exec(input);
|
231
|
+
return makeUrl(match[1], match[2] || '', match[3], match[4] || '', match[5] || '/', match[6] || '', match[7] || '');
|
232
|
+
}
|
233
|
+
function parseFileUrl(input) {
|
234
|
+
const match = fileRegex.exec(input);
|
235
|
+
const path = match[2];
|
236
|
+
return makeUrl('file:', '', match[1] || '', '', isAbsolutePath(path) ? path : '/' + path, match[3] || '', match[4] || '');
|
237
|
+
}
|
238
|
+
function makeUrl(scheme, user, host, port, path, query, hash) {
|
239
|
+
return {
|
240
|
+
scheme,
|
241
|
+
user,
|
242
|
+
host,
|
243
|
+
port,
|
244
|
+
path,
|
245
|
+
query,
|
246
|
+
hash,
|
247
|
+
type: UrlType.Absolute,
|
248
|
+
};
|
249
|
+
}
|
250
|
+
function parseUrl(input) {
|
251
|
+
if (isSchemeRelativeUrl(input)) {
|
252
|
+
const url = parseAbsoluteUrl('http:' + input);
|
253
|
+
url.scheme = '';
|
254
|
+
url.type = UrlType.SchemeRelative;
|
255
|
+
return url;
|
256
|
+
}
|
257
|
+
if (isAbsolutePath(input)) {
|
258
|
+
const url = parseAbsoluteUrl('http://foo.com' + input);
|
259
|
+
url.scheme = '';
|
260
|
+
url.host = '';
|
261
|
+
url.type = UrlType.AbsolutePath;
|
262
|
+
return url;
|
263
|
+
}
|
264
|
+
if (isFileUrl(input))
|
265
|
+
return parseFileUrl(input);
|
266
|
+
if (isAbsoluteUrl(input))
|
267
|
+
return parseAbsoluteUrl(input);
|
268
|
+
const url = parseAbsoluteUrl('http://foo.com/' + input);
|
269
|
+
url.scheme = '';
|
270
|
+
url.host = '';
|
271
|
+
url.type = input
|
272
|
+
? input.startsWith('?')
|
273
|
+
? UrlType.Query
|
274
|
+
: input.startsWith('#')
|
275
|
+
? UrlType.Hash
|
276
|
+
: UrlType.RelativePath
|
277
|
+
: UrlType.Empty;
|
278
|
+
return url;
|
279
|
+
}
|
280
|
+
function stripPathFilename(path) {
|
281
|
+
// If a path ends with a parent directory "..", then it's a relative path with excess parent
|
282
|
+
// paths. It's not a file, so we can't strip it.
|
283
|
+
if (path.endsWith('/..'))
|
284
|
+
return path;
|
285
|
+
const index = path.lastIndexOf('/');
|
286
|
+
return path.slice(0, index + 1);
|
287
|
+
}
|
288
|
+
function mergePaths(url, base) {
|
289
|
+
normalizePath(base, base.type);
|
290
|
+
// If the path is just a "/", then it was an empty path to begin with (remember, we're a relative
|
291
|
+
// path).
|
292
|
+
if (url.path === '/') {
|
293
|
+
url.path = base.path;
|
294
|
+
}
|
295
|
+
else {
|
296
|
+
// Resolution happens relative to the base path's directory, not the file.
|
297
|
+
url.path = stripPathFilename(base.path) + url.path;
|
298
|
+
}
|
299
|
+
}
|
300
|
+
/**
|
301
|
+
* The path can have empty directories "//", unneeded parents "foo/..", or current directory
|
302
|
+
* "foo/.". We need to normalize to a standard representation.
|
303
|
+
*/
|
304
|
+
function normalizePath(url, type) {
|
305
|
+
const rel = type <= UrlType.RelativePath;
|
306
|
+
const pieces = url.path.split('/');
|
307
|
+
// We need to preserve the first piece always, so that we output a leading slash. The item at
|
308
|
+
// pieces[0] is an empty string.
|
309
|
+
let pointer = 1;
|
310
|
+
// Positive is the number of real directories we've output, used for popping a parent directory.
|
311
|
+
// Eg, "foo/bar/.." will have a positive 2, and we can decrement to be left with just "foo".
|
312
|
+
let positive = 0;
|
313
|
+
// We need to keep a trailing slash if we encounter an empty directory (eg, splitting "foo/" will
|
314
|
+
// generate `["foo", ""]` pieces). And, if we pop a parent directory. But once we encounter a
|
315
|
+
// real directory, we won't need to append, unless the other conditions happen again.
|
316
|
+
let addTrailingSlash = false;
|
317
|
+
for (let i = 1; i < pieces.length; i++) {
|
318
|
+
const piece = pieces[i];
|
319
|
+
// An empty directory, could be a trailing slash, or just a double "//" in the path.
|
320
|
+
if (!piece) {
|
321
|
+
addTrailingSlash = true;
|
322
|
+
continue;
|
323
|
+
}
|
324
|
+
// If we encounter a real directory, then we don't need to append anymore.
|
325
|
+
addTrailingSlash = false;
|
326
|
+
// A current directory, which we can always drop.
|
327
|
+
if (piece === '.')
|
328
|
+
continue;
|
329
|
+
// A parent directory, we need to see if there are any real directories we can pop. Else, we
|
330
|
+
// have an excess of parents, and we'll need to keep the "..".
|
331
|
+
if (piece === '..') {
|
332
|
+
if (positive) {
|
333
|
+
addTrailingSlash = true;
|
334
|
+
positive--;
|
335
|
+
pointer--;
|
336
|
+
}
|
337
|
+
else if (rel) {
|
338
|
+
// If we're in a relativePath, then we need to keep the excess parents. Else, in an absolute
|
339
|
+
// URL, protocol relative URL, or an absolute path, we don't need to keep excess.
|
340
|
+
pieces[pointer++] = piece;
|
341
|
+
}
|
342
|
+
continue;
|
343
|
+
}
|
344
|
+
// We've encountered a real directory. Move it to the next insertion pointer, which accounts for
|
345
|
+
// any popped or dropped directories.
|
346
|
+
pieces[pointer++] = piece;
|
347
|
+
positive++;
|
348
|
+
}
|
349
|
+
let path = '';
|
350
|
+
for (let i = 1; i < pointer; i++) {
|
351
|
+
path += '/' + pieces[i];
|
352
|
+
}
|
353
|
+
if (!path || (addTrailingSlash && !path.endsWith('/..'))) {
|
354
|
+
path += '/';
|
355
|
+
}
|
356
|
+
url.path = path;
|
357
|
+
}
|
358
|
+
/**
|
359
|
+
* Attempts to resolve `input` URL/path relative to `base`.
|
360
|
+
*/
|
361
|
+
function resolve$1(input, base) {
|
362
|
+
if (!input && !base)
|
363
|
+
return '';
|
364
|
+
const url = parseUrl(input);
|
365
|
+
let inputType = url.type;
|
366
|
+
if (base && inputType !== UrlType.Absolute) {
|
367
|
+
const baseUrl = parseUrl(base);
|
368
|
+
const baseType = baseUrl.type;
|
369
|
+
switch (inputType) {
|
370
|
+
case UrlType.Empty:
|
371
|
+
url.hash = baseUrl.hash;
|
372
|
+
// fall through
|
373
|
+
case UrlType.Hash:
|
374
|
+
url.query = baseUrl.query;
|
375
|
+
// fall through
|
376
|
+
case UrlType.Query:
|
377
|
+
case UrlType.RelativePath:
|
378
|
+
mergePaths(url, baseUrl);
|
379
|
+
// fall through
|
380
|
+
case UrlType.AbsolutePath:
|
381
|
+
// The host, user, and port are joined, you can't copy one without the others.
|
382
|
+
url.user = baseUrl.user;
|
383
|
+
url.host = baseUrl.host;
|
384
|
+
url.port = baseUrl.port;
|
385
|
+
// fall through
|
386
|
+
case UrlType.SchemeRelative:
|
387
|
+
// The input doesn't have a schema at least, so we need to copy at least that over.
|
388
|
+
url.scheme = baseUrl.scheme;
|
389
|
+
}
|
390
|
+
if (baseType > inputType)
|
391
|
+
inputType = baseType;
|
392
|
+
}
|
393
|
+
normalizePath(url, inputType);
|
394
|
+
const queryHash = url.query + url.hash;
|
395
|
+
switch (inputType) {
|
396
|
+
// This is impossible, because of the empty checks at the start of the function.
|
397
|
+
// case UrlType.Empty:
|
398
|
+
case UrlType.Hash:
|
399
|
+
case UrlType.Query:
|
400
|
+
return queryHash;
|
401
|
+
case UrlType.RelativePath: {
|
402
|
+
// The first char is always a "/", and we need it to be relative.
|
403
|
+
const path = url.path.slice(1);
|
404
|
+
if (!path)
|
405
|
+
return queryHash || '.';
|
406
|
+
if (isRelative(base || input) && !isRelative(path)) {
|
407
|
+
// If base started with a leading ".", or there is no base and input started with a ".",
|
408
|
+
// then we need to ensure that the relative path starts with a ".". We don't know if
|
409
|
+
// relative starts with a "..", though, so check before prepending.
|
410
|
+
return './' + path + queryHash;
|
411
|
+
}
|
412
|
+
return path + queryHash;
|
413
|
+
}
|
414
|
+
case UrlType.AbsolutePath:
|
415
|
+
return url.path + queryHash;
|
416
|
+
default:
|
417
|
+
return url.scheme + '//' + url.user + url.host + url.port + url.path + queryHash;
|
418
|
+
}
|
419
|
+
}
|
420
|
+
|
421
|
+
function resolve(input, base) {
|
422
|
+
// The base is always treated as a directory, if it's not empty.
|
423
|
+
// https://github.com/mozilla/source-map/blob/8cb3ee57/lib/util.js#L327
|
424
|
+
// https://github.com/chromium/chromium/blob/da4adbb3/third_party/blink/renderer/devtools/front_end/sdk/SourceMap.js#L400-L401
|
425
|
+
if (base && !base.endsWith('/'))
|
426
|
+
base += '/';
|
427
|
+
return resolve$1(input, base);
|
428
|
+
}
|
429
|
+
|
430
|
+
/**
|
431
|
+
* Removes everything after the last "/", but leaves the slash.
|
432
|
+
*/
|
433
|
+
function stripFilename(path) {
|
434
|
+
if (!path)
|
435
|
+
return '';
|
436
|
+
const index = path.lastIndexOf('/');
|
437
|
+
return path.slice(0, index + 1);
|
438
|
+
}
|
439
|
+
|
440
|
+
const COLUMN = 0;
|
441
|
+
const SOURCES_INDEX = 1;
|
442
|
+
const SOURCE_LINE = 2;
|
443
|
+
const SOURCE_COLUMN = 3;
|
444
|
+
const NAMES_INDEX = 4;
|
445
|
+
const REV_GENERATED_LINE = 1;
|
446
|
+
const REV_GENERATED_COLUMN = 2;
|
447
|
+
|
448
|
+
function maybeSort(mappings, owned) {
|
449
|
+
const unsortedIndex = nextUnsortedSegmentLine(mappings, 0);
|
450
|
+
if (unsortedIndex === mappings.length)
|
451
|
+
return mappings;
|
452
|
+
// If we own the array (meaning we parsed it from JSON), then we're free to directly mutate it. If
|
453
|
+
// not, we do not want to modify the consumer's input array.
|
454
|
+
if (!owned)
|
455
|
+
mappings = mappings.slice();
|
456
|
+
for (let i = unsortedIndex; i < mappings.length; i = nextUnsortedSegmentLine(mappings, i + 1)) {
|
457
|
+
mappings[i] = sortSegments(mappings[i], owned);
|
458
|
+
}
|
459
|
+
return mappings;
|
460
|
+
}
|
461
|
+
function nextUnsortedSegmentLine(mappings, start) {
|
462
|
+
for (let i = start; i < mappings.length; i++) {
|
463
|
+
if (!isSorted(mappings[i]))
|
464
|
+
return i;
|
465
|
+
}
|
466
|
+
return mappings.length;
|
467
|
+
}
|
468
|
+
function isSorted(line) {
|
469
|
+
for (let j = 1; j < line.length; j++) {
|
470
|
+
if (line[j][COLUMN] < line[j - 1][COLUMN]) {
|
471
|
+
return false;
|
472
|
+
}
|
473
|
+
}
|
474
|
+
return true;
|
475
|
+
}
|
476
|
+
function sortSegments(line, owned) {
|
477
|
+
if (!owned)
|
478
|
+
line = line.slice();
|
479
|
+
return line.sort(sortComparator);
|
480
|
+
}
|
481
|
+
function sortComparator(a, b) {
|
482
|
+
return a[COLUMN] - b[COLUMN];
|
483
|
+
}
|
484
|
+
|
485
|
+
let found = false;
|
486
|
+
/**
|
487
|
+
* A binary search implementation that returns the index if a match is found.
|
488
|
+
* If no match is found, then the left-index (the index associated with the item that comes just
|
489
|
+
* before the desired index) is returned. To maintain proper sort order, a splice would happen at
|
490
|
+
* the next index:
|
491
|
+
*
|
492
|
+
* ```js
|
493
|
+
* const array = [1, 3];
|
494
|
+
* const needle = 2;
|
495
|
+
* const index = binarySearch(array, needle, (item, needle) => item - needle);
|
496
|
+
*
|
497
|
+
* assert.equal(index, 0);
|
498
|
+
* array.splice(index + 1, 0, needle);
|
499
|
+
* assert.deepEqual(array, [1, 2, 3]);
|
500
|
+
* ```
|
501
|
+
*/
|
502
|
+
function binarySearch(haystack, needle, low, high) {
|
503
|
+
while (low <= high) {
|
504
|
+
const mid = low + ((high - low) >> 1);
|
505
|
+
const cmp = haystack[mid][COLUMN] - needle;
|
506
|
+
if (cmp === 0) {
|
507
|
+
found = true;
|
508
|
+
return mid;
|
509
|
+
}
|
510
|
+
if (cmp < 0) {
|
511
|
+
low = mid + 1;
|
512
|
+
}
|
513
|
+
else {
|
514
|
+
high = mid - 1;
|
515
|
+
}
|
516
|
+
}
|
517
|
+
found = false;
|
518
|
+
return low - 1;
|
519
|
+
}
|
520
|
+
function upperBound(haystack, needle, index) {
|
521
|
+
for (let i = index + 1; i < haystack.length; index = i++) {
|
522
|
+
if (haystack[i][COLUMN] !== needle)
|
523
|
+
break;
|
524
|
+
}
|
525
|
+
return index;
|
526
|
+
}
|
527
|
+
function lowerBound(haystack, needle, index) {
|
528
|
+
for (let i = index - 1; i >= 0; index = i--) {
|
529
|
+
if (haystack[i][COLUMN] !== needle)
|
530
|
+
break;
|
531
|
+
}
|
532
|
+
return index;
|
533
|
+
}
|
534
|
+
function memoizedState() {
|
535
|
+
return {
|
536
|
+
lastKey: -1,
|
537
|
+
lastNeedle: -1,
|
538
|
+
lastIndex: -1,
|
539
|
+
};
|
540
|
+
}
|
541
|
+
/**
|
542
|
+
* This overly complicated beast is just to record the last tested line/column and the resulting
|
543
|
+
* index, allowing us to skip a few tests if mappings are monotonically increasing.
|
544
|
+
*/
|
545
|
+
function memoizedBinarySearch(haystack, needle, state, key) {
|
546
|
+
const { lastKey, lastNeedle, lastIndex } = state;
|
547
|
+
let low = 0;
|
548
|
+
let high = haystack.length - 1;
|
549
|
+
if (key === lastKey) {
|
550
|
+
if (needle === lastNeedle) {
|
551
|
+
found = lastIndex !== -1 && haystack[lastIndex][COLUMN] === needle;
|
552
|
+
return lastIndex;
|
553
|
+
}
|
554
|
+
if (needle >= lastNeedle) {
|
555
|
+
// lastIndex may be -1 if the previous needle was not found.
|
556
|
+
low = lastIndex === -1 ? 0 : lastIndex;
|
557
|
+
}
|
558
|
+
else {
|
559
|
+
high = lastIndex;
|
560
|
+
}
|
561
|
+
}
|
562
|
+
state.lastKey = key;
|
563
|
+
state.lastNeedle = needle;
|
564
|
+
return (state.lastIndex = binarySearch(haystack, needle, low, high));
|
565
|
+
}
|
566
|
+
|
567
|
+
// Rebuilds the original source files, with mappings that are ordered by source line/column instead
|
568
|
+
// of generated line/column.
|
569
|
+
function buildBySources(decoded, memos) {
|
570
|
+
const sources = memos.map(buildNullArray);
|
571
|
+
for (let i = 0; i < decoded.length; i++) {
|
572
|
+
const line = decoded[i];
|
573
|
+
for (let j = 0; j < line.length; j++) {
|
574
|
+
const seg = line[j];
|
575
|
+
if (seg.length === 1)
|
576
|
+
continue;
|
577
|
+
const sourceIndex = seg[SOURCES_INDEX];
|
578
|
+
const sourceLine = seg[SOURCE_LINE];
|
579
|
+
const sourceColumn = seg[SOURCE_COLUMN];
|
580
|
+
const originalSource = sources[sourceIndex];
|
581
|
+
const originalLine = (originalSource[sourceLine] || (originalSource[sourceLine] = []));
|
582
|
+
const memo = memos[sourceIndex];
|
583
|
+
// The binary search either found a match, or it found the left-index just before where the
|
584
|
+
// segment should go. Either way, we want to insert after that. And there may be multiple
|
585
|
+
// generated segments associated with an original location, so there may need to move several
|
586
|
+
// indexes before we find where we need to insert.
|
587
|
+
const index = upperBound(originalLine, sourceColumn, memoizedBinarySearch(originalLine, sourceColumn, memo, sourceLine));
|
588
|
+
insert(originalLine, (memo.lastIndex = index + 1), [sourceColumn, i, seg[COLUMN]]);
|
589
|
+
}
|
590
|
+
}
|
591
|
+
return sources;
|
592
|
+
}
|
593
|
+
function insert(array, index, value) {
|
594
|
+
for (let i = array.length; i > index; i--) {
|
595
|
+
array[i] = array[i - 1];
|
596
|
+
}
|
597
|
+
array[index] = value;
|
598
|
+
}
|
599
|
+
// Null arrays allow us to use ordered index keys without actually allocating contiguous memory like
|
600
|
+
// a real array. We use a null-prototype object to avoid prototype pollution and deoptimizations.
|
601
|
+
// Numeric properties on objects are magically sorted in ascending order by the engine regardless of
|
602
|
+
// the insertion order. So, by setting any numeric keys, even out of order, we'll get ascending
|
603
|
+
// order when iterating with for-in.
|
604
|
+
function buildNullArray() {
|
605
|
+
return { __proto__: null };
|
606
|
+
}
|
607
|
+
|
608
|
+
const LINE_GTR_ZERO = '`line` must be greater than 0 (lines start at line 1)';
|
609
|
+
const COL_GTR_EQ_ZERO = '`column` must be greater than or equal to 0 (columns start at column 0)';
|
610
|
+
const LEAST_UPPER_BOUND = -1;
|
611
|
+
const GREATEST_LOWER_BOUND = 1;
|
612
|
+
/**
|
613
|
+
* Returns the decoded (array of lines of segments) form of the SourceMap's mappings field.
|
614
|
+
*/
|
615
|
+
let decodedMappings;
|
616
|
+
/**
|
617
|
+
* A higher-level API to find the source/line/column associated with a generated line/column
|
618
|
+
* (think, from a stack trace). Line is 1-based, but column is 0-based, due to legacy behavior in
|
619
|
+
* `source-map` library.
|
620
|
+
*/
|
621
|
+
let originalPositionFor;
|
622
|
+
/**
|
623
|
+
* Finds the generated line/column position of the provided source/line/column source position.
|
624
|
+
*/
|
625
|
+
let generatedPositionFor;
|
626
|
+
class TraceMap {
|
627
|
+
constructor(map, mapUrl) {
|
628
|
+
const isString = typeof map === 'string';
|
629
|
+
if (!isString && map._decodedMemo)
|
630
|
+
return map;
|
631
|
+
const parsed = (isString ? JSON.parse(map) : map);
|
632
|
+
const { version, file, names, sourceRoot, sources, sourcesContent } = parsed;
|
633
|
+
this.version = version;
|
634
|
+
this.file = file;
|
635
|
+
this.names = names;
|
636
|
+
this.sourceRoot = sourceRoot;
|
637
|
+
this.sources = sources;
|
638
|
+
this.sourcesContent = sourcesContent;
|
639
|
+
const from = resolve(sourceRoot || '', stripFilename(mapUrl));
|
640
|
+
this.resolvedSources = sources.map((s) => resolve(s || '', from));
|
641
|
+
const { mappings } = parsed;
|
642
|
+
if (typeof mappings === 'string') {
|
643
|
+
this._encoded = mappings;
|
644
|
+
this._decoded = undefined;
|
645
|
+
}
|
646
|
+
else {
|
647
|
+
this._encoded = undefined;
|
648
|
+
this._decoded = maybeSort(mappings, isString);
|
649
|
+
}
|
650
|
+
this._decodedMemo = memoizedState();
|
651
|
+
this._bySources = undefined;
|
652
|
+
this._bySourceMemos = undefined;
|
653
|
+
}
|
654
|
+
}
|
655
|
+
(() => {
|
656
|
+
decodedMappings = (map) => {
|
657
|
+
return (map._decoded || (map._decoded = decode(map._encoded)));
|
658
|
+
};
|
659
|
+
originalPositionFor = (map, { line, column, bias }) => {
|
660
|
+
line--;
|
661
|
+
if (line < 0)
|
662
|
+
throw new Error(LINE_GTR_ZERO);
|
663
|
+
if (column < 0)
|
664
|
+
throw new Error(COL_GTR_EQ_ZERO);
|
665
|
+
const decoded = decodedMappings(map);
|
666
|
+
// It's common for parent source maps to have pointers to lines that have no
|
667
|
+
// mapping (like a "//# sourceMappingURL=") at the end of the child file.
|
668
|
+
if (line >= decoded.length)
|
669
|
+
return OMapping(null, null, null, null);
|
670
|
+
const segments = decoded[line];
|
671
|
+
const index = traceSegmentInternal(segments, map._decodedMemo, line, column, bias || GREATEST_LOWER_BOUND);
|
672
|
+
if (index === -1)
|
673
|
+
return OMapping(null, null, null, null);
|
674
|
+
const segment = segments[index];
|
675
|
+
if (segment.length === 1)
|
676
|
+
return OMapping(null, null, null, null);
|
677
|
+
const { names, resolvedSources } = map;
|
678
|
+
return OMapping(resolvedSources[segment[SOURCES_INDEX]], segment[SOURCE_LINE] + 1, segment[SOURCE_COLUMN], segment.length === 5 ? names[segment[NAMES_INDEX]] : null);
|
679
|
+
};
|
680
|
+
generatedPositionFor = (map, { source, line, column, bias }) => {
|
681
|
+
return generatedPosition(map, source, line, column, bias || GREATEST_LOWER_BOUND, false);
|
682
|
+
};
|
683
|
+
function generatedPosition(map, source, line, column, bias, all) {
|
684
|
+
line--;
|
685
|
+
if (line < 0)
|
686
|
+
throw new Error(LINE_GTR_ZERO);
|
687
|
+
if (column < 0)
|
688
|
+
throw new Error(COL_GTR_EQ_ZERO);
|
689
|
+
const { sources, resolvedSources } = map;
|
690
|
+
let sourceIndex = sources.indexOf(source);
|
691
|
+
if (sourceIndex === -1)
|
692
|
+
sourceIndex = resolvedSources.indexOf(source);
|
693
|
+
if (sourceIndex === -1)
|
694
|
+
return all ? [] : GMapping(null, null);
|
695
|
+
const generated = (map._bySources || (map._bySources = buildBySources(decodedMappings(map), (map._bySourceMemos = sources.map(memoizedState)))));
|
696
|
+
const segments = generated[sourceIndex][line];
|
697
|
+
if (segments == null)
|
698
|
+
return all ? [] : GMapping(null, null);
|
699
|
+
const memo = map._bySourceMemos[sourceIndex];
|
700
|
+
if (all)
|
701
|
+
return sliceGeneratedPositions(segments, memo, line, column, bias);
|
702
|
+
const index = traceSegmentInternal(segments, memo, line, column, bias);
|
703
|
+
if (index === -1)
|
704
|
+
return GMapping(null, null);
|
705
|
+
const segment = segments[index];
|
706
|
+
return GMapping(segment[REV_GENERATED_LINE] + 1, segment[REV_GENERATED_COLUMN]);
|
707
|
+
}
|
708
|
+
})();
|
709
|
+
function OMapping(source, line, column, name) {
|
710
|
+
return { source, line, column, name };
|
711
|
+
}
|
712
|
+
function GMapping(line, column) {
|
713
|
+
return { line, column };
|
714
|
+
}
|
715
|
+
function traceSegmentInternal(segments, memo, line, column, bias) {
|
716
|
+
let index = memoizedBinarySearch(segments, column, memo, line);
|
717
|
+
if (found) {
|
718
|
+
index = (bias === LEAST_UPPER_BOUND ? upperBound : lowerBound)(segments, column, index);
|
719
|
+
}
|
720
|
+
else if (bias === LEAST_UPPER_BOUND)
|
721
|
+
index++;
|
722
|
+
if (index === -1 || index === segments.length)
|
723
|
+
return -1;
|
724
|
+
return index;
|
725
|
+
}
|
726
|
+
function sliceGeneratedPositions(segments, memo, line, column, bias) {
|
727
|
+
let min = traceSegmentInternal(segments, memo, line, column, GREATEST_LOWER_BOUND);
|
728
|
+
// We ignored the bias when tracing the segment so that we're guarnateed to find the first (in
|
729
|
+
// insertion order) segment that matched. Even if we did respect the bias when tracing, we would
|
730
|
+
// still need to call `lowerBound()` to find the first segment, which is slower than just looking
|
731
|
+
// for the GREATEST_LOWER_BOUND to begin with. The only difference that matters for us is when the
|
732
|
+
// binary search didn't match, in which case GREATEST_LOWER_BOUND just needs to increment to
|
733
|
+
// match LEAST_UPPER_BOUND.
|
734
|
+
if (!found && bias === LEAST_UPPER_BOUND)
|
735
|
+
min++;
|
736
|
+
if (min === -1 || min === segments.length)
|
737
|
+
return [];
|
738
|
+
// We may have found the segment that started at an earlier column. If this is the case, then we
|
739
|
+
// need to slice all generated segments that match _that_ column, because all such segments span
|
740
|
+
// to our desired column.
|
741
|
+
const matchedColumn = found ? column : segments[min][COLUMN];
|
742
|
+
// The binary search is not guaranteed to find the lower bound when a match wasn't found.
|
743
|
+
if (!found)
|
744
|
+
min = lowerBound(segments, matchedColumn, min);
|
745
|
+
const max = upperBound(segments, matchedColumn, min);
|
746
|
+
const result = [];
|
747
|
+
for (; min <= max; min++) {
|
748
|
+
const segment = segments[min];
|
749
|
+
result.push(GMapping(segment[REV_GENERATED_LINE] + 1, segment[REV_GENERATED_COLUMN]));
|
750
|
+
}
|
751
|
+
return result;
|
752
|
+
}
|
753
|
+
|
754
|
+
const CHROME_IE_STACK_REGEXP = /^\s*at .*(\S+:\d+|\(native\))/m;
|
755
|
+
const SAFARI_NATIVE_CODE_REGEXP = /^(eval@)?(\[native code])?$/;
|
756
|
+
const stackIgnorePatterns = [
|
757
|
+
"node:internal",
|
758
|
+
/\/packages\/\w+\/dist\//,
|
759
|
+
/\/@vitest\/\w+\/dist\//,
|
760
|
+
"/vitest/dist/",
|
761
|
+
"/vitest/src/",
|
762
|
+
"/vite-node/dist/",
|
763
|
+
"/vite-node/src/",
|
764
|
+
"/node_modules/chai/",
|
765
|
+
"/node_modules/tinypool/",
|
766
|
+
"/node_modules/tinyspy/",
|
767
|
+
"/deps/chai.js",
|
768
|
+
/__vitest_browser__/
|
769
|
+
];
|
770
|
+
function extractLocation(urlLike) {
|
771
|
+
if (!urlLike.includes(":"))
|
772
|
+
return [urlLike];
|
773
|
+
const regExp = /(.+?)(?::(\d+))?(?::(\d+))?$/;
|
774
|
+
const parts = regExp.exec(urlLike.replace(/^\(|\)$/g, ""));
|
775
|
+
if (!parts)
|
776
|
+
return [urlLike];
|
777
|
+
let url = parts[1];
|
778
|
+
if (url.startsWith("http:") || url.startsWith("https:")) {
|
779
|
+
const urlObj = new URL(url);
|
780
|
+
url = urlObj.pathname;
|
781
|
+
}
|
782
|
+
if (url.startsWith("/@fs/")) {
|
783
|
+
url = url.slice(typeof process !== "undefined" && process.platform === "win32" ? 5 : 4);
|
784
|
+
}
|
785
|
+
return [url, parts[2] || void 0, parts[3] || void 0];
|
786
|
+
}
|
787
|
+
function parseSingleFFOrSafariStack(raw) {
|
788
|
+
let line = raw.trim();
|
789
|
+
if (SAFARI_NATIVE_CODE_REGEXP.test(line))
|
790
|
+
return null;
|
791
|
+
if (line.includes(" > eval"))
|
792
|
+
line = line.replace(/ line (\d+)(?: > eval line \d+)* > eval:\d+:\d+/g, ":$1");
|
793
|
+
if (!line.includes("@") && !line.includes(":"))
|
794
|
+
return null;
|
795
|
+
const functionNameRegex = /((.*".+"[^@]*)?[^@]*)(?:@)/;
|
796
|
+
const matches = line.match(functionNameRegex);
|
797
|
+
const functionName = matches && matches[1] ? matches[1] : void 0;
|
798
|
+
const [url, lineNumber, columnNumber] = extractLocation(line.replace(functionNameRegex, ""));
|
799
|
+
if (!url || !lineNumber || !columnNumber)
|
800
|
+
return null;
|
801
|
+
return {
|
802
|
+
file: url,
|
803
|
+
method: functionName || "",
|
804
|
+
line: Number.parseInt(lineNumber),
|
805
|
+
column: Number.parseInt(columnNumber)
|
806
|
+
};
|
807
|
+
}
|
808
|
+
function parseSingleStack(raw) {
|
809
|
+
const line = raw.trim();
|
810
|
+
if (!CHROME_IE_STACK_REGEXP.test(line))
|
811
|
+
return parseSingleFFOrSafariStack(line);
|
812
|
+
return parseSingleV8Stack(line);
|
813
|
+
}
|
814
|
+
function parseSingleV8Stack(raw) {
|
815
|
+
let line = raw.trim();
|
816
|
+
if (!CHROME_IE_STACK_REGEXP.test(line))
|
817
|
+
return null;
|
818
|
+
if (line.includes("(eval "))
|
819
|
+
line = line.replace(/eval code/g, "eval").replace(/(\(eval at [^()]*)|(,.*$)/g, "");
|
820
|
+
let sanitizedLine = line.replace(/^\s+/, "").replace(/\(eval code/g, "(").replace(/^.*?\s+/, "");
|
821
|
+
const location = sanitizedLine.match(/ (\(.+\)$)/);
|
822
|
+
sanitizedLine = location ? sanitizedLine.replace(location[0], "") : sanitizedLine;
|
823
|
+
const [url, lineNumber, columnNumber] = extractLocation(location ? location[1] : sanitizedLine);
|
824
|
+
let method = location && sanitizedLine || "";
|
825
|
+
let file = url && ["eval", "<anonymous>"].includes(url) ? void 0 : url;
|
826
|
+
if (!file || !lineNumber || !columnNumber)
|
827
|
+
return null;
|
828
|
+
if (method.startsWith("async "))
|
829
|
+
method = method.slice(6);
|
830
|
+
if (file.startsWith("file://"))
|
831
|
+
file = file.slice(7);
|
832
|
+
file = resolve$2(file);
|
833
|
+
return {
|
834
|
+
method,
|
835
|
+
file,
|
836
|
+
line: Number.parseInt(lineNumber),
|
837
|
+
column: Number.parseInt(columnNumber)
|
838
|
+
};
|
839
|
+
}
|
840
|
+
function parseStacktrace(stack, options = {}) {
|
841
|
+
const { ignoreStackEntries = stackIgnorePatterns } = options;
|
842
|
+
let stacks = !CHROME_IE_STACK_REGEXP.test(stack) ? parseFFOrSafariStackTrace(stack) : parseV8Stacktrace(stack);
|
843
|
+
if (ignoreStackEntries.length)
|
844
|
+
stacks = stacks.filter((stack2) => !ignoreStackEntries.some((p) => stack2.file.match(p)));
|
845
|
+
return stacks.map((stack2) => {
|
846
|
+
var _a;
|
847
|
+
const map = (_a = options.getSourceMap) == null ? void 0 : _a.call(options, stack2.file);
|
848
|
+
if (!map || typeof map !== "object" || !map.version)
|
849
|
+
return stack2;
|
850
|
+
const traceMap = new TraceMap(map);
|
851
|
+
const { line, column } = originalPositionFor(traceMap, stack2);
|
852
|
+
if (line != null && column != null)
|
853
|
+
return { ...stack2, line, column };
|
854
|
+
return stack2;
|
855
|
+
});
|
856
|
+
}
|
857
|
+
function parseFFOrSafariStackTrace(stack) {
|
858
|
+
return stack.split("\n").map((line) => parseSingleFFOrSafariStack(line)).filter(notNullish);
|
859
|
+
}
|
860
|
+
function parseV8Stacktrace(stack) {
|
861
|
+
return stack.split("\n").map((line) => parseSingleV8Stack(line)).filter(notNullish);
|
862
|
+
}
|
863
|
+
function parseErrorStacktrace(e, options = {}) {
|
864
|
+
if (!e || isPrimitive(e))
|
865
|
+
return [];
|
866
|
+
if (e.stacks)
|
867
|
+
return e.stacks;
|
868
|
+
const stackStr = e.stack || e.stackStr || "";
|
869
|
+
const stackFrames = parseStacktrace(stackStr, options);
|
870
|
+
e.stacks = stackFrames;
|
871
|
+
return stackFrames;
|
872
|
+
}
|
873
|
+
|
874
|
+
export { TraceMap, generatedPositionFor, originalPositionFor, parseErrorStacktrace, parseSingleFFOrSafariStack, parseSingleStack, parseSingleV8Stack, parseStacktrace };
|
package/package.json
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
{
|
2
2
|
"name": "@vitest/utils",
|
3
3
|
"type": "module",
|
4
|
-
"version": "0.
|
4
|
+
"version": "0.34.0",
|
5
5
|
"description": "Shared Vitest utility functions",
|
6
6
|
"license": "MIT",
|
7
7
|
"funding": "https://opencollective.com/vitest",
|
@@ -32,6 +32,10 @@
|
|
32
32
|
"types": "./dist/helpers.d.ts",
|
33
33
|
"import": "./dist/helpers.js"
|
34
34
|
},
|
35
|
+
"./source-map": {
|
36
|
+
"types": "./dist/source-map.d.ts",
|
37
|
+
"import": "./dist/source-map.js"
|
38
|
+
},
|
35
39
|
"./*": "./*"
|
36
40
|
},
|
37
41
|
"main": "./dist/index.js",
|
@@ -46,6 +50,9 @@
|
|
46
50
|
"loupe": "^2.3.6",
|
47
51
|
"pretty-format": "^29.5.0"
|
48
52
|
},
|
53
|
+
"devDependencies": {
|
54
|
+
"@jridgewell/trace-mapping": "^0.3.18"
|
55
|
+
},
|
49
56
|
"scripts": {
|
50
57
|
"build": "rimraf dist && rollup -c",
|
51
58
|
"dev": "rollup -c --watch"
|