@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 +22 -24
- package/dist/index.js +53 -29
- package/package.json +6 -6
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
|
|
95
|
+
* The full path to the snapshot file
|
|
89
96
|
*
|
|
90
|
-
* @example "src/tests/feature
|
|
97
|
+
* @example "src/tests/feature/test/when_x_then_y"
|
|
91
98
|
*/
|
|
92
|
-
|
|
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
|
|
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(
|
|
10
|
-
return fs.readFileSync(
|
|
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(
|
|
17
|
-
fs.mkdirSync(
|
|
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,
|
|
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
|
|
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,
|
|
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.
|
|
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.
|
|
36
|
+
"@types/node": "22.18.0",
|
|
37
37
|
"@vitest/coverage-istanbul": "3.2.4",
|
|
38
|
-
"eslint": "9.
|
|
38
|
+
"eslint": "9.34.0",
|
|
39
39
|
"eslint-config-prettier": "10.1.8",
|
|
40
|
-
"eslint-plugin-unused-imports": "4.
|
|
40
|
+
"eslint-plugin-unused-imports": "4.2.0",
|
|
41
41
|
"prettier": "3.6.2",
|
|
42
42
|
"tsup": "8.5.0",
|
|
43
|
-
"typescript": "5.
|
|
44
|
-
"typescript-eslint": "8.
|
|
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
|
},
|