@cronn/lib-file-snapshots 1.0.0 → 1.1.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.mts +52 -19
- package/dist/index.mjs +54 -17
- package/package.json +16 -12
package/dist/index.d.mts
CHANGED
|
@@ -1,15 +1,33 @@
|
|
|
1
|
-
//#region src/
|
|
2
|
-
interface
|
|
1
|
+
//#region src/models/table.d.ts
|
|
2
|
+
interface TableData<TRow extends TableRow = TableRow> {
|
|
3
|
+
columns: Array<string>;
|
|
4
|
+
rows: Array<TRow>;
|
|
5
|
+
}
|
|
6
|
+
type TableRow = Array<TableCell>;
|
|
7
|
+
type TableCell = string | number | boolean | null | undefined;
|
|
8
|
+
type TableRowRecord = Record<string, TableCell>;
|
|
9
|
+
declare class Table<TRow extends TableRow = TableRow> implements TableData<TRow> {
|
|
10
|
+
readonly columns: Array<string>;
|
|
11
|
+
readonly rows: Array<TRow>;
|
|
12
|
+
private constructor();
|
|
3
13
|
/**
|
|
4
|
-
*
|
|
14
|
+
* Defines a table
|
|
5
15
|
*/
|
|
6
|
-
|
|
16
|
+
static define<TRow extends TableRow>(data: TableData<TRow>): Table<TRow>;
|
|
7
17
|
/**
|
|
8
|
-
*
|
|
18
|
+
* Defines a table from record-based rows
|
|
9
19
|
*
|
|
10
|
-
*
|
|
20
|
+
* Columns are derived from keys, rows from values.
|
|
11
21
|
*/
|
|
12
|
-
|
|
22
|
+
static fromRecords<TRow extends TableRowRecord>(rows: Array<TRow>): Table;
|
|
23
|
+
}
|
|
24
|
+
//#endregion
|
|
25
|
+
//#region src/types/serializer.d.ts
|
|
26
|
+
interface SnapshotSerializer<TValue> {
|
|
27
|
+
/**
|
|
28
|
+
* The file extension associated with the serialized value
|
|
29
|
+
*/
|
|
30
|
+
readonly fileExtension: string;
|
|
13
31
|
/**
|
|
14
32
|
* Serializes value
|
|
15
33
|
*
|
|
@@ -17,7 +35,7 @@ interface SnapshotSerializer {
|
|
|
17
35
|
* @return {string} The serialized value
|
|
18
36
|
* @throws {Error} Will throw an error if value cannot be serialized.
|
|
19
37
|
*/
|
|
20
|
-
serialize(value:
|
|
38
|
+
serialize(value: TValue): string;
|
|
21
39
|
}
|
|
22
40
|
//#endregion
|
|
23
41
|
//#region src/serializers/json-serializer.d.ts
|
|
@@ -44,13 +62,12 @@ interface JsonNormalizerContext {
|
|
|
44
62
|
key?: string;
|
|
45
63
|
index?: number;
|
|
46
64
|
}
|
|
47
|
-
declare class JsonSerializer implements SnapshotSerializer {
|
|
65
|
+
declare class JsonSerializer implements SnapshotSerializer<unknown> {
|
|
48
66
|
readonly fileExtension = "json";
|
|
49
67
|
private readonly includeUndefinedObjectProperties;
|
|
50
68
|
private readonly normalizers;
|
|
51
69
|
private readonly indentSize;
|
|
52
70
|
constructor(options?: JsonSerializerOptions);
|
|
53
|
-
canSerialize(_value: unknown): boolean;
|
|
54
71
|
serialize(value: unknown): string;
|
|
55
72
|
private normalizeValueRecursive;
|
|
56
73
|
private normalizeNumber;
|
|
@@ -64,6 +81,23 @@ declare class JsonSerializer implements SnapshotSerializer {
|
|
|
64
81
|
private applyCustomNormalizers;
|
|
65
82
|
}
|
|
66
83
|
//#endregion
|
|
84
|
+
//#region src/serializers/markdown-table-serializer.d.ts
|
|
85
|
+
interface MarkdownTableSerializerOptions {
|
|
86
|
+
/**
|
|
87
|
+
* Custom normalizers to apply before serialization
|
|
88
|
+
*/
|
|
89
|
+
normalizers?: Array<MarkdownTableNormalizer>;
|
|
90
|
+
}
|
|
91
|
+
type MarkdownTableNormalizer = (value: TableCell) => TableCell;
|
|
92
|
+
declare class MarkdownTableSerializer implements SnapshotSerializer<TableData> {
|
|
93
|
+
readonly fileExtension = "md";
|
|
94
|
+
private readonly normalizers;
|
|
95
|
+
constructor(options?: MarkdownTableSerializerOptions);
|
|
96
|
+
serialize(value: TableData): string;
|
|
97
|
+
private serializeCellValue;
|
|
98
|
+
private mapCellValueToString;
|
|
99
|
+
}
|
|
100
|
+
//#endregion
|
|
67
101
|
//#region src/serializers/text-serializer.d.ts
|
|
68
102
|
interface TextSerializerOptions {
|
|
69
103
|
/**
|
|
@@ -78,17 +112,16 @@ interface TextSerializerOptions {
|
|
|
78
112
|
fileExtension?: string;
|
|
79
113
|
}
|
|
80
114
|
type TextNormalizer = (value: string) => string;
|
|
81
|
-
declare class TextSerializer implements SnapshotSerializer {
|
|
115
|
+
declare class TextSerializer implements SnapshotSerializer<string> {
|
|
82
116
|
readonly fileExtension: string;
|
|
83
117
|
private readonly normalizers;
|
|
84
118
|
constructor(options?: TextSerializerOptions);
|
|
85
|
-
|
|
86
|
-
serialize(value: unknown): string;
|
|
119
|
+
serialize(value: string): string;
|
|
87
120
|
private normalizeValue;
|
|
88
121
|
}
|
|
89
122
|
//#endregion
|
|
90
123
|
//#region src/types/matcher.d.ts
|
|
91
|
-
interface ValidationFileMatcherConfig {
|
|
124
|
+
interface ValidationFileMatcherConfig<TValue> {
|
|
92
125
|
/**
|
|
93
126
|
* Directory in which golden masters are stored
|
|
94
127
|
*/
|
|
@@ -106,7 +139,7 @@ interface ValidationFileMatcherConfig {
|
|
|
106
139
|
/**
|
|
107
140
|
* The serializer to use for the snapshot
|
|
108
141
|
*/
|
|
109
|
-
serializer: SnapshotSerializer
|
|
142
|
+
serializer: SnapshotSerializer<TValue>;
|
|
110
143
|
/**
|
|
111
144
|
* Whether to update golden masters with the actual result.
|
|
112
145
|
*
|
|
@@ -131,15 +164,15 @@ interface FilePathResolverParams {
|
|
|
131
164
|
}
|
|
132
165
|
//#endregion
|
|
133
166
|
//#region src/matcher/validation-file-matcher.d.ts
|
|
134
|
-
declare class ValidationFileMatcher {
|
|
167
|
+
declare class ValidationFileMatcher<TValue> {
|
|
135
168
|
private readonly updateSnapshots;
|
|
136
169
|
private readonly serializer;
|
|
137
170
|
private readonly filePaths;
|
|
138
171
|
private validationFile;
|
|
139
|
-
constructor(config: ValidationFileMatcherConfig);
|
|
172
|
+
constructor(config: ValidationFileMatcherConfig<TValue>);
|
|
140
173
|
get isValidationFileMissing(): boolean;
|
|
141
174
|
get isUpdate(): boolean;
|
|
142
|
-
matchFileSnapshot(actual:
|
|
175
|
+
matchFileSnapshot(actual: TValue): ValidationFileMatcherResult;
|
|
143
176
|
private buildFilePaths;
|
|
144
177
|
private readValidationFile;
|
|
145
178
|
private createMatcherResult;
|
|
@@ -160,4 +193,4 @@ declare function isArray(value: unknown): value is Array<unknown>;
|
|
|
160
193
|
type PlainObject = Record<PropertyKey, unknown>;
|
|
161
194
|
declare function isPlainObject(value: unknown): value is PlainObject;
|
|
162
195
|
//#endregion
|
|
163
|
-
export { type FilePathResolver, type FilePathResolverParams, type JsonNormalizer, type JsonNormalizerContext, JsonSerializer, type PlainObject, type SnapshotSerializer, type TextNormalizer, TextSerializer, type UpdateSnapshotsType, ValidationFileMatcher, type ValidationFileMatcherResult, isArray, isPlainObject, isString, normalizeFileName, resolveNameAsFile, resolveNameAsFileSuffix };
|
|
196
|
+
export { type FilePathResolver, type FilePathResolverParams, type JsonNormalizer, type JsonNormalizerContext, JsonSerializer, type MarkdownTableNormalizer, MarkdownTableSerializer, type PlainObject, type SnapshotSerializer, Table, type TableCell, type TableData, type TableRow, type TextNormalizer, TextSerializer, type UpdateSnapshotsType, ValidationFileMatcher, type ValidationFileMatcherResult, isArray, isPlainObject, isString, normalizeFileName, resolveNameAsFile, resolveNameAsFileSuffix };
|
package/dist/index.mjs
CHANGED
|
@@ -3,7 +3,35 @@ import fs from "node:fs";
|
|
|
3
3
|
import os from "node:os";
|
|
4
4
|
import * as path$1 from "node:path";
|
|
5
5
|
import path from "node:path";
|
|
6
|
-
|
|
6
|
+
import { markdownTable } from "markdown-table";
|
|
7
|
+
//#region src/models/table.ts
|
|
8
|
+
var Table = class Table {
|
|
9
|
+
columns;
|
|
10
|
+
rows;
|
|
11
|
+
constructor(data) {
|
|
12
|
+
this.columns = data.columns;
|
|
13
|
+
this.rows = data.rows;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Defines a table
|
|
17
|
+
*/
|
|
18
|
+
static define(data) {
|
|
19
|
+
return new Table(data);
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Defines a table from record-based rows
|
|
23
|
+
*
|
|
24
|
+
* Columns are derived from keys, rows from values.
|
|
25
|
+
*/
|
|
26
|
+
static fromRecords(rows) {
|
|
27
|
+
const [firstRow] = rows;
|
|
28
|
+
return new Table({
|
|
29
|
+
columns: firstRow !== void 0 ? Object.keys(firstRow) : [],
|
|
30
|
+
rows: rows.map((row) => Object.values(row))
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
//#endregion
|
|
7
35
|
//#region src/utils/file.ts
|
|
8
36
|
const NEW_LINE_SEPARATOR = "\n";
|
|
9
37
|
const EMOJI_REGEXP = /(?!(\*|#|\d))[\p{Extended_Pictographic}\p{Emoji_Component}]|[\u0030-\u0039]\ufe0f?[\u20e3]|[\u002A\u0023]?\ufe0f?[\u20e3]/gu;
|
|
@@ -28,7 +56,6 @@ function addTrailingNewLine(data) {
|
|
|
28
56
|
function addMissingFileMarker(data) {
|
|
29
57
|
return `===== missing file =====${NEW_LINE_SEPARATOR}${data}`;
|
|
30
58
|
}
|
|
31
|
-
|
|
32
59
|
//#endregion
|
|
33
60
|
//#region src/utils/guards.ts
|
|
34
61
|
function isString(value) {
|
|
@@ -45,13 +72,11 @@ function isPlainObject(value) {
|
|
|
45
72
|
const proto = Object.getPrototypeOf(value);
|
|
46
73
|
return proto === null || proto === Object.prototype;
|
|
47
74
|
}
|
|
48
|
-
|
|
49
75
|
//#endregion
|
|
50
76
|
//#region src/utils/validators.ts
|
|
51
77
|
function isPositiveInteger(value) {
|
|
52
78
|
return Number.isInteger(value) && value > 0;
|
|
53
79
|
}
|
|
54
|
-
|
|
55
80
|
//#endregion
|
|
56
81
|
//#region src/serializers/json-serializer.ts
|
|
57
82
|
var JsonSerializer = class {
|
|
@@ -65,9 +90,6 @@ var JsonSerializer = class {
|
|
|
65
90
|
this.normalizers = options.normalizers ?? [];
|
|
66
91
|
this.indentSize = options.indentSize ?? 2;
|
|
67
92
|
}
|
|
68
|
-
canSerialize(_value) {
|
|
69
|
-
return true;
|
|
70
|
-
}
|
|
71
93
|
serialize(value) {
|
|
72
94
|
const jsonValue = this.normalizeValueRecursive(value);
|
|
73
95
|
return addTrailingNewLine(JSON.stringify(jsonValue, void 0, this.indentSize));
|
|
@@ -145,7 +167,30 @@ var JsonSerializer = class {
|
|
|
145
167
|
return normalizedValue;
|
|
146
168
|
}
|
|
147
169
|
};
|
|
148
|
-
|
|
170
|
+
//#endregion
|
|
171
|
+
//#region src/serializers/markdown-table-serializer.ts
|
|
172
|
+
var MarkdownTableSerializer = class {
|
|
173
|
+
fileExtension = "md";
|
|
174
|
+
normalizers;
|
|
175
|
+
constructor(options = {}) {
|
|
176
|
+
this.normalizers = options.normalizers ?? [];
|
|
177
|
+
}
|
|
178
|
+
serialize(value) {
|
|
179
|
+
const { columns, rows } = value;
|
|
180
|
+
if (columns.length === 0) throw new Error("Markdown table must have at least one column.");
|
|
181
|
+
return addTrailingNewLine(markdownTable([columns, ...rows.map((row) => row.map((cellValue) => this.serializeCellValue(cellValue)))]));
|
|
182
|
+
}
|
|
183
|
+
serializeCellValue(value) {
|
|
184
|
+
let normalizedValue = value;
|
|
185
|
+
for (const normalizer of this.normalizers) normalizedValue = normalizer(normalizedValue);
|
|
186
|
+
return this.mapCellValueToString(normalizedValue);
|
|
187
|
+
}
|
|
188
|
+
mapCellValueToString(value) {
|
|
189
|
+
if (value === void 0) return "undefined";
|
|
190
|
+
if (value === null) return "null";
|
|
191
|
+
return value.toString().trim();
|
|
192
|
+
}
|
|
193
|
+
};
|
|
149
194
|
//#endregion
|
|
150
195
|
//#region src/serializers/text-serializer.ts
|
|
151
196
|
var TextSerializer = class {
|
|
@@ -155,11 +200,7 @@ var TextSerializer = class {
|
|
|
155
200
|
this.normalizers = options.normalizers ?? [];
|
|
156
201
|
this.fileExtension = options.fileExtension ?? "txt";
|
|
157
202
|
}
|
|
158
|
-
canSerialize(value) {
|
|
159
|
-
return isString(value);
|
|
160
|
-
}
|
|
161
203
|
serialize(value) {
|
|
162
|
-
if (!this.canSerialize(value)) throw new Error(`Missing text serialization for value of type ${typeof value}.`);
|
|
163
204
|
return addTrailingNewLine(this.normalizeValue(value));
|
|
164
205
|
}
|
|
165
206
|
normalizeValue(value) {
|
|
@@ -168,7 +209,6 @@ var TextSerializer = class {
|
|
|
168
209
|
return normalizedValue.trim();
|
|
169
210
|
}
|
|
170
211
|
};
|
|
171
|
-
|
|
172
212
|
//#endregion
|
|
173
213
|
//#region src/matcher/validation-file-matcher.ts
|
|
174
214
|
var ValidationFileMatcher = class {
|
|
@@ -189,7 +229,6 @@ var ValidationFileMatcher = class {
|
|
|
189
229
|
return this.updateSnapshots === "all" || this.isValidationFileMissing && this.updateSnapshots === "missing";
|
|
190
230
|
}
|
|
191
231
|
matchFileSnapshot(actual) {
|
|
192
|
-
if (!this.serializer.canSerialize(actual)) throw new Error(`Cannot serialize value of type ${typeof actual}`);
|
|
193
232
|
const serializedActual = this.serializer.serialize(actual);
|
|
194
233
|
const expected = this.resolveExpected(serializedActual);
|
|
195
234
|
return this.createMatcherResult({
|
|
@@ -238,7 +277,6 @@ var ValidationFileMatcher = class {
|
|
|
238
277
|
return this.validationFile;
|
|
239
278
|
}
|
|
240
279
|
};
|
|
241
|
-
|
|
242
280
|
//#endregion
|
|
243
281
|
//#region src/matcher/file-path-resolver.ts
|
|
244
282
|
function resolveNameAsFile(params) {
|
|
@@ -261,6 +299,5 @@ function resolveFilePath(params, resolveNamedFilePath) {
|
|
|
261
299
|
normalizedName: normalizeFileName(name)
|
|
262
300
|
});
|
|
263
301
|
}
|
|
264
|
-
|
|
265
302
|
//#endregion
|
|
266
|
-
export { JsonSerializer, TextSerializer, ValidationFileMatcher, isArray, isPlainObject, isString, normalizeFileName, resolveNameAsFile, resolveNameAsFileSuffix };
|
|
303
|
+
export { JsonSerializer, MarkdownTableSerializer, Table, TextSerializer, ValidationFileMatcher, isArray, isPlainObject, isString, normalizeFileName, resolveNameAsFile, resolveNameAsFileSuffix };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cronn/lib-file-snapshots",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "The library agnostic core for testing file snapshots",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"file snapshots"
|
|
@@ -22,12 +22,12 @@
|
|
|
22
22
|
"devEngines": {
|
|
23
23
|
"runtime": {
|
|
24
24
|
"name": "node",
|
|
25
|
-
"version": ">=24.
|
|
25
|
+
"version": ">=24.14.1 <25",
|
|
26
26
|
"onFail": "error"
|
|
27
27
|
},
|
|
28
28
|
"packageManager": {
|
|
29
29
|
"name": "pnpm",
|
|
30
|
-
"version": ">=10.
|
|
30
|
+
"version": ">=10.33.0 <11",
|
|
31
31
|
"onFail": "error"
|
|
32
32
|
}
|
|
33
33
|
},
|
|
@@ -45,17 +45,20 @@
|
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"@arethetypeswrong/core": "0.18.2",
|
|
47
47
|
"@trivago/prettier-plugin-sort-imports": "6.0.2",
|
|
48
|
-
"@
|
|
49
|
-
"@
|
|
50
|
-
"@vitest/coverage-v8": "4.
|
|
51
|
-
"eslint": "10.0
|
|
48
|
+
"@types/node": "24.12.2",
|
|
49
|
+
"@typescript/native-preview": "7.0.0-dev.20260406.1",
|
|
50
|
+
"@vitest/coverage-v8": "4.1.4",
|
|
51
|
+
"eslint": "10.2.0",
|
|
52
52
|
"eslint-config-prettier": "10.1.8",
|
|
53
|
+
"eslint-plugin-check-file": "3.3.1",
|
|
53
54
|
"eslint-plugin-unused-imports": "4.4.1",
|
|
55
|
+
"markdown-table": "3.0.4",
|
|
54
56
|
"prettier": "3.8.1",
|
|
55
|
-
"publint": "0.3.
|
|
56
|
-
"
|
|
57
|
-
"
|
|
58
|
-
"
|
|
57
|
+
"publint": "0.3.18",
|
|
58
|
+
"rimraf": "6.1.3",
|
|
59
|
+
"tsdown": "0.21.7",
|
|
60
|
+
"typescript-eslint": "8.58.0",
|
|
61
|
+
"vitest": "4.1.4",
|
|
59
62
|
"@cronn/shared-configs": "0.0.0"
|
|
60
63
|
},
|
|
61
64
|
"scripts": {
|
|
@@ -64,6 +67,7 @@
|
|
|
64
67
|
"test": "vitest run",
|
|
65
68
|
"test:coverage": "vitest run --coverage",
|
|
66
69
|
"compile": "tsgo",
|
|
67
|
-
"build": "tsdown"
|
|
70
|
+
"build": "tsdown",
|
|
71
|
+
"clean": "rimraf .turbo dist coverage"
|
|
68
72
|
}
|
|
69
73
|
}
|