@cronn/lib-file-snapshots 0.12.0 → 0.14.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 CHANGED
@@ -30,6 +30,12 @@ interface JsonSerializerOptions {
30
30
  * Custom normalizers to apply before serialization
31
31
  */
32
32
  normalizers?: Array<JsonNormalizer>;
33
+ /**
34
+ * Indentation size in spaces
35
+ *
36
+ * @default 2
37
+ */
38
+ indentSize?: number;
33
39
  }
34
40
  type JsonNormalizer = (value: unknown, context: JsonNormalizerContext) => unknown;
35
41
  interface JsonNormalizerContext {
@@ -40,6 +46,7 @@ declare class JsonSerializer implements SnapshotSerializer {
40
46
  readonly fileExtension = "json";
41
47
  private readonly includeUndefinedObjectProperties;
42
48
  private readonly normalizers;
49
+ private readonly indentSize;
43
50
  constructor(options?: JsonSerializerOptions);
44
51
  canSerialize(_value: unknown): boolean;
45
52
  serialize(value: unknown): string;
@@ -85,35 +92,16 @@ interface ValidationFileMatcherConfig {
85
92
  */
86
93
  outputDir?: string;
87
94
  /**
88
- * The full path to the current test file
95
+ * The full path to the snapshot file
89
96
  *
90
- * @example "src/tests/feature.test.ts"
97
+ * @example "src/tests/feature/test/when_x_then_y"
91
98
  */
92
- testPath: string;
93
- /**
94
- * The full path of titles describing the current test, including nested blocks
95
- *
96
- * @example ["test A", "when x, then y"]
97
- */
98
- titlePath: Array<string>;
99
- /**
100
- * Unique name of the file snapshot
101
- *
102
- * Used to distinguish multiple file snapshots within the same `test`.
103
- */
104
- name?: string;
105
- /**
106
- * The naming strategy to use for storing the file snapshot
107
- *
108
- * @default "file"
109
- */
110
- namingStrategy?: SnapshotNamingStrategy;
99
+ filePath: string;
111
100
  /**
112
101
  * The serializer to use for the snapshot
113
102
  */
114
103
  serializer: SnapshotSerializer;
115
104
  }
116
- type SnapshotNamingStrategy = "file" | "fileSuffix";
117
105
  interface ValidationFileMatcherResult {
118
106
  actual: string;
119
107
  expected: string;
@@ -122,6 +110,12 @@ interface ValidationFileMatcherResult {
122
110
  message: () => string;
123
111
  writeFileSnapshots: () => void;
124
112
  }
113
+ type FilePathResolver = (params: FilePathResolverParams) => string;
114
+ interface FilePathResolverParams {
115
+ testPath: string;
116
+ titlePath: Array<string>;
117
+ name?: string;
118
+ }
125
119
 
126
120
  declare class ValidationFileMatcher {
127
121
  private readonly serializer;
@@ -131,15 +125,19 @@ declare class ValidationFileMatcher {
131
125
  get isValidationFileMissing(): boolean;
132
126
  matchFileSnapshot(actual: unknown): ValidationFileMatcherResult;
133
127
  private buildFilePaths;
134
- private applyNamingStrategy;
135
128
  private readValidationFile;
136
129
  private createMatcherResult;
137
130
  private writeFileSnapshots;
138
131
  }
139
132
 
133
+ declare function resolveNameAsFile(params: FilePathResolverParams): string;
134
+ declare function resolveNameAsFileSuffix(params: FilePathResolverParams): string;
135
+
136
+ declare function normalizeFileName(testName: string): string;
137
+
140
138
  declare function isString(value: unknown): value is string;
141
139
  declare function isArray(value: unknown): value is Array<unknown>;
142
140
  type PlainObject = Record<PropertyKey, unknown>;
143
141
  declare function isPlainObject(value: unknown): value is PlainObject;
144
142
 
145
- export { type JsonNormalizer, type JsonNormalizerContext, JsonSerializer, type PlainObject, type SnapshotNamingStrategy, type SnapshotSerializer, type TextNormalizer, TextSerializer, ValidationFileMatcher, type ValidationFileMatcherResult, isArray, isPlainObject, isString };
143
+ export { type FilePathResolver, type FilePathResolverParams, type JsonNormalizer, type JsonNormalizerContext, JsonSerializer, type PlainObject, type SnapshotSerializer, type TextNormalizer, TextSerializer, ValidationFileMatcher, type ValidationFileMatcherResult, isArray, isPlainObject, isString, normalizeFileName, resolveNameAsFile, resolveNameAsFileSuffix };
package/dist/index.js CHANGED
@@ -6,15 +6,15 @@ var EMOJI_REGEXP = /(?!(\*|#|\d))[\p{Extended_Pictographic}\p{Emoji_Component}]|
6
6
  function normalizeFileName(testName) {
7
7
  return testName.replaceAll(EMOJI_REGEXP, "").replaceAll(/[+*%~<>?!$#'"`|\\/()[\]{}]/g, "").replaceAll(/[\s.:,;]+/g, "_").replaceAll(/_{2,}/g, "_");
8
8
  }
9
- function readSnapshotFile(path3) {
10
- return fs.readFileSync(path3, { encoding: "utf8" });
9
+ function readSnapshotFile(path4) {
10
+ return fs.readFileSync(path4, { encoding: "utf8" });
11
11
  }
12
12
  function writeSnapshotFile(file, data) {
13
13
  mkdirRecursive(path.dirname(file));
14
14
  fs.writeFileSync(file, data, { encoding: "utf8" });
15
15
  }
16
- function mkdirRecursive(path3) {
17
- fs.mkdirSync(path3, { recursive: true });
16
+ function mkdirRecursive(path4) {
17
+ fs.mkdirSync(path4, { recursive: true });
18
18
  }
19
19
  function addTrailingNewLine(data) {
20
20
  return `${data}${NEW_LINE_SEPARATOR}`;
@@ -41,21 +41,33 @@ function isPlainObject(value) {
41
41
  return proto === null || proto === Object.prototype;
42
42
  }
43
43
 
44
+ // src/utils/validators.ts
45
+ function isPositiveInteger(value) {
46
+ return Number.isInteger(value) && value > 0;
47
+ }
48
+
44
49
  // src/serializers/json-serializer.ts
45
50
  var JsonSerializer = class {
46
51
  fileExtension = "json";
47
52
  includeUndefinedObjectProperties;
48
53
  normalizers;
54
+ indentSize;
49
55
  constructor(options = {}) {
56
+ if (options.indentSize !== void 0 && !isPositiveInteger(options.indentSize)) {
57
+ throw new Error(
58
+ "Invalid option indentSize: value must be a positive integer."
59
+ );
60
+ }
50
61
  this.includeUndefinedObjectProperties = options.includeUndefinedObjectProperties ?? false;
51
62
  this.normalizers = options.normalizers ?? [];
63
+ this.indentSize = options.indentSize ?? 2;
52
64
  }
53
65
  canSerialize(_value) {
54
66
  return true;
55
67
  }
56
68
  serialize(value) {
57
69
  const jsonValue = this.normalizeValueRecursive(value);
58
- const jsonString = JSON.stringify(jsonValue, void 0, 2);
70
+ const jsonString = JSON.stringify(jsonValue, void 0, this.indentSize);
59
71
  return addTrailingNewLine(jsonString);
60
72
  }
61
73
  normalizeValueRecursive(value, context) {
@@ -262,32 +274,12 @@ var ValidationFileMatcher = class {
262
274
  buildFilePaths(config) {
263
275
  const validationDir = config.validationDir ?? "data/test/validation";
264
276
  const outputDir = config.outputDir ?? "data/test/output";
265
- const normalizedTitlePath = config.titlePath.map(normalizeFileName);
266
- const relativeFilePath = path2.join(config.testPath, ...normalizedTitlePath);
267
- const relativeFilePathWithName = this.applyNamingStrategy(
268
- relativeFilePath,
269
- config.name,
270
- config.namingStrategy
271
- );
272
- const relativeFilePathWithExtension = `${relativeFilePathWithName}.${this.serializer.fileExtension}`;
277
+ const filePathWithExtenion = `${config.filePath}.${config.serializer.fileExtension}`;
273
278
  return {
274
- outputFilePath: path2.join(outputDir, relativeFilePathWithExtension),
275
- validationFilePath: path2.join(
276
- validationDir,
277
- relativeFilePathWithExtension
278
- )
279
+ outputFilePath: path2.join(outputDir, filePathWithExtenion),
280
+ validationFilePath: path2.join(validationDir, filePathWithExtenion)
279
281
  };
280
282
  }
281
- applyNamingStrategy(filePath, snapshotName, namingStrategy = "file") {
282
- if (snapshotName === void 0) {
283
- return filePath;
284
- }
285
- const normalizedSnapshotName = normalizeFileName(snapshotName);
286
- if (namingStrategy === "fileSuffix") {
287
- return `${filePath}_${normalizedSnapshotName}`;
288
- }
289
- return path2.join(filePath, normalizedSnapshotName);
290
- }
291
283
  readValidationFile() {
292
284
  const { validationFilePath } = this.filePaths;
293
285
  if (!fs2.existsSync(validationFilePath)) {
@@ -317,11 +309,43 @@ does not match validation file '${validationFilePath}'`,
317
309
  }
318
310
  }
319
311
  };
312
+
313
+ // src/matcher/file-path-resolver.ts
314
+ import path3 from "path";
315
+ function resolveNameAsFile(params) {
316
+ return resolveFilePath(
317
+ params,
318
+ ({ basePath, normalizedName }) => path3.join(basePath, normalizedName)
319
+ );
320
+ }
321
+ function resolveNameAsFileSuffix(params) {
322
+ return resolveFilePath(
323
+ params,
324
+ ({ basePath, normalizedName }) => `${basePath}_${normalizedName}`
325
+ );
326
+ }
327
+ function resolveBasePath(params) {
328
+ const { testPath, titlePath } = params;
329
+ const normalizedTitlePath = titlePath.map(normalizeFileName);
330
+ return path3.join(testPath, ...normalizedTitlePath);
331
+ }
332
+ function resolveFilePath(params, resolveNamedFilePath) {
333
+ const { name, ...baseParams } = params;
334
+ const basePath = resolveBasePath(baseParams);
335
+ if (name === void 0) {
336
+ return basePath;
337
+ }
338
+ const normalizedName = normalizeFileName(name);
339
+ return resolveNamedFilePath({ basePath, normalizedName });
340
+ }
320
341
  export {
321
342
  JsonSerializer,
322
343
  TextSerializer,
323
344
  ValidationFileMatcher,
324
345
  isArray,
325
346
  isPlainObject,
326
- isString
347
+ isString,
348
+ normalizeFileName,
349
+ resolveNameAsFile,
350
+ resolveNameAsFileSuffix
327
351
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cronn/lib-file-snapshots",
3
- "version": "0.12.0",
3
+ "version": "0.14.0",
4
4
  "description": "The library agnostic core for testing file snapshots",
5
5
  "keywords": [
6
6
  "file snapshots"
@@ -33,15 +33,15 @@
33
33
  ],
34
34
  "devDependencies": {
35
35
  "@trivago/prettier-plugin-sort-imports": "5.2.2",
36
- "@types/node": "22.16.5",
36
+ "@types/node": "22.18.0",
37
37
  "@vitest/coverage-istanbul": "3.2.4",
38
- "eslint": "9.32.0",
38
+ "eslint": "9.34.0",
39
39
  "eslint-config-prettier": "10.1.8",
40
- "eslint-plugin-unused-imports": "4.1.4",
40
+ "eslint-plugin-unused-imports": "4.2.0",
41
41
  "prettier": "3.6.2",
42
42
  "tsup": "8.5.0",
43
- "typescript": "5.8.3",
44
- "typescript-eslint": "8.38.0",
43
+ "typescript": "5.9.2",
44
+ "typescript-eslint": "8.42.0",
45
45
  "vitest": "3.2.4",
46
46
  "@cronn/shared-configs": "0.0.0"
47
47
  },