@fougere/testing 0.9.3-alpha.0 → 0.10.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.
Files changed (89) hide show
  1. package/README.md +1 -1
  2. package/dist/{comparison.d.ts → DoorContractCase.d.ts} +5 -13
  3. package/dist/DoorContractCase.d.ts.map +1 -0
  4. package/dist/{comparison.js → DoorContractCase.js} +31 -31
  5. package/dist/DoorContractCase.js.map +1 -0
  6. package/dist/DoorInput.d.ts +5 -0
  7. package/dist/DoorInput.d.ts.map +1 -0
  8. package/dist/DoorInput.js +2 -0
  9. package/dist/DoorInput.js.map +1 -0
  10. package/dist/DoorOptions.d.ts +7 -0
  11. package/dist/DoorOptions.d.ts.map +1 -0
  12. package/dist/DoorOptions.js +2 -0
  13. package/dist/DoorOptions.js.map +1 -0
  14. package/dist/all.d.ts +4 -4
  15. package/dist/all.d.ts.map +1 -1
  16. package/dist/all.js +3 -3
  17. package/dist/all.js.map +1 -1
  18. package/dist/app/TestApp.d.ts +15 -0
  19. package/dist/app/TestApp.d.ts.map +1 -0
  20. package/dist/{app.js → app/TestApp.js} +3 -3
  21. package/dist/app/TestApp.js.map +1 -0
  22. package/dist/{app.d.ts → app/TestAppOptions.d.ts} +2 -14
  23. package/dist/app/TestAppOptions.d.ts.map +1 -0
  24. package/dist/app/TestAppOptions.js +2 -0
  25. package/dist/app/TestAppOptions.js.map +1 -0
  26. package/dist/facades/CheckOptions.d.ts +6 -0
  27. package/dist/facades/CheckOptions.d.ts.map +1 -0
  28. package/dist/facades/CheckOptions.js +2 -0
  29. package/dist/facades/CheckOptions.js.map +1 -0
  30. package/dist/{doors.d.ts → facades/Verdict.d.ts} +4 -8
  31. package/dist/facades/Verdict.d.ts.map +1 -0
  32. package/dist/{doors.js → facades/Verdict.js} +4 -4
  33. package/dist/facades/Verdict.js.map +1 -0
  34. package/dist/index.d.ts +5 -4
  35. package/dist/index.d.ts.map +1 -1
  36. package/dist/index.js +4 -4
  37. package/dist/index.js.map +1 -1
  38. package/dist/load.d.ts +2 -2
  39. package/dist/load.d.ts.map +1 -1
  40. package/dist/load.js +4 -4
  41. package/dist/load.js.map +1 -1
  42. package/dist/spans.d.ts +1 -1
  43. package/dist/spans.js +1 -1
  44. package/dist/stub/Port.d.ts +3 -0
  45. package/dist/stub/Port.d.ts.map +1 -0
  46. package/dist/stub/Port.js +2 -0
  47. package/dist/stub/Port.js.map +1 -0
  48. package/dist/{stub.d.ts → stub/Stub.d.ts} +2 -3
  49. package/dist/stub/Stub.d.ts.map +1 -0
  50. package/dist/{stub.js → stub/Stub.js} +1 -1
  51. package/dist/stub/Stub.js.map +1 -0
  52. package/dist/{sync.d.ts → sync/SyncDrift.d.ts} +2 -10
  53. package/dist/sync/SyncDrift.d.ts.map +1 -0
  54. package/dist/{sync.js → sync/SyncDrift.js} +5 -18
  55. package/dist/sync/SyncDrift.js.map +1 -0
  56. package/dist/sync/SyncedRemote.d.ts +10 -0
  57. package/dist/sync/SyncedRemote.d.ts.map +1 -0
  58. package/dist/sync/SyncedRemote.js +15 -0
  59. package/dist/sync/SyncedRemote.js.map +1 -0
  60. package/dist/vitest.d.ts.map +1 -1
  61. package/dist/vitest.js +4 -0
  62. package/dist/vitest.js.map +1 -1
  63. package/package.json +14 -14
  64. package/src/{comparison.ts → DoorContractCase.ts} +34 -40
  65. package/src/DoorInput.ts +1 -0
  66. package/src/DoorOptions.ts +7 -0
  67. package/src/all.ts +7 -5
  68. package/src/{app.ts → app/TestApp.ts} +4 -26
  69. package/src/app/TestAppOptions.ts +25 -0
  70. package/src/facades/CheckOptions.ts +6 -0
  71. package/src/{doors.ts → facades/Verdict.ts} +5 -9
  72. package/src/index.ts +5 -7
  73. package/src/load.ts +6 -6
  74. package/src/spans.ts +1 -1
  75. package/src/stub/Port.ts +2 -0
  76. package/src/{stub.ts → stub/Stub.ts} +1 -3
  77. package/src/{sync.ts → sync/SyncDrift.ts} +3 -23
  78. package/src/sync/SyncedRemote.ts +22 -0
  79. package/src/vitest.ts +4 -0
  80. package/dist/app.d.ts.map +0 -1
  81. package/dist/app.js.map +0 -1
  82. package/dist/comparison.d.ts.map +0 -1
  83. package/dist/comparison.js.map +0 -1
  84. package/dist/doors.d.ts.map +0 -1
  85. package/dist/doors.js.map +0 -1
  86. package/dist/stub.d.ts.map +0 -1
  87. package/dist/stub.js.map +0 -1
  88. package/dist/sync.d.ts.map +0 -1
  89. package/dist/sync.js.map +0 -1
