@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.
Files changed (327) hide show
  1. package/LICENSE +96 -0
  2. package/README.md +35 -0
  3. package/dist/app.d.ts +294 -0
  4. package/dist/app.d.ts.map +1 -0
  5. package/dist/app.js +49 -0
  6. package/dist/app.js.map +1 -0
  7. package/dist/arrange.d.ts +185 -0
  8. package/dist/arrange.d.ts.map +1 -0
  9. package/dist/arrange.js +456 -0
  10. package/dist/arrange.js.map +1 -0
  11. package/dist/beginning.d.ts +65 -0
  12. package/dist/beginning.d.ts.map +1 -0
  13. package/dist/beginning.js +94 -0
  14. package/dist/beginning.js.map +1 -0
  15. package/dist/bind.d.ts +42 -0
  16. package/dist/bind.d.ts.map +1 -0
  17. package/dist/bind.js +26 -0
  18. package/dist/bind.js.map +1 -0
  19. package/dist/city.d.ts +93 -0
  20. package/dist/city.d.ts.map +1 -0
  21. package/dist/city.js +160 -0
  22. package/dist/city.js.map +1 -0
  23. package/dist/cli/check/arrangement.d.ts +13 -0
  24. package/dist/cli/check/arrangement.d.ts.map +1 -0
  25. package/dist/cli/check/arrangement.js +63 -0
  26. package/dist/cli/check/arrangement.js.map +1 -0
  27. package/dist/cli/check/beginnings.d.ts +16 -0
  28. package/dist/cli/check/beginnings.d.ts.map +1 -0
  29. package/dist/cli/check/beginnings.js +53 -0
  30. package/dist/cli/check/beginnings.js.map +1 -0
  31. package/dist/cli/check/brand.d.ts +17 -0
  32. package/dist/cli/check/brand.d.ts.map +1 -0
  33. package/dist/cli/check/brand.js +153 -0
  34. package/dist/cli/check/brand.js.map +1 -0
  35. package/dist/cli/check/city.d.ts +17 -0
  36. package/dist/cli/check/city.d.ts.map +1 -0
  37. package/dist/cli/check/city.js +58 -0
  38. package/dist/cli/check/city.js.map +1 -0
  39. package/dist/cli/check/context.d.ts +50 -0
  40. package/dist/cli/check/context.d.ts.map +1 -0
  41. package/dist/cli/check/context.js +37 -0
  42. package/dist/cli/check/context.js.map +1 -0
  43. package/dist/cli/check/fields.d.ts +16 -0
  44. package/dist/cli/check/fields.d.ts.map +1 -0
  45. package/dist/cli/check/fields.js +237 -0
  46. package/dist/cli/check/fields.js.map +1 -0
  47. package/dist/cli/check/index.d.ts +14 -0
  48. package/dist/cli/check/index.d.ts.map +1 -0
  49. package/dist/cli/check/index.js +14 -0
  50. package/dist/cli/check/index.js.map +1 -0
  51. package/dist/cli/check/intelligence.d.ts +17 -0
  52. package/dist/cli/check/intelligence.d.ts.map +1 -0
  53. package/dist/cli/check/intelligence.js +136 -0
  54. package/dist/cli/check/intelligence.js.map +1 -0
  55. package/dist/cli/check/lenses.d.ts +17 -0
  56. package/dist/cli/check/lenses.d.ts.map +1 -0
  57. package/dist/cli/check/lenses.js +239 -0
  58. package/dist/cli/check/lenses.js.map +1 -0
  59. package/dist/cli/check/migrations.d.ts +16 -0
  60. package/dist/cli/check/migrations.d.ts.map +1 -0
  61. package/dist/cli/check/migrations.js +43 -0
  62. package/dist/cli/check/migrations.js.map +1 -0
  63. package/dist/cli/check/modules.d.ts +16 -0
  64. package/dist/cli/check/modules.d.ts.map +1 -0
  65. package/dist/cli/check/modules.js +123 -0
  66. package/dist/cli/check/modules.js.map +1 -0
  67. package/dist/cli/check/policy.d.ts +16 -0
  68. package/dist/cli/check/policy.d.ts.map +1 -0
  69. package/dist/cli/check/policy.js +90 -0
  70. package/dist/cli/check/policy.js.map +1 -0
  71. package/dist/cli/check/relations.d.ts +29 -0
  72. package/dist/cli/check/relations.d.ts.map +1 -0
  73. package/dist/cli/check/relations.js +279 -0
  74. package/dist/cli/check/relations.js.map +1 -0
  75. package/dist/cli/check/routes.d.ts +16 -0
  76. package/dist/cli/check/routes.d.ts.map +1 -0
  77. package/dist/cli/check/routes.js +31 -0
  78. package/dist/cli/check/routes.js.map +1 -0
  79. package/dist/cli/check/settings.d.ts +16 -0
  80. package/dist/cli/check/settings.d.ts.map +1 -0
  81. package/dist/cli/check/settings.js +81 -0
  82. package/dist/cli/check/settings.js.map +1 -0
  83. package/dist/cli/check.d.ts +36 -0
  84. package/dist/cli/check.d.ts.map +1 -0
  85. package/dist/cli/check.js +76 -0
  86. package/dist/cli/check.js.map +1 -0
  87. package/dist/cli/create.d.ts +20 -0
  88. package/dist/cli/create.d.ts.map +1 -0
  89. package/dist/cli/create.js +251 -0
  90. package/dist/cli/create.js.map +1 -0
  91. package/dist/cli/describe.d.ts +35 -0
  92. package/dist/cli/describe.d.ts.map +1 -0
  93. package/dist/cli/describe.js +230 -0
  94. package/dist/cli/describe.js.map +1 -0
  95. package/dist/cli/docs.d.ts +11 -0
  96. package/dist/cli/docs.d.ts.map +1 -0
  97. package/dist/cli/docs.js +152 -0
  98. package/dist/cli/docs.js.map +1 -0
  99. package/dist/cli/index.d.ts +18 -0
  100. package/dist/cli/index.d.ts.map +1 -0
  101. package/dist/cli/index.js +281 -0
  102. package/dist/cli/index.js.map +1 -0
  103. package/dist/extend.d.ts +23 -0
  104. package/dist/extend.d.ts.map +1 -0
  105. package/dist/extend.js +53 -0
  106. package/dist/extend.js.map +1 -0
  107. package/dist/graph/diff.d.ts +31 -0
  108. package/dist/graph/diff.d.ts.map +1 -0
  109. package/dist/graph/diff.js +71 -0
  110. package/dist/graph/diff.js.map +1 -0
  111. package/dist/graph/graph.d.ts +69 -0
  112. package/dist/graph/graph.d.ts.map +1 -0
  113. package/dist/graph/graph.js +284 -0
  114. package/dist/graph/graph.js.map +1 -0
  115. package/dist/graph/primitives.d.ts +52 -0
  116. package/dist/graph/primitives.d.ts.map +1 -0
  117. package/dist/graph/primitives.js +62 -0
  118. package/dist/graph/primitives.js.map +1 -0
  119. package/dist/graph/tracked.d.ts +31 -0
  120. package/dist/graph/tracked.d.ts.map +1 -0
  121. package/dist/graph/tracked.js +69 -0
  122. package/dist/graph/tracked.js.map +1 -0
  123. package/dist/graph/types.d.ts +34 -0
  124. package/dist/graph/types.d.ts.map +1 -0
  125. package/dist/graph/types.js +0 -0
  126. package/dist/graph/types.js.map +1 -0
  127. package/dist/index.d.ts +100 -0
  128. package/dist/index.d.ts.map +1 -0
  129. package/dist/index.js +90 -0
  130. package/dist/index.js.map +1 -0
  131. package/dist/installation.d.ts +112 -0
  132. package/dist/installation.d.ts.map +1 -0
  133. package/dist/installation.js +193 -0
  134. package/dist/installation.js.map +1 -0
  135. package/dist/intelligence-bridge.d.ts +73 -0
  136. package/dist/intelligence-bridge.d.ts.map +1 -0
  137. package/dist/intelligence-bridge.js +31 -0
  138. package/dist/intelligence-bridge.js.map +1 -0
  139. package/dist/invariants/engine.d.ts +36 -0
  140. package/dist/invariants/engine.d.ts.map +1 -0
  141. package/dist/invariants/engine.js +88 -0
  142. package/dist/invariants/engine.js.map +1 -0
  143. package/dist/invariants/types.d.ts +75 -0
  144. package/dist/invariants/types.d.ts.map +1 -0
  145. package/dist/invariants/types.js +2 -0
  146. package/dist/invariants/types.js.map +1 -0
  147. package/dist/modules.d.ts +75 -0
  148. package/dist/modules.d.ts.map +1 -0
  149. package/dist/modules.js +87 -0
  150. package/dist/modules.js.map +1 -0
  151. package/dist/mutations/decidable.d.ts +26 -0
  152. package/dist/mutations/decidable.d.ts.map +1 -0
  153. package/dist/mutations/decidable.js +39 -0
  154. package/dist/mutations/decidable.js.map +1 -0
  155. package/dist/mutations/define-mutation.d.ts +32 -0
  156. package/dist/mutations/define-mutation.d.ts.map +1 -0
  157. package/dist/mutations/define-mutation.js +181 -0
  158. package/dist/mutations/define-mutation.js.map +1 -0
  159. package/dist/mutations/derive-edits.d.ts +75 -0
  160. package/dist/mutations/derive-edits.d.ts.map +1 -0
  161. package/dist/mutations/derive-edits.js +240 -0
  162. package/dist/mutations/derive-edits.js.map +1 -0
  163. package/dist/mutations/form.d.ts +63 -0
  164. package/dist/mutations/form.d.ts.map +1 -0
  165. package/dist/mutations/form.js +113 -0
  166. package/dist/mutations/form.js.map +1 -0
  167. package/dist/mutations/node-ref.d.ts +83 -0
  168. package/dist/mutations/node-ref.d.ts.map +1 -0
  169. package/dist/mutations/node-ref.js +113 -0
  170. package/dist/mutations/node-ref.js.map +1 -0
  171. package/dist/mutations/types.d.ts +136 -0
  172. package/dist/mutations/types.d.ts.map +1 -0
  173. package/dist/mutations/types.js +2 -0
  174. package/dist/mutations/types.js.map +1 -0
  175. package/dist/ops/log.d.ts +35 -0
  176. package/dist/ops/log.d.ts.map +1 -0
  177. package/dist/ops/log.js +103 -0
  178. package/dist/ops/log.js.map +1 -0
  179. package/dist/ops/types.d.ts +52 -0
  180. package/dist/ops/types.d.ts.map +1 -0
  181. package/dist/ops/types.js +2 -0
  182. package/dist/ops/types.js.map +1 -0
  183. package/dist/ops/undo.d.ts +33 -0
  184. package/dist/ops/undo.d.ts.map +1 -0
  185. package/dist/ops/undo.js +65 -0
  186. package/dist/ops/undo.js.map +1 -0
  187. package/dist/permissions/policy.d.ts +68 -0
  188. package/dist/permissions/policy.d.ts.map +1 -0
  189. package/dist/permissions/policy.js +191 -0
  190. package/dist/permissions/policy.js.map +1 -0
  191. package/dist/permissions/types.d.ts +78 -0
  192. package/dist/permissions/types.d.ts.map +1 -0
  193. package/dist/permissions/types.js +17 -0
  194. package/dist/permissions/types.js.map +1 -0
  195. package/dist/persistence/memory.d.ts +6 -0
  196. package/dist/persistence/memory.d.ts.map +1 -0
  197. package/dist/persistence/memory.js +31 -0
  198. package/dist/persistence/memory.js.map +1 -0
  199. package/dist/persistence/sqlite.d.ts +59 -0
  200. package/dist/persistence/sqlite.d.ts.map +1 -0
  201. package/dist/persistence/sqlite.js +131 -0
  202. package/dist/persistence/sqlite.js.map +1 -0
  203. package/dist/persistence/types.d.ts +22 -0
  204. package/dist/persistence/types.d.ts.map +1 -0
  205. package/dist/persistence/types.js +2 -0
  206. package/dist/persistence/types.js.map +1 -0
  207. package/dist/presence.d.ts +38 -0
  208. package/dist/presence.d.ts.map +1 -0
  209. package/dist/presence.js +50 -0
  210. package/dist/presence.js.map +1 -0
  211. package/dist/scaffold/domain.d.ts +8 -0
  212. package/dist/scaffold/domain.d.ts.map +1 -0
  213. package/dist/scaffold/domain.js +331 -0
  214. package/dist/scaffold/domain.js.map +1 -0
  215. package/dist/scaffold/index.d.ts +66 -0
  216. package/dist/scaffold/index.d.ts.map +1 -0
  217. package/dist/scaffold/index.js +142 -0
  218. package/dist/scaffold/index.js.map +1 -0
  219. package/dist/scaffold/lens.d.ts +31 -0
  220. package/dist/scaffold/lens.d.ts.map +1 -0
  221. package/dist/scaffold/lens.js +176 -0
  222. package/dist/scaffold/lens.js.map +1 -0
  223. package/dist/scaffold/names.d.ts +44 -0
  224. package/dist/scaffold/names.d.ts.map +1 -0
  225. package/dist/scaffold/names.js +69 -0
  226. package/dist/scaffold/names.js.map +1 -0
  227. package/dist/scaffold/project.d.ts +41 -0
  228. package/dist/scaffold/project.d.ts.map +1 -0
  229. package/dist/scaffold/project.js +604 -0
  230. package/dist/scaffold/project.js.map +1 -0
  231. package/dist/scaffold/ui.d.ts +15 -0
  232. package/dist/scaffold/ui.d.ts.map +1 -0
  233. package/dist/scaffold/ui.js +536 -0
  234. package/dist/scaffold/ui.js.map +1 -0
  235. package/dist/schema/define-node.d.ts +132 -0
  236. package/dist/schema/define-node.d.ts.map +1 -0
  237. package/dist/schema/define-node.js +254 -0
  238. package/dist/schema/define-node.js.map +1 -0
  239. package/dist/schema/figures.d.ts +42 -0
  240. package/dist/schema/figures.d.ts.map +1 -0
  241. package/dist/schema/figures.js +220 -0
  242. package/dist/schema/figures.js.map +1 -0
  243. package/dist/schema/json-schema.d.ts +39 -0
  244. package/dist/schema/json-schema.d.ts.map +1 -0
  245. package/dist/schema/json-schema.js +74 -0
  246. package/dist/schema/json-schema.js.map +1 -0
  247. package/dist/schema/schema.d.ts +43 -0
  248. package/dist/schema/schema.d.ts.map +1 -0
  249. package/dist/schema/schema.js +102 -0
  250. package/dist/schema/schema.js.map +1 -0
  251. package/dist/schema/types.d.ts +201 -0
  252. package/dist/schema/types.d.ts.map +1 -0
  253. package/dist/schema/types.js +2 -0
  254. package/dist/schema/types.js.map +1 -0
  255. package/dist/search.d.ts +215 -0
  256. package/dist/search.d.ts.map +1 -0
  257. package/dist/search.js +449 -0
  258. package/dist/search.js.map +1 -0
  259. package/dist/settings.d.ts +30 -0
  260. package/dist/settings.d.ts.map +1 -0
  261. package/dist/settings.js +74 -0
  262. package/dist/settings.js.map +1 -0
  263. package/dist/store.d.ts +284 -0
  264. package/dist/store.d.ts.map +1 -0
  265. package/dist/store.js +660 -0
  266. package/dist/store.js.map +1 -0
  267. package/dist/studio-door.d.ts +187 -0
  268. package/dist/studio-door.d.ts.map +1 -0
  269. package/dist/studio-door.js +20 -0
  270. package/dist/studio-door.js.map +1 -0
  271. package/dist/sync/conflict.d.ts +37 -0
  272. package/dist/sync/conflict.d.ts.map +1 -0
  273. package/dist/sync/conflict.js +56 -0
  274. package/dist/sync/conflict.js.map +1 -0
  275. package/dist/sync/engine.d.ts +118 -0
  276. package/dist/sync/engine.d.ts.map +1 -0
  277. package/dist/sync/engine.js +341 -0
  278. package/dist/sync/engine.js.map +1 -0
  279. package/dist/sync/google-calendar.d.ts +54 -0
  280. package/dist/sync/google-calendar.d.ts.map +1 -0
  281. package/dist/sync/google-calendar.js +167 -0
  282. package/dist/sync/google-calendar.js.map +1 -0
  283. package/dist/sync/types.d.ts +125 -0
  284. package/dist/sync/types.d.ts.map +1 -0
  285. package/dist/sync/types.js +6 -0
  286. package/dist/sync/types.js.map +1 -0
  287. package/dist/temporal/effectivity.d.ts +75 -0
  288. package/dist/temporal/effectivity.d.ts.map +1 -0
  289. package/dist/temporal/effectivity.js +89 -0
  290. package/dist/temporal/effectivity.js.map +1 -0
  291. package/dist/testing.d.ts +63 -0
  292. package/dist/testing.d.ts.map +1 -0
  293. package/dist/testing.js +194 -0
  294. package/dist/testing.js.map +1 -0
  295. package/dist/theme/contrast.d.ts +47 -0
  296. package/dist/theme/contrast.d.ts.map +1 -0
  297. package/dist/theme/contrast.js +172 -0
  298. package/dist/theme/contrast.js.map +1 -0
  299. package/dist/theme/derive.d.ts +81 -0
  300. package/dist/theme/derive.d.ts.map +1 -0
  301. package/dist/theme/derive.js +171 -0
  302. package/dist/theme/derive.js.map +1 -0
  303. package/dist/theme/kit.d.ts +106 -0
  304. package/dist/theme/kit.d.ts.map +1 -0
  305. package/dist/theme/kit.js +84 -0
  306. package/dist/theme/kit.js.map +1 -0
  307. package/dist/theme/palettes.d.ts +32 -0
  308. package/dist/theme/palettes.d.ts.map +1 -0
  309. package/dist/theme/palettes.js +96 -0
  310. package/dist/theme/palettes.js.map +1 -0
  311. package/dist/theme/types.d.ts +131 -0
  312. package/dist/theme/types.d.ts.map +1 -0
  313. package/dist/theme/types.js +23 -0
  314. package/dist/theme/types.js.map +1 -0
  315. package/dist/views/types.d.ts +89 -0
  316. package/dist/views/types.d.ts.map +1 -0
  317. package/dist/views/types.js +88 -0
  318. package/dist/views/types.js.map +1 -0
  319. package/dist/watched.d.ts +33 -0
  320. package/dist/watched.d.ts.map +1 -0
  321. package/dist/watched.js +50 -0
  322. package/dist/watched.js.map +1 -0
  323. package/dist/who.d.ts +26 -0
  324. package/dist/who.d.ts.map +1 -0
  325. package/dist/who.js +20 -0
  326. package/dist/who.js.map +1 -0
  327. package/package.json +77 -0
