autotel-message-contract 10.0.0 → 11.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/dist/index.cjs +9 -8
- package/dist/index.d.cts +5 -1
- package/dist/index.d.ts +5 -1
- package/dist/index.js +9 -8
- package/dist/serializer.cjs +2 -5
- package/dist/serializer.js +2 -5
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -77,7 +77,7 @@ function longestCommonSubsequence(a, b) {
|
|
|
77
77
|
//#endregion
|
|
78
78
|
//#region src/reader.ts
|
|
79
79
|
function isStandardSchema(reader) {
|
|
80
|
-
return
|
|
80
|
+
return reader instanceof Object && "~standard" in reader && reader["~standard"]?.validate !== void 0;
|
|
81
81
|
}
|
|
82
82
|
/**
|
|
83
83
|
* Run a reader against a deserialized value. Never throws — a thrown parse
|
|
@@ -119,9 +119,9 @@ function formatIssue(message, path) {
|
|
|
119
119
|
if (Array.isArray(path) && path.length > 0) return `${path.map(String).join(".")}: ${message}`;
|
|
120
120
|
return message;
|
|
121
121
|
}
|
|
122
|
-
function errorMessage(
|
|
123
|
-
if (
|
|
124
|
-
return String(
|
|
122
|
+
function errorMessage(cause) {
|
|
123
|
+
if (cause instanceof Error) return cause.message;
|
|
124
|
+
return String(cause);
|
|
125
125
|
}
|
|
126
126
|
|
|
127
127
|
//#endregion
|
|
@@ -253,7 +253,7 @@ function approvedSnapshot(location) {
|
|
|
253
253
|
};
|
|
254
254
|
}
|
|
255
255
|
function isApprovedSnapshotSource(value) {
|
|
256
|
-
return
|
|
256
|
+
return value instanceof Object && SNAPSHOT_SOURCE in value && value[SNAPSHOT_SOURCE] === true;
|
|
257
257
|
}
|
|
258
258
|
/** Start a contract check. */
|
|
259
259
|
function messageContract(options = {}) {
|
|
@@ -363,8 +363,9 @@ var CompatibilityStep = class {
|
|
|
363
363
|
const outcome = await read(this.reader, deserializedSource);
|
|
364
364
|
if (!outcome.ok) throw new ContractViolationError(`Not ${direction}-compatible: ${direction === "backward" ? "the newer reader" : "the older reader"} rejected a message ${direction === "backward" ? "an older writer" : "a newer writer"} produced.\n serializer: ${this.serializer.name}\n serialized: ${truncate(serialized)}\n issues:\n${outcome.issues.map((m) => ` - ${m}`).join("\n")}`);
|
|
365
365
|
this.assertStructuralCompatibility(deserializedSource, this.serializer.deserialize(this.serializer.serialize(outcome.value)), direction, serialized);
|
|
366
|
-
|
|
367
|
-
|
|
366
|
+
const value = outcome.value;
|
|
367
|
+
if (assert) await assert(value);
|
|
368
|
+
return value;
|
|
368
369
|
}
|
|
369
370
|
resolveSourceSerialized() {
|
|
370
371
|
if (isApprovedSnapshotSource(this.source)) {
|
|
@@ -416,7 +417,7 @@ function compareSharedStructure(sourceValue, targetValue, path, mismatches) {
|
|
|
416
417
|
if (!deepEqual(sourceValue, targetValue)) mismatches.push(`${path}: value differs (${formatValue(sourceValue)} vs ${formatValue(targetValue)})`);
|
|
417
418
|
}
|
|
418
419
|
function isPlainObject(value) {
|
|
419
|
-
if (value === null ||
|
|
420
|
+
if (value === null || !(value instanceof Object) || Array.isArray(value)) return false;
|
|
420
421
|
const proto = Object.getPrototypeOf(value);
|
|
421
422
|
return proto === Object.prototype || proto === null;
|
|
422
423
|
}
|
package/dist/index.d.cts
CHANGED
|
@@ -26,11 +26,15 @@ interface StandardSchemaLike<Output = unknown> {
|
|
|
26
26
|
readonly validate: (value: unknown) => StandardResult<Output> | Promise<StandardResult<Output>>;
|
|
27
27
|
};
|
|
28
28
|
}
|
|
29
|
+
/** Where in the message an issue was found, as Standard Schema reports it. */
|
|
30
|
+
type IssuePath = ReadonlyArray<PropertyKey | {
|
|
31
|
+
key: PropertyKey;
|
|
32
|
+
}>;
|
|
29
33
|
interface StandardResult<Output> {
|
|
30
34
|
value?: Output;
|
|
31
35
|
issues?: ReadonlyArray<{
|
|
32
36
|
readonly message: string;
|
|
33
|
-
readonly path?:
|
|
37
|
+
readonly path?: IssuePath;
|
|
34
38
|
}>;
|
|
35
39
|
}
|
|
36
40
|
/** A bare parse function: returns the typed value or throws. */
|
package/dist/index.d.ts
CHANGED
|
@@ -26,11 +26,15 @@ interface StandardSchemaLike<Output = unknown> {
|
|
|
26
26
|
readonly validate: (value: unknown) => StandardResult<Output> | Promise<StandardResult<Output>>;
|
|
27
27
|
};
|
|
28
28
|
}
|
|
29
|
+
/** Where in the message an issue was found, as Standard Schema reports it. */
|
|
30
|
+
type IssuePath = ReadonlyArray<PropertyKey | {
|
|
31
|
+
key: PropertyKey;
|
|
32
|
+
}>;
|
|
29
33
|
interface StandardResult<Output> {
|
|
30
34
|
value?: Output;
|
|
31
35
|
issues?: ReadonlyArray<{
|
|
32
36
|
readonly message: string;
|
|
33
|
-
readonly path?:
|
|
37
|
+
readonly path?: IssuePath;
|
|
34
38
|
}>;
|
|
35
39
|
}
|
|
36
40
|
/** A bare parse function: returns the typed value or throws. */
|
package/dist/index.js
CHANGED
|
@@ -48,7 +48,7 @@ function longestCommonSubsequence(a, b) {
|
|
|
48
48
|
//#endregion
|
|
49
49
|
//#region src/reader.ts
|
|
50
50
|
function isStandardSchema(reader) {
|
|
51
|
-
return
|
|
51
|
+
return reader instanceof Object && "~standard" in reader && reader["~standard"]?.validate !== void 0;
|
|
52
52
|
}
|
|
53
53
|
/**
|
|
54
54
|
* Run a reader against a deserialized value. Never throws — a thrown parse
|
|
@@ -90,9 +90,9 @@ function formatIssue(message, path) {
|
|
|
90
90
|
if (Array.isArray(path) && path.length > 0) return `${path.map(String).join(".")}: ${message}`;
|
|
91
91
|
return message;
|
|
92
92
|
}
|
|
93
|
-
function errorMessage(
|
|
94
|
-
if (
|
|
95
|
-
return String(
|
|
93
|
+
function errorMessage(cause) {
|
|
94
|
+
if (cause instanceof Error) return cause.message;
|
|
95
|
+
return String(cause);
|
|
96
96
|
}
|
|
97
97
|
|
|
98
98
|
//#endregion
|
|
@@ -224,7 +224,7 @@ function approvedSnapshot(location) {
|
|
|
224
224
|
};
|
|
225
225
|
}
|
|
226
226
|
function isApprovedSnapshotSource(value) {
|
|
227
|
-
return
|
|
227
|
+
return value instanceof Object && SNAPSHOT_SOURCE in value && value[SNAPSHOT_SOURCE] === true;
|
|
228
228
|
}
|
|
229
229
|
/** Start a contract check. */
|
|
230
230
|
function messageContract(options = {}) {
|
|
@@ -334,8 +334,9 @@ var CompatibilityStep = class {
|
|
|
334
334
|
const outcome = await read(this.reader, deserializedSource);
|
|
335
335
|
if (!outcome.ok) throw new ContractViolationError(`Not ${direction}-compatible: ${direction === "backward" ? "the newer reader" : "the older reader"} rejected a message ${direction === "backward" ? "an older writer" : "a newer writer"} produced.\n serializer: ${this.serializer.name}\n serialized: ${truncate(serialized)}\n issues:\n${outcome.issues.map((m) => ` - ${m}`).join("\n")}`);
|
|
336
336
|
this.assertStructuralCompatibility(deserializedSource, this.serializer.deserialize(this.serializer.serialize(outcome.value)), direction, serialized);
|
|
337
|
-
|
|
338
|
-
|
|
337
|
+
const value = outcome.value;
|
|
338
|
+
if (assert) await assert(value);
|
|
339
|
+
return value;
|
|
339
340
|
}
|
|
340
341
|
resolveSourceSerialized() {
|
|
341
342
|
if (isApprovedSnapshotSource(this.source)) {
|
|
@@ -387,7 +388,7 @@ function compareSharedStructure(sourceValue, targetValue, path, mismatches) {
|
|
|
387
388
|
if (!deepEqual(sourceValue, targetValue)) mismatches.push(`${path}: value differs (${formatValue(sourceValue)} vs ${formatValue(targetValue)})`);
|
|
388
389
|
}
|
|
389
390
|
function isPlainObject(value) {
|
|
390
|
-
if (value === null ||
|
|
391
|
+
if (value === null || !(value instanceof Object) || Array.isArray(value)) return false;
|
|
391
392
|
const proto = Object.getPrototypeOf(value);
|
|
392
393
|
return proto === Object.prototype || proto === null;
|
|
393
394
|
}
|
package/dist/serializer.cjs
CHANGED
|
@@ -9,14 +9,11 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
|
9
9
|
*/
|
|
10
10
|
function sortKeysDeep(value) {
|
|
11
11
|
if (Array.isArray(value)) return value.map((element) => sortKeysDeep(element));
|
|
12
|
-
if (value
|
|
13
|
-
const sorted = {};
|
|
14
|
-
for (const key of Object.keys(value).toSorted()) sorted[key] = sortKeysDeep(value[key]);
|
|
15
|
-
return sorted;
|
|
16
|
-
}
|
|
12
|
+
if (isPlainObject(value)) return Object.fromEntries(Object.keys(value).toSorted().map((key) => [key, sortKeysDeep(value[key])]));
|
|
17
13
|
return value;
|
|
18
14
|
}
|
|
19
15
|
function isPlainObject(value) {
|
|
16
|
+
if (value === null || !(value instanceof Object)) return false;
|
|
20
17
|
const proto = Object.getPrototypeOf(value);
|
|
21
18
|
return proto === Object.prototype || proto === null;
|
|
22
19
|
}
|
package/dist/serializer.js
CHANGED
|
@@ -7,14 +7,11 @@
|
|
|
7
7
|
*/
|
|
8
8
|
function sortKeysDeep(value) {
|
|
9
9
|
if (Array.isArray(value)) return value.map((element) => sortKeysDeep(element));
|
|
10
|
-
if (value
|
|
11
|
-
const sorted = {};
|
|
12
|
-
for (const key of Object.keys(value).toSorted()) sorted[key] = sortKeysDeep(value[key]);
|
|
13
|
-
return sorted;
|
|
14
|
-
}
|
|
10
|
+
if (isPlainObject(value)) return Object.fromEntries(Object.keys(value).toSorted().map((key) => [key, sortKeysDeep(value[key])]));
|
|
15
11
|
return value;
|
|
16
12
|
}
|
|
17
13
|
function isPlainObject(value) {
|
|
14
|
+
if (value === null || !(value instanceof Object)) return false;
|
|
18
15
|
const proto = Object.getPrototypeOf(value);
|
|
19
16
|
return proto === Object.prototype || proto === null;
|
|
20
17
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "autotel-message-contract",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "11.0.0",
|
|
4
4
|
"description": "Brokerless message contract testing for autotel — pin the serialized shape of your events/commands/messages and prove old and new versions stay compatible, as ordinary unit tests.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"author": "Jag Reehal <jag@jagreehal.com> (https://jagreehal.com)",
|
|
37
37
|
"license": "Apache-2.0",
|
|
38
38
|
"peerDependencies": {
|
|
39
|
-
"autotel": "
|
|
39
|
+
"autotel": "7.0.0"
|
|
40
40
|
},
|
|
41
41
|
"peerDependenciesMeta": {
|
|
42
42
|
"autotel": {
|