@@ -0,0 +1,3 @@
1
+ /** Anything a provider can be declared as: a class the container knows how to build. */
2
+ export type Port = abstract new (...args: never[]) => unknown;
3
+ //# sourceMappingURL=Port.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Port.d.ts","sourceRoot":"","sources":["../../src/stub/Port.ts"],"names":[],"mappings":"AAAA,wFAAwF;AACxF,MAAM,MAAM,IAAI,GAAG,QAAQ,MAAM,GAAG,IAAI,EAAE,KAAK,EAAE,KAAK,OAAO,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=Port.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Port.js","sourceRoot":"","sources":["../../src/stub/Port.ts"],"names":[],"mappings":""}
@@ -1,7 +1,6 @@
1
1
  import { type Mock } from 'vitest';
2
2
  import type { App } from '@fougere/core';
3
- /** Anything a provider can be declared as: a class the container knows how to build. */
4
- export type Port = abstract new (...args: never[]) => unknown;
3
+ import type { Port } from './Port.js';
5
4
  /** The double handed in place of a port — one spy per method the port declares. */
6
5
  export type Stub<T> = {
7
6
  [K in keyof T]: T[K] extends (...args: never[]) => unknown ? Mock : T[K];
@@ -12,4 +11,4 @@ export declare function methodsOf(port: Port): string[];
12
11
  export declare function stubOf<T>(port: Port): Stub<T>;
13
12
  /** Put doubles in front of ports, in every frond scope that answers under their name. */
14
13
  export declare function installStubs(app: App, ports: Port[]): Map<Port, Stub<unknown>>;
15
- //# sourceMappingURL=stub.d.ts.map
14
+ //# sourceMappingURL=Stub.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Stub.d.ts","sourceRoot":"","sources":["../../src/stub/Stub.ts"],"names":[],"mappings":"AAAA,OAAO,EAAM,KAAK,IAAI,EAAE,MAAM,QAAQ,CAAC;AAEvC,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEtC,mFAAmF;AACnF,MAAM,MAAM,IAAI,CAAC,CAAC,IAAI;KAAG,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,KAAK,EAAE,KAAK,OAAO,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC;CAAE,CAAC;AAEnG,6EAA6E;AAC7E,wBAAgB,SAAS,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,EAAE,CAY9C;AAED,2BAA2B;AAC3B,wBAAgB,MAAM,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,CAI7C;AAED,yFAAyF;AACzF,wBAAgB,YAAY,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,CAiB9E"}
@@ -39,4 +39,4 @@ export function installStubs(app, ports) {
39
39
  }
40
40
  return doubles;
41
41
  }
42
- //# sourceMappingURL=stub.js.map
42
+ //# sourceMappingURL=Stub.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Stub.js","sourceRoot":"","sources":["../../src/stub/Stub.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAa,MAAM,QAAQ,CAAC;AAQvC,6EAA6E;AAC7E,MAAM,UAAU,SAAS,CAAC,IAAU;IAClC,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAC;IAChC,IAAI,KAAK,GAAkB,IAAI,CAAC,SAAmB,CAAC;IACpD,OAAO,KAAK,IAAI,KAAK,KAAK,MAAM,CAAC,SAAS,EAAE,CAAC;QAC3C,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,mBAAmB,CAAC,KAAK,CAAC,EAAE,CAAC;YACrD,IAAI,IAAI,KAAK,aAAa;gBAAE,SAAS;YACrC,MAAM,QAAQ,GAAG,MAAM,CAAC,wBAAwB,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;YAC9D,IAAI,OAAO,QAAQ,EAAE,KAAK,KAAK,UAAU;gBAAE,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC7D,CAAC;QACD,KAAK,GAAG,MAAM,CAAC,cAAc,CAAC,KAAK,CAAkB,CAAC;IACxD,CAAC;IACD,OAAO,CAAC,GAAG,KAAK,CAAC,CAAC;AACpB,CAAC;AAED,2BAA2B;AAC3B,MAAM,UAAU,MAAM,CAAI,IAAU;IAClC,MAAM,MAAM,GAAyB,EAAE,CAAC;IACxC,KAAK,MAAM,MAAM,IAAI,SAAS,CAAC,IAAI,CAAC;QAAE,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;IAC/D,OAAO,MAAiB,CAAC;AAC3B,CAAC;AAED,yFAAyF;AACzF,MAAM,UAAU,YAAY,CAAC,GAAQ,EAAE,KAAa;IAClD,MAAM,OAAO,GAAG,IAAI,GAAG,EAAuB,CAAC;IAC/C,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,GAAG,CAAC,OAAO,CAAY,SAAS,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IAExF,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;QACjE,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC3B,MAAM,IAAI,KAAK,CACb,UAAU,IAAI,CAAC,IAAI,mDAAmD;kBACpE,sFAAsF,CACzF,CAAC;QACJ,CAAC;QACD,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;QAC5B,KAAK,MAAM,KAAK,IAAI,SAAS;YAAE,KAAK,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QACtE,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAC5B,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC"}
@@ -1,12 +1,6 @@
1
1
  import { type Change, type SchemaDescriptor } from '@fougere/schema';
2
2
  import type { IdentityCard } from '@fougere/core';
3
- /** One entry of `.fougere/remotes.json`, written by `fougere sync`. */
4
- export interface SyncedRemote {
5
- name: string;
6
- url: string;
7
- /** Where the synced classes were written. */
8
- path: string;
9
- }
3
+ import type { SyncedRemote } from './SyncedRemote.js';
10
4
  /** What separates a consumer's synced copy from what the producer serves today. */
11
5
  export interface SyncDrift {
12
6
  frond: string;
@@ -18,12 +12,10 @@ export interface SyncDrift {
18
12
  changes: Change[];
19
13
  }[];
20
14
  }
21
- /** The remotes a project synced, read from the file `fougere sync` writes. */
22
- export declare function syncedRemotes(root: string): Promise<SyncedRemote[]>;
23
15
  /** The shapes a consumer holds for one remote frond. */