@@ -0,0 +1,94 @@
1
+ import { deriveEditMutations } from "./mutations/derive-edits.js";
2
+ import { nodeRefArgs } from "./mutations/node-ref.js";
3
+ /** Every act the app has, declared and derived alike. */
4
+ function actsOf(app) {
5
+ return [...(app.mutations ?? []), ...deriveEditMutations(app.schema, app.mutations ?? [])];
6
+ }
7
+ export function beginning(app) {
8
+ const kinds = [...app.schema.kinds];
9
+ const acts = actsOf(app);
10
+ /** What each act must be handed, as kinds, ignoring optional arguments. */
11
+ const requires = new Map();
12
+ /** What each act makes. */
13
+ const makes = new Map();
14
+ for (const act of acts) {
15
+ makes.set(act.name, (act.creates ?? []));
16
+ const wanted = nodeRefArgs(act.input)
17
+ .filter((arg) => !arg.optional && !arg.kinds.includes("*"))
18
+ .flatMap((arg) => arg.kinds);
19
+ requires.set(act.name, [...new Set(wanted)]);
20
+ }
21
+ const madeBy = new Map();
22
+ for (const kind of kinds)
23
+ madeBy.set(kind, []);
24
+ for (const act of acts) {
25
+ for (const kind of makes.get(act.name) ?? [])
26
+ madeBy.get(kind)?.push(act.name);
27
+ }
28
+ /*
29
+ * THE SHORTEST CHAIN TO EACH KIND, by widening the set of what exists.
30
+ *
31
+ * Start with nothing; take every act whose required kinds are all present;
32
+ * whatever they make now exists, at this depth. Repeat until a pass adds
33
+ * nothing. Kinds left over are unreachable — which includes an act whose
34
+ * only door needs a kind only IT can make, a cycle nobody can enter.
35
+ */
36
+ const depth = new Map();
37
+ const present = new Set();
38
+ for (let round = 0;; round += 1) {
39
+ const arrived = [];
40
+ for (const act of acts) {
41
+ const wants = requires.get(act.name) ?? [];
42
+ if (!wants.every((kind) => present.has(kind)))
43
+ continue;
44
+ for (const kind of makes.get(act.name) ?? []) {
45
+ if (!present.has(kind))
46
+ arrived.push(kind);
47
+ }
48
+ }
49
+ if (arrived.length === 0)
50
+ break;
51
+ for (const kind of arrived) {
52
+ present.add(kind);
53
+ depth.set(kind, round);
54
+ }
55
+ }
56
+ const needsOf = (kind) => {
57
+ const doors = madeBy.get(kind) ?? [];
58
+ if (doors.length === 0)
59
+ return [];
60
+ /* The cheapest door decides, because one open door is enough. */
61
+ const cheapest = doors
62
+ .map((name) => requires.get(name) ?? [])
63
+ .sort((a, b) => a.length - b.length)[0];
64
+ return [...new Set(cheapest)].filter((wanted) => wanted !== kind);
65
+ };
66
+ const order = kinds
67
+ .map((kind) => ({
68
+ kind,
69
+ madeBy: [...(madeBy.get(kind) ?? [])].sort(),
70
+ needs: [...needsOf(kind)].sort(),
71
+ depth: depth.get(kind) ?? null,
72
+ }))
73
+ .sort((a, b) => (a.depth ?? Number.MAX_SAFE_INTEGER) - (b.depth ?? Number.MAX_SAFE_INTEGER) ||
74
+ a.kind.localeCompare(b.kind));
75
+ const roots = order.filter((entry) => entry.depth === 0).map((entry) => entry.kind);
76
+ const doors = [
77
+ ...new Set(acts
78
+ .filter((act) => (requires.get(act.name) ?? []).length === 0)
79
+ .filter((act) => (makes.get(act.name) ?? []).length > 0)
80
+ .map((act) => act.name)),
81
+ ].sort();
82
+ const unreachable = order
83
+ .filter((entry) => entry.depth === null)
84
+ .map((entry) => ({
85
+ kind: entry.kind,
86
+ why: entry.madeBy.length === 0
87
+ ? "no act declares that it creates this kind"
88
+ : `every act that makes it needs ${entry.needs
89
+ .map((kind) => `"${kind}"`)
90
+ .join(", ")}, which nothing can make first`,
91
+ }));
92
+ return { order, roots, doors, unreachable };
93
+ }
94
+ //# sourceMappingURL=beginning.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"beginning.js","sourceRoot":"","sources":["../src/beginning.ts"],"names":[],"mappings":"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"}
package/dist/bind.d.ts ADDED
@@ -0,0 +1,42 @@
1
+ import type { z } from "zod";
2
+ import type { InvariantDefinition, InvariantEvalArgs, Violation } from "./invariants/types.js";
3
+ import type { MutationDefinition, MutationDefinitionSpec } from "./mutations/types.js";
4
+ import type { AnySchema, KindOfSchema, NodeOfKind } from "./schema/schema.js";
5
+ import { type ViewRegistry } from "./views/types.js";
6
+ export interface SchemaBinding<S extends AnySchema> {
7
+ readonly schema: S;
8
+ /**
9
+ * Declares a mutation against this schema. Binding the schema up front is
10
+ * what lets TypeScript infer the argument type from `input` — so a
11
+ * mutation body sees real field types, and a renamed field breaks the
12
+ * build rather than the app.
13
+ */
14
+ defineMutation<const Name extends string, I extends z.ZodType>(name: Name, spec: MutationDefinitionSpec<S, I>): MutationDefinition<S, Name, I>;
15
+ defineInvariant<const K extends KindOfSchema<S>>(name: string, spec: {
16
+ readonly scope: {
17
+ readonly kind: K;
18
+ readonly match?: (node: NodeOfKind<S, K>) => boolean;
19
+ };
20
+ readonly label?: string;
21
+ readonly description?: string;
22
+ readonly repairs?: readonly string[];
23
+ /** Judge retired subjects too — see `InvariantDefinition.judgesPast`. */
24
+ readonly judgesPast?: boolean;
25
+ readonly evaluate: (args: InvariantEvalArgs<S, NodeOfKind<S, K>>) => Violation[];
26
+ }): InvariantDefinition<S>;
27
+ defineGraphInvariant(name: string, spec: {
28
+ readonly label?: string;
29
+ readonly description?: string;
30
+ readonly repairs?: readonly string[];
31
+ readonly evaluate: (args: InvariantEvalArgs<S, undefined>) => Violation[];
32
+ }): InvariantDefinition<S>;
33
+ createViews<V = unknown>(): ViewRegistry<S, V>;
34
+ }
35
+ /**
36
+ * Binds a schema so everything declared against it infers from it. Without
37
+ * this, TypeScript cannot infer a mutation's argument type and the schema
38
+ * type at once — and an argument typed `unknown` defeats the whole point of
39
+ * declaring the schema.
40
+ */
41
+ export declare function bindSchema<S extends AnySchema>(schema: S): SchemaBinding<S>;
42
+ //# sourceMappingURL=bind.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bind.d.ts","sourceRoot":"","sources":["../src/bind.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAE7B,OAAO,KAAK,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAC/F,OAAO,KAAK,EACV,kBAAkB,EAClB,sBAAsB,EACvB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAC9E,OAAO,EAAsB,KAAK,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAEzE,MAAM,WAAW,aAAa,CAAC,CAAC,SAAS,SAAS;IAChD,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IACnB;;;;;OAKG;IACH,cAAc,CAAC,KAAK,CAAC,IAAI,SAAS,MAAM,EAAE,CAAC,SAAS,CAAC,CAAC,OAAO,EAC3D,IAAI,EAAE,IAAI,EACV,IAAI,EAAE,sBAAsB,CAAC,CAAC,EAAE,CAAC,CAAC,GACjC,kBAAkB,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IAClC,eAAe,CAAC,KAAK,CAAC,CAAC,SAAS,YAAY,CAAC,CAAC,CAAC,EAC7C,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE;QACJ,QAAQ,CAAC,KAAK,EAAE;YAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;YAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,OAAO,CAAA;SAAE,CAAC;QAC3F,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QACxB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;QAC9B,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;QACrC,yEAAyE;QACzE,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,CAAC;QAC9B,QAAQ,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,iBAAiB,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,SAAS,EAAE,CAAC;KAClF,GACA,mBAAmB,CAAC,CAAC,CAAC,CAAC;IAC1B,oBAAoB,CAClB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE;QACJ,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QACxB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;QAC9B,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;QACrC,QAAQ,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,iBAAiB,CAAC,CAAC,EAAE,SAAS,CAAC,KAAK,SAAS,EAAE,CAAC;KAC3E,GACA,mBAAmB,CAAC,CAAC,CAAC,CAAC;IAC1B,WAAW,CAAC,CAAC,GAAG,OAAO,KAAK,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;CAChD;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,CAAC,SAAS,SAAS,EAAE,MAAM,EAAE,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,CAgB3E"}
package/dist/bind.js ADDED
@@ -0,0 +1,26 @@
1
+ import { defineInvariant } from "./invariants/engine.js";
2
+ import { createViewRegistry } from "./views/types.js";
3
+ /**
4
+ * Binds a schema so everything declared against it infers from it. Without
5
+ * this, TypeScript cannot infer a mutation's argument type and the schema
6
+ * type at once — and an argument typed `unknown` defeats the whole point of
7
+ * declaring the schema.
8
+ */
9
+ export function bindSchema(schema) {
10
+ return {
11
+ schema,
12
+ defineMutation(name, spec) {
13
+ return { ...spec, name };
14
+ },
15
+ defineInvariant(name, spec) {
16
+ return defineInvariant(name, spec);
17
+ },
18
+ defineGraphInvariant(name, spec) {
19
+ return defineInvariant(name, { ...spec, scope: "graph" });
20
+ },
21
+ createViews() {
22
+ return createViewRegistry(schema);
23
+ },
24
+ };
25
+ }
26
+ //# sourceMappingURL=bind.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bind.js","sourceRoot":"","sources":["../src/bind.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAOzD,OAAO,EAAE,kBAAkB,EAAqB,MAAM,kBAAkB,CAAC;AAsCzE;;;;;GAKG;AACH,MAAM,UAAU,UAAU,CAAsB,MAAS;IACvD,OAAO;QACL,MAAM;QACN,cAAc,CAAC,IAAI,EAAE,IAAI;YACvB,OAAO,EAAE,GAAG,IAAI,EAAE,IAAI,EAAE,CAAC;QAC3B,CAAC;QACD,eAAe,CAAC,IAAI,EAAE,IAAI;YACxB,OAAO,eAAe,CAAqB,IAAI,EAAE,IAAa,CAAC,CAAC;QAClE,CAAC;QACD,oBAAoB,CAAC,IAAI,EAAE,IAAI;YAC7B,OAAO,eAAe,CAAI,IAAI,EAAE,EAAE,GAAG,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;QAC/D,CAAC;QACD,WAAW;YACT,OAAO,kBAAkB,CAAO,MAAM,CAAC,CAAC;QAC1C,CAAC;KACF,CAAC;AACJ,CAAC"}
package/dist/city.d.ts ADDED
@@ -0,0 +1,93 @@
1
+ import type { AnySchema } from "./schema/schema.js";
2
+ /**
3
+ * THE CITY IS A MAP DRAWN FROM THE DECLARATION.
4
+ *
5
+ * A kind is a neighbourhood, and where it stands is decided by the
6
+ * declaration alone — never by today's data, never by what looks nice.
7
+ * Same declaration, same map; add a kind and every existing plot stays
8
+ * where it was; a kind that grows takes a bigger block on the same corner.
9
+ * That is what makes an address an address: the place a person remembers
10
+ * is the place they get.
11
+ *
12
+ * Units are LATTICE CELLS on the isometric ground, not pixels. `col` runs
13
+ * down-right along one diagonal, `row` down-left along the other; a plot
14
+ * occupies `side × side` cells from its corner. Plots sit on a block grid
15
+ * one `BLOCK` apart, so a plot growing to its largest side never reaches
16
+ * its neighbour: the street between is the cell left over.
17
+ *
18
+ * Placement walks the kinds in the order the declaration says a blank
19
+ * installation fills them (`beginning(app).order`, or sorted ids when
20
+ * nobody said), puts the first at the origin, and puts each next kind in
21
+ * the free block adjacent to the placed kind it shares the most declared
22
+ * edges with — ties by id — spiralling outward when the near blocks are
23
+ * taken. A kind declaring `plot` is put exactly there.
24
+ */
25
+ export interface Plot {
26
+ /** Corner cell, in lattice units. Multiples of BLOCK unless declared. */
27
+ readonly col: number;
28
+ readonly row: number;
29
+ /** Cells on a side: ceil(sqrt(count)), at least 1, at most MAX_SIDE. */
30
+ readonly side: number;
31
+ }
32
+ /** The most cells a plot takes on a side. */
33
+ export declare const MAX_SIDE = 4;
34
+ /** Block pitch: the largest side plus one cell of street. */
35
+ export declare const BLOCK: number;
36
+ export interface CityHints {
37
+ /** The kind chain a blank installation fills, first to last. */
38
+ readonly order?: readonly string[];
39
+ /** How many of each kind stand today. Changes side, never col or row. */
40
+ readonly counts?: Readonly<Record<string, number>>;
41
+ /** Hand-laid plots, by kind. Used verbatim; a declared `plot` on the kind wins first. */
42
+ readonly plots?: Readonly<Record<string, {
43
+ readonly col: number;
44
+ readonly row: number;
45
+ }>>;
46
+ }
47
+ export type CityMap = ReadonlyMap<string, Plot>;
48
+ /** A road: two kinds joined by declared edges, and which edges. */
49
+ export interface Road {
50
+ readonly from: string;
51
+ readonly to: string;
52
+ readonly edges: readonly string[];
53
+ }
54
+ /** Cells on a side for a population. */
55
+ export declare function sideFor(count: number | undefined): number;
56
+ /**
57
+ * How many declared edges join two kinds, either direction. A wildcard
58
+ * edge touches every kind and counts once toward each.
59
+ */
60
+ export declare function sharedEdges(schema: AnySchema, a: string, b: string): number;
61
+ export declare function cityMap(schema: AnySchema, hints?: CityHints): CityMap;
62
+ /** The roads between placed kinds: one per pair joined by any declared edge. */
63
+ export declare function roadsOf(schema: AnySchema, map: CityMap): readonly Road[];
64
+ /**
65
+ * Two plots overlap when their blocks do — the checker's question about
66
+ * hand-laid plots, asked at the block size so a plot growing to its
67
+ * largest side can never reach a neighbour.
68
+ */
69
+ export declare function plotsOverlap(a: {
70
+ readonly col: number;
71
+ readonly row: number;
72
+ }, b: {
73
+ readonly col: number;
74
+ readonly row: number;
75
+ }): boolean;
76
+ /** The map's extent in lattice cells: the smallest box holding every plot at its side. */
77
+ export declare function cityExtent(map: CityMap): {
78
+ readonly minCol: number;
79
+ readonly minRow: number;
80
+ readonly maxCol: number;
81
+ readonly maxRow: number;
82
+ };
83
+ /**
84
+ * THE 2:1 LATTICE, as a projection. A cell (col,row) meets the screen at
85
+ * x = (col − row) · w/2, y = (col + row) · h/2 with h = w/2 — the same
86
+ * pitch the ground's CSS draws (lines at ±atan 2), so a plot placed here
87
+ * sits on the grid a person can see.
88
+ */
89
+ export declare function toIso(col: number, row: number, cell: number): {
90
+ readonly x: number;
91
+ readonly y: number;
92
+ };
93
+ //# sourceMappingURL=city.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"city.d.ts","sourceRoot":"","sources":["../src/city.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAEpD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,MAAM,WAAW,IAAI;IACnB,yEAAyE;IACzE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,wEAAwE;IACxE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,6CAA6C;AAC7C,eAAO,MAAM,QAAQ,IAAI,CAAC;AAC1B,6DAA6D;AAC7D,eAAO,MAAM,KAAK,QAAe,CAAC;AAElC,MAAM,WAAW,SAAS;IACxB,gEAAgE;IAChE,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,yEAAyE;IACzE,QAAQ,CAAC,MAAM,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACnD,yFAAyF;IACzF,QAAQ,CAAC,KAAK,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE;QAAE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,CAAC;CAC3F;AAED,MAAM,MAAM,OAAO,GAAG,WAAW,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;AAEhD,mEAAmE;AACnE,MAAM,WAAW,IAAI;IACnB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;CACnC;AAID,wCAAwC;AACxC,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAGzD;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,SAAS,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAe3E;AAsBD,wBAAgB,OAAO,CAAC,MAAM,EAAE,SAAS,EAAE,KAAK,GAAE,SAAc,GAAG,OAAO,CAgDzE;AAED,gFAAgF;AAChF,wBAAgB,OAAO,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,OAAO,GAAG,SAAS,IAAI,EAAE,CAsBxE;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE;IAAE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;CAAE,EAAE,CAAC,EAAE;IAAE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAE1I;AAED,0FAA0F;AAC1F,wBAAgB,UAAU,CAAC,GAAG,EAAE,OAAO,GAAG;IAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAa/I;AAED;;;;;GAKG;AACH,wBAAgB,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG;IAAE,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAExG"}
package/dist/city.js ADDED
@@ -0,0 +1,160 @@
1
+ /** The most cells a plot takes on a side. */
2
+ export const MAX_SIDE = 4;
3
+ /** Block pitch: the largest side plus one cell of street. */
4
+ export const BLOCK = MAX_SIDE + 1;
5
+ const byId = (a, b) => (a < b ? -1 : a > b ? 1 : 0);
6
+ /** Cells on a side for a population. */
7
+ export function sideFor(count) {
8
+ if (!count || count <= 1)
9
+ return 1;
10
+ return Math.min(MAX_SIDE, Math.ceil(Math.sqrt(count)));
11
+ }
12
+ /**
13
+ * How many declared edges join two kinds, either direction. A wildcard
14
+ * edge touches every kind and counts once toward each.
15
+ */
16
+ export function sharedEdges(schema, a, b) {
17
+ if (a === b)
18
+ return 0;
19
+ const kinds = schema.kinds;
20
+ let shared = 0;
21
+ for (const [from, to] of [
22
+ [a, b],
23
+ [b, a],
24
+ ]) {
25
+ const definition = schema.tryDefinition(from);
26
+ for (const declaration of Object.values(definition?.edges ?? {})) {
27
+ const targets = declaration.to === "*" ? kinds : declaration.to;
28
+ if (targets.includes(to))
29
+ shared += 1;
30
+ }
31
+ }
32
+ return shared;
33
+ }
34
+ /** The block cells a plot at (col,row) reserves: every cell of the block. */
35
+ const blockKey = (col, row) => `${Math.floor(col / BLOCK)},${Math.floor(row / BLOCK)}`;
36
+ /**
37
+ * Blocks around `(col,row)` at Manhattan distance `d`, in a stable order:
38
+ * the four cardinal neighbours first (down-right, down-left, up-left,
39
+ * up-right), then the rest clockwise. Deterministic, so the walk is.
40
+ */
41
+ function ringAround(col, row, d) {
42
+ if (d === 0)
43
+ return [{ col, row }];
44
+ const out = [];
45
+ for (let i = 0; i < d; i++) {
46
+ out.push({ col: col + (d - i) * BLOCK, row: row + i * BLOCK });
47
+ out.push({ col: col - i * BLOCK, row: row + (d - i) * BLOCK });
48
+ out.push({ col: col - (d - i) * BLOCK, row: row - i * BLOCK });
49
+ out.push({ col: col + i * BLOCK, row: row - (d - i) * BLOCK });
50
+ }
51
+ return out;
52
+ }
53
+ export function cityMap(schema, hints = {}) {
54
+ const kinds = [...schema.kinds];
55
+ const order = [
56
+ ...(hints.order ?? []).filter((kind) => kinds.includes(kind)),
57
+ ...kinds.filter((kind) => !(hints.order ?? []).includes(kind)).sort(byId),
58
+ ].filter((kind, index, all) => all.indexOf(kind) === index);
59
+ const plots = new Map();
60
+ const taken = new Set();
61
+ const put = (kind, col, row) => {
62
+ plots.set(kind, { col, row, side: sideFor(hints.counts?.[kind]) });
63
+ taken.add(blockKey(col, row));
64
+ };
65
+ /* HAND-LAID FIRST, verbatim: a declared address is an address. */
66
+ for (const kind of order) {
67
+ const declared = schema.tryDefinition(kind)?.plot ?? hints.plots?.[kind];
68
+ if (declared)
69
+ put(kind, declared.col, declared.row);
70
+ }
71
+ for (const kind of order) {
72
+ if (plots.has(kind))
73
+ continue;
74
+ if (plots.size === 0) {
75
+ put(kind, 0, 0);
76
+ continue;
77
+ }
78
+ /*
79
+ * THE PLACED KIND IT SHARES THE MOST EDGES WITH. None shared means
80
+ * nothing to be near, and the city's first block is the anchor — so an
81
+ * unrelated kind still lands near the middle rather than off on its own.
82
+ */
83
+ let anchor;
84
+ let most = 0;
85
+ for (const placed of [...plots.keys()].sort(byId)) {
86
+ const shared = sharedEdges(schema, kind, placed);
87
+ if (shared > most || (shared === most && shared > 0 && anchor !== undefined && byId(placed, anchor) < 0)) {
88
+ most = shared;
89
+ anchor = placed;
90
+ }
91
+ }
92
+ const from = anchor ? plots.get(anchor) : plots.get(order.find((k) => plots.has(k)));
93
+ let found;
94
+ for (let d = 1; !found && d < 64; d++) {
95
+ found = ringAround(from.col, from.row, d).find((cell) => !taken.has(blockKey(cell.col, cell.row)));
96
+ }
97
+ put(kind, found?.col ?? from.col + BLOCK * plots.size, found?.row ?? from.row);
98
+ }
99
+ return plots;
100
+ }
101
+ /** The roads between placed kinds: one per pair joined by any declared edge. */
102
+ export function roadsOf(schema, map) {
103
+ const kinds = [...map.keys()].sort(byId);
104
+ const roads = [];
105
+ for (let i = 0; i < kinds.length; i++) {
106
+ for (let j = i + 1; j < kinds.length; j++) {
107
+ const a = kinds[i];
108
+ const b = kinds[j];
109
+ const edges = [];
110
+ for (const [from, to] of [
111
+ [a, b],
112
+ [b, a],
113
+ ]) {
114
+ const definition = schema.tryDefinition(from);
115
+ for (const [name, declaration] of Object.entries(definition?.edges ?? {})) {
116
+ const targets = declaration.to === "*" ? schema.kinds : declaration.to;
117
+ if (targets.includes(to))
118
+ edges.push(name);
119
+ }
120
+ }
121
+ if (edges.length > 0)
122
+ roads.push({ from: a, to: b, edges });
123
+ }
124
+ }
125
+ return roads;
126
+ }
127
+ /**
128
+ * Two plots overlap when their blocks do — the checker's question about
129
+ * hand-laid plots, asked at the block size so a plot growing to its
130
+ * largest side can never reach a neighbour.
131
+ */
132
+ export function plotsOverlap(a, b) {
133
+ return Math.abs(a.col - b.col) < BLOCK && Math.abs(a.row - b.row) < BLOCK;
134
+ }
135
+ /** The map's extent in lattice cells: the smallest box holding every plot at its side. */
136
+ export function cityExtent(map) {
137
+ let minCol = Infinity;
138
+ let minRow = Infinity;
139
+ let maxCol = -Infinity;
140
+ let maxRow = -Infinity;
141
+ for (const plot of map.values()) {
142
+ minCol = Math.min(minCol, plot.col);
143
+ minRow = Math.min(minRow, plot.row);
144
+ maxCol = Math.max(maxCol, plot.col + plot.side);
145
+ maxRow = Math.max(maxRow, plot.row + plot.side);
146
+ }
147
+ if (map.size === 0)
148
+ return { minCol: 0, minRow: 0, maxCol: 1, maxRow: 1 };
149
+ return { minCol, minRow, maxCol, maxRow };
150
+ }
151
+ /**
152
+ * THE 2:1 LATTICE, as a projection. A cell (col,row) meets the screen at
153
+ * x = (col − row) · w/2, y = (col + row) · h/2 with h = w/2 — the same
154
+ * pitch the ground's CSS draws (lines at ±atan 2), so a plot placed here
155
+ * sits on the grid a person can see.
156
+ */
157
+ export function toIso(col, row, cell) {
158
+ return { x: ((col - row) * cell) / 2, y: ((col + row) * cell) / 4 };
159
+ }
160
+ //# sourceMappingURL=city.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"city.js","sourceRoot":"","sources":["../src/city.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import type { AnySchema } from "../../schema/schema.js";
2
+ import type { CheckContext } from "./context.js";
3
+ /**
4
+ * WHAT A KIND SAYS IT IS ARRANGED BY has to be something it has.
5
+ *
6
+ * `fieldRoles.order` names the field a kind sorts by when nothing is asked;
7
+ * a lens's `arrangedBy` names how its picture opens. Both are strings in a
8
+ * declaration that nothing else reads until a person is looking, so a
9
+ * renamed field would leave a picture quietly opening unsorted. The
10
+ * arrangement module already knows what each kind offers; this asks it.
11
+ */
12
+ export declare function checkArrangement<S extends AnySchema>(ctx: CheckContext<S>): void;
13
+ //# sourceMappingURL=arrangement.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"arrangement.d.ts","sourceRoot":"","sources":["../../../src/cli/check/arrangement.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAEjD;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,SAAS,EAAE,GAAG,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,IAAI,CA6ChF"}
@@ -0,0 +1,63 @@
1
+ import { admitArrangement, arrangeable, parseArrangement } from "../../arrange.js";
2
+ /**
3
+ * WHAT A KIND SAYS IT IS ARRANGED BY has to be something it has.
4
+ *
5
+ * `fieldRoles.order` names the field a kind sorts by when nothing is asked;
6
+ * a lens's `arrangedBy` names how its picture opens. Both are strings in a
7
+ * declaration that nothing else reads until a person is looking, so a
8
+ * renamed field would leave a picture quietly opening unsorted. The
9
+ * arrangement module already knows what each kind offers; this asks it.
10
+ */
11
+ export function checkArrangement(ctx) {
12
+ const { app, add } = ctx;
13
+ for (const definition of app.schema.definitions) {
14
+ const order = definition.fieldRoles?.["order"];
15
+ if (order === undefined)
16
+ continue;
17
+ const shape = (definition.fields.shape ?? {});
18
+ if (order === "label" || order in shape)
19
+ continue;
20
+ add({
21
+ severity: "warning",
22
+ code: "order-role-unknown",
23
+ where: `defineNode("${definition.kind}").fieldRoles.order`,
24
+ message: `"${definition.kind}" says it sorts by "${order}", and has no such field — so nothing sorts it.`,
25
+ fix: `Point order at one of ${Object.keys(shape).join(", ") || "its fields"}, or drop it.`,
26
+ });
27
+ }
28
+ for (const lens of app.lenses ?? []) {
29
+ if (!lens.arrangedBy)
30
+ continue;
31
+ /*
32
+ * The kinds a lens is bound over: the keys of a fields binding, or the
33
+ * kinds an entities binding names. An arrangement is admitted against
34
+ * each; what none of them offers is noted.
35
+ */
36
+ const bound = new Set();
37
+ for (const [key, binding] of Object.entries(lens.bindings ?? {})) {
38
+ if (lens.binds === "entities") {
39
+ const kind = binding.kind;
40
+ if (typeof kind === "string")
41
+ bound.add(kind);
42
+ }
43
+ else {
44
+ bound.add(key);
45
+ }
46
+ }
47
+ if (bound.size === 0)
48
+ continue;
49
+ const asked = parseArrangement(lens.arrangedBy);
50
+ const dropped = [...bound].map((kind) => admitArrangement(asked, arrangeable(app.schema, kind)).dropped);
51
+ const byEvery = dropped.length > 0 ? dropped.reduce((common, these) => common.filter((part) => these.includes(part))) : [];
52
+ for (const part of byEvery) {
53
+ add({
54
+ severity: "note",
55
+ code: "lens-arrangement-unknown",
56
+ where: `lens "${lens.name}" arrangedBy`,
57
+ message: `The lens opens arranged by "${part}", and none of ${[...bound].join(", ")} can be arranged that way — the picture will open unarranged there.`,
58
+ fix: `Name a field, an edge or \`is\` the bound kind has; \`graview describe\` lists what each kind can be arranged by.`,
59
+ });
60
+ }
61
+ }
62
+ }
63
+ //# sourceMappingURL=arrangement.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"arrangement.js","sourceRoot":"","sources":["../../../src/cli/check/arrangement.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import type { AnySchema } from "../../schema/schema.js";
2
+ /**
3
+ * `note` is a QUESTION ASKED OUT LOUD, not a problem.
4
+ *
5
+ * Some things a checker can see are legitimate designs that the author
6
+ * should nonetheless have looked at once: a lens written for this app and
7
+ * never proved against another domain, a role name two vocabularies both
8
+ * use, a kind unreachable on an empty graph. Filed as warnings they would
9
+ * be warnings that can only ever be acknowledged, and those are the ones
10
+ * people learn to scroll past — which costs the checker its authority on
11
+ * the warnings that matter. So they have their own voice: counted, printed,
12
+ * and never a failure.
13
+ */
14
+ import type { CheckContext } from "./context.js";
15
+ export declare function checkBlankInstallation<S extends AnySchema>(ctx: CheckContext<S>): void;
16
+ //# sourceMappingURL=beginnings.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"beginnings.d.ts","sourceRoot":"","sources":["../../../src/cli/check/beginnings.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAExD;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAEjD,wBAAgB,sBAAsB,CAAC,CAAC,SAAS,SAAS,EAAE,GAAG,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,IAAI,CAgDtF"}
@@ -0,0 +1,53 @@
1
+ import { beginning } from "../../beginning.js";
2
+ export function checkBlankInstallation(ctx) {
3
+ const { app, kinds, add } = ctx;
4
+ /*
5
+ * WHAT A BLANK INSTALLATION CAN ACTUALLY DO.
6
+ *
7
+ * `creates` and a nodeRef argument are together a chain — a feature cannot
8
+ * be made until a zone exists — and it is invisible at build time: the
9
+ * declaration is well-formed, every act is correct, and the gap only
10
+ * appears at runtime on the one graph nobody tests against. A ten-kind app
11
+ * can ship with one door and seven silent districts, and the first person
12
+ * to open it is the first to find out.
13
+ *
14
+ * Notes rather than warnings, because every answer here is a legitimate
15
+ * design: a kind a migration seeds, a catalogue that arrives whole, a
16
+ * product whose data comes from a sync. The author should have to look at
17
+ * it once, not argue with it forever.
18
+ */
19
+ const chain = beginning(app);
20
+ /*
21
+ * Only an app that says it MAKES things is asked how. An app whose every
22
+ * act edits what is already there — a catalogue, a graph that arrives by
23
+ * seed or sync — never claimed a way in, and telling it there is none is
24
+ * a note with no question in it.
25
+ */
26
+ const claimsToMake = (app.mutations ?? []).some((mutation) => (mutation.creates ?? []).length > 0);
27
+ if (!claimsToMake) {
28
+ // Nothing to say: creation is not this app's business.
29
+ }
30
+ else if (chain.doors.length === 0 && kinds.size > 0) {
31
+ add({
32
+ severity: "note",
33
+ code: "blank-graph-has-no-door",
34
+ where: "mutations",
35
+ message: `Nothing can be made in an empty ${app.name}: every act that creates a kind needs a node that does not exist yet.`,
36
+ fix: `If the graph arrives seeded or synced, that is the answer and this is just the note. Otherwise give one act no required nodeRef, so a blank installation has a way in.`,
37
+ });
38
+ }
39
+ else if (chain.unreachable.length > 0) {
40
+ add({
41
+ severity: "note",
42
+ code: "blank-graph-unreachable",
43
+ where: "mutations",
44
+ message: `${chain.unreachable
45
+ .map((entry) => `"${entry.kind}"`)
46
+ .join(", ")} cannot be made from empty — ${chain.unreachable[0].why}. The way in is ${chain.doors
47
+ .map((door) => `"${door}"`)
48
+ .join(", ")}.`,
49
+ fix: `Declare creates: ["<kind>"] on the act that adds one, or accept that these arrive by seed, migration or sync.`,
50
+ });
51
+ }
52
+ }
53
+ //# sourceMappingURL=beginnings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"beginnings.js","sourceRoot":"","sources":["../../../src/cli/check/beginnings.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAiB/C,MAAM,UAAU,sBAAsB,CAAsB,GAAoB;IAC9E,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,GAAG,CAAC;IAChC;;;;;;;;;;;;;;OAcG;IACH,MAAM,KAAK,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC;IAC7B;;;;;OAKG;IACH,MAAM,YAAY,GAAG,CAAC,GAAG,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACnG,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,uDAAuD;IACzD,CAAC;SAAM,IAAI,KAAK,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,KAAK,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;QACtD,GAAG,CAAC;YACF,QAAQ,EAAE,MAAM;YAChB,IAAI,EAAE,yBAAyB;YAC/B,KAAK,EAAE,WAAW;YAClB,OAAO,EAAE,mCAAmC,GAAG,CAAC,IAAI,uEAAuE;YAC3H,GAAG,EAAE,wKAAwK;SAC9K,CAAC,CAAC;IACL,CAAC;SAAM,IAAI,KAAK,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACxC,GAAG,CAAC;YACF,QAAQ,EAAE,MAAM;YAChB,IAAI,EAAE,yBAAyB;YAC/B,KAAK,EAAE,WAAW;YAClB,OAAO,EAAE,GAAG,KAAK,CAAC,WAAW;iBAC1B,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,KAAK,CAAC,IAAI,GAAG,CAAC;iBACjC,IAAI,CAAC,IAAI,CAAC,gCAAgC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAE,CAAC,GAAG,mBAAmB,KAAK,CAAC,KAAK;iBACjG,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,IAAI,GAAG,CAAC;iBAC1B,IAAI,CAAC,IAAI,CAAC,GAAG;YAChB,GAAG,EAAE,+GAA+G;SACrH,CAAC,CAAC;IACL,CAAC;AACH,CAAC"}
@@ -0,0 +1,17 @@
1
+ import type { AnySchema } from "../../schema/schema.js";
2
+ /**
3
+ * `note` is a QUESTION ASKED OUT LOUD, not a problem.
4
+ *
5
+ * Some things a checker can see are legitimate designs that the author
6
+ * should nonetheless have looked at once: a lens written for this app and
7
+ * never proved against another domain, a role name two vocabularies both
8
+ * use, a kind unreachable on an empty graph. Filed as warnings they would
9
+ * be warnings that can only ever be acknowledged, and those are the ones
10
+ * people learn to scroll past — which costs the checker its authority on
11
+ * the warnings that matter. So they have their own voice: counted, printed,
12
+ * and never a failure.
13
+ */
14
+ import type { CheckContext } from "./context.js";
15
+ export declare function checkAccents<S extends AnySchema>(ctx: CheckContext<S>): void;
16
+ export declare function checkPalette<S extends AnySchema>(ctx: CheckContext<S>): void;
17
+ //# sourceMappingURL=brand.d.ts.map