@vitest/snapshot 2.0.0-beta.8 → 2.0.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/README.md CHANGED
@@ -12,7 +12,8 @@ import { SnapshotManager } from '@vitest/snapshot/manager'
12
12
  const client = new SnapshotClient({
13
13
  // you need to provide your own equality check implementation if you use it
14
14
  // this function is called when `.toMatchSnapshot({ property: 1 })` is called
15
- isEqual: (received, expected) => equals(received, expected, [iterableEquality, subsetEquality]),
15
+ isEqual: (received, expected) =>
16
+ equals(received, expected, [iterableEquality, subsetEquality]),
16
17
  })
17
18
 
18
19
  // class that implements snapshot saving and reading
@@ -53,7 +54,11 @@ const options = {
53
54
  snapshotEnvironment: environment,
54
55
  }
55
56
 
56
- await client.startCurrentRun(getCurrentFilepath(), getCurrentTestName(), options)
57
+ await client.startCurrentRun(
58
+ getCurrentFilepath(),
59
+ getCurrentTestName(),
60
+ options
61
+ )
57
62
 
58
63
  // this will save snapshot to a file which is returned by "snapshotEnvironment.resolvePath"
59
64
  client.assert({
@@ -1,3 +1,10 @@
1
+ interface ParsedStack {
2
+ method: string;
3
+ file: string;
4
+ line: number;
5
+ column: number;
6
+ }
7
+
1
8
  interface SnapshotEnvironment {
2
9
  getVersion: () => string;
3
10
  getHeader: () => string;
@@ -6,6 +13,7 @@ interface SnapshotEnvironment {
6
13
  saveSnapshotFile: (filepath: string, snapshot: string) => Promise<void>;
7
14
  readSnapshotFile: (filepath: string) => Promise<string | null>;
8
15
  removeSnapshotFile: (filepath: string) => Promise<void>;
16
+ processStackTrace?: (stack: ParsedStack) => ParsedStack;
9
17
  }
10
18
  interface SnapshotEnvironmentOptions {
11
19
  snapshotsDirName?: string;
@@ -1,4 +1,4 @@
1
- import { S as SnapshotEnvironment, a as SnapshotEnvironmentOptions } from './environment-BaTWxlGj.js';
1
+ import { S as SnapshotEnvironment, a as SnapshotEnvironmentOptions } from './environment-Ddx0EDtY.js';
2
2
 
3
3
  declare class NodeSnapshotEnvironment implements SnapshotEnvironment {
4
4
  private options;
@@ -16,10 +16,7 @@ class NodeSnapshotEnvironment {
16
16
  }
17
17
  async resolvePath(filepath) {
18
18
  return join(
19
- join(
20
- dirname(filepath),
21
- this.options.snapshotsDirName ?? "__snapshots__"
22
- ),
19
+ join(dirname(filepath), this.options.snapshotsDirName ?? "__snapshots__"),
23
20
  `${basename(filepath)}.snap`
24
21
  );
25
22
  }
@@ -31,13 +28,15 @@ class NodeSnapshotEnvironment {
31
28
  await promises.writeFile(filepath, snapshot, "utf-8");
32
29
  }
33
30
  async readSnapshotFile(filepath) {
34
- if (!existsSync(filepath))
31
+ if (!existsSync(filepath)) {
35
32
  return null;
33
+ }
36
34
  return promises.readFile(filepath, "utf-8");
37
35
  }
38
36
  async removeSnapshotFile(filepath) {
39
- if (existsSync(filepath))
37
+ if (existsSync(filepath)) {
40
38
  await promises.unlink(filepath);
39
+ }
41
40
  }
42
41
  }
43
42
 
@@ -1,5 +1,5 @@
1
1
  import { Plugin, OptionsReceived } from 'pretty-format';
2
- import { S as SnapshotEnvironment } from './environment-BaTWxlGj.js';
2
+ import { S as SnapshotEnvironment } from './environment-Ddx0EDtY.js';
3
3
 
4
4
  interface RawSnapshotInfo {
5
5
  file: string;
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { S as SnapshotStateOptions, a as SnapshotMatchOptions, b as SnapshotResult, R as RawSnapshotInfo } from './index-CTmsp3V1.js';
2
- export { c as SnapshotData, e as SnapshotSerializer, f as SnapshotSummary, d as SnapshotUpdateState, U as UncheckedSnapshot } from './index-CTmsp3V1.js';
3
- import { S as SnapshotEnvironment } from './environment-BaTWxlGj.js';
1
+ import { S as SnapshotStateOptions, a as SnapshotMatchOptions, b as SnapshotResult, R as RawSnapshotInfo } from './index-reKGmLsM.js';
2
+ export { c as SnapshotData, e as SnapshotSerializer, f as SnapshotSummary, d as SnapshotUpdateState, U as UncheckedSnapshot } from './index-reKGmLsM.js';
3
+ import { S as SnapshotEnvironment } from './environment-Ddx0EDtY.js';
4
4
  import { Plugin, Plugins } from 'pretty-format';
5
5
 
6
6
  interface ParsedStack {
package/dist/index.js CHANGED
@@ -86,19 +86,23 @@ function getCallLastIndex(code) {
86
86
  const char = code[charIndex];
87
87
  const isCharString = char === '"' || char === "'" || char === "`";
88
88
  if (isCharString && beforeChar !== "\\") {
89
- if (inString === char)
89
+ if (inString === char) {
90
90
  inString = null;
91
- else if (!inString)
91
+ } else if (!inString) {
92
92
  inString = char;
93
+ }
93
94
  }
94
95
  if (!inString) {
95
- if (char === "(")
96
+ if (char === "(") {
96
97
  startedBracers++;
97
- if (char === ")")
98
+ }
99
+ if (char === ")") {
98
100
  endedBracers++;
101
+ }
99
102
  }
100
- if (startedBracers && endedBracers && startedBracers === endedBracers)
103
+ if (startedBracers && endedBracers && startedBracers === endedBracers) {
101
104
  return charIndex;
105
+ }
102
106
  }
103
107
  return null;
104
108
  }
@@ -142,10 +146,12 @@ function positionToOffset(source, lineNumber, columnNumber) {
142
146
  const lines = source.split(lineSplitRE);
143
147
  const nl = /\r\n/.test(source) ? 2 : 1;
144
148
  let start = 0;
145
- if (lineNumber > lines.length)
149
+ if (lineNumber > lines.length) {
146
150
  return source.length;
147
- for (let i = 0; i < lineNumber - 1; i++)
151
+ }
152
+ for (let i = 0; i < lineNumber - 1; i++) {
148
153
  start += lines[i].length + nl;
154
+ }
149
155
  return start + columnNumber;
150
156
  }
151
157
  function offsetToLineNumber(source, offset) {
@@ -160,8 +166,9 @@ function offsetToLineNumber(source, offset) {
160
166
  let line = 0;
161
167
  for (; line < lines.length; line++) {
162
168
  const lineLength = lines[line].length + nl;
163
- if (counted + lineLength >= offset)
169
+ if (counted + lineLength >= offset) {
164
170
  break;
171
+ }
165
172
  counted += lineLength;
166
173
  }
167
174
  return line + 1;
@@ -231,7 +238,19 @@ const serialize$1 = (val, config, indentation, depth, refs, printer) => {
231
238
  let callsString = "";
232
239
  if (val.mock.calls.length !== 0) {
233
240
  const indentationNext = indentation + config.indent;
234
- callsString = ` {${config.spacingOuter}${indentationNext}"calls": ${printer(val.mock.calls, config, indentationNext, depth, refs)}${config.min ? ", " : ","}${config.spacingOuter}${indentationNext}"results": ${printer(val.mock.results, config, indentationNext, depth, refs)}${config.min ? "" : ","}${config.spacingOuter}${indentation}}`;
241
+ callsString = ` {${config.spacingOuter}${indentationNext}"calls": ${printer(
242
+ val.mock.calls,
243
+ config,
244
+ indentationNext,
245
+ depth,
246
+ refs
247
+ )}${config.min ? ", " : ","}${config.spacingOuter}${indentationNext}"results": ${printer(
248
+ val.mock.results,
249
+ config,
250
+ indentationNext,
251
+ depth,
252
+ refs
253
+ )}${config.min ? "" : ","}${config.spacingOuter}${indentation}}`;
235
254
  }
236
255
  return `[MockFunction${nameString}]${callsString}`;
237
256
  };
@@ -266,8 +285,9 @@ function testNameToKey(testName, count) {
266
285
  return `${testName} ${count}`;
267
286
  }
268
287
  function keyToTestName(key) {
269
- if (!/ \d+$/.test(key))
288
+ if (!/ \d+$/.test(key)) {
270
289
  throw new Error("Snapshot keys must end with a number.");
290
+ }
271
291
  return key.replace(/ \d+$/, "");
272
292
  }
273
293
  function getSnapshotData(content, options) {
@@ -284,8 +304,9 @@ function getSnapshotData(content, options) {
284
304
  }
285
305
  }
286
306
  const isInvalid = snapshotContents;
287
- if ((update === "all" || update === "new") && isInvalid)
307
+ if ((update === "all" || update === "new") && isInvalid) {
288
308
  dirty = true;
309
+ }
289
310
  return { data, dirty };
290
311
  }
291
312
  function addExtraLineBreaks(string) {
@@ -320,7 +341,9 @@ function normalizeNewlines(string) {
320
341
  }
321
342
  async function saveSnapshotFile(environment, snapshotData, snapshotPath) {
322
343
  const snapshots = Object.keys(snapshotData).sort(naturalCompare$1).map(
323
- (key) => `exports[${printBacktickString(key)}] = ${printBacktickString(normalizeNewlines(snapshotData[key]))};`
344
+ (key) => `exports[${printBacktickString(key)}] = ${printBacktickString(
345
+ normalizeNewlines(snapshotData[key])
346
+ )};`
324
347
  );
325
348
  const content = `${environment.getHeader()}
326
349
 
@@ -328,20 +351,19 @@ ${snapshots.join("\n\n")}
328
351
  `;
329
352
  const oldContent = await environment.readSnapshotFile(snapshotPath);
330
353
  const skipWriting = oldContent != null && oldContent === content;
331
- if (skipWriting)
354
+ if (skipWriting) {
332
355
  return;
333
- await environment.saveSnapshotFile(
334
- snapshotPath,
335
- content
336
- );
356
+ }
357
+ await environment.saveSnapshotFile(snapshotPath, content);
337
358
  }
338
359
  function prepareExpected(expected) {
339
360
  function findStartIndent() {
340
361
  var _a, _b;
341
362
  const matchObject = /^( +)\}\s+$/m.exec(expected || "");
342
363
  const objectIndent = (_a = matchObject == null ? void 0 : matchObject[1]) == null ? void 0 : _a.length;
343
- if (objectIndent)
364
+ if (objectIndent) {
344
365
  return objectIndent;
366
+ }
345
367
  const matchText = /^\n( +)"/.exec(expected || "");
346
368
  return ((_b = matchText == null ? void 0 : matchText[1]) == null ? void 0 : _b.length) || 0;
347
369
  }
@@ -371,9 +393,11 @@ function deepMergeSnapshot(target, source) {
371
393
  const mergedOutput = { ...target };
372
394
  Object.keys(source).forEach((key) => {
373
395
  if (isObject(source[key]) && !source[key].$$typeof) {
374
- if (!(key in target))
396
+ if (!(key in target)) {
375
397
  Object.assign(mergedOutput, { [key]: source[key] });
376
- else mergedOutput[key] = deepMergeSnapshot(target[key], source[key]);
398
+ } else {
399
+ mergedOutput[key] = deepMergeSnapshot(target[key], source[key]);
400
+ }
377
401
  } else if (Array.isArray(source[key])) {
378
402
  mergedOutput[key] = deepMergeArray(target[key], source[key]);
379
403
  } else {
@@ -959,21 +983,28 @@ const stackIgnorePatterns = [
959
983
  "/node_modules/tinypool/",
960
984
  "/node_modules/tinyspy/",
961
985
  // browser related deps
962
- "/deps/chai.js",
963
- "/deps/vitest___chai.js",
964
- "/deps/p-limit.js",
986
+ "/deps/chunk-",
987
+ "/deps/@vitest",
988
+ "/deps/loupe",
989
+ "/deps/chai",
965
990
  /node:\w+/,
966
991
  /__vitest_test__/,
967
- /__vitest_browser__/
992
+ /__vitest_browser__/,
993
+ /\/deps\/vitest_/
968
994
  ];
969
995
  function extractLocation(urlLike) {
970
- if (!urlLike.includes(":"))
996
+ if (!urlLike.includes(":")) {
971
997
  return [urlLike];
998
+ }
972
999
  const regExp = /(.+?)(?::(\d+))?(?::(\d+))?$/;
973
1000
  const parts = regExp.exec(urlLike.replace(/^\(|\)$/g, ""));
974
- if (!parts)
1001
+ if (!parts) {
975
1002
  return [urlLike];
1003
+ }
976
1004
  let url = parts[1];
1005
+ if (url.startsWith("async ")) {
1006
+ url = url.slice(6);
1007
+ }
977
1008
  if (url.startsWith("http:") || url.startsWith("https:")) {
978
1009
  const urlObj = new URL(url);
979
1010
  url = urlObj.pathname;
@@ -986,18 +1017,27 @@ function extractLocation(urlLike) {
986
1017
  }
987
1018
  function parseSingleFFOrSafariStack(raw) {
988
1019
  let line = raw.trim();
989
- if (SAFARI_NATIVE_CODE_REGEXP.test(line))
1020
+ if (SAFARI_NATIVE_CODE_REGEXP.test(line)) {
990
1021
  return null;
991
- if (line.includes(" > eval"))
992
- line = line.replace(/ line (\d+)(?: > eval line \d+)* > eval:\d+:\d+/g, ":$1");
993
- if (!line.includes("@") && !line.includes(":"))
1022
+ }
1023
+ if (line.includes(" > eval")) {
1024
+ line = line.replace(
1025
+ / line (\d+)(?: > eval line \d+)* > eval:\d+:\d+/g,
1026
+ ":$1"
1027
+ );
1028
+ }
1029
+ if (!line.includes("@") && !line.includes(":")) {
994
1030
  return null;
1031
+ }
995
1032
  const functionNameRegex = /((.*".+"[^@]*)?[^@]*)(@)/;
996
1033
  const matches = line.match(functionNameRegex);
997
1034
  const functionName = matches && matches[1] ? matches[1] : void 0;
998
- const [url, lineNumber, columnNumber] = extractLocation(line.replace(functionNameRegex, ""));
999
- if (!url || !lineNumber || !columnNumber)
1035
+ const [url, lineNumber, columnNumber] = extractLocation(
1036
+ line.replace(functionNameRegex, "")
1037
+ );
1038
+ if (!url || !lineNumber || !columnNumber) {
1000
1039
  return null;
1040
+ }
1001
1041
  return {
1002
1042
  file: url,
1003
1043
  method: functionName || "",
@@ -1007,25 +1047,33 @@ function parseSingleFFOrSafariStack(raw) {
1007
1047
  }
1008
1048
  function parseSingleV8Stack(raw) {
1009
1049
  let line = raw.trim();
1010
- if (!CHROME_IE_STACK_REGEXP.test(line))
1050
+ if (!CHROME_IE_STACK_REGEXP.test(line)) {
1011
1051
  return null;
1012
- if (line.includes("(eval "))
1052
+ }
1053
+ if (line.includes("(eval ")) {
1013
1054
  line = line.replace(/eval code/g, "eval").replace(/(\(eval at [^()]*)|(,.*$)/g, "");
1055
+ }
1014
1056
  let sanitizedLine = line.replace(/^\s+/, "").replace(/\(eval code/g, "(").replace(/^.*?\s+/, "");
1015
1057
  const location = sanitizedLine.match(/ (\(.+\)$)/);
1016
1058
  sanitizedLine = location ? sanitizedLine.replace(location[0], "") : sanitizedLine;
1017
- const [url, lineNumber, columnNumber] = extractLocation(location ? location[1] : sanitizedLine);
1059
+ const [url, lineNumber, columnNumber] = extractLocation(
1060
+ location ? location[1] : sanitizedLine
1061
+ );
1018
1062
  let method = location && sanitizedLine || "";
1019
1063
  let file = url && ["eval", "<anonymous>"].includes(url) ? void 0 : url;
1020
- if (!file || !lineNumber || !columnNumber)
1064
+ if (!file || !lineNumber || !columnNumber) {
1021
1065
  return null;
1022
- if (method.startsWith("async "))
1066
+ }
1067
+ if (method.startsWith("async ")) {
1023
1068
  method = method.slice(6);
1024
- if (file.startsWith("file://"))
1069
+ }
1070
+ if (file.startsWith("file://")) {
1025
1071
  file = file.slice(7);
1072
+ }
1026
1073
  file = resolve$2(file);
1027
- if (method)
1074
+ if (method) {
1028
1075
  method = method.replace(/__vite_ssr_import_\d+__\./g, "");
1076
+ }
1029
1077
  return {
1030
1078
  method,
1031
1079
  file,
@@ -1036,17 +1084,25 @@ function parseSingleV8Stack(raw) {
1036
1084
  function parseStacktrace(stack, options = {}) {
1037
1085
  const { ignoreStackEntries = stackIgnorePatterns } = options;
1038
1086
  let stacks = !CHROME_IE_STACK_REGEXP.test(stack) ? parseFFOrSafariStackTrace(stack) : parseV8Stacktrace(stack);
1039
- if (ignoreStackEntries.length)
1040
- stacks = stacks.filter((stack2) => !ignoreStackEntries.some((p) => stack2.file.match(p)));
1087
+ if (ignoreStackEntries.length) {
1088
+ stacks = stacks.filter(
1089
+ (stack2) => !ignoreStackEntries.some((p) => stack2.file.match(p))
1090
+ );
1091
+ }
1041
1092
  return stacks.map((stack2) => {
1042
1093
  var _a;
1094
+ if (options.getFileName) {
1095
+ stack2.file = options.getFileName(stack2.file);
1096
+ }
1043
1097
  const map = (_a = options.getSourceMap) == null ? void 0 : _a.call(options, stack2.file);
1044
- if (!map || typeof map !== "object" || !map.version)
1098
+ if (!map || typeof map !== "object" || !map.version) {
1045
1099
  return stack2;
1100
+ }
1046
1101
  const traceMap = new TraceMap(map);
1047
1102
  const { line, column } = originalPositionFor(traceMap, stack2);
1048
- if (line != null && column != null)
1103
+ if (line != null && column != null) {
1049
1104
  return { ...stack2, line, column };
1105
+ }
1050
1106
  return stack2;
1051
1107
  });
1052
1108
  }
@@ -1057,14 +1113,19 @@ function parseV8Stacktrace(stack) {
1057
1113
  return stack.split("\n").map((line) => parseSingleV8Stack(line)).filter(notNullish);
1058
1114
  }
1059
1115
  function parseErrorStacktrace(e, options = {}) {
1060
- if (!e || isPrimitive(e))
1116
+ if (!e || isPrimitive(e)) {
1061
1117
  return [];
1062
- if (e.stacks)
1118
+ }
1119
+ if (e.stacks) {
1063
1120
  return e.stacks;
1121
+ }
1064
1122
  const stackStr = e.stack || e.stackStr || "";
1065
1123
  let stackFrames = parseStacktrace(stackStr, options);
1066
- if (options.frameFilter)
1067
- stackFrames = stackFrames.filter((f) => options.frameFilter(e, f) !== false);
1124
+ if (options.frameFilter) {
1125
+ stackFrames = stackFrames.filter(
1126
+ (f) => options.frameFilter(e, f) !== false
1127
+ );
1128
+ }
1068
1129
  e.stacks = stackFrames;
1069
1130
  return stackFrames;
1070
1131
  }
@@ -1072,29 +1133,34 @@ function parseErrorStacktrace(e, options = {}) {
1072
1133
  async function saveInlineSnapshots(environment, snapshots) {
1073
1134
  const MagicString = (await import('magic-string')).default;
1074
1135
  const files = new Set(snapshots.map((i) => i.file));
1075
- await Promise.all(Array.from(files).map(async (file) => {
1076
- const snaps = snapshots.filter((i) => i.file === file);
1077
- const code = await environment.readSnapshotFile(file);
1078
- const s = new MagicString(code);
1079
- for (const snap of snaps) {
1080
- const index = positionToOffset(code, snap.line, snap.column);
1081
- replaceInlineSnap(code, s, index, snap.snapshot);
1082
- }
1083
- const transformed = s.toString();
1084
- if (transformed !== code)
1085
- await environment.saveSnapshotFile(file, transformed);
1086
- }));
1136
+ await Promise.all(
1137
+ Array.from(files).map(async (file) => {
1138
+ const snaps = snapshots.filter((i) => i.file === file);
1139
+ const code = await environment.readSnapshotFile(file);
1140
+ const s = new MagicString(code);
1141
+ for (const snap of snaps) {
1142
+ const index = positionToOffset(code, snap.line, snap.column);
1143
+ replaceInlineSnap(code, s, index, snap.snapshot);
1144
+ }
1145
+ const transformed = s.toString();
1146
+ if (transformed !== code) {
1147
+ await environment.saveSnapshotFile(file, transformed);
1148
+ }
1149
+ })
1150
+ );
1087
1151
  }
1088
1152
  const startObjectRegex = /(?:toMatchInlineSnapshot|toThrowErrorMatchingInlineSnapshot)\s*\(\s*(?:\/\*[\s\S]*\*\/\s*|\/\/.*(?:[\n\r\u2028\u2029]\s*|[\t\v\f \xA0\u1680\u2000-\u200A\u202F\u205F\u3000\uFEFF]))*\{/;
1089
1153
  function replaceObjectSnap(code, s, index, newSnap) {
1090
1154
  let _code = code.slice(index);
1091
1155
  const startMatch = startObjectRegex.exec(_code);
1092
- if (!startMatch)
1156
+ if (!startMatch) {
1093
1157
  return false;
1158
+ }
1094
1159
  _code = _code.slice(startMatch.index);
1095
1160
  let callEnd = getCallLastIndex(_code);
1096
- if (callEnd === null)
1161
+ if (callEnd === null) {
1097
1162
  return false;
1163
+ }
1098
1164
  callEnd += index + startMatch.index;
1099
1165
  const shapeStart = index + startMatch.index + startMatch[0].length;
1100
1166
  const shapeEnd = getObjectShapeEndIndex(code, shapeStart);
@@ -1111,10 +1177,11 @@ function getObjectShapeEndIndex(code, index) {
1111
1177
  let endBraces = 0;
1112
1178
  while (startBraces !== endBraces && index < code.length) {
1113
1179
  const s = code[index++];
1114
- if (s === "{")
1180
+ if (s === "{") {
1115
1181
  startBraces++;
1116
- else if (s === "}")
1182
+ } else if (s === "}") {
1117
1183
  endBraces++;
1184
+ }
1118
1185
  }
1119
1186
  return index;
1120
1187
  }
@@ -1126,19 +1193,45 @@ function prepareSnapString(snap, source, index) {
1126
1193
  const lines = snap.trim().replace(/\\/g, "\\\\").split(/\n/g);
1127
1194
  const isOneline = lines.length <= 1;
1128
1195
  const quote = "`";
1129
- if (isOneline)
1196
+ if (isOneline) {
1130
1197
  return `${quote}${lines.join("\n").replace(/`/g, "\\`").replace(/\$\{/g, "\\${")}${quote}`;
1198
+ }
1131
1199
  return `${quote}
1132
1200
  ${lines.map((i) => i ? indentNext + i : "").join("\n").replace(/`/g, "\\`").replace(/\$\{/g, "\\${")}
1133
1201
  ${indent}${quote}`;
1134
1202
  }
1203
+ const toMatchInlineName = "toMatchInlineSnapshot";
1204
+ const toThrowErrorMatchingInlineName = "toThrowErrorMatchingInlineSnapshot";
1205
+ function getCodeStartingAtIndex(code, index) {
1206
+ const indexInline = index - toMatchInlineName.length;
1207
+ if (code.slice(indexInline, index) === toMatchInlineName) {
1208
+ return {
1209
+ code: code.slice(indexInline),
1210
+ index: indexInline
1211
+ };
1212
+ }
1213
+ const indexThrowInline = index - toThrowErrorMatchingInlineName.length;
1214
+ if (code.slice(index - indexThrowInline, index) === toThrowErrorMatchingInlineName) {
1215
+ return {
1216
+ code: code.slice(index - indexThrowInline),
1217
+ index: index - indexThrowInline
1218
+ };
1219
+ }
1220
+ return {
1221
+ code: code.slice(index),
1222
+ index
1223
+ };
1224
+ }
1135
1225
  const startRegex = /(?:toMatchInlineSnapshot|toThrowErrorMatchingInlineSnapshot)\s*\(\s*(?:\/\*[\s\S]*\*\/\s*|\/\/.*(?:[\n\r\u2028\u2029]\s*|[\t\v\f \xA0\u1680\u2000-\u200A\u202F\u205F\u3000\uFEFF]))*[\w$]*(['"`)])/;
1136
- function replaceInlineSnap(code, s, index, newSnap) {
1137
- const codeStartingAtIndex = code.slice(index);
1226
+ function replaceInlineSnap(code, s, currentIndex, newSnap) {
1227
+ const { code: codeStartingAtIndex, index } = getCodeStartingAtIndex(code, currentIndex);
1138
1228
  const startMatch = startRegex.exec(codeStartingAtIndex);
1139
- const firstKeywordMatch = /toMatchInlineSnapshot|toThrowErrorMatchingInlineSnapshot/.exec(codeStartingAtIndex);
1140
- if (!startMatch || startMatch.index !== (firstKeywordMatch == null ? void 0 : firstKeywordMatch.index))
1229
+ const firstKeywordMatch = /toMatchInlineSnapshot|toThrowErrorMatchingInlineSnapshot/.exec(
1230
+ codeStartingAtIndex
1231
+ );
1232
+ if (!startMatch || startMatch.index !== (firstKeywordMatch == null ? void 0 : firstKeywordMatch.index)) {
1141
1233
  return replaceObjectSnap(code, s, index, newSnap);
1234
+ }
1142
1235
  const quote = startMatch[1];
1143
1236
  const startIndex = index + startMatch.index + startMatch[0].length;
1144
1237
  const snapString = prepareSnapString(newSnap, code, index);
@@ -1148,8 +1241,9 @@ function replaceInlineSnap(code, s, index, newSnap) {
1148
1241
  }
1149
1242
  const quoteEndRE = new RegExp(`(?:^|[^\\\\])${quote}`);
1150
1243
  const endMatch = quoteEndRE.exec(code.slice(startIndex));
1151
- if (!endMatch)
1244
+ if (!endMatch) {
1152
1245
  return false;
1246
+ }
1153
1247
  const endIndex = startIndex + endMatch.index + endMatch[0].length;
1154
1248
  s.overwrite(startIndex - 1, endIndex, snapString);
1155
1249
  return true;
@@ -1182,20 +1276,20 @@ function stripSnapshotIndentation(inlineSnapshot) {
1182
1276
  }
1183
1277
 
1184
1278
  async function saveRawSnapshots(environment, snapshots) {
1185
- await Promise.all(snapshots.map(async (snap) => {
1186
- if (!snap.readonly)
1187
- await environment.saveSnapshotFile(snap.file, snap.snapshot);
1188
- }));
1279
+ await Promise.all(
1280
+ snapshots.map(async (snap) => {
1281
+ if (!snap.readonly) {
1282
+ await environment.saveSnapshotFile(snap.file, snap.snapshot);
1283
+ }
1284
+ })
1285
+ );
1189
1286
  }
1190
1287
 
1191
1288
  class SnapshotState {
1192
1289
  constructor(testFilePath, snapshotPath, snapshotContent, options) {
1193
1290
  this.testFilePath = testFilePath;
1194
1291
  this.snapshotPath = snapshotPath;
1195
- const { data, dirty } = getSnapshotData(
1196
- snapshotContent,
1197
- options
1198
- );
1292
+ const { data, dirty } = getSnapshotData(snapshotContent, options);
1199
1293
  this._fileExists = snapshotContent != null;
1200
1294
  this._initialData = data;
1201
1295
  this._snapshotData = data;
@@ -1234,8 +1328,12 @@ class SnapshotState {
1234
1328
  unmatched;
1235
1329
  updated;
1236
1330
  static async create(testFilePath, options) {
1237
- const snapshotPath = await options.snapshotEnvironment.resolvePath(testFilePath);
1238
- const content = await options.snapshotEnvironment.readSnapshotFile(snapshotPath);
1331
+ const snapshotPath = await options.snapshotEnvironment.resolvePath(
1332
+ testFilePath
1333
+ );
1334
+ const content = await options.snapshotEnvironment.readSnapshotFile(
1335
+ snapshotPath
1336
+ );
1239
1337
  return new SnapshotState(testFilePath, snapshotPath, content, options);
1240
1338
  }
1241
1339
  get environment() {
@@ -1243,28 +1341,42 @@ class SnapshotState {
1243
1341
  }
1244
1342
  markSnapshotsAsCheckedForTest(testName) {
1245
1343
  this._uncheckedKeys.forEach((uncheckedKey) => {
1246
- if (keyToTestName(uncheckedKey) === testName)
1344
+ if (keyToTestName(uncheckedKey) === testName) {
1247
1345
  this._uncheckedKeys.delete(uncheckedKey);
1346
+ }
1248
1347
  });
1249
1348
  }
1250
1349
  _inferInlineSnapshotStack(stacks) {
1251
- const promiseIndex = stacks.findIndex((i) => i.method.match(/__VITEST_(RESOLVES|REJECTS)__/));
1252
- if (promiseIndex !== -1)
1350
+ const promiseIndex = stacks.findIndex(
1351
+ (i) => i.method.match(/__VITEST_(RESOLVES|REJECTS)__/)
1352
+ );
1353
+ if (promiseIndex !== -1) {
1253
1354
  return stacks[promiseIndex + 3];
1254
- const stackIndex = stacks.findIndex((i) => i.method.includes("__INLINE_SNAPSHOT__"));
1355
+ }
1356
+ const stackIndex = stacks.findIndex(
1357
+ (i) => i.method.includes("__INLINE_SNAPSHOT__")
1358
+ );
1255
1359
  return stackIndex !== -1 ? stacks[stackIndex + 2] : null;
1256
1360
  }
1257
1361
  _addSnapshot(key, receivedSerialized, options) {
1362
+ var _a, _b;
1258
1363
  this._dirty = true;
1259
1364
  if (options.isInline) {
1260
- const stacks = parseErrorStacktrace(options.error || new Error("snapshot"), { ignoreStackEntries: [] });
1261
- const stack = this._inferInlineSnapshotStack(stacks);
1262
- if (!stack) {
1365
+ const error = options.error || new Error("snapshot");
1366
+ const stacks = parseErrorStacktrace(
1367
+ error,
1368
+ { ignoreStackEntries: [] }
1369
+ );
1370
+ const _stack = this._inferInlineSnapshotStack(stacks);
1371
+ if (!_stack) {
1263
1372
  throw new Error(
1264
1373
  `@vitest/snapshot: Couldn't infer stack frame for inline snapshot.
1265
- ${JSON.stringify(stacks)}`
1374
+ ${JSON.stringify(
1375
+ stacks
1376
+ )}`
1266
1377
  );
1267
1378
  }
1379
+ const stack = ((_b = (_a = this.environment).processStackTrace) == null ? void 0 : _b.call(_a, _stack)) || _stack;
1268
1380
  stack.column--;
1269
1381
  this._inlineSnapshots.push({
1270
1382
  snapshot: receivedSerialized,
@@ -1299,13 +1411,19 @@ ${JSON.stringify(stacks)}`
1299
1411
  };
1300
1412
  if ((this._dirty || this._uncheckedKeys.size) && !isEmpty) {
1301
1413
  if (hasExternalSnapshots) {
1302
- await saveSnapshotFile(this._environment, this._snapshotData, this.snapshotPath);
1414
+ await saveSnapshotFile(
1415
+ this._environment,
1416
+ this._snapshotData,
1417
+ this.snapshotPath
1418
+ );
1303
1419
  this._fileExists = true;
1304
1420
  }
1305
- if (hasInlineSnapshots)
1421
+ if (hasInlineSnapshots) {
1306
1422
  await saveInlineSnapshots(this._environment, this._inlineSnapshots);
1307
- if (hasRawSnapshots)
1423
+ }
1424
+ if (hasRawSnapshots) {
1308
1425
  await saveRawSnapshots(this._environment, this._rawSnapshots);
1426
+ }
1309
1427
  status.saved = true;
1310
1428
  } else if (!hasExternalSnapshots && this._fileExists) {
1311
1429
  if (this._updateSnapshot === "all") {
@@ -1340,16 +1458,20 @@ ${JSON.stringify(stacks)}`
1340
1458
  }) {
1341
1459
  this._counters.set(testName, (this._counters.get(testName) || 0) + 1);
1342
1460
  const count = Number(this._counters.get(testName));
1343
- if (!key)
1461
+ if (!key) {
1344
1462
  key = testNameToKey(testName, count);
1345
- if (!(isInline && this._snapshotData[key] !== void 0))
1463
+ }
1464
+ if (!(isInline && this._snapshotData[key] !== void 0)) {
1346
1465
  this._uncheckedKeys.delete(key);
1466
+ }
1347
1467
  let receivedSerialized = rawSnapshot && typeof received === "string" ? received : serialize(received, void 0, this._snapshotFormat);
1348
- if (!rawSnapshot)
1468
+ if (!rawSnapshot) {
1349
1469
  receivedSerialized = addExtraLineBreaks(receivedSerialized);
1470
+ }
1350
1471
  if (rawSnapshot) {
1351
- if (rawSnapshot.content && rawSnapshot.content.match(/\r\n/) && !receivedSerialized.match(/\r\n/))
1472
+ if (rawSnapshot.content && rawSnapshot.content.match(/\r\n/) && !receivedSerialized.match(/\r\n/)) {
1352
1473
  rawSnapshot.content = normalizeNewlines(rawSnapshot.content);
1474
+ }
1353
1475
  }
1354
1476
  const expected = isInline ? inlineSnapshot : rawSnapshot ? rawSnapshot.content : this._snapshotData[key];
1355
1477
  const expectedTrimmed = prepareExpected(expected);
@@ -1362,16 +1484,25 @@ ${JSON.stringify(stacks)}`
1362
1484
  if (hasSnapshot && this._updateSnapshot === "all" || (!hasSnapshot || !snapshotIsPersisted) && (this._updateSnapshot === "new" || this._updateSnapshot === "all")) {
1363
1485
  if (this._updateSnapshot === "all") {
1364
1486
  if (!pass) {
1365
- if (hasSnapshot)
1487
+ if (hasSnapshot) {
1366
1488
  this.updated++;
1367
- else
1489
+ } else {
1368
1490
  this.added++;
1369
- this._addSnapshot(key, receivedSerialized, { error, isInline, rawSnapshot });
1491
+ }
1492
+ this._addSnapshot(key, receivedSerialized, {
1493
+ error,
1494
+ isInline,
1495
+ rawSnapshot
1496
+ });
1370
1497
  } else {
1371
1498
  this.matched++;
1372
1499
  }
1373
1500
  } else {
1374
- this._addSnapshot(key, receivedSerialized, { error, isInline, rawSnapshot });
1501
+ this._addSnapshot(key, receivedSerialized, {
1502
+ error,
1503
+ isInline,
1504
+ rawSnapshot
1505
+ });
1375
1506
  this.added++;
1376
1507
  }
1377
1508
  return {
@@ -1416,8 +1547,9 @@ ${JSON.stringify(stacks)}`
1416
1547
  };
1417
1548
  const uncheckedCount = this.getUncheckedCount();
1418
1549
  const uncheckedKeys = this.getUncheckedKeys();
1419
- if (uncheckedCount)
1550
+ if (uncheckedCount) {
1420
1551
  this.removeUncheckedKeys();
1552
+ }
1421
1553
  const status = await this.save();
1422
1554
  snapshot.fileDeleted = status.deleted;
1423
1555
  snapshot.added = this.added;
@@ -1464,10 +1596,7 @@ class SnapshotClient {
1464
1596
  if (!this.getSnapshotState(filepath)) {
1465
1597
  this.snapshotStateMap.set(
1466
1598
  filepath,
1467
- await SnapshotState.create(
1468
- filepath,
1469
- options
1470
- )
1599
+ await SnapshotState.create(filepath, options)
1471
1600
  );
1472
1601
  }
1473
1602
  this.snapshotState = this.getSnapshotState(filepath);
@@ -1498,26 +1627,33 @@ class SnapshotClient {
1498
1627
  rawSnapshot
1499
1628
  } = options;
1500
1629
  let { received } = options;
1501
- if (!filepath)
1630
+ if (!filepath) {
1502
1631
  throw new Error("Snapshot cannot be used outside of test");
1632
+ }
1503
1633
  if (typeof properties === "object") {
1504
- if (typeof received !== "object" || !received)
1505
- throw new Error("Received value must be an object when the matcher has properties");
1634
+ if (typeof received !== "object" || !received) {
1635
+ throw new Error(
1636
+ "Received value must be an object when the matcher has properties"
1637
+ );
1638
+ }
1506
1639
  try {
1507
1640
  const pass2 = ((_b = (_a = this.options).isEqual) == null ? void 0 : _b.call(_a, received, properties)) ?? false;
1508
- if (!pass2)
1509
- throw createMismatchError("Snapshot properties mismatched", (_c = this.snapshotState) == null ? void 0 : _c.expand, received, properties);
1510
- else
1641
+ if (!pass2) {
1642
+ throw createMismatchError(
1643
+ "Snapshot properties mismatched",
1644
+ (_c = this.snapshotState) == null ? void 0 : _c.expand,
1645
+ received,
1646
+ properties
1647
+ );
1648
+ } else {
1511
1649
  received = deepMergeSnapshot(received, properties);
1650
+ }
1512
1651
  } catch (err) {
1513
1652
  err.message = errorMessage || "Snapshot mismatched";
1514
1653
  throw err;
1515
1654
  }
1516
1655
  }
1517
- const testName = [
1518
- name,
1519
- ...message ? [message] : []
1520
- ].join(" > ");
1656
+ const testName = [name, ...message ? [message] : []].join(" > ");
1521
1657
  const snapshotState = this.getSnapshotState(filepath);
1522
1658
  const { actual, expected, key, pass } = snapshotState.match({
1523
1659
  testName,
@@ -1527,29 +1663,38 @@ class SnapshotClient {
1527
1663
  inlineSnapshot,
1528
1664
  rawSnapshot
1529
1665
  });
1530
- if (!pass)
1531
- throw createMismatchError(`Snapshot \`${key || "unknown"}\` mismatched`, (_d = this.snapshotState) == null ? void 0 : _d.expand, actual == null ? void 0 : actual.trim(), expected == null ? void 0 : expected.trim());
1666
+ if (!pass) {
1667
+ throw createMismatchError(
1668
+ `Snapshot \`${key || "unknown"}\` mismatched`,
1669
+ (_d = this.snapshotState) == null ? void 0 : _d.expand,
1670
+ actual == null ? void 0 : actual.trim(),
1671
+ expected == null ? void 0 : expected.trim()
1672
+ );
1673
+ }
1532
1674
  }
1533
1675
  async assertRaw(options) {
1534
- if (!options.rawSnapshot)
1676
+ if (!options.rawSnapshot) {
1535
1677
  throw new Error("Raw snapshot is required");
1536
- const {
1537
- filepath = this.filepath,
1538
- rawSnapshot
1539
- } = options;
1678
+ }
1679
+ const { filepath = this.filepath, rawSnapshot } = options;
1540
1680
  if (rawSnapshot.content == null) {
1541
- if (!filepath)
1681
+ if (!filepath) {
1542
1682
  throw new Error("Snapshot cannot be used outside of test");
1683
+ }
1543
1684
  const snapshotState = this.getSnapshotState(filepath);
1544
1685
  options.filepath || (options.filepath = filepath);
1545
- rawSnapshot.file = await snapshotState.environment.resolveRawPath(filepath, rawSnapshot.file);
1546
- rawSnapshot.content = await snapshotState.environment.readSnapshotFile(rawSnapshot.file) || void 0;
1686
+ rawSnapshot.file = await snapshotState.environment.resolveRawPath(
1687
+ filepath,
1688
+ rawSnapshot.file
1689
+ );
1690
+ rawSnapshot.content = await snapshotState.environment.readSnapshotFile(rawSnapshot.file) ?? void 0;
1547
1691
  }
1548
1692
  return this.assert(options);
1549
1693
  }
1550
1694
  async finishCurrentRun() {
1551
- if (!this.snapshotState)
1695
+ if (!this.snapshotState) {
1552
1696
  return null;
1697
+ }
1553
1698
  const result = await this.snapshotState.pack();
1554
1699
  this.snapshotState = void 0;
1555
1700
  return result;
package/dist/manager.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { S as SnapshotStateOptions, f as SnapshotSummary, b as SnapshotResult } from './index-CTmsp3V1.js';
1
+ import { S as SnapshotStateOptions, f as SnapshotSummary, b as SnapshotResult } from './index-reKGmLsM.js';
2
2
  import 'pretty-format';
3
- import './environment-BaTWxlGj.js';
3
+ import './environment-Ddx0EDtY.js';
4
4
 
5
5
  declare class SnapshotManager {
6
6
  options: Omit<SnapshotStateOptions, 'snapshotEnvironment'>;
package/dist/manager.js CHANGED
@@ -16,10 +16,7 @@ class SnapshotManager {
16
16
  resolvePath(testPath) {
17
17
  const resolver = this.options.resolveSnapshotPath || (() => {
18
18
  return join(
19
- join(
20
- dirname(testPath),
21
- "__snapshots__"
22
- ),
19
+ join(dirname(testPath), "__snapshots__"),
23
20
  `${basename(testPath)}${this.extension}`
24
21
  );
25
22
  });
@@ -50,14 +47,18 @@ function emptySummary(options) {
50
47
  return summary;
51
48
  }
52
49
  function addSnapshotResult(summary, result) {
53
- if (result.added)
50
+ if (result.added) {
54
51
  summary.filesAdded++;
55
- if (result.fileDeleted)
52
+ }
53
+ if (result.fileDeleted) {
56
54
  summary.filesRemoved++;
57
- if (result.unmatched)
55
+ }
56
+ if (result.unmatched) {
58
57
  summary.filesUnmatched++;
59
- if (result.updated)
58
+ }
59
+ if (result.updated) {
60
60
  summary.filesUpdated++;
61
+ }
61
62
  summary.added += result.added;
62
63
  summary.matched += result.matched;
63
64
  summary.unchecked += result.unchecked;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@vitest/snapshot",
3
3
  "type": "module",
4
- "version": "2.0.0-beta.8",
4
+ "version": "2.0.0",
5
5
  "description": "Vitest snapshot manager",
6
6
  "license": "MIT",
7
7
  "funding": "https://opencollective.com/vitest",
@@ -45,7 +45,7 @@
45
45
  "devDependencies": {
46
46
  "@types/natural-compare": "^1.4.3",
47
47
  "natural-compare": "^1.4.0",
48
- "@vitest/utils": "2.0.0-beta.8"
48
+ "@vitest/utils": "2.0.0"
49
49
  },
50
50
  "scripts": {
51
51
  "build": "rimraf dist && rollup -c",