24
16
  export declare function heldShapes(remote: SyncedRemote): Promise<Map<string, SchemaDescriptor>>;
25
17
  /** What the consumer's copy no longer matches. */
26
18
  export declare function syncDriftOf(held: Map<string, SchemaDescriptor>, card: IdentityCard, frond: string): SyncDrift;
27
19
  /** Whether the copy still matches. */
28
20
  export declare function inSync(drift: SyncDrift): boolean;
29
- //# sourceMappingURL=sync.d.ts.map
21
+ //# sourceMappingURL=SyncDrift.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SyncDrift.d.ts","sourceRoot":"","sources":["../../src/sync/SyncDrift.ts"],"names":[],"mappings":"AAEA,OAAO,EAAQ,KAAK,MAAM,EAAE,KAAK,gBAAgB,EAAmB,MAAM,iBAAiB,CAAC;AAC5F,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEtD,mFAAmF;AACnF,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,uEAAuE;IACvE,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,gEAAgE;IAChE,KAAK,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,EAAE,CAAA;KAAE,EAAE,CAAC;CAChD;AAED,wDAAwD;AACxD,wBAAsB,UAAU,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC,CAW7F;AAYD,kDAAkD;AAClD,wBAAgB,WAAW,CACzB,IAAI,EAAE,GAAG,CAAC,MAAM,EAAE,gBAAgB,CAAC,EACnC,IAAI,EAAE,YAAY,EAClB,KAAK,EAAE,MAAM,GACZ,SAAS,CAWX;AAED,sCAAsC;AACtC,wBAAgB,MAAM,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAEhD"}
@@ -1,19 +1,6 @@
1
- import { readFile } from 'node:fs/promises';
2
1
  import { join } from 'node:path';
3
2
  import { pathToFileURL } from 'node:url';
4
3
  import { Card } from '@fougere/schema';
5
- /** The remotes a project synced, read from the file `fougere sync` writes. */
6
- export async function syncedRemotes(root) {
7
- try {
8
- const raw = await readFile(join(root, '.fougere', 'remotes.json'), 'utf8');
9
- const parsed = JSON.parse(raw);
10
- return Object.entries(parsed).map(([name, one]) => ({ name, ...one }));
11
- }
12
- catch {
13
- // No file is the ordinary case: an app with no remote synced nothing.
14
- return [];
15
- }
16
- }
17
4
  /** The shapes a consumer holds for one remote frond. */
18
5
  export async function heldShapes(remote) {
19
6
  const cards = new Map();
@@ -27,15 +14,15 @@ export async function heldShapes(remote) {
27
14
  }
28
15
  return cards;
29
16
  }
30
- /** The shapes a card announces, by the name a door carries. */
17
+ /** The shapes a card announces, by the name a facade carries. */
31
18
  function servedShapes(card, frond) {
32
19
  const served = new Map();
33
20
  for (const one of card.fronds) {
34
21
  if (one.name !== frond)
35
22
  continue;
36
- for (const door of one.doors)
37
- if (door.schema)
38
- served.set(door.schema.title ?? door.name, door.schema);
23
+ for (const facade of one.facades)
24
+ if (facade.schema)
25
+ served.set(facade.schema.title ?? facade.name, facade.schema);
39
26
  }
40
27
  return served;
41
28
  }
