@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,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":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AACxF,OAAO,EACL,WAAW,EACX,UAAU,EACV,SAAS,EACT,OAAO,EACP,aAAa,EACb,YAAY,EACZ,UAAU,EACV,WAAW,EACX,QAAQ,EACR,aAAa,EACb,UAAU,EACV,SAAS,EACT,MAAM,EACN,KAAK,GACN,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,YAAY,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC9F,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAEhG,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AACjF,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAqEjE,MAAM,UAAU,eAAe,CAAC,OAAwB;IACtD,MAAM,QAAQ,GAAG,uBAAuB,CAAC,OAAO,CAAC,CAAC;IAClD,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IAE9D,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;IACjC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,MAAM,CAAC;IACpC,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC;IAC5C,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACzD,MAAM,cAAc,GAAG,OAAO,CAAC,cAAc,IAAI,MAAM,CAAC;IACxD,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,IAAI,CAAC;IAClC,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,GAAG,CAAC;IACnC,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,KAAK,IAAI,CAAC;IAC7C,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACnD;;;;OAIG;IACH,MAAM,IAAI,GAAG,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,QAAQ,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC;IAC1F,2EAA2E;IAC3E,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,SAAS,CAAC;IAE3C,6DAA6D;IAC7D,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IACvC,MAAM,YAAY,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IAC/C;;;;;;OAMG;IACH,MAAM,OAAO,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;IAClC,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACnE,MAAM,GAAG,GAAG;QACV,IAAI;QACJ,IAAI;QACJ,MAAM;QACN,MAAM;QACN,YAAY;QACZ,OAAO;QACP,OAAO;QACP,IAAI,EAAE,SAAS,CAAC,IAAI,CAAC;QACrB,MAAM,EAAE,SAAS,CAAC,MAAM,CAAC;QACzB,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC;QACpB,UAAU,EAAE,MAAM,CAAC,IAAI,CAAC;QACxB,MAAM,EAAE,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK;QACpC,QAAQ,EAAE,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,OAAO;QACxC,SAAS,EAAE,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,QAAQ;QAC1C,UAAU,EAAE,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,QAAQ;QAC5C,SAAS,EAAE,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,OAAO;QAC1C,YAAY,EAAE,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK;QAC3C,MAAM;QACN,IAAI;QACJ,IAAI;QACJ,aAAa,EAAE,OAAO,CAAC,aAAa;QACpC,KAAK;QACL,cAAc;QACd,WAAW;KACZ,CAAC;IAEF,MAAM,KAAK,GAAmB;QAC5B,EAAE,IAAI,EAAE,cAAc,EAAE,QAAQ,EAAE,WAAW,CAAC,GAAG,EAAE,SAAS,CAAC,EAAE;QAC/D,EAAE,IAAI,EAAE,eAAe,EAAE,QAAQ,EAAE,QAAQ,CAAC,SAAS,CAAC,EAAE;QACxD,EAAE,IAAI,EAAE,qBAAqB,EAAE,QAAQ,EAAE,aAAa,EAAE,EAAE;QAC1D,EAAE,IAAI,EAAE,gBAAgB,EAAE,QAAQ,EAAE,UAAU,CAAC,GAAG,CAAC,EAAE;QACrD,EAAE,IAAI,EAAE,YAAY,EAAE,QAAQ,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE;QAChD,EAAE,IAAI,EAAE,YAAY,EAAE,QAAQ,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE;QAChD,EAAE,IAAI,EAAE,YAAY,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE;QAC7C,EAAE,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE;QAC5C,EAAE,IAAI,EAAE,sBAAsB,EAAE,QAAQ,EAAE,QAAQ,CAAC,GAAG,CAAC,EAAE;QACzD,EAAE,IAAI,EAAE,yBAAyB,EAAE,QAAQ,EAAE,WAAW,CAAC,GAAG,CAAC,EAAE;QAC/D,EAAE,IAAI,EAAE,0BAA0B,EAAE,QAAQ,EAAE,YAAY,CAAC,GAAG,CAAC,EAAE;QACjE,EAAE,IAAI,EAAE,qBAAqB,EAAE,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,EAAE;QACvD,EAAE,IAAI,EAAE,mBAAmB,EAAE,QAAQ,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE;QACnD,EAAE,IAAI,EAAE,kBAAkB,EAAE,QAAQ,EAAE,QAAQ,CAAC,GAAG,CAAC,EAAE;QACrD,EAAE,IAAI,EAAE,gBAAgB,EAAE,QAAQ,EAAE,QAAQ,CAAC,GAAG,CAAC,EAAE;QACnD,EAAE,IAAI,EAAE,kBAAkB,EAAE,QAAQ,EAAE,QAAQ,CAAC,GAAG,CAAC,EAAE;QACrD,EAAE,IAAI,EAAE,cAAc,EAAE,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,EAAE;QAChD,EAAE,IAAI,EAAE,eAAe,EAAE,QAAQ,EAAE,QAAQ,CAAC,GAAG,CAAC,EAAE;QAClD,EAAE,IAAI,EAAE,sBAAsB,EAAE,QAAQ,EAAE,UAAU,CAAC,GAAG,CAAC,EAAE;QAC3D,EAAE,IAAI,EAAE,0BAA0B,EAAE,QAAQ,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE;KAC3D,CAAC;IAEF,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,KAAK,SAAS,EAAE,CAAC;IACtG,CAAC;IAED;;;;;;OAMG;IACH;;;;OAIG;IACH,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,CAAC,WAAW,EAAE,YAAY,EAAE,0BAA0B,CAAC,CAAC,CAAC;IAChF,MAAM,MAAM,GAAmB,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAChD,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,IAAI,EAAE,OAAO,IAAI,CAAC,IAAI,EAAE,EAAE,CACrE,CAAC;IACF,OAAO;QACL,KAAK,EAAE;YACL,EAAE,IAAI,EAAE,cAAc,EAAE,QAAQ,EAAE,aAAa,CAAC,GAAG,EAAE,QAAQ,CAAC,EAAE;YAChE,GAAG,CAAC,cAAc,KAAK,MAAM;gBAC3B,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,qBAAqB,EAAE,QAAQ,EAAE,sBAAsB,EAAE,CAAC;gBACrE,CAAC,CAAC,EAAE,CAAC;YACP,EAAE,IAAI,EAAE,oBAAoB,EAAE,QAAQ,EAAE,YAAY,EAAE,EAAE;YACxD,EAAE,IAAI,EAAE,kBAAkB,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE;YACpD,EAAE,IAAI,EAAE,oBAAoB,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,WAAW,EAAE,GAAG,CAAC,EAAE;YAC7E,EAAE,IAAI,EAAE,sBAAsB,EAAE,QAAQ,EAAE,OAAO,CAAC,UAAU,EAAE,UAAU,EAAE,GAAG,CAAC,EAAE;YAChF,EAAE,IAAI,EAAE,kBAAkB,EAAE,QAAQ,EAAE,OAAO,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,CAAC,EAAE;YACvE,GAAG,MAAM;SACV;QACD,IAAI;QACJ,WAAW;QACX,IAAI;QACJ,MAAM;QACN,cAAc;QACd,IAAI;QACJ,MAAM,EAAE,IAAI,KAAK,SAAS;KAC3B,CAAC;AACJ,CAAC"}
|
|
@@ -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"}
|