nervur 0.23.0 → 0.24.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/CONTRIBUTING.md +13 -0
- package/LICENSE +55 -202
- package/NOTICE +3 -8
- package/README.md +14 -156
- package/RELEASING.md +15 -0
- package/SECURITY.md +9 -0
- package/bin/nervur.js +6 -0
- package/package.json +26 -81
- package/AUTHORING.md +0 -935
- package/COMMAND.md +0 -179
- package/FACES.md +0 -280
- package/FACULTIES.md +0 -578
- package/GROUNDS.md +0 -315
- package/KIT-SPEC.md +0 -304
- package/WORLD.md +0 -195
- package/dist/app/app-ground.d.ts +0 -18
- package/dist/app/app-ground.js +0 -23
- package/dist/app/index.d.ts +0 -2
- package/dist/app/index.js +0 -5
- package/dist/app/native.d.ts +0 -11
- package/dist/app/native.js +0 -13
- package/dist/being/being.d.ts +0 -306
- package/dist/being/being.js +0 -20
- package/dist/being/covers.d.ts +0 -9
- package/dist/being/covers.js +0 -21
- package/dist/being/index.d.ts +0 -4
- package/dist/being/index.js +0 -6
- package/dist/being/need.d.ts +0 -49
- package/dist/being/need.js +0 -33
- package/dist/being/schema.d.ts +0 -100
- package/dist/being/schema.js +0 -132
- package/dist/being/table.d.ts +0 -48
- package/dist/being/table.js +0 -344
- package/dist/bench/bench-ground.d.ts +0 -73
- package/dist/bench/bench-ground.js +0 -153
- package/dist/bench/bench.d.ts +0 -101
- package/dist/bench/bench.js +0 -368
- package/dist/bench/fake-clock.d.ts +0 -17
- package/dist/bench/fake-clock.js +0 -34
- package/dist/bench/fake-memory.d.ts +0 -16
- package/dist/bench/fake-memory.js +0 -46
- package/dist/bench/fake-network.d.ts +0 -66
- package/dist/bench/fake-network.js +0 -222
- package/dist/bench/fake-unlock.d.ts +0 -6
- package/dist/bench/fake-unlock.js +0 -10
- package/dist/bench/index.d.ts +0 -3
- package/dist/bench/index.js +0 -5
- package/dist/bench/seeded.d.ts +0 -11
- package/dist/bench/seeded.js +0 -37
- package/dist/bench/settle.d.ts +0 -2
- package/dist/bench/settle.js +0 -49
- package/dist/bench/stewards.d.ts +0 -169
- package/dist/bench/stewards.js +0 -128
- package/dist/bodies/class-list.d.ts +0 -14
- package/dist/bodies/class-list.js +0 -33
- package/dist/bodies/joined-carry.d.ts +0 -29
- package/dist/bodies/joined-carry.js +0 -48
- package/dist/bodies/kept.d.ts +0 -44
- package/dist/bodies/kept.js +0 -91
- package/dist/bodies/noble-crypto.d.ts +0 -22
- package/dist/bodies/noble-crypto.js +0 -88
- package/dist/bodies/seed-keys.d.ts +0 -10
- package/dist/bodies/seed-keys.js +0 -42
- package/dist/bodies/strict-tools.d.ts +0 -10
- package/dist/bodies/strict-tools.js +0 -306
- package/dist/bodies/vouch.d.ts +0 -20
- package/dist/bodies/vouch.js +0 -71
- package/dist/bodies/web-carry.d.ts +0 -72
- package/dist/bodies/web-carry.js +0 -245
- package/dist/bodies/web-clock.d.ts +0 -12
- package/dist/bodies/web-clock.js +0 -33
- package/dist/browser/browser-ground.d.ts +0 -76
- package/dist/browser/browser-ground.js +0 -294
- package/dist/browser/index.d.ts +0 -4
- package/dist/browser/index.js +0 -7
- package/dist/browser/indexeddb-memory.d.ts +0 -17
- package/dist/browser/indexeddb-memory.js +0 -97
- package/dist/browser/locked-unlock.d.ts +0 -24
- package/dist/browser/locked-unlock.js +0 -85
- package/dist/browser/origin-classes.d.ts +0 -7
- package/dist/browser/origin-classes.js +0 -31
- package/dist/edge/durable-clock.d.ts +0 -19
- package/dist/edge/durable-clock.js +0 -61
- package/dist/edge/durable-memory.d.ts +0 -5
- package/dist/edge/durable-memory.js +0 -11
- package/dist/edge/durable.d.ts +0 -18
- package/dist/edge/durable.js +0 -24
- package/dist/edge/edge-ground.d.ts +0 -49
- package/dist/edge/edge-ground.js +0 -223
- package/dist/edge/index.d.ts +0 -7
- package/dist/edge/index.js +0 -9
- package/dist/edge/native-crypto.d.ts +0 -8
- package/dist/edge/native-crypto.js +0 -102
- package/dist/edge/secret-unlock.d.ts +0 -7
- package/dist/edge/secret-unlock.js +0 -13
- package/dist/edge/socket-carry.d.ts +0 -39
- package/dist/edge/socket-carry.js +0 -111
- package/dist/foundation.d.ts +0 -162
- package/dist/foundation.js +0 -4
- package/dist/ground/dock.d.ts +0 -1460
- package/dist/ground/dock.js +0 -1159
- package/dist/ground/ground.d.ts +0 -239
- package/dist/ground/ground.js +0 -787
- package/dist/ground/views.d.ts +0 -76
- package/dist/ground/views.js +0 -208
- package/dist/house/crossing.d.ts +0 -50
- package/dist/house/crossing.js +0 -153
- package/dist/house/house.d.ts +0 -88
- package/dist/house/house.js +0 -2069
- package/dist/house/rows-shape.d.ts +0 -110
- package/dist/house/rows-shape.js +0 -12
- package/dist/house/rows.d.ts +0 -27
- package/dist/house/rows.js +0 -185
- package/dist/index.d.ts +0 -33
- package/dist/index.js +0 -29
- package/dist/node/bridge.d.ts +0 -20
- package/dist/node/bridge.js +0 -284
- package/dist/node/cli.d.ts +0 -2
- package/dist/node/cli.js +0 -225
- package/dist/node/file-memory.d.ts +0 -13
- package/dist/node/file-memory.js +0 -86
- package/dist/node/folder-classes.d.ts +0 -5
- package/dist/node/folder-classes.js +0 -40
- package/dist/node/gone.d.ts +0 -2
- package/dist/node/gone.js +0 -7
- package/dist/node/hand.d.ts +0 -39
- package/dist/node/hand.js +0 -107
- package/dist/node/http.d.ts +0 -11
- package/dist/node/http.js +0 -90
- package/dist/node/index.d.ts +0 -11
- package/dist/node/index.js +0 -13
- package/dist/node/ledger-memory.d.ts +0 -17
- package/dist/node/ledger-memory.js +0 -152
- package/dist/node/lock.d.ts +0 -10
- package/dist/node/lock.js +0 -78
- package/dist/node/node-ground.d.ts +0 -26
- package/dist/node/node-ground.js +0 -228
- package/dist/node/notify.d.ts +0 -1
- package/dist/node/notify.js +0 -18
- package/dist/node/shell.d.ts +0 -11
- package/dist/node/shell.js +0 -35
- package/dist/node/sync-folder.d.ts +0 -6
- package/dist/node/sync-folder.js +0 -18
- package/dist/node/tcp-carry.d.ts +0 -42
- package/dist/node/tcp-carry.js +0 -193
- package/dist/node/unlock.d.ts +0 -17
- package/dist/node/unlock.js +0 -86
- package/dist/node/websocket.d.ts +0 -12
- package/dist/node/websocket.js +0 -134
- package/dist/quo/frame.d.ts +0 -33
- package/dist/quo/frame.js +0 -92
- package/dist/quo/index.d.ts +0 -1
- package/dist/quo/index.js +0 -5
- package/dist/quo/room.d.ts +0 -154
- package/dist/quo/room.js +0 -362
- package/dist/serve/index.d.ts +0 -45
- package/dist/serve/index.js +0 -71
package/dist/being/table.js
DELETED
|
@@ -1,344 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
-
// A class resolved: her declaration checked and settled into the table the
|
|
3
|
-
// house reads. Every way a class fails is gathered, and the refusal names
|
|
4
|
-
// each one.
|
|
5
|
-
import { DECLARATION, MEMBERS } from './being.js';
|
|
6
|
-
import { blueprintOf, method, WAIT_BOUND } from './need.js';
|
|
7
|
-
import { outside } from './schema.js';
|
|
8
|
-
/** The roles the house names. */
|
|
9
|
-
export const HOUSE_ROLES = new Set(['handle', 'stranger', 'steward', 'being', 'root']);
|
|
10
|
-
/** The state of a class that names none. */
|
|
11
|
-
export const READY = 'ready';
|
|
12
|
-
/** A class the house will not resolve, and every reason why. */
|
|
13
|
-
export class Refused extends Error {
|
|
14
|
-
reasons;
|
|
15
|
-
constructor(what, reasons) {
|
|
16
|
-
super(`${what} is refused: ${reasons.join('; ')}`);
|
|
17
|
-
this.name = 'Refused';
|
|
18
|
-
this.reasons = reasons;
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
const KIND = /^[a-z][a-z0-9-]*(\.[a-z][a-z0-9-]*){2,}$/;
|
|
22
|
-
const VIEW_BYTES = 65_536;
|
|
23
|
-
const NAME = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
24
|
-
const BLUEPRINT_NAME = /^[a-z][a-z0-9._-]*$/;
|
|
25
|
-
const ENTRY_FIELDS = new Set(['in', 'for', 'to', 'args', 'result', 'hints', 'examples', 'description', 'wait']);
|
|
26
|
-
const METHOD_FIELDS = new Set(['args', 'result', 'hints', 'description', 'wait']);
|
|
27
|
-
const HINTS = new Set(['readOnly', 'idempotent', 'destructive']);
|
|
28
|
-
const EXAMPLE_FIELDS = new Set(['description', 'given', 'role', 'args', 'fakes', 'gives']);
|
|
29
|
-
const STEP_FIELDS = new Set(['ask', 'args', 'role']);
|
|
30
|
-
const EVERY_OBJECT = new Set(Object.getOwnPropertyNames(Object.prototype));
|
|
31
|
-
// The bytes a text takes as UTF-8, where a lone surrogate takes the three of its replacement.
|
|
32
|
-
const utf8Length = (text) => {
|
|
33
|
-
let length = 0;
|
|
34
|
-
for (const char of text) {
|
|
35
|
-
const point = char.codePointAt(0);
|
|
36
|
-
length += point < 0x80 ? 1 : point < 0x800 ? 2 : point < 0x10000 ? 3 : 4;
|
|
37
|
-
}
|
|
38
|
-
return length;
|
|
39
|
-
};
|
|
40
|
-
const plain = (value) => {
|
|
41
|
-
if (typeof value !== 'object' || value === null || Array.isArray(value))
|
|
42
|
-
return false;
|
|
43
|
-
const proto = Object.getPrototypeOf(value);
|
|
44
|
-
return proto === Object.prototype || proto === null;
|
|
45
|
-
};
|
|
46
|
-
/** Whether a value is JSON, as cells and notes hold. */
|
|
47
|
-
export const isJson = (value) => {
|
|
48
|
-
if (value === null || typeof value === 'string' || typeof value === 'boolean')
|
|
49
|
-
return true;
|
|
50
|
-
if (typeof value === 'number')
|
|
51
|
-
return Number.isFinite(value);
|
|
52
|
-
if (Array.isArray(value))
|
|
53
|
-
return value.every(isJson);
|
|
54
|
-
return plain(value) && Object.values(value).every(isJson);
|
|
55
|
-
};
|
|
56
|
-
const names = (value, where, reasons) => {
|
|
57
|
-
if (value === undefined)
|
|
58
|
-
return null;
|
|
59
|
-
const list = typeof value === 'string' ? [value] : value;
|
|
60
|
-
if (!Array.isArray(list) || list.length === 0 || !list.every((name) => typeof name === 'string' && name.length > 0)) {
|
|
61
|
-
reasons.push(`${where} is not a name or a list of names`);
|
|
62
|
-
return [];
|
|
63
|
-
}
|
|
64
|
-
return Object.freeze([...new Set(list)]);
|
|
65
|
-
};
|
|
66
|
-
// Args are always an object: one, or a choice of several, as a reply is.
|
|
67
|
-
const objectSchema = (schema) => schema.type === 'object' || (Array.isArray(schema.anyOf) && schema.anyOf.length > 0 && schema.anyOf.every((branch) => plain(branch) && objectSchema(branch)));
|
|
68
|
-
const methodChecked = (spec, fields, where, reasons) => {
|
|
69
|
-
if (!plain(spec)) {
|
|
70
|
-
reasons.push(`${where} is not an object`);
|
|
71
|
-
return undefined;
|
|
72
|
-
}
|
|
73
|
-
for (const key of Object.keys(spec))
|
|
74
|
-
if (!fields.has(key))
|
|
75
|
-
reasons.push(`${where} names ${key}, which is no field`);
|
|
76
|
-
const { args, result, hints, description, wait } = spec;
|
|
77
|
-
if (wait !== undefined && !(Number.isInteger(wait) && wait > 0 && wait <= WAIT_BOUND))
|
|
78
|
-
reasons.push(`${where}.wait is not a count of milliseconds within five minutes`);
|
|
79
|
-
if (args !== undefined) {
|
|
80
|
-
reasons.push(...outside(args, `${where}.args`));
|
|
81
|
-
if (plain(args) && !objectSchema(args))
|
|
82
|
-
reasons.push(`${where}.args is not an object schema`);
|
|
83
|
-
}
|
|
84
|
-
if (result !== undefined)
|
|
85
|
-
reasons.push(...outside(result, `${where}.result`));
|
|
86
|
-
if (description !== undefined && typeof description !== 'string')
|
|
87
|
-
reasons.push(`${where}.description is not a string`);
|
|
88
|
-
if (hints !== undefined) {
|
|
89
|
-
if (!plain(hints))
|
|
90
|
-
reasons.push(`${where}.hints is not an object`);
|
|
91
|
-
else {
|
|
92
|
-
for (const [key, value] of Object.entries(hints)) {
|
|
93
|
-
if (!HINTS.has(key))
|
|
94
|
-
reasons.push(`${where}.hints names ${key}, which is no hint`);
|
|
95
|
-
else if (typeof value !== 'boolean')
|
|
96
|
-
reasons.push(`${where}.hints.${key} is not true or false`);
|
|
97
|
-
}
|
|
98
|
-
if (hints.readOnly === true && hints.idempotent === false)
|
|
99
|
-
reasons.push(`${where} is readOnly and not idempotent`);
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
return method(spec);
|
|
103
|
-
};
|
|
104
|
-
// A blueprint held to its rules as its author wrote it: a need keeps her
|
|
105
|
-
// methods as written beside the blueprint they settle into, and a program
|
|
106
|
-
// describes one as JSON. Settling drops a field and bounds a wait, so the
|
|
107
|
-
// written methods are what is checked.
|
|
108
|
-
const blueprintChecked = (value, where, reasons) => {
|
|
109
|
-
const settled = blueprintOf(value);
|
|
110
|
-
const written = settled === undefined ? value : { name: settled.name, methods: Object.fromEntries(Object.keys(settled.methods).map((name) => [name, value[name]])) };
|
|
111
|
-
if (!plain(written) || !plain(written.methods)) {
|
|
112
|
-
reasons.push(`${where} is not a need`);
|
|
113
|
-
return undefined;
|
|
114
|
-
}
|
|
115
|
-
const { name } = written;
|
|
116
|
-
if (typeof name !== 'string' || !BLUEPRINT_NAME.test(name))
|
|
117
|
-
reasons.push(`${where} has a name that is no blueprint name`);
|
|
118
|
-
const methods = {};
|
|
119
|
-
for (const [called, spec] of Object.entries(written.methods)) {
|
|
120
|
-
if (!NAME.test(called))
|
|
121
|
-
reasons.push(`${where}.${called} is no method name`);
|
|
122
|
-
const checked = methodChecked(spec, METHOD_FIELDS, `${where}.${called}`, reasons);
|
|
123
|
-
if (checked !== undefined)
|
|
124
|
-
methods[called] = checked;
|
|
125
|
-
}
|
|
126
|
-
return settled ?? Object.freeze({ name: String(name), methods: Object.freeze(methods) });
|
|
127
|
-
};
|
|
128
|
-
/**
|
|
129
|
-
* An offer's blueprint as it arrives, from a need or from a program's
|
|
130
|
-
* describe, held to the rules a need is: a keyword outside the subset,
|
|
131
|
-
* or a field that is none, refuses it where it arrives.
|
|
132
|
-
*/
|
|
133
|
-
export const offered = (value, where = 'the offer') => {
|
|
134
|
-
const reasons = [];
|
|
135
|
-
const blueprint = blueprintChecked(value, where, reasons);
|
|
136
|
-
if (blueprint === undefined || reasons.length > 0)
|
|
137
|
-
throw new Refused(where, reasons);
|
|
138
|
-
return blueprint;
|
|
139
|
-
};
|
|
140
|
-
// Her examples: each a history of her own asks, then the one it shows.
|
|
141
|
-
const examplesChecked = (examples, where, asks, reasons) => {
|
|
142
|
-
if (examples === undefined)
|
|
143
|
-
return [];
|
|
144
|
-
if (!Array.isArray(examples)) {
|
|
145
|
-
reasons.push(`${where}.examples is not a list`);
|
|
146
|
-
return [];
|
|
147
|
-
}
|
|
148
|
-
examples.forEach((example, index) => {
|
|
149
|
-
const at = `${where}.examples[${index}]`;
|
|
150
|
-
if (!plain(example) || !isJson(example)) {
|
|
151
|
-
reasons.push(`${at} is not a JSON object`);
|
|
152
|
-
return;
|
|
153
|
-
}
|
|
154
|
-
for (const key of Object.keys(example))
|
|
155
|
-
if (!EXAMPLE_FIELDS.has(key))
|
|
156
|
-
reasons.push(`${at} names ${key}, which is no field`);
|
|
157
|
-
const given = example.given;
|
|
158
|
-
if (given === undefined)
|
|
159
|
-
return;
|
|
160
|
-
if (!Array.isArray(given)) {
|
|
161
|
-
reasons.push(`${at}.given is not a list`);
|
|
162
|
-
return;
|
|
163
|
-
}
|
|
164
|
-
given.forEach((step, place) => {
|
|
165
|
-
const one = step;
|
|
166
|
-
if (!plain(step) || typeof one.ask !== 'string' || !asks.includes(one.ask))
|
|
167
|
-
reasons.push(`${at}.given[${place}] names no ask of hers`);
|
|
168
|
-
else
|
|
169
|
-
for (const key of Object.keys(step))
|
|
170
|
-
if (!STEP_FIELDS.has(key))
|
|
171
|
-
reasons.push(`${at}.given[${place}] names ${key}, which is no field`);
|
|
172
|
-
});
|
|
173
|
-
});
|
|
174
|
-
return Object.freeze([...examples]);
|
|
175
|
-
};
|
|
176
|
-
/** Her class checked and settled, or refused with every reason. */
|
|
177
|
-
export const resolve = (Class) => {
|
|
178
|
-
const declaration = typeof Class === 'function' ? Class[DECLARATION] : undefined;
|
|
179
|
-
if (declaration === undefined)
|
|
180
|
-
throw new Refused('the class', ['it is not a class of Being.of']);
|
|
181
|
-
const reasons = [];
|
|
182
|
-
const kind = declaration.kind;
|
|
183
|
-
if (typeof kind !== 'string' || !KIND.test(kind))
|
|
184
|
-
reasons.push('its kind is not a reversed domain and a name');
|
|
185
|
-
const what = typeof kind === 'string' ? kind : 'the class';
|
|
186
|
-
if (declaration.description !== undefined && typeof declaration.description !== 'string')
|
|
187
|
-
reasons.push('its description is not a string');
|
|
188
|
-
// A view is data a screen renders, never more than a screen holds.
|
|
189
|
-
if (declaration.view !== undefined && (typeof declaration.view !== 'string' || utf8Length(declaration.view) > VIEW_BYTES))
|
|
190
|
-
reasons.push('its view is not text of at most 64 KiB');
|
|
191
|
-
const cells = declaration.cells ?? {};
|
|
192
|
-
if (!plain(cells) || !isJson(cells))
|
|
193
|
-
reasons.push('its cells are not a JSON object');
|
|
194
|
-
// Needs, each a blueprint under her own member name.
|
|
195
|
-
const needs = {};
|
|
196
|
-
const declaredNeeds = declaration.needs ?? {};
|
|
197
|
-
if (!plain(declaredNeeds))
|
|
198
|
-
reasons.push('its needs are not an object');
|
|
199
|
-
else {
|
|
200
|
-
for (const [member, value] of Object.entries(declaredNeeds)) {
|
|
201
|
-
if (blueprintOf(value) === undefined) {
|
|
202
|
-
reasons.push(`its need ${member} is not a need`);
|
|
203
|
-
continue;
|
|
204
|
-
}
|
|
205
|
-
const blueprint = blueprintChecked(value, `its need ${member}`, reasons);
|
|
206
|
-
if (blueprint !== undefined)
|
|
207
|
-
needs[member] = blueprint;
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
// Roles, the author's tests over the asker and her cells.
|
|
211
|
-
const roles = declaration.roles ?? {};
|
|
212
|
-
if (!plain(roles))
|
|
213
|
-
reasons.push('its roles are not an object');
|
|
214
|
-
for (const [name, test] of Object.entries(plain(roles) ? roles : {})) {
|
|
215
|
-
if (HOUSE_ROLES.has(name))
|
|
216
|
-
reasons.push(`its role ${name} is the house's`);
|
|
217
|
-
if (typeof test !== 'function')
|
|
218
|
-
reasons.push(`its role ${name} is not a function`);
|
|
219
|
-
}
|
|
220
|
-
// Asks, each an entry and a method.
|
|
221
|
-
const asks = {};
|
|
222
|
-
const declaredAsks = declaration.asks;
|
|
223
|
-
if (!plain(declaredAsks))
|
|
224
|
-
reasons.push('its asks are not an object');
|
|
225
|
-
const prototype = Class.prototype;
|
|
226
|
-
for (const [name, entry] of Object.entries(plain(declaredAsks) ? declaredAsks : {})) {
|
|
227
|
-
const where = `its ask ${name}`;
|
|
228
|
-
if (!NAME.test(name))
|
|
229
|
-
reasons.push(`${where} is no method name`);
|
|
230
|
-
const settled = methodChecked(entry, ENTRY_FIELDS, where, reasons);
|
|
231
|
-
if (settled === undefined)
|
|
232
|
-
continue;
|
|
233
|
-
const raw = entry;
|
|
234
|
-
if (typeof prototype[name] !== 'function')
|
|
235
|
-
reasons.push(`${where} has no method`);
|
|
236
|
-
asks[name] = Object.freeze({
|
|
237
|
-
...settled,
|
|
238
|
-
method: name,
|
|
239
|
-
in: names(raw.in, `${where}.in`, reasons),
|
|
240
|
-
for: names(raw.for, `${where}.for`, reasons),
|
|
241
|
-
to: names(raw.to, `${where}.to`, reasons),
|
|
242
|
-
effect: raw.hints?.idempotent === false,
|
|
243
|
-
examples: examplesChecked(raw.examples, where, plain(declaredAsks) ? Object.keys(declaredAsks) : [], reasons),
|
|
244
|
-
});
|
|
245
|
-
}
|
|
246
|
-
// Member names: a need, an ask, a member of Being and her own methods.
|
|
247
|
-
const own = new Set();
|
|
248
|
-
for (let proto = prototype; proto !== null && proto !== Object.prototype; proto = Object.getPrototypeOf(proto)) {
|
|
249
|
-
for (const key of Object.getOwnPropertyNames(proto))
|
|
250
|
-
if (key !== 'constructor')
|
|
251
|
-
own.add(key);
|
|
252
|
-
}
|
|
253
|
-
for (const member of Object.keys(needs)) {
|
|
254
|
-
if (member in asks)
|
|
255
|
-
reasons.push(`its need ${member} and its ask ${member} share a name`);
|
|
256
|
-
if (MEMBERS.has(member))
|
|
257
|
-
reasons.push(`its need ${member} and Being's ${member} share a name`);
|
|
258
|
-
if (own.has(member))
|
|
259
|
-
reasons.push(`its need ${member} and its method ${member} share a name`);
|
|
260
|
-
if (EVERY_OBJECT.has(member))
|
|
261
|
-
reasons.push(`its need ${member} is a member of every object`);
|
|
262
|
-
}
|
|
263
|
-
for (const name of Object.keys(asks)) {
|
|
264
|
-
if (MEMBERS.has(name))
|
|
265
|
-
reasons.push(`its ask ${name} and Being's ${name} share a name`);
|
|
266
|
-
if (EVERY_OBJECT.has(name))
|
|
267
|
-
reasons.push(`its ask ${name} is a member of every object`);
|
|
268
|
-
}
|
|
269
|
-
// The state, and the state of her default cells.
|
|
270
|
-
const state = declaration.state ?? (() => READY);
|
|
271
|
-
let first = READY;
|
|
272
|
-
if (declaration.state !== undefined) {
|
|
273
|
-
if (typeof declaration.state !== 'function')
|
|
274
|
-
reasons.push('its state is not a function');
|
|
275
|
-
else {
|
|
276
|
-
try {
|
|
277
|
-
first = declaration.state({ id: '', position: 'normal', cells: cells });
|
|
278
|
-
}
|
|
279
|
-
catch {
|
|
280
|
-
reasons.push('its state throws on its default cells');
|
|
281
|
-
}
|
|
282
|
-
if (typeof first !== 'string' || first.length === 0)
|
|
283
|
-
reasons.push('its state names no state on its default cells');
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
const states = table(asks, roles, first, declaration.state !== undefined, reasons);
|
|
287
|
-
if (reasons.length > 0)
|
|
288
|
-
throw new Refused(what, reasons);
|
|
289
|
-
return Object.freeze({
|
|
290
|
-
kind,
|
|
291
|
-
...(declaration.description === undefined ? {} : { description: declaration.description }),
|
|
292
|
-
...(declaration.view === undefined ? {} : { view: declaration.view }),
|
|
293
|
-
cells: cells,
|
|
294
|
-
needs: Object.freeze(needs),
|
|
295
|
-
roles: Object.freeze({ ...roles }),
|
|
296
|
-
state: state,
|
|
297
|
-
first,
|
|
298
|
-
states,
|
|
299
|
-
asks: Object.freeze(asks),
|
|
300
|
-
});
|
|
301
|
-
};
|
|
302
|
-
// The table: every state reached from the first, every ask reached by a
|
|
303
|
-
// role, and every role named by an ask. A terminal state is allowed.
|
|
304
|
-
const table = (asks, roles, first, stated, reasons) => {
|
|
305
|
-
const named = new Set([first]);
|
|
306
|
-
for (const entry of Object.values(asks))
|
|
307
|
-
for (const name of [...(entry.in ?? []), ...(entry.to ?? [])])
|
|
308
|
-
named.add(name);
|
|
309
|
-
if (!stated)
|
|
310
|
-
for (const name of named)
|
|
311
|
-
if (name !== READY)
|
|
312
|
-
reasons.push(`it names the state ${name} and has no state of its own`);
|
|
313
|
-
const reached = new Set([first]);
|
|
314
|
-
const queue = [first];
|
|
315
|
-
while (queue.length > 0) {
|
|
316
|
-
const at = queue.shift();
|
|
317
|
-
for (const entry of Object.values(asks)) {
|
|
318
|
-
if (entry.in !== null && !entry.in.includes(at))
|
|
319
|
-
continue;
|
|
320
|
-
for (const next of entry.to ?? [at]) {
|
|
321
|
-
if (reached.has(next))
|
|
322
|
-
continue;
|
|
323
|
-
reached.add(next);
|
|
324
|
-
queue.push(next);
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
}
|
|
328
|
-
for (const name of named)
|
|
329
|
-
if (!reached.has(name))
|
|
330
|
-
reasons.push(`no ask reaches the state ${name}`);
|
|
331
|
-
const declared = new Set(Object.keys(roles));
|
|
332
|
-
const used = new Set();
|
|
333
|
-
for (const entry of Object.values(asks)) {
|
|
334
|
-
for (const role of entry.for ?? []) {
|
|
335
|
-
used.add(role);
|
|
336
|
-
if (!declared.has(role) && !HOUSE_ROLES.has(role))
|
|
337
|
-
reasons.push(`its ask ${entry.method} is for ${role}, which is no role`);
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
for (const role of declared)
|
|
341
|
-
if (!used.has(role))
|
|
342
|
-
reasons.push(`its role ${role} is named by no ask`);
|
|
343
|
-
return Object.freeze([...named]);
|
|
344
|
-
};
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
import { ClassList, Ground, type Body, type Registry } from '../index.ts';
|
|
2
|
-
import { FakeMemory } from './fake-memory.ts';
|
|
3
|
-
import { type FakeNetwork } from './fake-network.ts';
|
|
4
|
-
import { FakeUnlock } from './fake-unlock.ts';
|
|
5
|
-
import { SeededCrypto } from './seeded.ts';
|
|
6
|
-
type BeingClass = ConstructorParameters<typeof ClassList>[0]['steward'];
|
|
7
|
-
type Entry = Parameters<Ground['add']>[1];
|
|
8
|
-
type Standing = Awaited<ReturnType<Ground['add']>>;
|
|
9
|
-
/** A house module: what a folder's index exports. */
|
|
10
|
-
export interface HouseModule {
|
|
11
|
-
readonly steward: BeingClass;
|
|
12
|
-
readonly public?: BeingClass;
|
|
13
|
-
readonly beings?: readonly BeingClass[];
|
|
14
|
-
}
|
|
15
|
-
/** A body the test writes, living, with the kinds it is granted. */
|
|
16
|
-
export type Living = Body & {
|
|
17
|
-
readonly kinds?: readonly string[];
|
|
18
|
-
};
|
|
19
|
-
/** What a ground keeps across its lives: its key, its randomness, its memory, and each house's own where it names the `fake` body. */
|
|
20
|
-
export declare class Machine {
|
|
21
|
-
readonly unlock: FakeUnlock;
|
|
22
|
-
readonly crypto: SeededCrypto;
|
|
23
|
-
readonly memory: FakeMemory;
|
|
24
|
-
readonly houses: Map<string, FakeMemory>;
|
|
25
|
-
constructor(seed: string);
|
|
26
|
-
/** The memory of a house on the `fake` body, which a test may have refuse its next writes. */
|
|
27
|
-
memoryOf(house: string): FakeMemory;
|
|
28
|
-
}
|
|
29
|
-
export interface BenchGroundOptions {
|
|
30
|
-
/** The network it joins, whose clock it reads. */
|
|
31
|
-
readonly network: FakeNetwork;
|
|
32
|
-
/** Its host on the network. */
|
|
33
|
-
readonly host: string;
|
|
34
|
-
/** The names that point at it; a ground with none is a device, and is never dialled. */
|
|
35
|
-
readonly names?: readonly string[];
|
|
36
|
-
/** The house modules its entries name, by name. */
|
|
37
|
-
readonly modules?: Readonly<Record<string, HouseModule>>;
|
|
38
|
-
/** Faculties the test hands living, by name: each stands on its first up, granted the kinds it names. */
|
|
39
|
-
readonly faculties?: Readonly<Record<string, Living>>;
|
|
40
|
-
/** Makers beside the bench's own `module` classes and `fake` memory, as a host installs them. */
|
|
41
|
-
readonly registry?: Registry;
|
|
42
|
-
/** The machine it opens on; a fresh one, seeded by its host, where none is named. */
|
|
43
|
-
readonly machine?: Machine;
|
|
44
|
-
}
|
|
45
|
-
export declare class BenchGround {
|
|
46
|
-
#private;
|
|
47
|
-
readonly host: string;
|
|
48
|
-
readonly machine: Machine;
|
|
49
|
-
private constructor();
|
|
50
|
-
static open(options: BenchGroundOptions): Promise<BenchGround>;
|
|
51
|
-
/** The ground on its machine again, joined to the network, its ladder standing and every house of its drawer open. */
|
|
52
|
-
up(): Promise<void>;
|
|
53
|
-
/** The ground off: its houses closed, its host answering nothing. Its machine keeps everything. */
|
|
54
|
-
down(): Promise<void>;
|
|
55
|
-
/**
|
|
56
|
-
* A house: of a module by that module's name, keeping its places in the
|
|
57
|
-
* ground's memory, or on the whole entry the test gives, custom bodies
|
|
58
|
-
* and all.
|
|
59
|
-
*/
|
|
60
|
-
add(name: string, from?: string | Entry, rest?: Omit<Entry, 'classes'>): Promise<Standing>;
|
|
61
|
-
remove(name: string): Promise<void>;
|
|
62
|
-
list(): readonly Standing[];
|
|
63
|
-
/** A being in a house asked as `root`, the house's steward where no id is named. */
|
|
64
|
-
ask(request: Parameters<Ground['ask']>[0]): ReturnType<Ground['ask']>;
|
|
65
|
-
/** The ground's hand, as its owner holds it: `describe`, or an ask of a being in a house, or of the dock's steward where no house is named. */
|
|
66
|
-
hand(request: Parameters<Ground['hand']>[0]): ReturnType<Ground['hand']>;
|
|
67
|
-
/**
|
|
68
|
-
* A request to the ground's one listener, with no socket: each faculty's
|
|
69
|
-
* handler in turn, the first answer standing, and 404 where none takes it.
|
|
70
|
-
*/
|
|
71
|
-
fetch(request: Request): Promise<Response>;
|
|
72
|
-
}
|
|
73
|
-
export {};
|
|
@@ -1,153 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
-
// A ground in memory. It joins a FakeNetwork under its host, keeps its key
|
|
3
|
-
// and its memory in a machine that outlives it, and opens house modules by
|
|
4
|
-
// name. So a test turns it off, opens it again on the same machine, or
|
|
5
|
-
// moves the machine to another host.
|
|
6
|
-
import { s } from '../being/index.js';
|
|
7
|
-
import { ClassList, Ground } from '../index.js';
|
|
8
|
-
import { FakeMemory } from './fake-memory.js';
|
|
9
|
-
import { clockOf } from './fake-network.js';
|
|
10
|
-
import { FakeUnlock } from './fake-unlock.js';
|
|
11
|
-
import { SeededCrypto } from './seeded.js';
|
|
12
|
-
// Registries' faculties as one, the first first: a name one holds is refused to the next, never replaced.
|
|
13
|
-
const NONE = { args: s.object({}) };
|
|
14
|
-
const joined = (...each) => {
|
|
15
|
-
const all = {};
|
|
16
|
-
for (const faculties of each) {
|
|
17
|
-
for (const [name, faculty] of Object.entries(faculties)) {
|
|
18
|
-
if (Object.hasOwn(all, name))
|
|
19
|
-
throw new TypeError(`the faculty ${name} is the bench's own`);
|
|
20
|
-
all[name] = faculty;
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
return all;
|
|
24
|
-
};
|
|
25
|
-
/** What a ground keeps across its lives: its key, its randomness, its memory, and each house's own where it names the `fake` body. */
|
|
26
|
-
export class Machine {
|
|
27
|
-
unlock;
|
|
28
|
-
// One stream across every life, so a ground opened again never draws the bytes it drew before.
|
|
29
|
-
crypto;
|
|
30
|
-
memory = new FakeMemory();
|
|
31
|
-
houses = new Map();
|
|
32
|
-
constructor(seed) {
|
|
33
|
-
this.unlock = new FakeUnlock(seed);
|
|
34
|
-
this.crypto = new SeededCrypto(seed);
|
|
35
|
-
}
|
|
36
|
-
/** The memory of a house on the `fake` body, which a test may have refuse its next writes. */
|
|
37
|
-
memoryOf(house) {
|
|
38
|
-
return this.houses.get(house) ?? this.houses.set(house, new FakeMemory()).get(house);
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
export class BenchGround {
|
|
42
|
-
host;
|
|
43
|
-
machine;
|
|
44
|
-
#options;
|
|
45
|
-
#ground;
|
|
46
|
-
constructor(options, machine) {
|
|
47
|
-
this.host = options.host;
|
|
48
|
-
this.machine = machine;
|
|
49
|
-
this.#options = options;
|
|
50
|
-
}
|
|
51
|
-
static async open(options) {
|
|
52
|
-
const bench = new BenchGround(options, options.machine ?? new Machine(options.host));
|
|
53
|
-
await bench.up();
|
|
54
|
-
return bench;
|
|
55
|
-
}
|
|
56
|
-
#live() {
|
|
57
|
-
if (this.#ground === undefined)
|
|
58
|
-
throw new Error(`the ground ${this.host} is down`);
|
|
59
|
-
return this.#ground;
|
|
60
|
-
}
|
|
61
|
-
/** The ground on its machine again, joined to the network, its ladder standing and every house of its drawer open. */
|
|
62
|
-
async up() {
|
|
63
|
-
if (this.#ground !== undefined)
|
|
64
|
-
return;
|
|
65
|
-
const { network, host, names = [], modules = {}, faculties = {}, registry = {} } = this.#options;
|
|
66
|
-
network.up(host);
|
|
67
|
-
const machine = this.machine;
|
|
68
|
-
// Each living body the test hands stands through a faculty whose `up` answers it, as any body stands.
|
|
69
|
-
const living = Object.fromEntries(Object.entries(faculties).map(([name, { kinds: _kinds, ...body }]) => [name, { up: () => body }]));
|
|
70
|
-
const own = {
|
|
71
|
-
faculties: {
|
|
72
|
-
'bench-unlock': { takes: NONE, up: () => ({ serves: 'unlock', object: machine.unlock }) },
|
|
73
|
-
'bench-memory': { takes: NONE, up: () => ({ serves: 'memory', object: machine.memory }) },
|
|
74
|
-
seeded: { takes: NONE, up: () => ({ serves: 'crypto', object: machine.crypto }) },
|
|
75
|
-
// The test holds the hand in its own process, so this hand listens on nothing.
|
|
76
|
-
'bench-hand': { takes: NONE, up: () => ({ serves: 'hand' }) },
|
|
77
|
-
'bench-clock': { takes: NONE, up: () => ({ serves: 'clock', object: clockOf(network) }) },
|
|
78
|
-
// Its listener on the network is the ground's one, which its entry names in `faculties`.
|
|
79
|
-
'bench-carry': {
|
|
80
|
-
takes: NONE,
|
|
81
|
-
up: ({ faculties: called }) => {
|
|
82
|
-
const listener = called.listener;
|
|
83
|
-
const serve = async (request) => (await listener.fetch(request)) ?? new Response(null, { status: 404 });
|
|
84
|
-
return { serves: 'carry', schemes: ['bench'], object: network.join(host, { names, listens: names.length > 0, serve }) };
|
|
85
|
-
},
|
|
86
|
-
},
|
|
87
|
-
fake: { takes: NONE, up: () => ({ serves: 'memory', house: ({ house }) => machine.memoryOf(house) }) },
|
|
88
|
-
module: {
|
|
89
|
-
takes: NONE,
|
|
90
|
-
up: () => ({
|
|
91
|
-
serves: 'classes',
|
|
92
|
-
house: ({ args }) => {
|
|
93
|
-
const module = modules[args.name];
|
|
94
|
-
if (module === undefined)
|
|
95
|
-
throw new Error(`no house module ${String(args.name)}`);
|
|
96
|
-
return new ClassList({ steward: module.steward, ...(module.public === undefined ? {} : { public: module.public }), beings: module.beings ?? [] });
|
|
97
|
-
},
|
|
98
|
-
}),
|
|
99
|
-
},
|
|
100
|
-
},
|
|
101
|
-
};
|
|
102
|
-
this.#ground = await Ground.open({
|
|
103
|
-
// The bench's own faculties, then the test's beside them, never in their place.
|
|
104
|
-
registry: { faculties: joined(own.faculties ?? {}, living, registry.faculties ?? {}) },
|
|
105
|
-
primordial: { unlock: { make: 'bench-unlock' }, memory: { make: 'bench-memory' }, crypto: { make: 'seeded' }, tools: { make: 'strict' }, clock: { make: 'bench-clock' }, hand: { make: 'bench-hand' } },
|
|
106
|
-
entries: { listener: { make: 'listener' }, carry: { make: 'bench-carry', faculties: ['listener'] }, module: { make: 'module' }, fake: { make: 'fake' } },
|
|
107
|
-
});
|
|
108
|
-
// Each living faculty stands on its first up, as its owner would stand it through the hand.
|
|
109
|
-
for (const [name, { kinds }] of Object.entries(faculties)) {
|
|
110
|
-
const { why } = await this.#ground.stand(name, { make: name, ...(kinds === undefined ? {} : { kinds }) });
|
|
111
|
-
if (why !== undefined)
|
|
112
|
-
throw new Error(`the faculty ${name} did not stand: ${why}`);
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
/** The ground off: its houses closed, its host answering nothing. Its machine keeps everything. */
|
|
116
|
-
async down() {
|
|
117
|
-
const ground = this.#ground;
|
|
118
|
-
if (ground === undefined)
|
|
119
|
-
return;
|
|
120
|
-
this.#ground = undefined;
|
|
121
|
-
await ground.close();
|
|
122
|
-
this.#options.network.down(this.host);
|
|
123
|
-
}
|
|
124
|
-
/**
|
|
125
|
-
* A house: of a module by that module's name, keeping its places in the
|
|
126
|
-
* ground's memory, or on the whole entry the test gives, custom bodies
|
|
127
|
-
* and all.
|
|
128
|
-
*/
|
|
129
|
-
add(name, from = name, rest = {}) {
|
|
130
|
-
return this.#live().add(name, typeof from === 'string' ? { classes: { faculty: 'module', name: from }, ...rest } : from);
|
|
131
|
-
}
|
|
132
|
-
remove(name) {
|
|
133
|
-
return this.#live().remove(name);
|
|
134
|
-
}
|
|
135
|
-
list() {
|
|
136
|
-
return this.#live().list();
|
|
137
|
-
}
|
|
138
|
-
/** A being in a house asked as `root`, the house's steward where no id is named. */
|
|
139
|
-
ask(request) {
|
|
140
|
-
return this.#live().ask(request);
|
|
141
|
-
}
|
|
142
|
-
/** The ground's hand, as its owner holds it: `describe`, or an ask of a being in a house, or of the dock's steward where no house is named. */
|
|
143
|
-
hand(request) {
|
|
144
|
-
return this.#live().hand(request);
|
|
145
|
-
}
|
|
146
|
-
/**
|
|
147
|
-
* A request to the ground's one listener, with no socket: each faculty's
|
|
148
|
-
* handler in turn, the first answer standing, and 404 where none takes it.
|
|
149
|
-
*/
|
|
150
|
-
async fetch(request) {
|
|
151
|
-
return (await this.#live().handler.fetch(request)) ?? new Response(null, { status: 404 });
|
|
152
|
-
}
|
|
153
|
-
}
|
package/dist/bench/bench.d.ts
DELETED
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
import { type Json, type Table } from '../being/index.ts';
|
|
2
|
-
import type { ClassList, Offer } from '../index.ts';
|
|
3
|
-
type BeingClass = ConstructorParameters<typeof ClassList>[0]['steward'];
|
|
4
|
-
type Position = 'normal' | 'steward' | 'public';
|
|
5
|
-
/** What an ask answered. */
|
|
6
|
-
export type Answer = {
|
|
7
|
-
readonly result: Json;
|
|
8
|
-
} | {
|
|
9
|
-
readonly error: {
|
|
10
|
-
readonly message: string;
|
|
11
|
-
};
|
|
12
|
-
};
|
|
13
|
-
export interface BenchOptions {
|
|
14
|
-
/** Her classes, and any other class her beings meet. */
|
|
15
|
-
readonly classes: readonly BeingClass[];
|
|
16
|
-
/** Fakes of the faculties her needs name. */
|
|
17
|
-
readonly offers?: readonly Offer[];
|
|
18
|
-
/** One seed, so a bench runs the same each time. */
|
|
19
|
-
readonly seed?: string;
|
|
20
|
-
/** Her steward, placed as the author's house's steward; the bench's own where none is given. */
|
|
21
|
-
readonly steward?: BeingClass;
|
|
22
|
-
/** Her public being, placed as the author's house's public being. */
|
|
23
|
-
readonly public?: BeingClass;
|
|
24
|
-
}
|
|
25
|
-
/** Where a check places her: a normal being, the steward, or the public being. */
|
|
26
|
-
export interface CheckOptions {
|
|
27
|
-
readonly classes?: readonly BeingClass[];
|
|
28
|
-
readonly seed?: string;
|
|
29
|
-
readonly position?: Position;
|
|
30
|
-
/** The steward beside her, where she is not it. */
|
|
31
|
-
readonly steward?: BeingClass;
|
|
32
|
-
}
|
|
33
|
-
/** One thing the bench checked: what, and why it failed where it did. */
|
|
34
|
-
export interface Finding {
|
|
35
|
-
readonly ok: boolean;
|
|
36
|
-
readonly what: string;
|
|
37
|
-
readonly why?: string;
|
|
38
|
-
}
|
|
39
|
-
/** What a being shows one asker. */
|
|
40
|
-
interface Described {
|
|
41
|
-
readonly state: string;
|
|
42
|
-
readonly asks: readonly {
|
|
43
|
-
readonly method: string;
|
|
44
|
-
}[];
|
|
45
|
-
}
|
|
46
|
-
/** A being the bench placed, asked and described as any role the bench can play. */
|
|
47
|
-
export declare class Placed {
|
|
48
|
-
#private;
|
|
49
|
-
readonly id: string;
|
|
50
|
-
readonly position: Position;
|
|
51
|
-
constructor(bench: Bench, id: string, position: Position, table: Table);
|
|
52
|
-
/** The role an ask's entry names first; `root` where it names every occupant. */
|
|
53
|
-
roleFor(method: string): string;
|
|
54
|
-
/**
|
|
55
|
-
* One ask, as whoever plays `role`. An effect's answer is the reply it
|
|
56
|
-
* brings once it lands, and `null` is silence.
|
|
57
|
-
*/
|
|
58
|
-
ask(method: string, args?: Json, { role }?: {
|
|
59
|
-
role?: string;
|
|
60
|
-
}): Promise<Answer | null>;
|
|
61
|
-
/** Her describe as `role` sees it: her state and the asks it shows. */
|
|
62
|
-
describe({ role }?: {
|
|
63
|
-
role?: string;
|
|
64
|
-
}): Promise<Described | null>;
|
|
65
|
-
/** Her cells as last landed, read through the hand, as her owner reads them. */
|
|
66
|
-
cells(): Promise<Record<string, Json>>;
|
|
67
|
-
}
|
|
68
|
-
export declare class Bench {
|
|
69
|
-
#private;
|
|
70
|
-
private constructor();
|
|
71
|
-
static open({ classes, offers, seed, steward, public: open }: BenchOptions): Promise<Bench>;
|
|
72
|
-
/**
|
|
73
|
-
* Her class here: the steward or the public being where the bench opened
|
|
74
|
-
* with her there, and otherwise borne by the bench's own steward, from
|
|
75
|
-
* her `born`.
|
|
76
|
-
*/
|
|
77
|
-
place(Class: BeingClass, { id, born }?: {
|
|
78
|
-
id?: string;
|
|
79
|
-
born?: Record<string, Json>;
|
|
80
|
-
}): Promise<Placed>;
|
|
81
|
-
/** Lets every ask, effect and reply the houses started run to its end. */
|
|
82
|
-
settle(): Promise<void>;
|
|
83
|
-
/** The clock moved on, and what came due run. */
|
|
84
|
-
advance(ms: number): Promise<void>;
|
|
85
|
-
/** A placed being's cells, read through the hand. */
|
|
86
|
-
cellsOf(placed: Placed): Promise<Record<string, Json>>;
|
|
87
|
-
/** One ask of a placed being, as whoever plays the role. */
|
|
88
|
-
asked(placed: Placed, table: Table, role: string, method: string, args: Json): Promise<Answer | null>;
|
|
89
|
-
/** What a placed being shows whoever plays the role. */
|
|
90
|
-
described(placed: Placed, table: Table, role: string): Promise<Described | null>;
|
|
91
|
-
/** Every example of her class run, twice, on two fresh benches. */
|
|
92
|
-
static examples(Class: BeingClass, options?: CheckOptions): Promise<Finding[]>;
|
|
93
|
-
/**
|
|
94
|
-
* Every state her `born` and her examples' histories reach, described to
|
|
95
|
-
* every role the bench can play: what each is shown is what her table owes.
|
|
96
|
-
*/
|
|
97
|
-
static walk(Class: BeingClass, options?: CheckOptions): Promise<Finding[]>;
|
|
98
|
-
/** Her examples and her walk, and an error naming every finding that failed. */
|
|
99
|
-
static check(Class: BeingClass, options?: CheckOptions): Promise<Finding[]>;
|
|
100
|
-
}
|
|
101
|
-
export {};
|