@@ -59,4 +46,4 @@ export function syncDriftOf(held, card, frond) {
59
46
  export function inSync(drift) {
60
47
  return drift.gone.length === 0 && drift.moved.length === 0;
61
48
  }
62
- //# sourceMappingURL=sync.js.map
49
+ //# sourceMappingURL=SyncDrift.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SyncDrift.js","sourceRoot":"","sources":["../../src/sync/SyncDrift.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,IAAI,EAAuD,MAAM,iBAAiB,CAAC;AAa5F,wDAAwD;AACxD,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,MAAoB;IACnD,MAAM,KAAK,GAAG,IAAI,GAAG,EAA4B,CAAC;IAClD,MAAM,KAAK,GAAG,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC;IAChE,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,KAAK,CAA4B,CAAC;IAE9D,KAAK,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QACtD,MAAM,MAAM,GAAG,QAAkC,CAAC;QAClD,IAAI,OAAO,MAAM,KAAK,UAAU,IAAI,OAAQ,MAAqB,CAAC,SAAS,KAAK,UAAU;YAAE,SAAS;QACrG,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,UAAU,CAAC,CAAC;IACtD,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,iEAAiE;AACjE,SAAS,YAAY,CAAC,IAAkB,EAAE,KAAa;IACrD,MAAM,MAAM,GAAG,IAAI,GAAG,EAAmB,CAAC;IAC1C,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;QAC9B,IAAI,GAAG,CAAC,IAAI,KAAK,KAAK;YAAE,SAAS;QACjC,KAAK,MAAM,MAAM,IAAI,GAAG,CAAC,OAAO;YAAE,IAAI,MAAM,CAAC,MAAM;gBAAE,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,IAAI,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;IACrH,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,kDAAkD;AAClD,MAAM,UAAU,WAAW,CACzB,IAAmC,EACnC,IAAkB,EAClB,KAAa;IAEb,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IACzC,MAAM,KAAK,GAAc,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;IAExD,KAAK,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC;QAChC,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;QAClE,IAAI,CAAC,MAAM,EAAE,CAAC;YAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAAC,SAAS;QAAC,CAAC;QACjD,MAAM,KAAK,GAAG,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,MAA0B,CAAC,CAAC,CAAC;QAC9F,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC;YAAE,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;IAC3F,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,sCAAsC;AACtC,MAAM,UAAU,MAAM,CAAC,KAAgB;IACrC,OAAO,KAAK,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,KAAK,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC;AAC7D,CAAC"}
@@ -0,0 +1,10 @@
1
+ /** One entry of `.fougere/remotes.json`, written by `fougere sync`. */
2
+ export interface SyncedRemote {
3
+ name: string;
4
+ url: string;
5
+ /** Where the synced classes were written. */
6
+ path: string;
7
+ }
8
+ /** The remotes a project synced, read from the file `fougere sync` writes. */
9
+ export declare function syncedRemotes(root: string): Promise<SyncedRemote[]>;
10
+ //# sourceMappingURL=SyncedRemote.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SyncedRemote.d.ts","sourceRoot":"","sources":["../../src/sync/SyncedRemote.ts"],"names":[],"mappings":"AAGA,uEAAuE;AACvE,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,6CAA6C;IAC7C,IAAI,EAAE,MAAM,CAAC;CACd;AAED,8EAA8E;AAC9E,wBAAsB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CASzE"}
@@ -0,0 +1,15 @@
1
+ import { readFile } from 'node:fs/promises';
2
+ import { join } from 'node:path';
3
+ /** The remotes a project synced, read from the file `fougere sync` writes. */
4
+ export async function syncedRemotes(root) {
5
+ try {
6
+ const raw = await readFile(join(root, '.fougere', 'remotes.json'), 'utf8');
7
+ const parsed = JSON.parse(raw);
8
+ return Object.entries(parsed).map(([name, one]) => ({ name, ...one }));
9
+ }
10
+ catch {
11
+ // No file is the ordinary case: an app with no remote synced nothing.
12
+ return [];
13
+ }
14
+ }
15
+ //# sourceMappingURL=SyncedRemote.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SyncedRemote.js","sourceRoot":"","sources":["../../src/sync/SyncedRemote.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAUjC,8EAA8E;AAC9E,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,IAAY;IAC9C,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,UAAU,EAAE,cAAc,CAAC,EAAE,MAAM,CAAC,CAAC;QAC3E,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAkD,CAAC;QAChF,OAAO,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,GAAG,GAAG,EAAE,CAAC,CAAC,CAAC;IACzE,CAAC;IAAC,MAAM,CAAC;QACP,sEAAsE;QACtE,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"vitest.d.ts","sourceRoot":"","sources":["../src/vitest.ts"],"names":[],"mappings":"AAEA,sFAAsF;AACtF,wBAAgB,WAAW,CAAC,SAAS,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAyB5F"}
1
+ {"version":3,"file":"vitest.d.ts","sourceRoot":"","sources":["../src/vitest.ts"],"names":[],"mappings":"AAEA,sFAAsF;AACtF,wBAAgB,WAAW,CAAC,SAAS,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CA6B5F"}
package/dist/vitest.js CHANGED
@@ -16,6 +16,10 @@ export function fougereTest(overrides = {}) {
16
16
  // the fronds when it is about several of them.
17
17
  include: ['tests/**/*.test.ts', 'fronds/*/tests/**/*.test.ts'],
18
18
  server: { deps: { inline: [/@fougere\//, '@pothos/core'] } },
19
+ // A Fougere test boots an app, and a boot runs the scan — a tsc program over the
20
+ // project. Vitest's 5s default times that out on a cold machine, which three
21
+ // packages had each discovered and patched on their own.
22
+ testTimeout: 20_000,
19
23
  },
20
24
  };
21
25
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"vitest.js","sourceRoot":"","sources":["../src/vitest.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,sFAAsF;AACtF,MAAM,UAAU,WAAW,CAAC,SAAS,GAA4B,EAAE;IACjE,MAAM,OAAO,GAAG,aAAa,CAAC,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;IAC/C,IAAI,UAA8B,CAAC;IACnC,IAAI,CAAC;QACH,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC;IACtE,CAAC;IAAC,MAAM,CAAC;QACP,+CAA+C;IACjD,CAAC;IAED,MAAM,IAAI,GAAG;QACX,OAAO,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,UAAU,EAAE,EAAE,MAAM,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACpF,IAAI,EAAE;YACJ,gFAAgF;YAChF,+CAA+C;YAC/C,OAAO,EAAE,CAAC,oBAAoB,EAAE,6BAA6B,CAAC;YAC9D,MAAM,EAAE,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,CAAC,YAAY,EAAE,cAAc,CAAC,EAAE,EAAE;SAC7D;KACF,CAAC;IAEF,OAAO;QACL,GAAG,IAAI;QACP,GAAG,SAAS;QACZ,OAAO,EAAE,EAAE,GAAG,IAAI,CAAC,OAAO,EAAE,GAAG,CAAC,SAAS,CAAC,OAAiB,IAAI,EAAE,CAAC,EAAE;QACpE,IAAI,EAAE,EAAE,GAAG,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC,SAAS,CAAC,IAAc,IAAI,EAAE,CAAC,EAAE;KAC5D,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"vitest.js","sourceRoot":"","sources":["../src/vitest.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,sFAAsF;AACtF,MAAM,UAAU,WAAW,CAAC,SAAS,GAA4B,EAAE;IACjE,MAAM,OAAO,GAAG,aAAa,CAAC,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;IAC/C,IAAI,UAA8B,CAAC;IACnC,IAAI,CAAC;QACH,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC;IACtE,CAAC;IAAC,MAAM,CAAC;QACP,+CAA+C;IACjD,CAAC;IAED,MAAM,IAAI,GAAG;QACX,OAAO,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,UAAU,EAAE,EAAE,MAAM,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACpF,IAAI,EAAE;YACJ,gFAAgF;YAChF,+CAA+C;YAC/C,OAAO,EAAE,CAAC,oBAAoB,EAAE,6BAA6B,CAAC;YAC9D,MAAM,EAAE,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,CAAC,YAAY,EAAE,cAAc,CAAC,EAAE,EAAE;YAC5D,iFAAiF;YACjF,6EAA6E;YAC7E,yDAAyD;YACzD,WAAW,EAAE,MAAM;SACpB;KACF,CAAC;IAEF,OAAO;QACL,GAAG,IAAI;QACP,GAAG,SAAS;QACZ,OAAO,EAAE,EAAE,GAAG,IAAI,CAAC,OAAO,EAAE,GAAG,CAAC,SAAS,CAAC,OAAiB,IAAI,EAAE,CAAC,EAAE;QACpE,IAAI,EAAE,EAAE,GAAG,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC,SAAS,CAAC,IAAc,IAAI,EAAE,CAAC,EAAE;KAC5D,CAAC;AACJ,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fougere/testing",
3
- "version": "0.9.3-alpha.0",
3
+ "version": "0.10.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,22 +34,22 @@
34
34
  ],
35
35
  "dependencies": {
36
36
  "json-schema-faker": "^0.6.3",
37
- "@fougere/container": "0.9.3-alpha.0",
38
- "@fougere/schema": "0.9.3-alpha.0",
39
- "@fougere/compiler": "0.9.3-alpha.0",
40
- "@fougere/defaults": "0.9.3-alpha.0",
41
- "@fougere/app": "0.9.3-alpha.0",
42
- "@fougere/core": "0.9.3-alpha.0",
43
- "@fougere/transport-http": "0.9.3-alpha.0"
37
+ "@fougere/core": "0.10.0-alpha.0",
38
+ "@fougere/transport-http": "0.10.0-alpha.0",
39
+ "@fougere/schema": "0.10.0-alpha.0",
40
+ "@fougere/app": "0.10.0-alpha.0",
41
+ "@fougere/container": "0.10.0-alpha.0",
42
+ "@fougere/defaults": "0.10.0-alpha.0",
43
+ "@fougere/compiler": "0.10.0-alpha.0"
44
44
  },
45
45
  "publishConfig": {
46
46
  "access": "public"
47
47
  },
48
48
  "peerDependencies": {
49
49
  "vitest": ">=2",
50
- "@fougere/observability": "0.9.3-alpha.0",
51
- "@fougere/adapter-sql": "0.9.3-alpha.0",
52
- "@fougere/adapter-graphql": "0.9.3-alpha.0"
50
+ "@fougere/adapter-graphql": "0.10.0-alpha.0",
51
+ "@fougere/observability": "0.10.0-alpha.0",
52
+ "@fougere/adapter-sql": "0.10.0-alpha.0"
53
53
  },
54
54
  "peerDependenciesMeta": {
55
55
  "vitest": {
@@ -67,9 +67,9 @@
67
67
  },
68
68
  "devDependencies": {
69
69
  "vitest": "^4.1.0",
70
- "@fougere/adapter-graphql": "0.9.3-alpha.0",
71
- "@fougere/adapter-sql": "0.9.3-alpha.0",
72
- "@fougere/observability": "0.9.3-alpha.0"
70
+ "@fougere/adapter-sql": "0.10.0-alpha.0",
71
+ "@fougere/adapter-graphql": "0.10.0-alpha.0",
72
+ "@fougere/observability": "0.10.0-alpha.0"
73
73
  },
74
74
  "scripts": {
75
75
  "build": "rm -rf dist && tsc",
@@ -4,9 +4,11 @@ import { Invocation } from '@fougere/core/contract';
4
4
  import { serveRest, serveRpc, tableOf } from '@fougere/app';
5
5
  import { lowerFirst, type SchemaView } from '@fougere/schema';
6
6
  import { listQuery, findQuery, mutationFor, at } from './gql.js';
7
- import { sampleInput, type SampleOptions } from './sample.js';
7
+ import { sampleInput } from './sample.js';
8
+ import type { DoorOptions } from './DoorOptions.js';
9
+ import type { DoorInput } from './DoorInput.js';
8
10
 
9
- /** The rows a door hands back, with its own envelope taken off. */
11
+ /** The rows a facade hands back, with its own envelope taken off. */
10
12
  function rowsOf(value: unknown): unknown {
11
13
  if (Array.isArray(value)) return [...value];
12
14
  const page = value as { items?: unknown } | null;
@@ -23,21 +25,13 @@ function written(value: unknown, sent: Record<string, unknown>): unknown {
23
25
  return wire(Object.fromEntries(Object.keys(sent).map((key) => [key, row[key]])));
24
26
  }
25
27
 
26
- export interface DoorOptions extends SampleOptions {
27
- given?: Record<string, unknown>;
28
- /** The audience, when the app serves named surfaces. */
29
- surface?: string;
30
- }
31
-
32
- interface Doors {
28
+ interface Facades {
33
29
  local: (op: string, call?: DoorInput) => Promise<unknown>;
34
30
  rpc: (op: string, call?: DoorInput) => Promise<unknown>;
35
31
  rest: (op: string, call?: DoorInput) => Promise<unknown>;
36
32
  graphql: (op: string, call?: DoorInput) => Promise<unknown>;
37
33
  }
38
34
 
39
- export interface DoorInput { id?: string; input?: Record<string, unknown> }
40
-
41
35
  export interface DoorContractCase {
42
36
  /** What this case proves — becomes the test name. */
43
37
  name: string;
@@ -48,17 +42,17 @@ export interface DoorContractCase {
48
42
  expected: unknown;
49
43
  }
50
44
 
51
- /** One entity, four doors, the same answers. */
45
+ /** One entity, four facades, the same answers. */
52
46
  export function checkDoors(app: App, entity: SchemaView, options: DoorOptions = {}): void {
53
47
  const name = lowerFirst(entity.name ?? '');
54
- const doors = doorsOf(app, entity, name, options.surface);
48
+ const facades = facadesOf(app, entity, name, options.surface);
55
49
  const inputOf = () => sampleInput(entity, options.given ?? {}, options);
56
50
 
57
- describe(`${entity.name} — the doors agree`, () => {
51
+ describe(`${entity.name} — the facades agree`, () => {
58
52
  it('on create, over what the caller sent', async () => {
59
53
  const sent = inputOf();
60
54
  const answers = await Promise.all(
61
- (['local', 'rpc', 'rest', 'graphql'] as const).map((door) => doors[door]('create', { input: sent })),
55
+ (['local', 'rpc', 'rest', 'graphql'] as const).map((facade) => facades[facade]('create', { input: sent })),
62
56
  );
63
57
 
64
58
  const [local, ...others] = answers.map((answer) => written(answer, sent));
@@ -68,33 +62,33 @@ export function checkDoors(app: App, entity: SchemaView, options: DoorOptions =
68
62
  });
69
63
 
70
64
  it('on list', async () => {
71
- await doors.local('create', { input: inputOf() });
65
+ await facades.local('create', { input: inputOf() });
72
66
 
73
- const local = wire(rowsOf(await doors.local('list')));
67
+ const local = wire(rowsOf(await facades.local('list')));
74
68
  expect(Array.isArray(local) && local.length > 0, 'nothing to compare').toBe(true);
75
69
 
76
- expect(wire(rowsOf(await doors.rpc('list'))), 'rpc ≠ local').toEqual(local);
77
- expect(wire(rowsOf(await doors.rest('list'))), 'rest ≠ local').toEqual(local);
78
- expect(wire(rowsOf(await doors.graphql('list'))), 'graphql ≠ local').toEqual(local);
70
+ expect(wire(rowsOf(await facades.rpc('list'))), 'rpc ≠ local').toEqual(local);
71
+ expect(wire(rowsOf(await facades.rest('list'))), 'rest ≠ local').toEqual(local);
72
+ expect(wire(rowsOf(await facades.graphql('list'))), 'graphql ≠ local').toEqual(local);
79
73
  });
80
74
 
81
75
  it('on findById', async () => {
82
- const row = await doors.local('create', { input: inputOf() }) as { id: string };
76
+ const row = await facades.local('create', { input: inputOf() }) as { id: string };
83
77
 
84
- const local = wire(await doors.local('findById', { id: row.id }));
78
+ const local = wire(await facades.local('findById', { id: row.id }));
85
79
 
86
- expect(wire(await doors.rpc('findById', { id: row.id })), 'rpc ≠ local').toEqual(local);
87
- expect(wire(await doors.rest('findById', { id: row.id })), 'rest ≠ local').toEqual(local);
88
- expect(wire(await doors.graphql('findById', { id: row.id })), 'graphql ≠ local').toEqual(local);
80
+ expect(wire(await facades.rpc('findById', { id: row.id })), 'rpc ≠ local').toEqual(local);
81
+ expect(wire(await facades.rest('findById', { id: row.id })), 'rest ≠ local').toEqual(local);
82
+ expect(wire(await facades.graphql('findById', { id: row.id })), 'graphql ≠ local').toEqual(local);
89
83
  });
90
84
 
91
85
  it('on update, over what the caller sent', async () => {
92
- const rows = await Promise.all([1, 2, 3, 4].map(() => doors.local('create', { input: inputOf() }))) as { id: string }[];
86
+ const rows = await Promise.all([1, 2, 3, 4].map(() => facades.local('create', { input: inputOf() }))) as { id: string }[];
93
87
  const patch = inputOf();
94
88
 
95
89
  const answers = await Promise.all(
96
90
  (['local', 'rpc', 'rest', 'graphql'] as const)
97
- .map((door, index) => doors[door]('update', { id: rows[index].id, input: patch })),
91
+ .map((facade, index) => facades[facade]('update', { id: rows[index].id, input: patch })),
98
92
  );
99
93
 
100
94
  const [local, ...others] = answers.map((answer) => written(answer, patch));
@@ -104,32 +98,32 @@ export function checkDoors(app: App, entity: SchemaView, options: DoorOptions =
104
98
  });
105
99
 
106
100
  it('on delete', async () => {
107
- const rows = await Promise.all([1, 2, 3, 4].map(() => doors.local('create', { input: inputOf() }))) as { id: string }[];
101
+ const rows = await Promise.all([1, 2, 3, 4].map(() => facades.local('create', { input: inputOf() }))) as { id: string }[];
108
102
 
109
103
  const answers = await Promise.all(
110
- (['local', 'rpc', 'rest', 'graphql'] as const).map((door, index) => doors[door]('delete', { id: rows[index].id })),
104
+ (['local', 'rpc', 'rest', 'graphql'] as const).map((facade, index) => facades[facade]('delete', { id: rows[index].id })),
111
105
  );
112
106
 
113
107
  // REST answers a deletion with no content at all, which is the protocol saying yes.
114
108
  const onTheWire = answers.map((answer) => (answer === undefined || answer === null ? true : wire(answer)));
115
- expect(new Set(onTheWire).size, `the doors disagree: ${JSON.stringify(onTheWire)}`).toBe(1);
109
+ expect(new Set(onTheWire).size, `the facades disagree: ${JSON.stringify(onTheWire)}`).toBe(1);
116
110
  });
117
111
 
118
112
  it('on a refusal', async () => {
119
- // A refusal is where the doors diverge most, and where each is most tempted to
113
+ // A refusal is where the facades diverge most, and where each is most tempted to
120
114
  // answer in its own words. What must match is that it WAS refused.
121
115
  const bad = { ...inputOf(), __unknown__: 'x' };
122
116
  const refusals = await Promise.all(
123
- (['local', 'rpc', 'rest', 'graphql'] as const).map((door) => refused(() => doors[door]('create', { input: bad }))),
117
+ (['local', 'rpc', 'rest', 'graphql'] as const).map((facade) => refused(() => facades[facade]('create', { input: bad }))),
124
118
  );
125
119
 
126
120
  expect(refusals[0], 'local accepted a body outside the contract').toBe(true);
127
- expect(refusals, `the doors disagree: ${JSON.stringify(refusals)}`).toEqual([true, true, true, true]);
121
+ expect(refusals, `the facades disagree: ${JSON.stringify(refusals)}`).toEqual([true, true, true, true]);
128
122
  });
129
123
  });
130
124
  }
131
125
 
132
- /** Run one hand-written invocation contract through every door. */
126
+ /** Run one hand-written invocation contract through every facade. */
133
127
  export function checkDoorContract(
134
128
  app: App,
135
129
  entity: SchemaView,
@@ -137,13 +131,13 @@ export function checkDoorContract(
137
131
  options: Pick<DoorOptions, 'surface'> = {},
138
132
  ): void {
139
133
  const name = lowerFirst(entity.name ?? '');
140
- const doors = doorsOf(app, entity, name, options.surface);
134
+ const facades = facadesOf(app, entity, name, options.surface);
141
135
  const names = ['local', 'rpc', 'rest', 'graphql'] as const;
142
136
 
143
- describe(`${entity.name} — its invocation contract crosses every door`, () => {
137
+ describe(`${entity.name} — its invocation contract crosses every facade`, () => {
144
138
  for (const one of cases) {
145
139
  it(one.name, async () => {
146
- const answers = await Promise.all(names.map((door) => doors[door](one.operation, one.input)));
140
+ const answers = await Promise.all(names.map((facade) => facades[facade](one.operation, one.input)));
147
141
  for (const [index, answer] of answers.entries()) {
148
142
  expect(wire(answer), `${names[index]} disagrees with the canonical invocation`).toEqual(wire(one.expected));
149
143
  }
@@ -156,8 +150,8 @@ async function refused(call: () => Promise<unknown>): Promise<boolean> {
156
150
  try { await call(); return false; } catch { return true; }
157
151
  }
158
152
 
159
- /** The four doors, each reduced to `(op, input) => answer` so the tests above read alike. */
160
- function doorsOf(app: App, entity: SchemaView, name: string, surface?: string): Doors {
153
+ /** The four facades, each reduced to `(op, input) => answer` so the tests above read alike. */
154
+ function facadesOf(app: App, entity: SchemaView, name: string, surface?: string): Facades {
161
155
  const run = createLocalRunner(app, surface);
162
156
  const state: Record<string, unknown> = {};
163
157
 
@@ -181,7 +175,7 @@ function doorsOf(app: App, entity: SchemaView, name: string, surface?: string):
181
175
  },
182
176
 
183
177
  rest: async (op, call) => {
184
- // The route the REST door itself would match, read from its own table — rebuilding
178
+ // The route the REST facade itself would match, read from its own table — rebuilding
185
179
  // the path here would be a second opinion on where an entity lives.
186
180
  const route = tableOf(app).find((one) => one.entityName === name && one.operationName === op);
187
181
  if (!route) throw new Error(`[checkDoors] REST serves no ${name}.${op}`);
@@ -0,0 +1 @@
1
+ export interface DoorInput { id?: string; input?: Record<string, unknown> }
@@ -0,0 +1,7 @@
1
+ import { type SampleOptions } from './sample.js';
2
+
3
+ export interface DoorOptions extends SampleOptions {
4
+ given?: Record<string, unknown>;
5
+ /** The audience, when the app serves named surfaces. */
6
+ surface?: string;
7
+ }
package/src/all.ts CHANGED
@@ -1,14 +1,16 @@
1
1
  import { describe, it, expect } from 'vitest';
2
2
  import type { App } from '@fougere/core';
3
3
  import type { SchemaView } from '@fougere/schema';
4
- import { checkContract, checkOutput, type CheckOptions } from './doors.js';
5
- import { checkDoors, type DoorOptions } from './comparison.js';
4
+ import { type CheckOptions } from './facades/CheckOptions.js';
5
+ import { checkContract, checkOutput } from './facades/Verdict.js';
6
+ import { checkDoors } from './DoorContractCase.js';
7
+ import { type DoorOptions } from './DoorOptions.js';
6
8
 
7
9
  export interface CheckAllOptions extends DoorOptions, CheckOptions {
8
10
  /** Entities to leave out, by name — one whose rows a test cannot seed, typically. */
9
11
  except?: string[];
10
- /** Skip the four-door comparison. The contract and the leak are still checked. */
11
- doors?: boolean;
12
+ /** Skip the four-facade comparison. The contract and the leak are still checked. */
13
+ facades?: boolean;
12
14
  }
13
15
 
14
16
  /** Every entity the app SERVES, with its handler. */
@@ -37,6 +39,6 @@ export function checkAll(app: App, options: CheckAllOptions = {}): void {
37
39
  for (const { entity } of served) {
38
40
  checkContract(app, entity, options);
39
41
  checkOutput(app, entity, options);
40
- if (options.doors !== false) checkDoors(app, entity, options);
42
+ if (options.facades !== false) checkDoors(app, entity, options);
41
43
  }
42
44
  }
@@ -2,33 +2,11 @@ import { type App } from '@fougere/core';
2
2
  import { boot } from '@fougere/compiler';
3
3
  import { createContainer } from '@fougere/container';
4
4
  import { resolveStorage, type DbConfig } from '@fougere/defaults';
5
- import { installStubs, type Port, type Stub } from './stub.js';
6
- import { scopeOfRun } from './scope.js';
5
+ import { installStubs, type Stub } from '../stub/Stub.js';
6
+ import type { Port } from '../stub/Port.js';
7
+ import { scopeOfRun } from '../scope.js';
7
8
  import { lowerFirst } from '@fougere/schema';
8
-
9
- export interface TestAppOptions {
10
- /** The project to scan. */
11
- root?: string;
12
- /** Boot only these fronds, by name. Deduced from the position when absent. */
13
- fronds?: string[];
14
- /**
15
- * The running test file, for hosts other than vitest. Vitest is read automatically
16
- * through `expect.getState()`; anything else hands its own path in.
17
- */
18
- testPath?: string;
19
- /** Where the rows go. */
20
- db?: string;
21
- /**
22
- * Follow `remotes:` from the config. False by default — a test that meant to exercise
23
- * one frond should not silently reach for a process that is not running.
24
- */
25
- topology?: boolean;
26
- /**
27
- * Ports answered by a double instead of their realization. A double carries every
28
- * method the port declares and returns nothing until the test says what it returns.
29
- */
30
- stub?: Port[];
31
- }
9
+ import type { TestAppOptions } from './TestAppOptions.js';
32
10
 
33
11
  /** An app, plus the doubles standing in front of its ports and the facts it announced. */
34
12
  export interface TestApp extends App {
@@ -0,0 +1,25 @@
1
+ import type { Port } from '../stub/Port.js';
2
+
3
+ export interface TestAppOptions {
4
+ /** The project to scan. */
5
+ root?: string;
6
+ /** Boot only these fronds, by name. Deduced from the position when absent. */
7
+ fronds?: string[];
8
+ /**
9
+ * The running test file, for hosts other than vitest. Vitest is read automatically
10
+ * through `expect.getState()`; anything else hands its own path in.
11
+ */
12
+ testPath?: string;
13
+ /** Where the rows go. */
14
+ db?: string;
15
+ /**
16
+ * Follow `remotes:` from the config. False by default — a test that meant to exercise
17
+ * one frond should not silently reach for a process that is not running.
18
+ */
19
+ topology?: boolean;
20
+ /**
21
+ * Ports answered by a double instead of their realization. A double carries every
22
+ * method the port declares and returns nothing until the test says what it returns.
23
+ */
24
+ stub?: Port[];
25
+ }
@@ -0,0 +1,6 @@
1
+ import { type SampleOptions } from '../sample.js';
2
+
3
+ export interface CheckOptions extends SampleOptions {
4
+ /** Values the generator cannot invent — the id of a row a `ref()` points at. */
5
+ given?: Record<string, unknown>;
6
+ }
@@ -3,16 +3,17 @@ import { createLocalRunner, validationErrorsOf, type App } from '@fougere/core';
3
3
  import { Invocation } from '@fougere/core/contract';
4
4
  import { lowerFirst, Visibility, type SchemaView, type ValidationError } from '@fougere/schema';
5
5
  import { Cases } from '@fougere/schema';
6
- import { derivedCases } from './derive.js';
7
- import { sampleInput, replaySeed, type SampleOptions } from './sample.js';
6
+ import { derivedCases } from '../derive.js';
7
+ import { sampleInput, replaySeed } from '../sample.js';
8
+ import type { CheckOptions } from './CheckOptions.js';
8
9
 
9
- /** The one shape both the local validator and a door already speak. */
10
+ /** The one shape both the local validator and a facade already speak. */
10
11
  export interface Verdict {
11
12
  success: boolean;
12
13
  errors?: ValidationError[];
13
14
  }
14
15
 
15
- /** What a door answers, in the shape a verdict is compared in. */
16
+ /** What a facade answers, in the shape a verdict is compared in. */
16
17
  export async function verdictOf(call: () => Promise<unknown>): Promise<Verdict> {
17
18
  try {
18
19
  await call();
@@ -29,11 +30,6 @@ function opsFor(entity: SchemaView): { create: string; update: string; name: str
29
30
  return { name, create: 'create', update: 'update' };
30
31
  }
31
32
 
32
- export interface CheckOptions extends SampleOptions {
33
- /** Values the generator cannot invent — the id of a row a `ref()` points at. */
34
- given?: Record<string, unknown>;
35
- }
36
-
37
33
  /** The declared contract, posed to the façade that will receive it. */
38
34
  export function checkContract(app: App, entity: SchemaView, options: CheckOptions = {}): void {
39
35
  const { name, create, update } = opsFor(entity);
package/src/index.ts CHANGED
@@ -1,17 +1,15 @@
1
1
  export { sampleInput } from './sample.js';
2
2
  // The derivation itself lives with the axes it reads.
3
3
  export { Cases, type ValidationCase } from '@fougere/schema';
4
- export { testApp } from './app.js';
5
- export { checkContract, checkOutput, verdictOf, type Verdict } from './doors.js';
6
- export { stubOf, type Port, type Stub } from './stub.js';
4
+ export { testApp } from './app/TestApp.js';
5
+ export { checkContract, checkOutput, verdictOf, type Verdict } from './facades/Verdict.js';
6
+ export { type Port } from './stub/Port.js';
7
+ export { stubOf, type Stub } from './stub/Stub.js';
7
8
  export { frondOf, type Scope } from './scope.js';
8
9
  export { loadScript, reachableOps } from './load.js';
9
10
  export { statementsOf } from './statements.js';
10
11
  export { spansOf } from './spans.js';
11
- export {
12
- checkDoorContract,
13
- checkDoors,
14
- } from './comparison.js';
12
+ export { checkDoorContract, checkDoors } from './DoorContractCase.js';
15
13
  export { at } from './gql.js';
16
14
  export { driftOf, agrees, explain, type CardDrift } from './remotes.js';
17
15
  export { checkAll } from './all.js';