@suluk/cockpit 0.1.10 → 0.1.11

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@suluk/cockpit",
3
- "version": "0.1.10",
3
+ "version": "0.1.11",
4
4
  "description": "The pure cockpit core (cycle model · builder model · codegen · deploy planning · validate/audit/preview) shared by the vscode extension and the /superadmin web admin panel. CANDIDATE tooling.",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
package/src/builder.ts CHANGED
@@ -8,6 +8,7 @@
8
8
  import type { OpenAPIv4Document, SchemaOrRef } from "@suluk/core";
9
9
  import { buildApp, toShadcnRegistry, type Entity, type BuiltApp, type DslDocument, type ParamSpec } from "@suluk/builder";
10
10
  import type { Registry } from "@suluk/builder";
11
+ import { contractToD2, diagramViews } from "./diagram";
11
12
 
12
13
  export interface BuilderNode {
13
14
  tier: "page" | "section" | "block" | "component";
@@ -88,9 +89,27 @@ export function generateAppFiles(doc: OpenAPIv4Document): GeneratedFile[] {
88
89
  const reg = toShadcnRegistry(app, { name: (doc.info?.title ?? "app").toLowerCase().replace(/\s+/g, "-") });
89
90
  files.push({ path: "registry.json", content: JSON.stringify(reg.index, null, 2) });
90
91
  for (const item of reg.items) files.push({ path: `registry/${item.name}.json`, content: JSON.stringify(item, null, 2) });
92
+ // diagrams — another projection: the app ships D2 of its own data model, cycle, and operation surface
93
+ for (const v of diagramViews()) files.push({ path: `docs/${v.id}.d2`, content: contractToD2(doc, v.id) });
94
+ files.push({ path: "docs/README.md", content: diagramsReadme(doc) });
91
95
  return files;
92
96
  }
93
97
 
98
+ function diagramsReadme(doc: OpenAPIv4Document): string {
99
+ const title = doc.info?.title ?? "this app";
100
+ return [
101
+ `# ${title} — diagrams`,
102
+ "",
103
+ "Generated from the v4 contract by Suluk. Each is [D2](https://d2lang.com) source — render with the d2 CLI",
104
+ "(`d2 erd.d2 erd.svg`), the D2 VS Code extension, or paste into <https://play.d2lang.com>.",
105
+ "",
106
+ ...diagramViews().map((v) => `- **[\`${v.id}.d2\`](./${v.id}.d2)** — ${v.description}`),
107
+ "",
108
+ "Regenerate after the contract changes: re-run **Generate full app** in the Suluk extension.",
109
+ "",
110
+ ].join("\n");
111
+ }
112
+
94
113
  /** The shadcn registry (index + items) as a pretty JSON string — the "Export shadcn registry" action. */
95
114
  export function generateRegistryJson(doc: OpenAPIv4Document): string {
96
115
  const { app } = buildBuilderModel(doc);
@@ -2,6 +2,7 @@ import { test, expect, describe } from "bun:test";
2
2
  import { parseDocument } from "@suluk/core";
3
3
  import { installModule, ECOMMERCE } from "@suluk/builder";
4
4
  import { contractToD2, diagramViews } from "../src/diagram";
5
+ import { generateAppFiles } from "../src/builder";
5
6
 
6
7
  const host = () => parseDocument(`openapi: 4.0.0-candidate
7
8
  info: { title: Shop, version: 1.0.0 }
@@ -64,6 +65,14 @@ components: { schemas: { Box: { type: object, properties: { shape: { type: strin
64
65
  expect(d2).toContain("listProduct");
65
66
  expect(d2).toContain("POST"); // createProduct etc.
66
67
  });
68
+ test("the GENERATED APP ships the contract's diagrams (docs/*.d2 + a README)", () => {
69
+ const files = generateAppFiles(doc);
70
+ const paths = files.map((f) => f.path);
71
+ for (const v of diagramViews()) expect(paths).toContain(`docs/${v.id}.d2`);
72
+ expect(paths).toContain("docs/README.md");
73
+ const erd = files.find((f) => f.path === "docs/erd.d2")!;
74
+ expect(erd.content).toContain("shape: sql_table"); // the app's own data model, as D2
75
+ });
67
76
  test("an empty contract still produces valid (non-empty) D2 for every view", () => {
68
77
  const empty = parseDocument(`openapi: 4.0.0-candidate
69
78
  info: { title: E, version: 1.0.0 }