@graview/core 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +96 -0
- package/README.md +35 -0
- package/dist/app.d.ts +294 -0
- package/dist/app.d.ts.map +1 -0
- package/dist/app.js +49 -0
- package/dist/app.js.map +1 -0
- package/dist/arrange.d.ts +185 -0
- package/dist/arrange.d.ts.map +1 -0
- package/dist/arrange.js +456 -0
- package/dist/arrange.js.map +1 -0
- package/dist/beginning.d.ts +65 -0
- package/dist/beginning.d.ts.map +1 -0
- package/dist/beginning.js +94 -0
- package/dist/beginning.js.map +1 -0
- package/dist/bind.d.ts +42 -0
- package/dist/bind.d.ts.map +1 -0
- package/dist/bind.js +26 -0
- package/dist/bind.js.map +1 -0
- package/dist/city.d.ts +93 -0
- package/dist/city.d.ts.map +1 -0
- package/dist/city.js +160 -0
- package/dist/city.js.map +1 -0
- package/dist/cli/check/arrangement.d.ts +13 -0
- package/dist/cli/check/arrangement.d.ts.map +1 -0
- package/dist/cli/check/arrangement.js +63 -0
- package/dist/cli/check/arrangement.js.map +1 -0
- package/dist/cli/check/beginnings.d.ts +16 -0
- package/dist/cli/check/beginnings.d.ts.map +1 -0
- package/dist/cli/check/beginnings.js +53 -0
- package/dist/cli/check/beginnings.js.map +1 -0
- package/dist/cli/check/brand.d.ts +17 -0
- package/dist/cli/check/brand.d.ts.map +1 -0
- package/dist/cli/check/brand.js +153 -0
- package/dist/cli/check/brand.js.map +1 -0
- package/dist/cli/check/city.d.ts +17 -0
- package/dist/cli/check/city.d.ts.map +1 -0
- package/dist/cli/check/city.js +58 -0
- package/dist/cli/check/city.js.map +1 -0
- package/dist/cli/check/context.d.ts +50 -0
- package/dist/cli/check/context.d.ts.map +1 -0
- package/dist/cli/check/context.js +37 -0
- package/dist/cli/check/context.js.map +1 -0
- package/dist/cli/check/fields.d.ts +16 -0
- package/dist/cli/check/fields.d.ts.map +1 -0
- package/dist/cli/check/fields.js +237 -0
- package/dist/cli/check/fields.js.map +1 -0
- package/dist/cli/check/index.d.ts +14 -0
- package/dist/cli/check/index.d.ts.map +1 -0
- package/dist/cli/check/index.js +14 -0
- package/dist/cli/check/index.js.map +1 -0
- package/dist/cli/check/intelligence.d.ts +17 -0
- package/dist/cli/check/intelligence.d.ts.map +1 -0
- package/dist/cli/check/intelligence.js +136 -0
- package/dist/cli/check/intelligence.js.map +1 -0
- package/dist/cli/check/lenses.d.ts +17 -0
- package/dist/cli/check/lenses.d.ts.map +1 -0
- package/dist/cli/check/lenses.js +239 -0
- package/dist/cli/check/lenses.js.map +1 -0
- package/dist/cli/check/migrations.d.ts +16 -0
- package/dist/cli/check/migrations.d.ts.map +1 -0
- package/dist/cli/check/migrations.js +43 -0
- package/dist/cli/check/migrations.js.map +1 -0
- package/dist/cli/check/modules.d.ts +16 -0
- package/dist/cli/check/modules.d.ts.map +1 -0
- package/dist/cli/check/modules.js +123 -0
- package/dist/cli/check/modules.js.map +1 -0
- package/dist/cli/check/policy.d.ts +16 -0
- package/dist/cli/check/policy.d.ts.map +1 -0
- package/dist/cli/check/policy.js +90 -0
- package/dist/cli/check/policy.js.map +1 -0
- package/dist/cli/check/relations.d.ts +29 -0
- package/dist/cli/check/relations.d.ts.map +1 -0
- package/dist/cli/check/relations.js +279 -0
- package/dist/cli/check/relations.js.map +1 -0
- package/dist/cli/check/routes.d.ts +16 -0
- package/dist/cli/check/routes.d.ts.map +1 -0
- package/dist/cli/check/routes.js +31 -0
- package/dist/cli/check/routes.js.map +1 -0
- package/dist/cli/check/settings.d.ts +16 -0
- package/dist/cli/check/settings.d.ts.map +1 -0
- package/dist/cli/check/settings.js +81 -0
- package/dist/cli/check/settings.js.map +1 -0
- package/dist/cli/check.d.ts +36 -0
- package/dist/cli/check.d.ts.map +1 -0
- package/dist/cli/check.js +76 -0
- package/dist/cli/check.js.map +1 -0
- package/dist/cli/create.d.ts +20 -0
- package/dist/cli/create.d.ts.map +1 -0
- package/dist/cli/create.js +251 -0
- package/dist/cli/create.js.map +1 -0
- package/dist/cli/describe.d.ts +35 -0
- package/dist/cli/describe.d.ts.map +1 -0
- package/dist/cli/describe.js +230 -0
- package/dist/cli/describe.js.map +1 -0
- package/dist/cli/docs.d.ts +11 -0
- package/dist/cli/docs.d.ts.map +1 -0
- package/dist/cli/docs.js +152 -0
- package/dist/cli/docs.js.map +1 -0
- package/dist/cli/index.d.ts +18 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +281 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/extend.d.ts +23 -0
- package/dist/extend.d.ts.map +1 -0
- package/dist/extend.js +53 -0
- package/dist/extend.js.map +1 -0
- package/dist/graph/diff.d.ts +31 -0
- package/dist/graph/diff.d.ts.map +1 -0
- package/dist/graph/diff.js +71 -0
- package/dist/graph/diff.js.map +1 -0
- package/dist/graph/graph.d.ts +69 -0
- package/dist/graph/graph.d.ts.map +1 -0
- package/dist/graph/graph.js +284 -0
- package/dist/graph/graph.js.map +1 -0
- package/dist/graph/primitives.d.ts +52 -0
- package/dist/graph/primitives.d.ts.map +1 -0
- package/dist/graph/primitives.js +62 -0
- package/dist/graph/primitives.js.map +1 -0
- package/dist/graph/tracked.d.ts +31 -0
- package/dist/graph/tracked.d.ts.map +1 -0
- package/dist/graph/tracked.js +69 -0
- package/dist/graph/tracked.js.map +1 -0
- package/dist/graph/types.d.ts +34 -0
- package/dist/graph/types.d.ts.map +1 -0
- package/dist/graph/types.js +0 -0
- package/dist/graph/types.js.map +1 -0
- package/dist/index.d.ts +100 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +90 -0
- package/dist/index.js.map +1 -0
- package/dist/installation.d.ts +112 -0
- package/dist/installation.d.ts.map +1 -0
- package/dist/installation.js +193 -0
- package/dist/installation.js.map +1 -0
- package/dist/intelligence-bridge.d.ts +73 -0
- package/dist/intelligence-bridge.d.ts.map +1 -0
- package/dist/intelligence-bridge.js +31 -0
- package/dist/intelligence-bridge.js.map +1 -0
- package/dist/invariants/engine.d.ts +36 -0
- package/dist/invariants/engine.d.ts.map +1 -0
- package/dist/invariants/engine.js +88 -0
- package/dist/invariants/engine.js.map +1 -0
- package/dist/invariants/types.d.ts +75 -0
- package/dist/invariants/types.d.ts.map +1 -0
- package/dist/invariants/types.js +2 -0
- package/dist/invariants/types.js.map +1 -0
- package/dist/modules.d.ts +75 -0
- package/dist/modules.d.ts.map +1 -0
- package/dist/modules.js +87 -0
- package/dist/modules.js.map +1 -0
- package/dist/mutations/decidable.d.ts +26 -0
- package/dist/mutations/decidable.d.ts.map +1 -0
- package/dist/mutations/decidable.js +39 -0
- package/dist/mutations/decidable.js.map +1 -0
- package/dist/mutations/define-mutation.d.ts +32 -0
- package/dist/mutations/define-mutation.d.ts.map +1 -0
- package/dist/mutations/define-mutation.js +181 -0
- package/dist/mutations/define-mutation.js.map +1 -0
- package/dist/mutations/derive-edits.d.ts +75 -0
- package/dist/mutations/derive-edits.d.ts.map +1 -0
- package/dist/mutations/derive-edits.js +240 -0
- package/dist/mutations/derive-edits.js.map +1 -0
- package/dist/mutations/form.d.ts +63 -0
- package/dist/mutations/form.d.ts.map +1 -0
- package/dist/mutations/form.js +113 -0
- package/dist/mutations/form.js.map +1 -0
- package/dist/mutations/node-ref.d.ts +83 -0
- package/dist/mutations/node-ref.d.ts.map +1 -0
- package/dist/mutations/node-ref.js +113 -0
- package/dist/mutations/node-ref.js.map +1 -0
- package/dist/mutations/types.d.ts +136 -0
- package/dist/mutations/types.d.ts.map +1 -0
- package/dist/mutations/types.js +2 -0
- package/dist/mutations/types.js.map +1 -0
- package/dist/ops/log.d.ts +35 -0
- package/dist/ops/log.d.ts.map +1 -0
- package/dist/ops/log.js +103 -0
- package/dist/ops/log.js.map +1 -0
- package/dist/ops/types.d.ts +52 -0
- package/dist/ops/types.d.ts.map +1 -0
- package/dist/ops/types.js +2 -0
- package/dist/ops/types.js.map +1 -0
- package/dist/ops/undo.d.ts +33 -0
- package/dist/ops/undo.d.ts.map +1 -0
- package/dist/ops/undo.js +65 -0
- package/dist/ops/undo.js.map +1 -0
- package/dist/permissions/policy.d.ts +68 -0
- package/dist/permissions/policy.d.ts.map +1 -0
- package/dist/permissions/policy.js +191 -0
- package/dist/permissions/policy.js.map +1 -0
- package/dist/permissions/types.d.ts +78 -0
- package/dist/permissions/types.d.ts.map +1 -0
- package/dist/permissions/types.js +17 -0
- package/dist/permissions/types.js.map +1 -0
- package/dist/persistence/memory.d.ts +6 -0
- package/dist/persistence/memory.d.ts.map +1 -0
- package/dist/persistence/memory.js +31 -0
- package/dist/persistence/memory.js.map +1 -0
- package/dist/persistence/sqlite.d.ts +59 -0
- package/dist/persistence/sqlite.d.ts.map +1 -0
- package/dist/persistence/sqlite.js +131 -0
- package/dist/persistence/sqlite.js.map +1 -0
- package/dist/persistence/types.d.ts +22 -0
- package/dist/persistence/types.d.ts.map +1 -0
- package/dist/persistence/types.js +2 -0
- package/dist/persistence/types.js.map +1 -0
- package/dist/presence.d.ts +38 -0
- package/dist/presence.d.ts.map +1 -0
- package/dist/presence.js +50 -0
- package/dist/presence.js.map +1 -0
- package/dist/scaffold/domain.d.ts +8 -0
- package/dist/scaffold/domain.d.ts.map +1 -0
- package/dist/scaffold/domain.js +331 -0
- package/dist/scaffold/domain.js.map +1 -0
- package/dist/scaffold/index.d.ts +66 -0
- package/dist/scaffold/index.d.ts.map +1 -0
- package/dist/scaffold/index.js +142 -0
- package/dist/scaffold/index.js.map +1 -0
- package/dist/scaffold/lens.d.ts +31 -0
- package/dist/scaffold/lens.d.ts.map +1 -0
- package/dist/scaffold/lens.js +176 -0
- package/dist/scaffold/lens.js.map +1 -0
- package/dist/scaffold/names.d.ts +44 -0
- package/dist/scaffold/names.d.ts.map +1 -0
- package/dist/scaffold/names.js +69 -0
- package/dist/scaffold/names.js.map +1 -0
- package/dist/scaffold/project.d.ts +41 -0
- package/dist/scaffold/project.d.ts.map +1 -0
- package/dist/scaffold/project.js +604 -0
- package/dist/scaffold/project.js.map +1 -0
- package/dist/scaffold/ui.d.ts +15 -0
- package/dist/scaffold/ui.d.ts.map +1 -0
- package/dist/scaffold/ui.js +536 -0
- package/dist/scaffold/ui.js.map +1 -0
- package/dist/schema/define-node.d.ts +132 -0
- package/dist/schema/define-node.d.ts.map +1 -0
- package/dist/schema/define-node.js +254 -0
- package/dist/schema/define-node.js.map +1 -0
- package/dist/schema/figures.d.ts +42 -0
- package/dist/schema/figures.d.ts.map +1 -0
- package/dist/schema/figures.js +220 -0
- package/dist/schema/figures.js.map +1 -0
- package/dist/schema/json-schema.d.ts +39 -0
- package/dist/schema/json-schema.d.ts.map +1 -0
- package/dist/schema/json-schema.js +74 -0
- package/dist/schema/json-schema.js.map +1 -0
- package/dist/schema/schema.d.ts +43 -0
- package/dist/schema/schema.d.ts.map +1 -0
- package/dist/schema/schema.js +102 -0
- package/dist/schema/schema.js.map +1 -0
- package/dist/schema/types.d.ts +201 -0
- package/dist/schema/types.d.ts.map +1 -0
- package/dist/schema/types.js +2 -0
- package/dist/schema/types.js.map +1 -0
- package/dist/search.d.ts +215 -0
- package/dist/search.d.ts.map +1 -0
- package/dist/search.js +449 -0
- package/dist/search.js.map +1 -0
- package/dist/settings.d.ts +30 -0
- package/dist/settings.d.ts.map +1 -0
- package/dist/settings.js +74 -0
- package/dist/settings.js.map +1 -0
- package/dist/store.d.ts +284 -0
- package/dist/store.d.ts.map +1 -0
- package/dist/store.js +660 -0
- package/dist/store.js.map +1 -0
- package/dist/studio-door.d.ts +187 -0
- package/dist/studio-door.d.ts.map +1 -0
- package/dist/studio-door.js +20 -0
- package/dist/studio-door.js.map +1 -0
- package/dist/sync/conflict.d.ts +37 -0
- package/dist/sync/conflict.d.ts.map +1 -0
- package/dist/sync/conflict.js +56 -0
- package/dist/sync/conflict.js.map +1 -0
- package/dist/sync/engine.d.ts +118 -0
- package/dist/sync/engine.d.ts.map +1 -0
- package/dist/sync/engine.js +341 -0
- package/dist/sync/engine.js.map +1 -0
- package/dist/sync/google-calendar.d.ts +54 -0
- package/dist/sync/google-calendar.d.ts.map +1 -0
- package/dist/sync/google-calendar.js +167 -0
- package/dist/sync/google-calendar.js.map +1 -0
- package/dist/sync/types.d.ts +125 -0
- package/dist/sync/types.d.ts.map +1 -0
- package/dist/sync/types.js +6 -0
- package/dist/sync/types.js.map +1 -0
- package/dist/temporal/effectivity.d.ts +75 -0
- package/dist/temporal/effectivity.d.ts.map +1 -0
- package/dist/temporal/effectivity.js +89 -0
- package/dist/temporal/effectivity.js.map +1 -0
- package/dist/testing.d.ts +63 -0
- package/dist/testing.d.ts.map +1 -0
- package/dist/testing.js +194 -0
- package/dist/testing.js.map +1 -0
- package/dist/theme/contrast.d.ts +47 -0
- package/dist/theme/contrast.d.ts.map +1 -0
- package/dist/theme/contrast.js +172 -0
- package/dist/theme/contrast.js.map +1 -0
- package/dist/theme/derive.d.ts +81 -0
- package/dist/theme/derive.d.ts.map +1 -0
- package/dist/theme/derive.js +171 -0
- package/dist/theme/derive.js.map +1 -0
- package/dist/theme/kit.d.ts +106 -0
- package/dist/theme/kit.d.ts.map +1 -0
- package/dist/theme/kit.js +84 -0
- package/dist/theme/kit.js.map +1 -0
- package/dist/theme/palettes.d.ts +32 -0
- package/dist/theme/palettes.d.ts.map +1 -0
- package/dist/theme/palettes.js +96 -0
- package/dist/theme/palettes.js.map +1 -0
- package/dist/theme/types.d.ts +131 -0
- package/dist/theme/types.d.ts.map +1 -0
- package/dist/theme/types.js +23 -0
- package/dist/theme/types.js.map +1 -0
- package/dist/views/types.d.ts +89 -0
- package/dist/views/types.d.ts.map +1 -0
- package/dist/views/types.js +88 -0
- package/dist/views/types.js.map +1 -0
- package/dist/watched.d.ts +33 -0
- package/dist/watched.d.ts.map +1 -0
- package/dist/watched.js +50 -0
- package/dist/watched.js.map +1 -0
- package/dist/who.d.ts +26 -0
- package/dist/who.d.ts.map +1 -0
- package/dist/who.js +20 -0
- package/dist/who.js.map +1 -0
- package/package.json +77 -0
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import type { Author } from "../ops/types.js";
|
|
2
|
+
/**
|
|
3
|
+
* How one node kind corresponds to one external resource.
|
|
4
|
+
*
|
|
5
|
+
* Declarative, the way a lens binds roles rather than field names: an app says
|
|
6
|
+
* "a block IS an event, and its start is `dtstart`", and the engine does the
|
|
7
|
+
* rest. No app writes per-field sync code, because per-field sync code is
|
|
8
|
+
* where two-way sync goes wrong — it is written once per field, drifts once
|
|
9
|
+
* per field, and fails silently once per field.
|
|
10
|
+
*/
|
|
11
|
+
export interface ResourceMapping {
|
|
12
|
+
/** The node kind on our side. */
|
|
13
|
+
readonly kind: string;
|
|
14
|
+
/** What the remote calls this thing. */
|
|
15
|
+
readonly resource: string;
|
|
16
|
+
/**
|
|
17
|
+
* Our field name → theirs. Only what is mapped is synced; anything else is
|
|
18
|
+
* ours alone and is never sent, which is the difference between syncing and
|
|
19
|
+
* replicating.
|
|
20
|
+
*/
|
|
21
|
+
readonly fields: Readonly<Record<string, string>>;
|
|
22
|
+
/**
|
|
23
|
+
* Narrows which nodes of the kind participate. A household's shifts may
|
|
24
|
+
* belong on a calendar while its naps do not.
|
|
25
|
+
*/
|
|
26
|
+
readonly match?: (node: Record<string, unknown>) => boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Fields we will send but never accept back. Useful where the remote
|
|
29
|
+
* rewrites something on save — Google normalises a timezone — and echoing
|
|
30
|
+
* that back as "someone changed it" would start a loop.
|
|
31
|
+
*/
|
|
32
|
+
readonly ours?: readonly string[];
|
|
33
|
+
/**
|
|
34
|
+
* Where the two systems disagree about REPRESENTATION, not about names.
|
|
35
|
+
*
|
|
36
|
+
* A mapping is a rename, plus this. The household example stores a block's start as
|
|
37
|
+
* minutes since midnight, and Google wants an RFC 3339 datetime; pretending
|
|
38
|
+
* a rename is enough is how a sync layer ships a field full of nonsense and
|
|
39
|
+
* finds out from a user. Keyed by OUR field name, both directions.
|
|
40
|
+
*
|
|
41
|
+
* `encode` also receives the node, because a conversion often needs a
|
|
42
|
+
* sibling field — minutes are meaningless without a date.
|
|
43
|
+
*/
|
|
44
|
+
readonly encode?: Readonly<Record<string, (value: unknown, node: Record<string, unknown>) => unknown>>;
|
|
45
|
+
readonly decode?: Readonly<Record<string, (value: unknown) => unknown>>;
|
|
46
|
+
}
|
|
47
|
+
export interface SyncMapping {
|
|
48
|
+
/** Names the system, and appears as the author of every inbound change. */
|
|
49
|
+
readonly system: string;
|
|
50
|
+
readonly resources: readonly ResourceMapping[];
|
|
51
|
+
}
|
|
52
|
+
/** One thing the remote says changed. */
|
|
53
|
+
export interface RemoteChange {
|
|
54
|
+
readonly resource: string;
|
|
55
|
+
/** The remote's own id. */
|
|
56
|
+
readonly id: string;
|
|
57
|
+
/**
|
|
58
|
+
* The remote's version of this record — an etag, a sequence number, a
|
|
59
|
+
* timestamp. This is what makes an echo recognisable, so a remote that has
|
|
60
|
+
* none cannot be synced two-way safely and the engine says so.
|
|
61
|
+
*/
|
|
62
|
+
readonly version: string;
|
|
63
|
+
/** Absent when the record was deleted remotely. */
|
|
64
|
+
readonly fields?: Readonly<Record<string, unknown>>;
|
|
65
|
+
readonly deleted?: boolean;
|
|
66
|
+
}
|
|
67
|
+
/** One thing we want the remote to do. */
|
|
68
|
+
export interface RemoteWrite {
|
|
69
|
+
readonly resource: string;
|
|
70
|
+
/** Absent when we are creating; the engine learns the id from the ack. */
|
|
71
|
+
readonly id?: string;
|
|
72
|
+
/** Our node id, so the ack can be matched back without guessing. */
|
|
73
|
+
readonly localId: string;
|
|
74
|
+
readonly fields?: Readonly<Record<string, unknown>>;
|
|
75
|
+
readonly deleted?: boolean;
|
|
76
|
+
}
|
|
77
|
+
/** What the remote did with a write, and the version it produced. */
|
|
78
|
+
export interface RemoteAck {
|
|
79
|
+
readonly localId: string;
|
|
80
|
+
readonly id: string;
|
|
81
|
+
readonly version: string;
|
|
82
|
+
/** Set when the remote refused. The engine keeps the local state and says so. */
|
|
83
|
+
readonly error?: string;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* The transport. Everything Google-specific, or Notion-specific, lives behind
|
|
87
|
+
* these three methods.
|
|
88
|
+
*/
|
|
89
|
+
export interface RemoteSystem {
|
|
90
|
+
readonly name: string;
|
|
91
|
+
/**
|
|
92
|
+
* Everything that changed since `cursor`, and a new cursor. A remote with
|
|
93
|
+
* no incremental API returns everything and a constant cursor; the engine
|
|
94
|
+
* still behaves, it just does more work.
|
|
95
|
+
*/
|
|
96
|
+
pull(cursor?: string): Promise<{
|
|
97
|
+
readonly changes: readonly RemoteChange[];
|
|
98
|
+
readonly cursor: string;
|
|
99
|
+
}>;
|
|
100
|
+
push(writes: readonly RemoteWrite[]): Promise<readonly RemoteAck[]>;
|
|
101
|
+
}
|
|
102
|
+
/** What the engine remembers between runs. */
|
|
103
|
+
export interface SyncState {
|
|
104
|
+
readonly cursor?: string;
|
|
105
|
+
/** Local id → what the remote knows about it. */
|
|
106
|
+
readonly links: Readonly<Record<string, RemoteLink>>;
|
|
107
|
+
/** Writes that have not reached the remote yet. */
|
|
108
|
+
readonly outbox: readonly RemoteWrite[];
|
|
109
|
+
}
|
|
110
|
+
export interface RemoteLink {
|
|
111
|
+
readonly resource: string;
|
|
112
|
+
readonly id: string;
|
|
113
|
+
/**
|
|
114
|
+
* The last version WE caused. An inbound change carrying this version is
|
|
115
|
+
* our own write coming back, and re-applying it is how a naive two-way sync
|
|
116
|
+
* starts a loop.
|
|
117
|
+
*/
|
|
118
|
+
readonly version: string;
|
|
119
|
+
/** The mapped values as of that version, so a genuine conflict is detectable. */
|
|
120
|
+
readonly fields: Readonly<Record<string, unknown>>;
|
|
121
|
+
}
|
|
122
|
+
export declare const EMPTY_SYNC_STATE: SyncState;
|
|
123
|
+
/** The author every inbound change is attributed to. */
|
|
124
|
+
export declare function systemAuthor(system: string): Author;
|
|
125
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/sync/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAE9C;;;;;;;;GAQG;AACH,MAAM,WAAW,eAAe;IAC9B,iCAAiC;IACjC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,wCAAwC;IACxC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B;;;;OAIG;IACH,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAClD;;;OAGG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC;IAC5D;;;;OAIG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,QAAQ,CACxB,MAAM,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,CAC3E,CAAC;IACF,QAAQ,CAAC,MAAM,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC,CAAC,CAAC;CACzE;AAED,MAAM,WAAW,WAAW;IAC1B,2EAA2E;IAC3E,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,SAAS,EAAE,SAAS,eAAe,EAAE,CAAC;CAChD;AAED,yCAAyC;AACzC,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,2BAA2B;IAC3B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,mDAAmD;IACnD,QAAQ,CAAC,MAAM,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACpD,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED,0CAA0C;AAC1C,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,0EAA0E;IAC1E,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC;IACrB,oEAAoE;IACpE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACpD,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED,qEAAqE;AACrE,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,iFAAiF;IACjF,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;QAC7B,QAAQ,CAAC,OAAO,EAAE,SAAS,YAAY,EAAE,CAAC;QAC1C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;KACzB,CAAC,CAAC;IACH,IAAI,CAAC,MAAM,EAAE,SAAS,WAAW,EAAE,GAAG,OAAO,CAAC,SAAS,SAAS,EAAE,CAAC,CAAC;CACrE;AAED,8CAA8C;AAC9C,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,iDAAiD;IACjD,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC;IACrD,mDAAmD;IACnD,QAAQ,CAAC,MAAM,EAAE,SAAS,WAAW,EAAE,CAAC;CACzC;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,iFAAiF;IACjF,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CACpD;AAED,eAAO,MAAM,gBAAgB,EAAE,SAAqC,CAAC;AAErE,wDAAwD;AACxD,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEnD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/sync/types.ts"],"names":[],"mappings":"AAoIA,MAAM,CAAC,MAAM,gBAAgB,GAAc,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;AAErE,wDAAwD;AACxD,MAAM,UAAU,YAAY,CAAC,MAAc;IACzC,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC;AACxC,CAAC"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* WHEN something is true, as a construct the framework owns rather than one
|
|
4
|
+
* each domain invents.
|
|
5
|
+
*
|
|
6
|
+
* Two apps arrived at the same idea from different directions. A household has
|
|
7
|
+
* agreements that come into force and later lapse, and blocks whose recurrence
|
|
8
|
+
* started in September. A club has a team you picked FOR a fixture — the
|
|
9
|
+
* eleven that were true on the fourteenth, not the eleven that are true now.
|
|
10
|
+
* Both are the same question: as of when?
|
|
11
|
+
*
|
|
12
|
+
* Left alone they would have become two constructs with different field names
|
|
13
|
+
* and slightly different edge semantics, and a lens or a rule that wanted to
|
|
14
|
+
* ask "was this true then" would have had to know which app it was in.
|
|
15
|
+
*/
|
|
16
|
+
/** A calendar day, `YYYY-MM-DD`. Not a timestamp: effectivity is a day question. */
|
|
17
|
+
export declare const isoDate: z.ZodString;
|
|
18
|
+
/**
|
|
19
|
+
* The fields a kind spreads into its own to become temporal.
|
|
20
|
+
*
|
|
21
|
+
* Half-open on purpose: `effectiveFrom` includes its day, `effectiveUntil`
|
|
22
|
+
* excludes it. That is the only convention under which two consecutive
|
|
23
|
+
* versions of a thing do not both hold on the day they change over, and
|
|
24
|
+
* getting it wrong is invisible until the one day of the year it matters.
|
|
25
|
+
*/
|
|
26
|
+
export declare const effectivity: {
|
|
27
|
+
effectiveFrom: z.ZodOptional<z.ZodString>;
|
|
28
|
+
effectiveUntil: z.ZodOptional<z.ZodString>;
|
|
29
|
+
};
|
|
30
|
+
export interface Effectivity {
|
|
31
|
+
readonly effectiveFrom?: string | undefined;
|
|
32
|
+
readonly effectiveUntil?: string | undefined;
|
|
33
|
+
}
|
|
34
|
+
/** Whether something holds on a given day. */
|
|
35
|
+
export declare function isEffectiveOn(node: Effectivity, date: string): boolean;
|
|
36
|
+
/** Whether something holds at any point in `[from, until)`. */
|
|
37
|
+
export declare function isEffectiveBetween(node: Effectivity, from: string, until: string): boolean;
|
|
38
|
+
/**
|
|
39
|
+
* A CHECKPOINT: a moment a selection is true as of.
|
|
40
|
+
*
|
|
41
|
+
* This is the construct the framework had avoided, and the reason to admit it
|
|
42
|
+
* is that the alternative is worse. A team picked for a fixture is a
|
|
43
|
+
* relationship between three things — this player, in this position, for this
|
|
44
|
+
* match — and a graph of nodes and edges has no ternary relation.
|
|
45
|
+
*
|
|
46
|
+
* The honest options were: a ternary relation (a new primitive, and every
|
|
47
|
+
* traversal, lens and rule learns about it), or a NODE standing for the moment,
|
|
48
|
+
* with ordinary binary edges to it. The second is what this is, and it is not
|
|
49
|
+
* a workaround: the moment is a real thing in the domain. A coach talks about
|
|
50
|
+
* "the team for Saturday" as an object — names it, changes it, compares it to
|
|
51
|
+
* last week's. Reifying it is admitting what was already true.
|
|
52
|
+
*
|
|
53
|
+
* A checkpoint is any node carrying `at`. What it means to be selected AS OF
|
|
54
|
+
* it is the app's business; what the framework guarantees is one shape.
|
|
55
|
+
*/
|
|
56
|
+
export declare const checkpoint: {
|
|
57
|
+
/** The day this checkpoint stands for. */
|
|
58
|
+
at: z.ZodString;
|
|
59
|
+
};
|
|
60
|
+
export interface Checkpoint {
|
|
61
|
+
readonly id: string;
|
|
62
|
+
readonly at: string;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* The checkpoint in force on a day: the latest one at or before it.
|
|
66
|
+
*
|
|
67
|
+
* "In force" rather than "matching", because a selection made for the
|
|
68
|
+
* fourteenth is still what was true on the fifteenth if nobody has picked a
|
|
69
|
+
* new one — and a lookup that returned nothing on any day without its own
|
|
70
|
+
* checkpoint would make every question about a Tuesday unanswerable.
|
|
71
|
+
*/
|
|
72
|
+
export declare function checkpointOn<C extends Checkpoint>(checkpoints: readonly C[], date: string): C | undefined;
|
|
73
|
+
/** Every checkpoint within `[from, until)`, in order. */
|
|
74
|
+
export declare function checkpointsBetween<C extends Checkpoint>(checkpoints: readonly C[], from: string, until: string): readonly C[];
|
|
75
|
+
//# sourceMappingURL=effectivity.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"effectivity.d.ts","sourceRoot":"","sources":["../../src/temporal/effectivity.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;;;;;;;;;;GAaG;AAEH,oFAAoF;AACpF,eAAO,MAAM,OAAO,aAEkC,CAAC;AAEvD;;;;;;;GAOG;AACH,eAAO,MAAM,WAAW;;;CAGvB,CAAC;AAEF,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5C,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC9C;AAED,8CAA8C;AAC9C,wBAAgB,aAAa,CAAC,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAItE;AAED,+DAA+D;AAC/D,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,WAAW,EACjB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,GACZ,OAAO,CAIT;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,UAAU;IACrB,0CAA0C;;CAE3C,CAAC;AAEF,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,CAAC,SAAS,UAAU,EAC/C,WAAW,EAAE,SAAS,CAAC,EAAE,EACzB,IAAI,EAAE,MAAM,GACX,CAAC,GAAG,SAAS,CAIf;AAED,yDAAyD;AACzD,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,UAAU,EACrD,WAAW,EAAE,SAAS,CAAC,EAAE,EACzB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,GACZ,SAAS,CAAC,EAAE,CAId"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* WHEN something is true, as a construct the framework owns rather than one
|
|
4
|
+
* each domain invents.
|
|
5
|
+
*
|
|
6
|
+
* Two apps arrived at the same idea from different directions. A household has
|
|
7
|
+
* agreements that come into force and later lapse, and blocks whose recurrence
|
|
8
|
+
* started in September. A club has a team you picked FOR a fixture — the
|
|
9
|
+
* eleven that were true on the fourteenth, not the eleven that are true now.
|
|
10
|
+
* Both are the same question: as of when?
|
|
11
|
+
*
|
|
12
|
+
* Left alone they would have become two constructs with different field names
|
|
13
|
+
* and slightly different edge semantics, and a lens or a rule that wanted to
|
|
14
|
+
* ask "was this true then" would have had to know which app it was in.
|
|
15
|
+
*/
|
|
16
|
+
/** A calendar day, `YYYY-MM-DD`. Not a timestamp: effectivity is a day question. */
|
|
17
|
+
export const isoDate = z
|
|
18
|
+
.string()
|
|
19
|
+
.regex(/^\d{4}-\d{2}-\d{2}$/, "expected YYYY-MM-DD");
|
|
20
|
+
/**
|
|
21
|
+
* The fields a kind spreads into its own to become temporal.
|
|
22
|
+
*
|
|
23
|
+
* Half-open on purpose: `effectiveFrom` includes its day, `effectiveUntil`
|
|
24
|
+
* excludes it. That is the only convention under which two consecutive
|
|
25
|
+
* versions of a thing do not both hold on the day they change over, and
|
|
26
|
+
* getting it wrong is invisible until the one day of the year it matters.
|
|
27
|
+
*/
|
|
28
|
+
export const effectivity = {
|
|
29
|
+
effectiveFrom: isoDate.optional(),
|
|
30
|
+
effectiveUntil: isoDate.optional(),
|
|
31
|
+
};
|
|
32
|
+
/** Whether something holds on a given day. */
|
|
33
|
+
export function isEffectiveOn(node, date) {
|
|
34
|
+
if (node.effectiveFrom && date < node.effectiveFrom)
|
|
35
|
+
return false;
|
|
36
|
+
if (node.effectiveUntil && date >= node.effectiveUntil)
|
|
37
|
+
return false;
|
|
38
|
+
return true;
|
|
39
|
+
}
|
|
40
|
+
/** Whether something holds at any point in `[from, until)`. */
|
|
41
|
+
export function isEffectiveBetween(node, from, until) {
|
|
42
|
+
if (node.effectiveFrom && node.effectiveFrom >= until)
|
|
43
|
+
return false;
|
|
44
|
+
if (node.effectiveUntil && node.effectiveUntil <= from)
|
|
45
|
+
return false;
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* A CHECKPOINT: a moment a selection is true as of.
|
|
50
|
+
*
|
|
51
|
+
* This is the construct the framework had avoided, and the reason to admit it
|
|
52
|
+
* is that the alternative is worse. A team picked for a fixture is a
|
|
53
|
+
* relationship between three things — this player, in this position, for this
|
|
54
|
+
* match — and a graph of nodes and edges has no ternary relation.
|
|
55
|
+
*
|
|
56
|
+
* The honest options were: a ternary relation (a new primitive, and every
|
|
57
|
+
* traversal, lens and rule learns about it), or a NODE standing for the moment,
|
|
58
|
+
* with ordinary binary edges to it. The second is what this is, and it is not
|
|
59
|
+
* a workaround: the moment is a real thing in the domain. A coach talks about
|
|
60
|
+
* "the team for Saturday" as an object — names it, changes it, compares it to
|
|
61
|
+
* last week's. Reifying it is admitting what was already true.
|
|
62
|
+
*
|
|
63
|
+
* A checkpoint is any node carrying `at`. What it means to be selected AS OF
|
|
64
|
+
* it is the app's business; what the framework guarantees is one shape.
|
|
65
|
+
*/
|
|
66
|
+
export const checkpoint = {
|
|
67
|
+
/** The day this checkpoint stands for. */
|
|
68
|
+
at: isoDate,
|
|
69
|
+
};
|
|
70
|
+
/**
|
|
71
|
+
* The checkpoint in force on a day: the latest one at or before it.
|
|
72
|
+
*
|
|
73
|
+
* "In force" rather than "matching", because a selection made for the
|
|
74
|
+
* fourteenth is still what was true on the fifteenth if nobody has picked a
|
|
75
|
+
* new one — and a lookup that returned nothing on any day without its own
|
|
76
|
+
* checkpoint would make every question about a Tuesday unanswerable.
|
|
77
|
+
*/
|
|
78
|
+
export function checkpointOn(checkpoints, date) {
|
|
79
|
+
return [...checkpoints]
|
|
80
|
+
.filter((candidate) => candidate.at <= date)
|
|
81
|
+
.sort((a, b) => b.at.localeCompare(a.at))[0];
|
|
82
|
+
}
|
|
83
|
+
/** Every checkpoint within `[from, until)`, in order. */
|
|
84
|
+
export function checkpointsBetween(checkpoints, from, until) {
|
|
85
|
+
return [...checkpoints]
|
|
86
|
+
.filter((candidate) => candidate.at >= from && candidate.at < until)
|
|
87
|
+
.sort((a, b) => a.at.localeCompare(b.at));
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=effectivity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"effectivity.js","sourceRoot":"","sources":["../../src/temporal/effectivity.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;;;;;;;;;;GAaG;AAEH,oFAAoF;AACpF,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC;KACrB,MAAM,EAAE;KACR,KAAK,CAAC,qBAAqB,EAAE,qBAAqB,CAAC,CAAC;AAEvD;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,aAAa,EAAE,OAAO,CAAC,QAAQ,EAAE;IACjC,cAAc,EAAE,OAAO,CAAC,QAAQ,EAAE;CACnC,CAAC;AAOF,8CAA8C;AAC9C,MAAM,UAAU,aAAa,CAAC,IAAiB,EAAE,IAAY;IAC3D,IAAI,IAAI,CAAC,aAAa,IAAI,IAAI,GAAG,IAAI,CAAC,aAAa;QAAE,OAAO,KAAK,CAAC;IAClE,IAAI,IAAI,CAAC,cAAc,IAAI,IAAI,IAAI,IAAI,CAAC,cAAc;QAAE,OAAO,KAAK,CAAC;IACrE,OAAO,IAAI,CAAC;AACd,CAAC;AAED,+DAA+D;AAC/D,MAAM,UAAU,kBAAkB,CAChC,IAAiB,EACjB,IAAY,EACZ,KAAa;IAEb,IAAI,IAAI,CAAC,aAAa,IAAI,IAAI,CAAC,aAAa,IAAI,KAAK;QAAE,OAAO,KAAK,CAAC;IACpE,IAAI,IAAI,CAAC,cAAc,IAAI,IAAI,CAAC,cAAc,IAAI,IAAI;QAAE,OAAO,KAAK,CAAC;IACrE,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,0CAA0C;IAC1C,EAAE,EAAE,OAAO;CACZ,CAAC;AAOF;;;;;;;GAOG;AACH,MAAM,UAAU,YAAY,CAC1B,WAAyB,EACzB,IAAY;IAEZ,OAAO,CAAC,GAAG,WAAW,CAAC;SACpB,MAAM,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,EAAE,IAAI,IAAI,CAAC;SAC3C,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACjD,CAAC;AAED,yDAAyD;AACzD,MAAM,UAAU,kBAAkB,CAChC,WAAyB,EACzB,IAAY,EACZ,KAAa;IAEb,OAAO,CAAC,GAAG,WAAW,CAAC;SACpB,MAAM,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,EAAE,IAAI,IAAI,IAAI,SAAS,CAAC,EAAE,GAAG,KAAK,CAAC;SACnE,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AAC9C,CAAC"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { type GraviewApp } from "./app.js";
|
|
2
|
+
import type { GraphSnapshot } from "./graph/types.js";
|
|
3
|
+
/**
|
|
4
|
+
* A DECLARATION BUILT TO BE AWKWARD.
|
|
5
|
+
*
|
|
6
|
+
* The framework derives an interface from a declaration, so the framework's
|
|
7
|
+
* correctness IS the derivation's correctness — and the derivation was only
|
|
8
|
+
* ever tested against the three apps in this repository, all of which have
|
|
9
|
+
* four or five kinds, short plurals, no chain worth the name, and people who
|
|
10
|
+
* are not part of the domain. A second product with ten kinds found thirty
|
|
11
|
+
* of the consequences in an afternoon, and every one of them was the same
|
|
12
|
+
* sentence: this holds for the examples and stops just past them.
|
|
13
|
+
*
|
|
14
|
+
* So: a generator of the shapes the examples never had, and properties
|
|
15
|
+
* asserted over the derivations rather than screenshots taken of three apps.
|
|
16
|
+
* It ships rather than hiding in a test directory because a PRODUCT wants it
|
|
17
|
+
* too — a lens claiming to be reusable can be built against this, and an
|
|
18
|
+
* app's own views can be held to the same properties as the framework's.
|
|
19
|
+
*
|
|
20
|
+
* Nothing here is random. A generated declaration is a pure function of its
|
|
21
|
+
* options, so a property that fails names a shape rather than a seed.
|
|
22
|
+
*/
|
|
23
|
+
export interface AwkwardOptions {
|
|
24
|
+
/** How many domain kinds. The examples have four; real domains have ten. */
|
|
25
|
+
readonly kinds?: number;
|
|
26
|
+
/**
|
|
27
|
+
* Whether each kind's creating act needs the one before it — the chain
|
|
28
|
+
* that makes a blank installation a queue rather than a menu.
|
|
29
|
+
*/
|
|
30
|
+
readonly chain?: boolean;
|
|
31
|
+
/** Include the installation's kinds, and an edge from the domain to a person. */
|
|
32
|
+
readonly people?: boolean;
|
|
33
|
+
/** A kind nothing creates: the catalogue that arrives with the data. */
|
|
34
|
+
readonly unreachable?: boolean;
|
|
35
|
+
/** Plural length. Long ones are what a district row actually has to hold. */
|
|
36
|
+
readonly plurals?: "short" | "long";
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* An app of the shape a real product has: several kinds, a chain between
|
|
40
|
+
* them, people in the domain, and a kind nothing can make.
|
|
41
|
+
*/
|
|
42
|
+
export declare function awkwardApp(options?: AwkwardOptions): GraviewApp;
|
|
43
|
+
/**
|
|
44
|
+
* Three of every kind, joined to nothing, every field filled with the least
|
|
45
|
+
* interesting value that parses.
|
|
46
|
+
*
|
|
47
|
+
* It is the state a real installation passes through on its second
|
|
48
|
+
* afternoon — some ground named, some concerns raised, none of it joined up
|
|
49
|
+
* — and it is the state that breaks anything written while looking at a
|
|
50
|
+
* finished graph.
|
|
51
|
+
*/
|
|
52
|
+
export interface AwkwardGraphOptions {
|
|
53
|
+
readonly per?: number;
|
|
54
|
+
/**
|
|
55
|
+
* Values for fields this cannot guess — a discriminated union, a tuple
|
|
56
|
+
* with a meaning. Keyed `kind.field`, and each is offered to the field's
|
|
57
|
+
* own schema like any other candidate, so a wrong one is a refusal here
|
|
58
|
+
* rather than a mystery three layers down.
|
|
59
|
+
*/
|
|
60
|
+
readonly fill?: Readonly<Record<string, unknown>>;
|
|
61
|
+
}
|
|
62
|
+
export declare function awkwardGraph(app: GraviewApp, options?: number | AwkwardGraphOptions): GraphSnapshot;
|
|
63
|
+
//# sourceMappingURL=testing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"testing.d.ts","sourceRoot":"","sources":["../src/testing.ts"],"names":[],"mappings":"AACA,OAAO,EAAa,KAAK,UAAU,EAAE,MAAM,UAAU,CAAC;AAMtD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEtD;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,MAAM,WAAW,cAAc;IAC7B,4EAA4E;IAC5E,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB;;;OAGG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IACzB,iFAAiF;IACjF,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAC1B,wEAAwE;IACxE,QAAQ,CAAC,WAAW,CAAC,EAAE,OAAO,CAAC;IAC/B,6EAA6E;IAC7E,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;CACrC;AA6CD;;;GAGG;AACH,wBAAgB,UAAU,CAAC,OAAO,GAAE,cAAmB,GAAG,UAAU,CAuEnE;AA6CD;;;;;;;;GAQG;AACH,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB;;;;;OAKG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CACnD;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,UAAU,EAAE,OAAO,GAAE,MAAM,GAAG,mBAAwB,GAAG,aAAa,CA+BvG"}
|
package/dist/testing.js
ADDED
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { defineApp } from "./app.js";
|
|
3
|
+
import { declareInstallation } from "./installation.js";
|
|
4
|
+
import { bindSchema } from "./bind.js";
|
|
5
|
+
import { nodeRef } from "./mutations/node-ref.js";
|
|
6
|
+
import { createSchema } from "./schema/schema.js";
|
|
7
|
+
import { defineNode } from "./schema/define-node.js";
|
|
8
|
+
/* Plurals of the length a real domain has. The district row breaks on these
|
|
9
|
+
and never on "Jobs", which is why the examples never found it. */
|
|
10
|
+
const LONG = [
|
|
11
|
+
["responsibility", "Responsibilities"],
|
|
12
|
+
["consideration", "Considerations"],
|
|
13
|
+
["practicality", "Practicalities"],
|
|
14
|
+
["arrangement", "Arrangements"],
|
|
15
|
+
["requirement", "Requirements"],
|
|
16
|
+
["observation", "Observations"],
|
|
17
|
+
["preparation", "Preparations"],
|
|
18
|
+
["description", "Descriptions"],
|
|
19
|
+
["measurement", "Measurements"],
|
|
20
|
+
["instruction", "Instructions"],
|
|
21
|
+
["expectation", "Expectations"],
|
|
22
|
+
["certification", "Certifications"],
|
|
23
|
+
["qualification", "Qualifications"],
|
|
24
|
+
["recommendation", "Recommendations"],
|
|
25
|
+
];
|
|
26
|
+
const SHORT = [
|
|
27
|
+
["zone", "Zones"],
|
|
28
|
+
["bed", "Beds"],
|
|
29
|
+
["tool", "Tools"],
|
|
30
|
+
["job", "Jobs"],
|
|
31
|
+
["note", "Notes"],
|
|
32
|
+
["run", "Runs"],
|
|
33
|
+
["plot", "Plots"],
|
|
34
|
+
["crew", "Crews"],
|
|
35
|
+
["kit", "Kits"],
|
|
36
|
+
["bay", "Bays"],
|
|
37
|
+
["dock", "Docks"],
|
|
38
|
+
["lane", "Lanes"],
|
|
39
|
+
["yard", "Yards"],
|
|
40
|
+
["gate", "Gates"],
|
|
41
|
+
];
|
|
42
|
+
/** A name for kind number `index`, and the plural a district has to draw. */
|
|
43
|
+
function named(index, plurals) {
|
|
44
|
+
const words = plurals === "long" ? LONG : SHORT;
|
|
45
|
+
const [singular, plural] = words[index % words.length];
|
|
46
|
+
const suffix = index >= words.length ? String(index) : "";
|
|
47
|
+
return { kind: `${singular}${suffix}`, plural: `${plural}${suffix}` };
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* An app of the shape a real product has: several kinds, a chain between
|
|
51
|
+
* them, people in the domain, and a kind nothing can make.
|
|
52
|
+
*/
|
|
53
|
+
export function awkwardApp(options = {}) {
|
|
54
|
+
const count = Math.max(1, options.kinds ?? 10);
|
|
55
|
+
const plurals = options.plurals ?? "long";
|
|
56
|
+
const people = options.people ?? true;
|
|
57
|
+
const installation = declareInstallation({ roles: ["keeper", "helper"], admin: "keeper", required: true });
|
|
58
|
+
const names = Array.from({ length: count }, (_, index) => named(index, plurals));
|
|
59
|
+
const definitions = names.map(({ kind, plural }, index) => defineNode(kind, {
|
|
60
|
+
fields: z.object({ label: z.string() }),
|
|
61
|
+
plural,
|
|
62
|
+
...(index === 0 && people
|
|
63
|
+
? {
|
|
64
|
+
edges: {
|
|
65
|
+
"kept-by": { to: ["user"], description: "who looks after it", inverse: "what they keep" },
|
|
66
|
+
},
|
|
67
|
+
}
|
|
68
|
+
: {}),
|
|
69
|
+
}));
|
|
70
|
+
const catalogue = options.unreachable
|
|
71
|
+
? [defineNode("almanac", { fields: z.object({ label: z.string() }), plural: "Almanacs" })]
|
|
72
|
+
: [];
|
|
73
|
+
const schema = createSchema([
|
|
74
|
+
...definitions,
|
|
75
|
+
...catalogue,
|
|
76
|
+
...(people ? [...installation.kinds] : []),
|
|
77
|
+
]);
|
|
78
|
+
const { defineMutation } = bindSchema(schema);
|
|
79
|
+
const acts = names.map(({ kind }, index) => {
|
|
80
|
+
const needs = options.chain !== false && index > 0 ? names[index - 1].kind : undefined;
|
|
81
|
+
return defineMutation(`add-${kind}`, {
|
|
82
|
+
title: `Add ${kind}`,
|
|
83
|
+
/* Well-formed in every way but its SHAPE: a fixture that trips the
|
|
84
|
+
checker on its own carelessness proves nothing about the shapes it
|
|
85
|
+
exists to test. */
|
|
86
|
+
description: `Adds ${kind} to the graph.`,
|
|
87
|
+
creates: [kind],
|
|
88
|
+
/* A real chain: the argument is a nodeRef, which is what makes the
|
|
89
|
+
act unofferable until something exists to point it at. */
|
|
90
|
+
input: needs
|
|
91
|
+
? z.object({ label: z.string(), [`${needs}Id`]: nodeRef([needs]) })
|
|
92
|
+
: z.object({ label: z.string() }),
|
|
93
|
+
apply(ctx, args) {
|
|
94
|
+
ctx.addNode({ id: ctx.freshId(String(args["label"]), kind), kind, label: args["label"] });
|
|
95
|
+
},
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
return defineApp({
|
|
99
|
+
name: "awkward",
|
|
100
|
+
schema: schema,
|
|
101
|
+
mutations: [...acts, ...(people ? installation.mutations : [])],
|
|
102
|
+
...(people
|
|
103
|
+
? {
|
|
104
|
+
modules: installation.modules,
|
|
105
|
+
policy: installation.withPolicy({
|
|
106
|
+
roles: ["keeper", "helper"],
|
|
107
|
+
grants: [
|
|
108
|
+
{
|
|
109
|
+
roles: ["keeper"],
|
|
110
|
+
mutations: "*",
|
|
111
|
+
describe: "The keeper keeps all of it.",
|
|
112
|
+
},
|
|
113
|
+
],
|
|
114
|
+
}),
|
|
115
|
+
}
|
|
116
|
+
: {}),
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
/** A graph with `per` of each kind the app declares, and the edges between them. */
|
|
120
|
+
/**
|
|
121
|
+
* A VALUE THAT PARSES, found rather than known.
|
|
122
|
+
*
|
|
123
|
+
* The first version of this filled three field names it had met — `email`,
|
|
124
|
+
* `roles`, `status` — which was enough for the fixtures it was written
|
|
125
|
+
* beside and enough for nothing else. The first real product to reach for
|
|
126
|
+
* it got `zone 0 does not match what zone declares`, because a zone has a
|
|
127
|
+
* surface and nobody had told this about surfaces.
|
|
128
|
+
*
|
|
129
|
+
* So it asks. Each candidate is offered to the field's own schema and the
|
|
130
|
+
* first one accepted is used, which means a kind can declare whatever it
|
|
131
|
+
* likes — an enum, a date, a tuple of numbers — without this having to
|
|
132
|
+
* have heard of it. `undefined` goes first so an optional field stays
|
|
133
|
+
* unset: the awkward graph should be the SPARSEST one that parses, not the
|
|
134
|
+
* fullest.
|
|
135
|
+
*/
|
|
136
|
+
function parseable(field, hint) {
|
|
137
|
+
const schema = field;
|
|
138
|
+
if (typeof schema?.safeParse !== "function")
|
|
139
|
+
return { found: false };
|
|
140
|
+
const entries = schema.def?.entries;
|
|
141
|
+
const enumerated = entries && typeof entries === "object" ? Object.values(entries) : [];
|
|
142
|
+
const candidates = [
|
|
143
|
+
undefined,
|
|
144
|
+
...enumerated,
|
|
145
|
+
hint,
|
|
146
|
+
"2026-05-04",
|
|
147
|
+
`${hint}@example.test`,
|
|
148
|
+
1,
|
|
149
|
+
0,
|
|
150
|
+
true,
|
|
151
|
+
[],
|
|
152
|
+
[hint],
|
|
153
|
+
{},
|
|
154
|
+
{ x: 0.5, y: 0.5 },
|
|
155
|
+
null,
|
|
156
|
+
];
|
|
157
|
+
for (const candidate of candidates) {
|
|
158
|
+
if (schema.safeParse(candidate).success)
|
|
159
|
+
return { found: true, value: candidate };
|
|
160
|
+
}
|
|
161
|
+
return { found: false };
|
|
162
|
+
}
|
|
163
|
+
export function awkwardGraph(app, options = {}) {
|
|
164
|
+
const { per = 3, fill = {} } = typeof options === "number" ? { per: options, fill: {} } : options;
|
|
165
|
+
const nodes = [];
|
|
166
|
+
for (const kind of app.schema.kinds) {
|
|
167
|
+
const definition = app.schema.tryDefinition(kind);
|
|
168
|
+
const shape = (definition?.fields.shape ?? {});
|
|
169
|
+
for (let index = 0; index < per; index += 1) {
|
|
170
|
+
const node = { id: `${kind}-${index}`, kind, label: `${kind} ${index}` };
|
|
171
|
+
for (const [name, field] of Object.entries(shape)) {
|
|
172
|
+
if (name === "id" || name === "kind" || name === "label")
|
|
173
|
+
continue;
|
|
174
|
+
const given = fill[`${kind}.${name}`];
|
|
175
|
+
const answer = given === undefined
|
|
176
|
+
? parseable(field, `${kind}-${index}`)
|
|
177
|
+
: field.safeParse(given).success
|
|
178
|
+
? { found: true, value: given }
|
|
179
|
+
: { found: false };
|
|
180
|
+
if (!answer.found) {
|
|
181
|
+
throw new Error(given === undefined
|
|
182
|
+
? `awkwardGraph cannot fill ${kind}.${name}: none of the values it knows how to offer were accepted. ` +
|
|
183
|
+
`Pass one it cannot guess as fill: { "${kind}.${name}": … }.`
|
|
184
|
+
: `awkwardGraph was given a fill for ${kind}.${name} that ${kind} does not accept.`);
|
|
185
|
+
}
|
|
186
|
+
if (answer.value !== undefined)
|
|
187
|
+
node[name] = answer.value;
|
|
188
|
+
}
|
|
189
|
+
nodes.push(node);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
return { nodes: nodes, edges: [] };
|
|
193
|
+
}
|
|
194
|
+
//# sourceMappingURL=testing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"testing.js","sourceRoot":"","sources":["../src/testing.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { type ThemeTokens } from "./types.js";
|
|
2
|
+
/** Straight sRGB, 0–255, with alpha 0–1. */
|
|
3
|
+
export interface Rgba {
|
|
4
|
+
readonly r: number;
|
|
5
|
+
readonly g: number;
|
|
6
|
+
readonly b: number;
|
|
7
|
+
readonly a: number;
|
|
8
|
+
}
|
|
9
|
+
/** sRGB back to HSL, so a colour can be moved in lightness and stay itself. */
|
|
10
|
+
export declare function rgbToHsl(colour: Rgba): {
|
|
11
|
+
h: number;
|
|
12
|
+
s: number;
|
|
13
|
+
l: number;
|
|
14
|
+
};
|
|
15
|
+
export declare function hsl(h: number, s: number, l: number): Rgba;
|
|
16
|
+
/**
|
|
17
|
+
* Every colour a token value mentions.
|
|
18
|
+
*
|
|
19
|
+
* A gradient is not one colour and pretending otherwise is how a check passes
|
|
20
|
+
* on a value it never looked at. `bar` and `float` are gradients in both
|
|
21
|
+
* built-in schemes; a pair drawn on one owes its contrast against the WORST
|
|
22
|
+
* stop, because that is where the text will be at some point along it.
|
|
23
|
+
*/
|
|
24
|
+
export declare function coloursIn(value: string): Rgba[];
|
|
25
|
+
/** One colour laid over another, straight alpha. */
|
|
26
|
+
export declare function composite(over: Rgba, under: Rgba): Rgba;
|
|
27
|
+
export declare function luminance(colour: Rgba): number;
|
|
28
|
+
/** WCAG 2.1 contrast ratio, 1 to 21. */
|
|
29
|
+
export declare function contrast(a: Rgba, b: Rgba): number;
|
|
30
|
+
export interface ContrastFinding {
|
|
31
|
+
readonly ink: string;
|
|
32
|
+
readonly on: string;
|
|
33
|
+
readonly where: string;
|
|
34
|
+
readonly ratio: number;
|
|
35
|
+
readonly requires: number;
|
|
36
|
+
/** Set when a value could not be read at all, rather than read and failed. */
|
|
37
|
+
readonly unreadable?: string;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Every text pair in a palette, measured.
|
|
41
|
+
*
|
|
42
|
+
* Returns the failures AND the unreadable values. A token this cannot parse
|
|
43
|
+
* is reported rather than skipped: silently passing a value nobody looked at
|
|
44
|
+
* is exactly the failure mode a contrast check exists to prevent.
|
|
45
|
+
*/
|
|
46
|
+
export declare function checkContrast(tokens: ThemeTokens): readonly ContrastFinding[];
|
|
47
|
+
//# sourceMappingURL=contrast.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contrast.d.ts","sourceRoot":"","sources":["../../src/theme/contrast.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,KAAK,WAAW,EAAE,MAAM,YAAY,CAAC;AAE1D,4CAA4C;AAC5C,MAAM,WAAW,IAAI;IACnB,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;CACpB;AAuCD,+EAA+E;AAC/E,wBAAgB,QAAQ,CAAC,MAAM,EAAE,IAAI,GAAG;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAiB1E;AAED,wBAAgB,GAAG,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAEzD;AA0BD;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,EAAE,CAW/C;AAED,oDAAoD;AACpD,wBAAgB,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,GAAG,IAAI,CAKvD;AAOD,wBAAgB,SAAS,CAAC,MAAM,EAAE,IAAI,GAAG,MAAM,CAI9C;AAED,wCAAwC;AACxC,wBAAgB,QAAQ,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,GAAG,MAAM,CAGjD;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,8EAA8E;IAC9E,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,WAAW,GAAG,SAAS,eAAe,EAAE,CAyC7E"}
|