@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,331 @@
1
+ import { escapeString, escapeTemplate } from "./names.js";
2
+ /*
3
+ * THE DECLARATION A NEW PROJECT STARTS WITH: one kind, its acts, its rule,
4
+ * its brand, the app that holds them, and the test that proves they hold.
5
+ */
6
+ /* --------------------------------------------------------------- domain */
7
+ export function schemaTs(ids) {
8
+ return `import { createSchema, defineNode } from "@graview/core";
9
+ import { z } from "@graview/core";
10
+
11
+ /**
12
+ * The first kind. Model one thing well before modelling the domain: the
13
+ * loop that matters on day one is declare → \`graview check\` → look at it →
14
+ * declare more.
15
+ */
16
+ export const ${ids.kindVar} = defineNode("${ids.kind}", {
17
+ description: "${ids.ASpoken}: something ${escapeString(ids.name)} keeps track of.",
18
+ fields: z.object({
19
+ // A name, bounded: a model filling it writes a name, not a paragraph.
20
+ label: z.string().min(1).max(60),
21
+ status: z.enum(["open", "closed"]),
22
+ }),
23
+ edges: {
24
+ // An edge to a kind nobody declared is a typecheck failure, not a
25
+ // runtime surprise.
26
+ // One edge, two readings: each end is captioned in its own words.
27
+ "depends-on": {
28
+ to: ["${ids.kind}"],
29
+ description: "what has to be closed first",
30
+ inverse: "what is waiting on this",
31
+ },
32
+ },
33
+ plural: "${ids.Plural}",
34
+ label: (node) => node.label,
35
+ /*
36
+ * The horizon: a closed ${ids.spoken} leaves the counts but never the graph.
37
+ * Districts say "+N past" instead of drowning, and \`past=1\` widens the view.
38
+ */
39
+ lifecycle: { field: "status", retired: ["closed"] },
40
+ });
41
+
42
+ export const ${ids.schemaVar} = createSchema([${ids.kindVar}]);
43
+ export type ${ids.SchemaType} = typeof ${ids.schemaVar};
44
+ `;
45
+ }
46
+ export function mutationsTs(ids) {
47
+ return `import { bindSchema, nodeRef, type GraphReader } from "@graview/core";
48
+ import { z } from "@graview/core";
49
+ import { ${ids.schemaVar} } from "./schema.js";
50
+
51
+ const { defineMutation } = bindSchema(${ids.schemaVar});
52
+
53
+ type Reader = GraphReader<{ id: string; kind: string } & Record<string, unknown>>;
54
+ const nameOf = (graph: Reader, id: string): string => {
55
+ const node = graph.getNode(id);
56
+ return typeof node?.["label"] === "string" ? (node["label"] as string) : id;
57
+ };
58
+
59
+ /**
60
+ * Every change is a named act. The title is the label in the strip and the
61
+ * instruction in an agent's tool schema, so an opaque one costs twice.
62
+ */
63
+
64
+ export const add${ids.KindPascal} = defineMutation("add-${ids.kind}", {
65
+ title: "Add ${ids.aSpoken}",
66
+ description: "Bring a new ${ids.spoken} into ${escapeString(ids.name)}.",
67
+ // Says what it brings into existence: an EMPTY district offers this act
68
+ // as its own beginning, which is the whole onboarding of a blank graph.
69
+ creates: ["${ids.kind}"],
70
+ input: z.object({ label: z.string().min(1).max(60) }),
71
+ describe: (args) => \`Add \${args.label}\`,
72
+ apply(ctx, args) {
73
+ ctx.addNode({
74
+ id: ctx.freshId(args.label, "${ids.kind}"),
75
+ kind: "${ids.kind}",
76
+ label: args.label,
77
+ status: "open",
78
+ });
79
+ },
80
+ });
81
+
82
+ export const link${ids.KindPascal} = defineMutation("link-${ids.kind}", {
83
+ title: "Depends on",
84
+ description: "Say one ${ids.spoken} has to be closed before another.",
85
+ subject: { kinds: ["${ids.kind}"], arg: "id" },
86
+ // Names the edge kind it makes: the drawn line becomes selectable, and
87
+ // the act is offered from either end.
88
+ connects: ["depends-on"],
89
+ input: z.object({ id: nodeRef(["${ids.kind}"]), dependsOn: nodeRef(["${ids.kind}"]) }),
90
+ describe: (args, graph) =>
91
+ \`\${nameOf(graph as Reader, args.id)} depends on \${nameOf(graph as Reader, args.dependsOn)}\`,
92
+ apply(ctx, args) {
93
+ if (args.id === args.dependsOn) return;
94
+ ctx.addEdge({ kind: "depends-on", from: args.id, to: args.dependsOn });
95
+ },
96
+ });
97
+
98
+ export const unlink${ids.KindPascal} = defineMutation("unlink-${ids.kind}", {
99
+ title: "No longer depends on",
100
+ description: "Take back a dependency between two ${ids.spokenPlural}.",
101
+ subject: { kinds: ["${ids.kind}"], arg: "id" },
102
+ // Names the edge kind it breaks: a relation you can make but never unmake
103
+ // is a check warning, and a drawn line with nothing to sever hides the act.
104
+ severs: ["depends-on"],
105
+ input: z.object({ id: nodeRef(["${ids.kind}"]), dependsOn: nodeRef(["${ids.kind}"]) }),
106
+ describe: (args, graph) =>
107
+ \`\${nameOf(graph as Reader, args.id)} no longer depends on \${nameOf(graph as Reader, args.dependsOn)}\`,
108
+ apply(ctx, args) {
109
+ ctx.removeEdge({ kind: "depends-on", from: args.id, to: args.dependsOn });
110
+ },
111
+ });
112
+
113
+ export const close${ids.KindPascal} = defineMutation("close-${ids.kind}", {
114
+ title: "Close it",
115
+ description: "Mark ${ids.aSpoken} closed. It leaves the picture, never the record.",
116
+ subject: { kinds: ["${ids.kind}"], arg: "id" },
117
+ // Writes the status without asking for it, and says so.
118
+ writes: ["status"],
119
+ input: z.object({ id: nodeRef(["${ids.kind}"]) }),
120
+ describe: (args, graph) => \`Close \${nameOf(graph as Reader, args.id)}\`,
121
+ apply(ctx, args) {
122
+ ctx.patchNode(args.id, { status: "closed" });
123
+ },
124
+ });
125
+
126
+ export const mutations = [add${ids.KindPascal}, link${ids.KindPascal}, unlink${ids.KindPascal}, close${ids.KindPascal}];
127
+ `;
128
+ }
129
+ export function invariantsTs(ids) {
130
+ return `import { bindSchema, type Violation } from "@graview/core";
131
+ import { ${ids.schemaVar} } from "./schema.js";
132
+
133
+ const { defineInvariant } = bindSchema(${ids.schemaVar});
134
+
135
+ /**
136
+ * The first rule, and the repair it names. A rule that only complains is
137
+ * half a rule: the repairs below become one-click fixes in the interface
138
+ * and legal moves for an agent, so name the mutation that resolves it.
139
+ *
140
+ * It judges the OPEN ${ids.spoken}: a closed one is behind the horizon, and
141
+ * the horizon is exactly the promise that what is closed stops asking for
142
+ * attention. What is wrong here is that something closed still leans on
143
+ * something open.
144
+ */
145
+ export const closedInOrder = defineInvariant("closed-in-order", {
146
+ label: "Closed in order",
147
+ description: "Nothing closed may still depend on an open ${ids.spoken}.",
148
+ scope: { kind: "${ids.kind}" },
149
+ repairs: ["close-${ids.kind}"],
150
+ evaluate({ graph, subject }): Violation[] {
151
+ if (subject.status === "closed") return [];
152
+ const closed = graph
153
+ .in(subject.id, "depends-on")
154
+ .filter((other) => (other as { status: string }).status === "closed");
155
+ if (closed.length === 0) return [];
156
+ return [
157
+ {
158
+ invariant: "closed-in-order",
159
+ subjectId: subject.id,
160
+ label: subject.label,
161
+ message: \`\${subject.label} is still open, but \${closed.length} closed \${closed.length === 1 ? "${ids.spoken} depends" : "${ids.spokenPlural} depend"} on it\`,
162
+ nodeIds: [subject.id, ...closed.map((other) => other.id)],
163
+ repairs: [
164
+ {
165
+ mutation: "close-${ids.kind}",
166
+ args: { id: subject.id },
167
+ label: \`Close \${subject.label}\`,
168
+ },
169
+ ],
170
+ },
171
+ ];
172
+ },
173
+ });
174
+
175
+ export const invariants = [closedInOrder];
176
+ `;
177
+ }
178
+ export function brandTs(ids) {
179
+ return `import { brandFromAccent, DARK, LIGHT, type Brand } from "@graview/core";
180
+
181
+ /**
182
+ * One accent, and both schemes derived from it. \`graview check\` measures
183
+ * every text pair against AA rather than trusting the colour; if the accent
184
+ * cannot label a pending action legibly, the derivation says which pair
185
+ * failed and why instead of shipping it.
186
+ */
187
+ const ACCENT = "${ids.accent}";
188
+
189
+ const derived = brandFromAccent({ accent: ACCENT, base: { dark: DARK, light: LIGHT } });
190
+
191
+ if (!derived.ok) {
192
+ throw new Error(
193
+ \`${escapeTemplate(ids.name)} cannot be derived from \${ACCENT} alone. Needs: \${derived.missing.join(", ")} — \${derived.why}\`,
194
+ );
195
+ }
196
+
197
+ export const ${ids.brandVar}: Brand = {
198
+ name: "${escapeString(ids.name)}",
199
+ // A mark: replace it with your own. Sixteen pixels, currentColor.
200
+ logo:
201
+ '<svg viewBox="0 0 24 24" width="16" height="16" aria-hidden="true" fill="none" ' +
202
+ 'stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">' +
203
+ '<circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 3"/></svg>',
204
+ typography: {
205
+ body: 'ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif',
206
+ display: 'ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif',
207
+ mono: 'ui-monospace, SFMono-Regular, Menlo, Consolas, monospace',
208
+ },
209
+ shape: { radius: 10, density: 1 },
210
+ // Colour-by-kind, declared rather than hashed: one hue per kind.
211
+ accents: { "${ids.kind}": 150 },
212
+ schemes: derived.schemes,
213
+ };
214
+ `;
215
+ }
216
+ export function appTs(ids) {
217
+ return `import { defineApp, readerSettings, Store, type StoreOptions } from "@graview/core";
218
+ import { ${ids.brandVar} } from "./brand.js";
219
+ import { invariants } from "./invariants.js";
220
+ import { mutations } from "./mutations.js";
221
+ import { ${ids.schemaVar}, type ${ids.SchemaType} } from "./schema.js";
222
+
223
+ /**
224
+ * The whole surface, in one object. \`graview check\` reads this; so do the
225
+ * docs generator, the tool surface, the pages face and the scene. Keep React
226
+ * out of this directory and the declaration stays inspectable by a build, a
227
+ * CLI and an agent.
228
+ */
229
+ export const ${ids.appVar} = defineApp({
230
+ name: "${escapeString(ids.name)}",
231
+ schema: ${ids.schemaVar},
232
+ mutations,
233
+ invariants,
234
+ brand: ${ids.brandVar},
235
+ /*
236
+ * What belongs to the READER rather than to this installation: how big
237
+ * the words are, and whether things move. The profile pane on the bar
238
+ * draws exactly what is declared here, and the shell has already carried
239
+ * the answer to the root element — every surface is sized in \`rem\`, so
240
+ * one answer resizes the picture, the panes and the pages together.
241
+ */
242
+ settings: readerSettings(),
243
+ /*
244
+ * The intelligence, declared. The starter provider proposes first data
245
+ * from the schema alone (no key, no model); a real model plugs the same
246
+ * seam with one completion function. Both may only call what is listed.
247
+ */
248
+ intelligence: [
249
+ {
250
+ name: "starter",
251
+ kind: "graph",
252
+ description: "Proposes first data and open repairs from the declaration alone.",
253
+ may: ["add-${ids.kind}", "link-${ids.kind}", "unlink-${ids.kind}", "close-${ids.kind}"],
254
+ },
255
+ ],
256
+ });
257
+
258
+ export type ${ids.StoreType} = Store<${ids.SchemaType}>;
259
+
260
+ export function createStore(options: Partial<StoreOptions<${ids.SchemaType}>> = {}): ${ids.StoreType} {
261
+ return new Store<${ids.SchemaType}>({ schema: ${ids.schemaVar}, mutations, invariants, ...options });
262
+ }
263
+
264
+ export default ${ids.appVar};
265
+ `;
266
+ }
267
+ /* ---------------------------------------------------------------- tests */
268
+ export function domainTest(ids) {
269
+ return `import { checkApp } from "@graview/core";
270
+ import { kindCardId } from "@graview/layout";
271
+ import { deriveAffordances } from "@graview/tools";
272
+ import { describe, expect, it } from "vitest";
273
+ import { ${ids.appVar}, createStore } from "../src/domain/app.js";
274
+
275
+ /**
276
+ * The domain tier has no DOM in it, so these run headless. The test worth
277
+ * having is the one that catches a real regression: the rule fires on a
278
+ * graph that breaks it, and the repair it names resolves it.
279
+ */
280
+
281
+ describe("the declaration", () => {
282
+ it("passes its own check", () => {
283
+ const result = checkApp(${ids.appVar});
284
+ expect(result.findings.filter((f) => f.severity === "error")).toEqual([]);
285
+ expect(result.ok).toBe(true);
286
+ });
287
+
288
+ it("offers an empty district its own beginnings, through creates", () => {
289
+ const store = createStore();
290
+ const { affordances } = deriveAffordances(store, [kindCardId("${ids.kind}")], {
291
+ kindSelection: ["${ids.kind}"],
292
+ });
293
+ expect(affordances.map((a) => a.mutation)).toContain("add-${ids.kind}");
294
+ });
295
+ });
296
+
297
+ describe("the rule", () => {
298
+ const broken = () => {
299
+ const store = createStore();
300
+ store.apply({ name: "add-${ids.kind}", args: { label: "First" } });
301
+ store.apply({ name: "add-${ids.kind}", args: { label: "Second" } });
302
+ const [first, second] = store.graph.nodesOfKind("${ids.kind}");
303
+ store.apply({ name: "link-${ids.kind}", args: { id: second!.id, dependsOn: first!.id } });
304
+ store.apply({ name: "close-${ids.kind}", args: { id: second!.id } });
305
+ return store;
306
+ };
307
+
308
+ it("fires when a closed ${ids.spoken} still depends on an open one", () => {
309
+ // One rule at a time: the second rule you declare must not fail this test.
310
+ const violations = broken().violations().filter((v) => v.invariant === "closed-in-order");
311
+ expect(violations).toHaveLength(1);
312
+ expect(violations[0]?.message).toMatch(/still open, but 1 closed/);
313
+ expect(violations[0]?.repairs).toHaveLength(1);
314
+ });
315
+
316
+ it("is resolved by the repair it names", () => {
317
+ const store = broken();
318
+ const repair = store.violations().find((v) => v.invariant === "closed-in-order")!.repairs[0]!;
319
+ store.apply({ name: repair.mutation, args: { ...repair.args } });
320
+ expect(store.violations().filter((v) => v.invariant === "closed-in-order")).toEqual([]);
321
+ });
322
+
323
+ it("keeps a closed ${ids.spoken} in the record, behind the horizon", () => {
324
+ const store = broken();
325
+ const closed = store.graph.nodesOfKind("${ids.kind}").filter((n) => n.status === "closed");
326
+ expect(closed).toHaveLength(1);
327
+ });
328
+ });
329
+ `;
330
+ }
331
+ //# sourceMappingURL=domain.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"domain.js","sourceRoot":"","sources":["../../src/scaffold/domain.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,66 @@
1
+ export { pascal, slugify, titleCase, validateScaffoldOptions } from "./names.js";
2
+ export { GRAVIEW_PACKAGES, LINKED_PACKAGES } from "./project.js";
3
+ export interface ScaffoldOptions {
4
+ /** The product's name, as a person would say it: "Field Notes". */
5
+ readonly name: string;
6
+ /** The first node kind, as a slug: "note". Defaults to "item". */
7
+ readonly kind?: string;
8
+ /** The kind's plural, for districts and routes. Defaults to `${kind}s`. */
9
+ readonly plural?: string;
10
+ /** The npm package name. Defaults to the name, slugged. */
11
+ readonly packageName?: string;
12
+ /**
13
+ * The version range every `@graview/*` dependency takes. A published
14
+ * project wants the version of the packages that scaffolded it.
15
+ */
16
+ readonly range?: string;
17
+ /**
18
+ * A path to the framework repository, relative to the new project, for a
19
+ * project that consumes the framework by path rather than from a registry
20
+ * (`link:` dependencies, aliases into its sources, the dev server allowed
21
+ * to read it). This is how the first-party products are wired.
22
+ */
23
+ readonly link?: string;
24
+ /**
25
+ * In link mode: the framework's repository as "owner/name", so the
26
+ * project's CI can check it out as a sibling and build it before verify.
27
+ * Without it the workflow says what to fill in.
28
+ */
29
+ readonly frameworkRepo?: string;
30
+ /** Which package manager the project's scripts and CI assume. */
31
+ readonly packageManager?: "pnpm" | "npm";
32
+ /** The dev server's port. */
33
+ readonly port?: number;
34
+ /** The brand accent, as a hex colour. */
35
+ readonly accent?: string;
36
+ /**
37
+ * THE LAYOUT EVERY REAL PRODUCT ENDS UP WITH: a workspace root with the
38
+ * app under `app/`.
39
+ *
40
+ * A single standalone package is what this wrote, and no first-party
41
+ * product is one — because a real product accretes sibling things:
42
+ * `scripts/` for the harnesses, `docs/`, a PRD, a second surface. The
43
+ * harnesses are the tell. The framework documents `survey`, `audit-ui`,
44
+ * `a11y`, `shrunk` and `seat` as the things a serious product should
45
+ * steal, and then scaffolded a layout with nowhere to put them, so two
46
+ * products independently hand-wrote a workspace root around the scaffold.
47
+ * Two is a gap rather than a taste.
48
+ */
49
+ readonly workspace?: boolean;
50
+ }
51
+ export interface ScaffoldFile {
52
+ readonly path: string;
53
+ readonly contents: string;
54
+ }
55
+ export interface Scaffold {
56
+ readonly files: readonly ScaffoldFile[];
57
+ readonly name: string;
58
+ readonly packageName: string;
59
+ readonly kind: string;
60
+ readonly plural: string;
61
+ readonly packageManager: "pnpm" | "npm";
62
+ readonly port: number;
63
+ readonly linked: boolean;
64
+ }
65
+ export declare function scaffoldProject(options: ScaffoldOptions): Scaffold;
66
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/scaffold/index.ts"],"names":[],"mappings":"AAmCA,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AACjF,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAEjE,MAAM,WAAW,eAAe;IAC9B,mEAAmE;IACnE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,kEAAkE;IAClE,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,2EAA2E;IAC3E,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,2DAA2D;IAC3D,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B;;;OAGG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB;;;;;OAKG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB;;;;OAIG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,iEAAiE;IACjE,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IACzC,6BAA6B;IAC7B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,yCAAyC;IACzC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB;;;;;;;;;;;;OAYG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,KAAK,EAAE,SAAS,YAAY,EAAE,CAAC;IACxC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,cAAc,EAAE,MAAM,GAAG,KAAK,CAAC;IACxC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;CAC1B;AAID,wBAAgB,eAAe,CAAC,OAAO,EAAE,eAAe,GAAG,QAAQ,CA6HlE"}
@@ -0,0 +1,142 @@
1
+ /**
2
+ * A new project, as a list of files.
3
+ *
4
+ * This module writes nothing. It takes a name and a first kind and returns
5
+ * every file a product on Graview starts with — the declaration split into
6
+ * domain and UI, the shell, the tests, the CI — so that the CLI can put them
7
+ * on disk, a test can assert on them without a filesystem, and a host that
8
+ * provisions apps from a declaration can call the same thing in-process.
9
+ *
10
+ * The shape here IS the shape the `graview-new-app` skill describes. When one
11
+ * changes, the other has to, and `scripts/smoke-create.mjs` is what notices:
12
+ * it scaffolds a project from the packed tarballs, installs it the way a
13
+ * stranger would, and runs the project's own `verify`.
14
+ */
15
+ import { withArticle } from "../schema/define-node.js";
16
+ import { slugify, titleCase, camel, pascal, validateScaffoldOptions } from "./names.js";
17
+ import { SURVEY_SAYS, AUDIT_SAYS, A11Y_SAYS, harness, workspaceRoot, tsconfigBase, rootVitest, packageJson, tsconfig, tsconfigBuild, viteConfig, gitignore, readme, ciYml, } from "./project.js";
18
+ import { schemaTs, mutationsTs, invariantsTs, brandTs, appTs, domainTest } from "./domain.js";
19
+ import { indexHtml, embedHtml, embedTsx, viewsTsx, uiAppTsx, pagesTsx, mainTsx } from "./ui.js";
20
+ export { pascal, slugify, titleCase, validateScaffoldOptions } from "./names.js";
21
+ export { GRAVIEW_PACKAGES, LINKED_PACKAGES } from "./project.js";
22
+ export function scaffoldProject(options) {
23
+ const problems = validateScaffoldOptions(options);
24
+ if (problems.length > 0)
25
+ throw new Error(problems.join("\n"));
26
+ const name = options.name.trim();
27
+ const kind = options.kind ?? "item";
28
+ const plural = options.plural ?? `${kind}s`;
29
+ const packageName = options.packageName ?? slugify(name);
30
+ const packageManager = options.packageManager ?? "pnpm";
31
+ const port = options.port ?? 5170;
32
+ const range = options.range ?? "*";
33
+ const workspace = options.workspace === true;
34
+ const rootLink = options.link?.replace(/\/+$/, "");
35
+ /*
36
+ * Every path the APP writes is one directory deeper in a workspace, so
37
+ * the link it consumes the framework by is one `../` longer. The root's
38
+ * own files use the link as given.
39
+ */
40
+ const link = rootLink === undefined ? undefined : workspace ? `../${rootLink}` : rootLink;
41
+ // A worked green that clears the checker's contrast pairs in both schemes.
42
+ const accent = options.accent ?? "#2e7d32";
43
+ // "work-order" is an identifier; a button says "work order".
44
+ const spoken = kind.replace(/-/g, " ");
45
+ const spokenPlural = plural.replace(/-/g, " ");
46
+ /*
47
+ * "Add a item" is what a template writes when the article is a literal.
48
+ * The kind is the author's word and half of them begin with a vowel, so
49
+ * every generated sentence takes its article from `withArticle` — the same
50
+ * one the checker and the strip use, so the project a stranger reads and
51
+ * the framework talking about it cannot disagree.
52
+ */
53
+ const aSpoken = withArticle(kind);
54
+ const ASpoken = aSpoken.charAt(0).toUpperCase() + aSpoken.slice(1);
55
+ const ids = {
56
+ name,
57
+ kind,
58
+ plural,
59
+ spoken,
60
+ spokenPlural,
61
+ aSpoken,
62
+ ASpoken,
63
+ Kind: titleCase(kind),
64
+ Plural: titleCase(plural),
65
+ kindVar: camel(kind),
66
+ KindPascal: pascal(kind),
67
+ appVar: `${camel(slugify(name))}App`,
68
+ brandVar: `${camel(slugify(name))}Brand`,
69
+ schemaVar: `${camel(slugify(name))}Schema`,
70
+ SchemaType: `${pascal(slugify(name))}Schema`,
71
+ StoreType: `${pascal(slugify(name))}Store`,
72
+ AppComponent: `${pascal(slugify(name))}App`,
73
+ accent,
74
+ port,
75
+ link,
76
+ frameworkRepo: options.frameworkRepo,
77
+ range,
78
+ packageManager,
79
+ packageName,
80
+ };
81
+ const files = [
82
+ { path: "package.json", contents: packageJson(ids, workspace) },
83
+ { path: "tsconfig.json", contents: tsconfig(workspace) },
84
+ { path: "tsconfig.build.json", contents: tsconfigBuild() },
85
+ { path: "vite.config.ts", contents: viteConfig(ids) },
86
+ { path: "index.html", contents: indexHtml(ids) },
87
+ { path: "embed.html", contents: embedHtml(ids) },
88
+ { path: ".gitignore", contents: gitignore() },
89
+ { path: "README.md", contents: readme(ids) },
90
+ { path: "src/domain/schema.ts", contents: schemaTs(ids) },
91
+ { path: "src/domain/mutations.ts", contents: mutationsTs(ids) },
92
+ { path: "src/domain/invariants.ts", contents: invariantsTs(ids) },
93
+ { path: "src/domain/brand.ts", contents: brandTs(ids) },
94
+ { path: "src/domain/app.ts", contents: appTs(ids) },
95
+ { path: "src/ui/views.tsx", contents: viewsTsx(ids) },
96
+ { path: "src/ui/app.tsx", contents: uiAppTsx(ids) },
97
+ { path: "src/ui/pages.tsx", contents: pagesTsx(ids) },
98
+ { path: "src/main.tsx", contents: mainTsx(ids) },
99
+ { path: "src/embed.tsx", contents: embedTsx(ids) },
100
+ { path: "tests/domain.test.ts", contents: domainTest(ids) },
101
+ { path: ".github/workflows/ci.yml", contents: ciYml(ids) },
102
+ ];
103
+ if (!workspace) {
104
+ return { files, name, packageName, kind, plural, packageManager, port, linked: link !== undefined };
105
+ }
106
+ /*
107
+ * THE WORKSPACE: the app under `app/`, and a root that has somewhere to
108
+ * put the things a product accretes. The harnesses are the point — they
109
+ * want to live at a root and drive the app — so they are written as stubs
110
+ * that say what they would measure rather than as a `scripts/` directory
111
+ * somebody has to invent.
112
+ */
113
+ /*
114
+ * What belongs to the PRODUCT rather than to the app package stays at the
115
+ * root: the README a person reads first, the CI that verifies the whole
116
+ * workspace, and the one .gitignore.
117
+ */
118
+ const atRoot = new Set(["README.md", ".gitignore", ".github/workflows/ci.yml"]);
119
+ const rooted = files.map((file) => atRoot.has(file.path) ? file : { ...file, path: `app/${file.path}` });
120
+ return {
121
+ files: [
122
+ { path: "package.json", contents: workspaceRoot(ids, rootLink) },
123
+ ...(packageManager === "pnpm"
124
+ ? [{ path: "pnpm-workspace.yaml", contents: "packages:\n - app\n" }]
125
+ : []),
126
+ { path: "tsconfig.base.json", contents: tsconfigBase() },
127
+ { path: "vitest.config.ts", contents: rootVitest() },
128
+ { path: "scripts/survey.mjs", contents: harness("survey", SURVEY_SAYS, ids) },
129
+ { path: "scripts/audit-ui.mjs", contents: harness("audit-ui", AUDIT_SAYS, ids) },
130
+ { path: "scripts/a11y.mjs", contents: harness("a11y", A11Y_SAYS, ids) },
131
+ ...rooted,
132
+ ],
133
+ name,
134
+ packageName,
135
+ kind,
136
+ plural,
137
+ packageManager,
138
+ port,
139
+ linked: link !== undefined,
140
+ };
141
+ }
142
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/scaffold/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ import type { ScaffoldFile } from "./index.js";
2
+ /**
3
+ * `graview lens <name>`: a lens, started.
4
+ *
5
+ * `graview figure` draws line art for a kind, and nothing generated a lens.
6
+ * The `graview-lens` skill is excellent about the RULES — bind roles not
7
+ * field names, fail loudly on a bad binding, mark every target with
8
+ * `data-graview-pick`, three fidelities, a title that makes it a place — and
9
+ * those are exactly the rules that are easy to agree with and easy to forget
10
+ * at line 300.
11
+ *
12
+ * So the stub has all of them already in it, and the reuse test — the one
13
+ * instruction with nothing enforcing it — starts life as a RED test in a
14
+ * domain the app is not about, rather than as a good intention. A lens whose
15
+ * reuse test cannot be written is a view; the stub says so in the place
16
+ * where you would find that out.
17
+ */
18
+ export interface LensScaffoldOptions {
19
+ /** The lens's name, as a slug: "grounds-map". */
20
+ readonly name: string;
21
+ /** Roles the lens requires an app to bind. */
22
+ readonly roles: readonly string[];
23
+ /** Field names onto roles, or roles onto whole kinds and edges. */
24
+ readonly binds?: "fields" | "entities";
25
+ /** Where the lens goes. Defaults to `src/ui/lens`. */
26
+ readonly dir?: string;
27
+ }
28
+ export declare function validateLensOptions(options: LensScaffoldOptions): readonly string[];
29
+ /** The files a new lens is: the lens itself, and the test that proves it. */
30
+ export declare function scaffoldLens(options: LensScaffoldOptions): readonly ScaffoldFile[];
31
+ //# sourceMappingURL=lens.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lens.d.ts","sourceRoot":"","sources":["../../src/scaffold/lens.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C;;;;;;;;;;;;;;;GAeG;AAEH,MAAM,WAAW,mBAAmB;IAClC,iDAAiD;IACjD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,8CAA8C;IAC9C,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,mEAAmE;IACnE,QAAQ,CAAC,KAAK,CAAC,EAAE,QAAQ,GAAG,UAAU,CAAC;IACvC,sDAAsD;IACtD,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,mBAAmB,GAAG,SAAS,MAAM,EAAE,CAYnF;AAED,6EAA6E;AAC7E,wBAAgB,YAAY,CAAC,OAAO,EAAE,mBAAmB,GAAG,SAAS,YAAY,EAAE,CAUlF"}