@fougere/testing 0.4.0-alpha.0 → 0.5.0-alpha.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/remotes.d.ts +4 -45
- package/dist/remotes.d.ts.map +1 -1
- package/dist/remotes.js +4 -117
- package/dist/remotes.js.map +1 -1
- package/package.json +9 -9
- package/src/remotes.ts +4 -122
package/dist/remotes.d.ts
CHANGED
|
@@ -1,49 +1,8 @@
|
|
|
1
|
-
import { type Change } from '@fougere/schema';
|
|
2
|
-
import type { IdentityCard } from '@fougere/core';
|
|
3
|
-
/** What separates the copy a consumer holds from what the producer actually serves. */
|
|
4
|
-
export interface CardDrift {
|
|
5
|
-
frond: string;
|
|
6
|
-
/** A door the consumer calls that the producer no longer serves. */
|
|
7
|
-
missingDoors: string[];
|
|
8
|
-
/** An operation the consumer calls that the door no longer has. */
|
|
9
|
-
missingOps: {
|
|
10
|
-
door: string;
|
|
11
|
-
ops: string[];
|
|
12
|
-
}[];
|
|
13
|
-
/** A shape that moved under a door the consumer still calls. */
|
|
14
|
-
shapes: {
|
|
15
|
-
door: string;
|
|
16
|
-
changes: Change[];
|
|
17
|
-
}[];
|
|
18
|
-
/** A fact the consumer subscribes to whose shape moved, or that is gone. */
|
|
19
|
-
facts: {
|
|
20
|
-
fact: string;
|
|
21
|
-
changes: Change[] | 'gone';
|
|
22
|
-
}[];
|
|
23
|
-
}
|
|
24
1
|
/**
|
|
25
|
-
*
|
|
2
|
+
* Contract drift moved to `@fougere/core`, beside the card it compares.
|
|
26
3
|
*
|
|
27
|
-
*
|
|
28
|
-
* is
|
|
29
|
-
* consumer's copy three weeks ago, the producer moved on, and it still compiles —
|
|
30
|
-
* production is where that is found today. This is what Pact sells; the material was
|
|
31
|
-
* already here, in `rpc.discover` and in `Card.diff`.
|
|
32
|
-
*
|
|
33
|
-
* Read in ONE direction on purpose: what the consumer holds, checked against what is
|
|
34
|
-
* served. A producer serving MORE than the consumer knows is not drift — it is a producer
|
|
35
|
-
* that moved forward without breaking anyone, which is the whole point of the order the
|
|
36
|
-
* repo already states (re-sync the readers, then deploy the sender).
|
|
37
|
-
*/
|
|
38
|
-
export declare function driftOf(mine: IdentityCard, theirs: IdentityCard, frond: string): CardDrift;
|
|
39
|
-
/** Whether anything at all separates the two cards. */
|
|
40
|
-
export declare function agrees(drift: CardDrift): boolean;
|
|
41
|
-
/**
|
|
42
|
-
* The drift, in the words a deploy needs.
|
|
43
|
-
*
|
|
44
|
-
* A fact says the order out loud, because the repo already states it as a rule and
|
|
45
|
-
* nothing enforced it: a fact is judged strictly, so a reader that has not been re-synced
|
|
46
|
-
* refuses what the sender now announces.
|
|
4
|
+
* Republished here because a test states its subject by where it sits, and `agrees(driftOf(…))`
|
|
5
|
+
* is a testing gesture — the function is core's, the assertion is this package's.
|
|
47
6
|
*/
|
|
48
|
-
export
|
|
7
|
+
export { driftOf, agrees, explain, type CardDrift } from '@fougere/core';
|
|
49
8
|
//# sourceMappingURL=remotes.d.ts.map
|
package/dist/remotes.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"remotes.d.ts","sourceRoot":"","sources":["../src/remotes.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"remotes.d.ts","sourceRoot":"","sources":["../src/remotes.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,eAAe,CAAC"}
|
package/dist/remotes.js
CHANGED
|
@@ -1,121 +1,8 @@
|
|
|
1
|
-
import { Card } from '@fougere/schema';
|
|
2
|
-
/** Every door of a card, by name. */
|
|
3
|
-
function doorsOf(card, frond) {
|
|
4
|
-
const found = new Map();
|
|
5
|
-
for (const one of card.fronds) {
|
|
6
|
-
if (one.name !== frond)
|
|
7
|
-
continue;
|
|
8
|
-
for (const door of one.doors) {
|
|
9
|
-
found.set(door.name, { ops: new Set(door.ops.map((op) => op.name)), schema: door.schema });
|
|
10
|
-
}
|
|
11
|
-
}
|
|
12
|
-
return found;
|
|
13
|
-
}
|
|
14
|
-
function factsOf(card, frond) {
|
|
15
|
-
const found = new Map();
|
|
16
|
-
for (const one of card.fronds) {
|
|
17
|
-
if (one.name !== frond)
|
|
18
|
-
continue;
|
|
19
|
-
for (const fact of one.facts ?? [])
|
|
20
|
-
found.set(fact.name, fact.schema);
|
|
21
|
-
}
|
|
22
|
-
return found;
|
|
23
|
-
}
|
|
24
1
|
/**
|
|
25
|
-
*
|
|
2
|
+
* Contract drift moved to `@fougere/core`, beside the card it compares.
|
|
26
3
|
*
|
|
27
|
-
*
|
|
28
|
-
* is
|
|
29
|
-
* consumer's copy three weeks ago, the producer moved on, and it still compiles —
|
|
30
|
-
* production is where that is found today. This is what Pact sells; the material was
|
|
31
|
-
* already here, in `rpc.discover` and in `Card.diff`.
|
|
32
|
-
*
|
|
33
|
-
* Read in ONE direction on purpose: what the consumer holds, checked against what is
|
|
34
|
-
* served. A producer serving MORE than the consumer knows is not drift — it is a producer
|
|
35
|
-
* that moved forward without breaking anyone, which is the whole point of the order the
|
|
36
|
-
* repo already states (re-sync the readers, then deploy the sender).
|
|
37
|
-
*/
|
|
38
|
-
export function driftOf(mine, theirs, frond) {
|
|
39
|
-
const held = doorsOf(mine, frond);
|
|
40
|
-
const served = doorsOf(theirs, frond);
|
|
41
|
-
const drift = { frond, missingDoors: [], missingOps: [], shapes: [], facts: [] };
|
|
42
|
-
for (const [name, door] of held) {
|
|
43
|
-
const there = served.get(name);
|
|
44
|
-
if (!there) {
|
|
45
|
-
drift.missingDoors.push(name);
|
|
46
|
-
continue;
|
|
47
|
-
}
|
|
48
|
-
const missing = [...door.ops].filter((op) => !there.ops.has(op));
|
|
49
|
-
if (missing.length > 0)
|
|
50
|
-
drift.missingOps.push({ door: name, ops: missing.sort() });
|
|
51
|
-
if (door.schema && there.schema) {
|
|
52
|
-
// `Card.diff` never guesses a rename — a field gone plus a field appeared lands in
|
|
53
|
-
// `ambiguous`, and only a declaration settles it. Here nobody can declare one, so
|
|
54
|
-
// the pair is reported as it is and a human reads it.
|
|
55
|
-
const moved = Card.fromDescriptor(door.schema).diff(Card.fromDescriptor(there.schema));
|
|
56
|
-
if (moved.changes.length > 0)
|
|
57
|
-
drift.shapes.push({ door: name, changes: moved.changes });
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
const heldFacts = factsOf(mine, frond);
|
|
61
|
-
const servedFacts = factsOf(theirs, frond);
|
|
62
|
-
for (const [name, shape] of heldFacts) {
|
|
63
|
-
if (!servedFacts.has(name)) {
|
|
64
|
-
drift.facts.push({ fact: name, changes: 'gone' });
|
|
65
|
-
continue;
|
|
66
|
-
}
|
|
67
|
-
const there = servedFacts.get(name);
|
|
68
|
-
if (!shape || !there)
|
|
69
|
-
continue;
|
|
70
|
-
const moved = Card.fromDescriptor(shape).diff(Card.fromDescriptor(there));
|
|
71
|
-
if (moved.changes.length > 0)
|
|
72
|
-
drift.facts.push({ fact: name, changes: moved.changes });
|
|
73
|
-
}
|
|
74
|
-
return drift;
|
|
75
|
-
}
|
|
76
|
-
/** Whether anything at all separates the two cards. */
|
|
77
|
-
export function agrees(drift) {
|
|
78
|
-
return drift.missingDoors.length === 0
|
|
79
|
-
&& drift.missingOps.length === 0
|
|
80
|
-
&& drift.shapes.length === 0
|
|
81
|
-
&& drift.facts.length === 0;
|
|
82
|
-
}
|
|
83
|
-
/**
|
|
84
|
-
* The drift, in the words a deploy needs.
|
|
85
|
-
*
|
|
86
|
-
* A fact says the order out loud, because the repo already states it as a rule and
|
|
87
|
-
* nothing enforced it: a fact is judged strictly, so a reader that has not been re-synced
|
|
88
|
-
* refuses what the sender now announces.
|
|
4
|
+
* Republished here because a test states its subject by where it sits, and `agrees(driftOf(…))`
|
|
5
|
+
* is a testing gesture — the function is core's, the assertion is this package's.
|
|
89
6
|
*/
|
|
90
|
-
export
|
|
91
|
-
const lines = [];
|
|
92
|
-
for (const door of drift.missingDoors)
|
|
93
|
-
lines.push(`${drift.frond}.${door} — you call it, it is not served`);
|
|
94
|
-
for (const { door, ops } of drift.missingOps)
|
|
95
|
-
lines.push(`${drift.frond}.${door} — gone: ${ops.join(', ')}`);
|
|
96
|
-
for (const { door, changes } of drift.shapes) {
|
|
97
|
-
for (const change of changes)
|
|
98
|
-
lines.push(`${drift.frond}.${door} — ${describe(change)}`);
|
|
99
|
-
}
|
|
100
|
-
for (const { fact, changes } of drift.facts) {
|
|
101
|
-
if (changes === 'gone') {
|
|
102
|
-
lines.push(`${fact} — you subscribe to it, it is no longer announced`);
|
|
103
|
-
continue;
|
|
104
|
-
}
|
|
105
|
-
for (const change of changes)
|
|
106
|
-
lines.push(`${fact} — ${describe(change)} → re-sync and deploy the readers, THEN the sender`);
|
|
107
|
-
}
|
|
108
|
-
return lines;
|
|
109
|
-
}
|
|
110
|
-
function describe(change) {
|
|
111
|
-
switch (change.kind) {
|
|
112
|
-
case 'added': return `+ ${change.field}${change.required ? ' (required)' : ''}`;
|
|
113
|
-
case 'removed': return `- ${change.field}`;
|
|
114
|
-
case 'renamed': return `${change.from} → ${change.to}`;
|
|
115
|
-
case 'retyped': return `${change.field}: ${[...change.from].join('|')} → ${[...change.to].join('|')}`;
|
|
116
|
-
case 'reshaped': return `${change.field}: its bounds moved`;
|
|
117
|
-
case 'required': return `${change.field}: ${change.from ? 'no longer' : 'now'} required`;
|
|
118
|
-
case 'restated': return `${change.field}: its ${change.axis} moved`;
|
|
119
|
-
}
|
|
120
|
-
}
|
|
7
|
+
export { driftOf, agrees, explain } from '@fougere/core';
|
|
121
8
|
//# sourceMappingURL=remotes.js.map
|
package/dist/remotes.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"remotes.js","sourceRoot":"","sources":["../src/remotes.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"remotes.js","sourceRoot":"","sources":["../src/remotes.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAkB,MAAM,eAAe,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fougere/testing",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0-alpha.0",
|
|
4
4
|
"description": "Tests derived from the declaration — cases, stubs and a gradient of realities.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"fougere",
|
|
@@ -34,19 +34,19 @@
|
|
|
34
34
|
],
|
|
35
35
|
"dependencies": {
|
|
36
36
|
"json-schema-faker": "^0.6.3",
|
|
37
|
-
"@fougere/
|
|
38
|
-
"@fougere/
|
|
39
|
-
"@fougere/schema": "0.
|
|
40
|
-
"@fougere/defaults": "0.
|
|
41
|
-
"@fougere/transport-http": "0.
|
|
42
|
-
"@fougere/app": "0.
|
|
37
|
+
"@fougere/container": "0.5.0-alpha.0",
|
|
38
|
+
"@fougere/core": "0.5.0-alpha.0",
|
|
39
|
+
"@fougere/schema": "0.5.0-alpha.0",
|
|
40
|
+
"@fougere/defaults": "0.5.0-alpha.0",
|
|
41
|
+
"@fougere/transport-http": "0.5.0-alpha.0",
|
|
42
|
+
"@fougere/app": "0.5.0-alpha.0"
|
|
43
43
|
},
|
|
44
44
|
"publishConfig": {
|
|
45
45
|
"access": "public"
|
|
46
46
|
},
|
|
47
47
|
"peerDependencies": {
|
|
48
48
|
"vitest": ">=2",
|
|
49
|
-
"@fougere/adapter-graphql": "0.
|
|
49
|
+
"@fougere/adapter-graphql": "0.5.0-alpha.0"
|
|
50
50
|
},
|
|
51
51
|
"peerDependenciesMeta": {
|
|
52
52
|
"vitest": {
|
|
@@ -58,7 +58,7 @@
|
|
|
58
58
|
},
|
|
59
59
|
"devDependencies": {
|
|
60
60
|
"vitest": "^4.1.0",
|
|
61
|
-
"@fougere/adapter-graphql": "0.
|
|
61
|
+
"@fougere/adapter-graphql": "0.5.0-alpha.0"
|
|
62
62
|
},
|
|
63
63
|
"scripts": {
|
|
64
64
|
"build": "rm -rf dist && tsc",
|
package/src/remotes.ts
CHANGED
|
@@ -1,125 +1,7 @@
|
|
|
1
|
-
import { Card, type Change, type SchemaDescriptor } from '@fougere/schema';
|
|
2
|
-
import type { IdentityCard } from '@fougere/core';
|
|
3
|
-
|
|
4
|
-
/** What separates the copy a consumer holds from what the producer actually serves. */
|
|
5
|
-
export interface CardDrift {
|
|
6
|
-
frond: string;
|
|
7
|
-
/** A door the consumer calls that the producer no longer serves. */
|
|
8
|
-
missingDoors: string[];
|
|
9
|
-
/** An operation the consumer calls that the door no longer has. */
|
|
10
|
-
missingOps: { door: string; ops: string[] }[];
|
|
11
|
-
/** A shape that moved under a door the consumer still calls. */
|
|
12
|
-
shapes: { door: string; changes: Change[] }[];
|
|
13
|
-
/** A fact the consumer subscribes to whose shape moved, or that is gone. */
|
|
14
|
-
facts: { fact: string; changes: Change[] | 'gone' }[];
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/** Every door of a card, by name. */
|
|
18
|
-
function doorsOf(card: IdentityCard, frond: string): Map<string, { ops: Set<string>; schema?: SchemaDescriptor }> {
|
|
19
|
-
const found = new Map<string, { ops: Set<string>; schema?: SchemaDescriptor }>();
|
|
20
|
-
for (const one of card.fronds) {
|
|
21
|
-
if (one.name !== frond) continue;
|
|
22
|
-
for (const door of one.doors) {
|
|
23
|
-
found.set(door.name, { ops: new Set(door.ops.map((op) => op.name)), schema: door.schema });
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
return found;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
function factsOf(card: IdentityCard, frond: string): Map<string, SchemaDescriptor | undefined> {
|
|
30
|
-
const found = new Map<string, SchemaDescriptor | undefined>();
|
|
31
|
-
for (const one of card.fronds) {
|
|
32
|
-
if (one.name !== frond) continue;
|
|
33
|
-
for (const fact of one.facts ?? []) found.set(fact.name, fact.schema as SchemaDescriptor | undefined);
|
|
34
|
-
}
|
|
35
|
-
return found;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
1
|
/**
|
|
39
|
-
*
|
|
2
|
+
* Contract drift moved to `@fougere/core`, beside the card it compares.
|
|
40
3
|
*
|
|
41
|
-
*
|
|
42
|
-
* is
|
|
43
|
-
* consumer's copy three weeks ago, the producer moved on, and it still compiles —
|
|
44
|
-
* production is where that is found today. This is what Pact sells; the material was
|
|
45
|
-
* already here, in `rpc.discover` and in `Card.diff`.
|
|
46
|
-
*
|
|
47
|
-
* Read in ONE direction on purpose: what the consumer holds, checked against what is
|
|
48
|
-
* served. A producer serving MORE than the consumer knows is not drift — it is a producer
|
|
49
|
-
* that moved forward without breaking anyone, which is the whole point of the order the
|
|
50
|
-
* repo already states (re-sync the readers, then deploy the sender).
|
|
51
|
-
*/
|
|
52
|
-
export function driftOf(mine: IdentityCard, theirs: IdentityCard, frond: string): CardDrift {
|
|
53
|
-
const held = doorsOf(mine, frond);
|
|
54
|
-
const served = doorsOf(theirs, frond);
|
|
55
|
-
const drift: CardDrift = { frond, missingDoors: [], missingOps: [], shapes: [], facts: [] };
|
|
56
|
-
|
|
57
|
-
for (const [name, door] of held) {
|
|
58
|
-
const there = served.get(name);
|
|
59
|
-
if (!there) { drift.missingDoors.push(name); continue; }
|
|
60
|
-
|
|
61
|
-
const missing = [...door.ops].filter((op) => !there.ops.has(op));
|
|
62
|
-
if (missing.length > 0) drift.missingOps.push({ door: name, ops: missing.sort() });
|
|
63
|
-
|
|
64
|
-
if (door.schema && there.schema) {
|
|
65
|
-
// `Card.diff` never guesses a rename — a field gone plus a field appeared lands in
|
|
66
|
-
// `ambiguous`, and only a declaration settles it. Here nobody can declare one, so
|
|
67
|
-
// the pair is reported as it is and a human reads it.
|
|
68
|
-
const moved = Card.fromDescriptor(door.schema).diff(Card.fromDescriptor(there.schema));
|
|
69
|
-
if (moved.changes.length > 0) drift.shapes.push({ door: name, changes: moved.changes });
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
const heldFacts = factsOf(mine, frond);
|
|
74
|
-
const servedFacts = factsOf(theirs, frond);
|
|
75
|
-
for (const [name, shape] of heldFacts) {
|
|
76
|
-
if (!servedFacts.has(name)) { drift.facts.push({ fact: name, changes: 'gone' }); continue; }
|
|
77
|
-
const there = servedFacts.get(name);
|
|
78
|
-
if (!shape || !there) continue;
|
|
79
|
-
const moved = Card.fromDescriptor(shape).diff(Card.fromDescriptor(there));
|
|
80
|
-
if (moved.changes.length > 0) drift.facts.push({ fact: name, changes: moved.changes });
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
return drift;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
/** Whether anything at all separates the two cards. */
|
|
87
|
-
export function agrees(drift: CardDrift): boolean {
|
|
88
|
-
return drift.missingDoors.length === 0
|
|
89
|
-
&& drift.missingOps.length === 0
|
|
90
|
-
&& drift.shapes.length === 0
|
|
91
|
-
&& drift.facts.length === 0;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* The drift, in the words a deploy needs.
|
|
96
|
-
*
|
|
97
|
-
* A fact says the order out loud, because the repo already states it as a rule and
|
|
98
|
-
* nothing enforced it: a fact is judged strictly, so a reader that has not been re-synced
|
|
99
|
-
* refuses what the sender now announces.
|
|
4
|
+
* Republished here because a test states its subject by where it sits, and `agrees(driftOf(…))`
|
|
5
|
+
* is a testing gesture — the function is core's, the assertion is this package's.
|
|
100
6
|
*/
|
|
101
|
-
export
|
|
102
|
-
const lines: string[] = [];
|
|
103
|
-
for (const door of drift.missingDoors) lines.push(`${drift.frond}.${door} — you call it, it is not served`);
|
|
104
|
-
for (const { door, ops } of drift.missingOps) lines.push(`${drift.frond}.${door} — gone: ${ops.join(', ')}`);
|
|
105
|
-
for (const { door, changes } of drift.shapes) {
|
|
106
|
-
for (const change of changes) lines.push(`${drift.frond}.${door} — ${describe(change)}`);
|
|
107
|
-
}
|
|
108
|
-
for (const { fact, changes } of drift.facts) {
|
|
109
|
-
if (changes === 'gone') { lines.push(`${fact} — you subscribe to it, it is no longer announced`); continue; }
|
|
110
|
-
for (const change of changes) lines.push(`${fact} — ${describe(change)} → re-sync and deploy the readers, THEN the sender`);
|
|
111
|
-
}
|
|
112
|
-
return lines;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
function describe(change: Change): string {
|
|
116
|
-
switch (change.kind) {
|
|
117
|
-
case 'added': return `+ ${change.field}${change.required ? ' (required)' : ''}`;
|
|
118
|
-
case 'removed': return `- ${change.field}`;
|
|
119
|
-
case 'renamed': return `${change.from} → ${change.to}`;
|
|
120
|
-
case 'retyped': return `${change.field}: ${[...change.from].join('|')} → ${[...change.to].join('|')}`;
|
|
121
|
-
case 'reshaped': return `${change.field}: its bounds moved`;
|
|
122
|
-
case 'required': return `${change.field}: ${change.from ? 'no longer' : 'now'} required`;
|
|
123
|
-
case 'restated': return `${change.field}: its ${change.axis} moved`;
|
|
124
|
-
}
|
|
125
|
-
}
|
|
7
|
+
export { driftOf, agrees, explain, type CardDrift } from '@fougere/core';
|