@pylonts/dsl 1.1.5 → 1.1.6

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 (62) hide show
  1. package/dist/controller.d.ts +27 -0
  2. package/dist/controller.js +11 -0
  3. package/dist/convert.d.ts +18 -6
  4. package/dist/convert.js +12 -2
  5. package/dist/curd.d.ts +0 -2
  6. package/dist/curd.js +7 -0
  7. package/dist/dao.d.ts +111 -2
  8. package/dist/dao.js +28 -2
  9. package/dist/db.js +3 -0
  10. package/dist/dsl.d.ts +16 -1
  11. package/dist/dsl.js +6 -0
  12. package/dist/dto.d.ts +6 -2
  13. package/dist/dto.js +20 -9
  14. package/dist/endpoint.d.ts +15 -0
  15. package/dist/endpoint.js +3 -0
  16. package/dist/exception.d.ts +14 -0
  17. package/dist/exception.js +9 -0
  18. package/dist/field-rule.d.ts +20 -0
  19. package/dist/field-rule.js +19 -0
  20. package/dist/flow.d.ts +24 -2
  21. package/dist/flow.js +16 -4
  22. package/dist/index.d.ts +7 -0
  23. package/dist/index.js +9 -0
  24. package/dist/mermaid-driver.js +32 -3
  25. package/dist/method.d.ts +11 -0
  26. package/dist/method.js +3 -0
  27. package/dist/mysql-driver.js +4 -0
  28. package/dist/provider.d.ts +6 -11
  29. package/dist/provider.js +2 -2
  30. package/dist/service.d.ts +16 -6
  31. package/dist/service.js +13 -2
  32. package/dist/third-service.d.ts +75 -0
  33. package/dist/third-service.js +96 -0
  34. package/dist/typebox-driver.d.ts +6 -0
  35. package/dist/typebox-driver.js +73 -12
  36. package/dist/utils.d.ts +25 -10
  37. package/dist/utils.js +28 -11
  38. package/docs/dto.md +73 -66
  39. package/docs/third-service.md +122 -0
  40. package/package.json +4 -1
  41. package/src/controller.ts +40 -0
  42. package/src/convert.ts +42 -15
  43. package/src/curd.ts +98 -93
  44. package/src/dao.ts +172 -13
  45. package/src/db.ts +186 -181
  46. package/src/dsl.ts +26 -1
  47. package/src/dto.ts +263 -247
  48. package/src/endpoint.ts +18 -0
  49. package/src/exception.ts +28 -0
  50. package/src/field-rule.ts +47 -0
  51. package/src/flow.ts +143 -103
  52. package/src/index.ts +43 -33
  53. package/src/mermaid-driver.ts +112 -84
  54. package/src/method.ts +20 -0
  55. package/src/mysql-driver.ts +4 -0
  56. package/src/provider.ts +67 -72
  57. package/src/service.ts +42 -20
  58. package/src/third-service.ts +186 -0
  59. package/src/typebox-driver.ts +82 -11
  60. package/src/utils.ts +63 -26
  61. package/dist/check-inheritance.d.ts +0 -9
  62. package/dist/check-inheritance.js +0 -58
package/src/flow.ts CHANGED
@@ -1,104 +1,144 @@
1
- import { SchemaBase } from './dsl.js';
2
-
3
- // Flow model: nodes and edges are separate entities. A FlowNode is a plain
4
- // named step; a FlowEdge references its start/end node objects directly (no
5
- // ids). Because a node object may appear in many edges, the graph can share
6
- // nodes, merge branches, and form cycles (e.g. poll-and-retry loops).
7
-
8
- export interface FlowNode extends SchemaBase {
9
- /** Optional sub-flow. When present, entering this node runs the sub-flow;
10
- * after the sub-flow reaches any terminal node, the outer flow continues
11
- * via this node's outgoing edges. Sub-flows nest recursively. */
12
- flow?: FlowSchema;
13
- }
14
-
15
- export interface FlowEdge extends SchemaBase {
16
- /** Trigger condition; undefined = default path (success/normal). */
17
- when?: string;
18
- start: FlowNode;
19
- end: FlowNode;
20
- }
21
-
22
- export interface FlowSchema extends SchemaBase {
23
- /** Entry node. */
24
- start: FlowNode;
25
- /** All nodes, collected from edges (deduplicated by object identity). */
26
- nodes: FlowNode[];
27
- /** Independent edges; a node may be start of many edges, so cycles are expressible. */
28
- edges: FlowEdge[];
29
- }
30
-
31
- export function node(name: string, flow?: FlowSchema, description?: string): FlowNode {
32
- return { name, flow, description };
33
- }
34
-
35
- export function edge(start: FlowNode, end: FlowNode, when?: string, description?: string): FlowEdge {
36
- // Auto name for uniformity with SchemaBase; `when` stays the branch marker.
37
- return { name: `${start.name}->${end.name}`, start, end, when, description };
38
- }
39
-
40
- export function defineFlow(
41
- name: string,
42
- schema: {
43
- start: FlowNode;
44
- edges: FlowEdge[];
45
- description?: string;
46
- },
47
- ): FlowSchema {
48
- const seen = new Set<FlowNode>();
49
- const nodes: FlowNode[] = [];
50
- for (const e of schema.edges) {
51
- for (const n of [e.start, e.end]) {
52
- if (!seen.has(n)) {
53
- seen.add(n);
54
- nodes.push(n);
55
- }
56
- }
57
- }
58
- if (!seen.has(schema.start)) {
59
- seen.add(schema.start);
60
- nodes.push(schema.start);
61
- }
62
- const flow: FlowSchema = { name, description: schema.description, start: schema.start, nodes, edges: schema.edges };
63
- validate(flow);
64
- return flow;
65
- }
66
-
67
- // Nodes that never appear as an edge start are terminals. Reverse BFS from all
68
- // terminals marks every node that can reach a terminal; unmarked nodes sit on
69
- // a path that never ends (e.g. a cycle without an exit) — reject them at
70
- // definition time.
71
- function validate(schema: FlowSchema): void {
72
- const starts = new Set<FlowNode>();
73
- for (const e of schema.edges) starts.add(e.start);
74
-
75
- const reverse = new Map<FlowNode, FlowNode[]>();
76
- for (const n of schema.nodes) reverse.set(n, []);
77
- for (const e of schema.edges) {
78
- reverse.get(e.end)!.push(e.start);
79
- }
80
-
81
- const reached = new Set<FlowNode>();
82
- const queue: FlowNode[] = [];
83
- for (const n of schema.nodes) {
84
- if (!starts.has(n)) {
85
- reached.add(n);
86
- queue.push(n);
87
- }
88
- }
89
- while (queue.length > 0) {
90
- const cur = queue.shift()!;
91
- for (const prev of reverse.get(cur)!) {
92
- if (!reached.has(prev)) {
93
- reached.add(prev);
94
- queue.push(prev);
95
- }
96
- }
97
- }
98
-
99
- for (const n of schema.nodes) {
100
- if (!reached.has(n)) {
101
- throw new Error(`flow ${schema.name}: node "${n.name}" cannot reach a terminal`);
102
- }
103
- }
1
+ import { SchemaBase } from './dsl.js';
2
+ import type { MethodSchema } from './method.js';
3
+ import type { ConvertSchema } from './convert.js';
4
+ import type { DaoMethodSchema } from './dao.js';
5
+ import type { ServiceMethodSchema } from './service.js';
6
+ import type { ThirdServiceMethodSchema } from './third-service.js';
7
+ import type { UtilsMethodSchema } from './utils.js';
8
+
9
+ // Flow model: nodes and edges are separate entities. A FlowNode is a plain
10
+ // named step; a FlowEdge references its start/end node objects directly (no
11
+ // ids). Because a node object may appear in many edges, the graph can share
12
+ // nodes, merge branches, and form cycles (e.g. poll-and-retry loops).
13
+
14
+ /** A method a flow node can invoke: contract references, or a pure descriptor
15
+ * (MethodSchema) for the period before the contract file exists. */
16
+ export type FlowMethodRef =
17
+ | MethodSchema
18
+ | ConvertSchema
19
+ | DaoMethodSchema
20
+ | ServiceMethodSchema
21
+ | ThirdServiceMethodSchema
22
+ | UtilsMethodSchema;
23
+
24
+ export interface FlowNode extends SchemaBase {
25
+ /** Optional sub-flow. When present, entering this node runs the sub-flow;
26
+ * after the sub-flow reaches any terminal node, the outer flow continues
27
+ * via this node's outgoing edges. Sub-flows nest recursively. */
28
+ flow?: FlowSchema;
29
+ /** Methods this node invokes — contract references or pure descriptors
30
+ * (rendered under the node label). */
31
+ methods?: FlowMethodRef[];
32
+ }
33
+
34
+ export interface FlowEdge extends SchemaBase {
35
+ /** Trigger condition; undefined = default path (success/normal). */
36
+ when?: string;
37
+ start: FlowNode;
38
+ end: FlowNode;
39
+ /** Exception path (rendered dashed); defaults to normal. */
40
+ exception?: boolean;
41
+ }
42
+
43
+ export interface FlowSchema extends SchemaBase {
44
+ /** Entry node. */
45
+ start: FlowNode;
46
+ /** All nodes, collected from edges (deduplicated by object identity). */
47
+ nodes: FlowNode[];
48
+ /** Independent edges; a node may be start of many edges, so cycles are expressible. */
49
+ edges: FlowEdge[];
50
+ }
51
+
52
+ export function node(
53
+ name: string,
54
+ options: { flow?: FlowSchema; description?: string; methods?: FlowMethodRef[] } = {},
55
+ ): FlowNode {
56
+ return {
57
+ name,
58
+ flow: options.flow,
59
+ description: options.description,
60
+ methods: options.methods,
61
+ };
62
+ }
63
+
64
+ export function edge(
65
+ start: FlowNode,
66
+ end: FlowNode,
67
+ options: { when?: string; description?: string; exception?: boolean } = {},
68
+ ): FlowEdge {
69
+ // Auto name for uniformity with SchemaBase; `when` stays the branch marker.
70
+ return {
71
+ name: `${start.name}->${end.name}`,
72
+ start,
73
+ end,
74
+ when: options.when,
75
+ description: options.description,
76
+ exception: options.exception,
77
+ };
78
+ }
79
+
80
+ export function defineFlow(
81
+ name: string,
82
+ schema: {
83
+ start: FlowNode;
84
+ edges: FlowEdge[];
85
+ description?: string;
86
+ },
87
+ ): FlowSchema {
88
+ const seen = new Set<FlowNode>();
89
+ const nodes: FlowNode[] = [];
90
+ for (const e of schema.edges) {
91
+ for (const n of [e.start, e.end]) {
92
+ if (!seen.has(n)) {
93
+ seen.add(n);
94
+ nodes.push(n);
95
+ }
96
+ }
97
+ }
98
+ if (!seen.has(schema.start)) {
99
+ seen.add(schema.start);
100
+ nodes.push(schema.start);
101
+ }
102
+ const flow: FlowSchema = { name, description: schema.description, start: schema.start, nodes, edges: schema.edges };
103
+ validate(flow);
104
+ return flow;
105
+ }
106
+
107
+ // Nodes that never appear as an edge start are terminals. Reverse BFS from all
108
+ // terminals marks every node that can reach a terminal; unmarked nodes sit on
109
+ // a path that never ends (e.g. a cycle without an exit) — reject them at
110
+ // definition time.
111
+ function validate(schema: FlowSchema): void {
112
+ const starts = new Set<FlowNode>();
113
+ for (const e of schema.edges) starts.add(e.start);
114
+
115
+ const reverse = new Map<FlowNode, FlowNode[]>();
116
+ for (const n of schema.nodes) reverse.set(n, []);
117
+ for (const e of schema.edges) {
118
+ reverse.get(e.end)!.push(e.start);
119
+ }
120
+
121
+ const reached = new Set<FlowNode>();
122
+ const queue: FlowNode[] = [];
123
+ for (const n of schema.nodes) {
124
+ if (!starts.has(n)) {
125
+ reached.add(n);
126
+ queue.push(n);
127
+ }
128
+ }
129
+ while (queue.length > 0) {
130
+ const cur = queue.shift()!;
131
+ for (const prev of reverse.get(cur)!) {
132
+ if (!reached.has(prev)) {
133
+ reached.add(prev);
134
+ queue.push(prev);
135
+ }
136
+ }
137
+ }
138
+
139
+ for (const n of schema.nodes) {
140
+ if (!reached.has(n)) {
141
+ throw new Error(`flow ${schema.name}: node "${n.name}" cannot reach a terminal`);
142
+ }
143
+ }
104
144
  }
package/src/index.ts CHANGED
@@ -1,33 +1,43 @@
1
- export * from './dsl.js';
2
- export * from './db.js';
3
- export * from './mock.js';
4
- export * from './asset.js';
5
- export * from './dto.js';
6
- export * from './db-config.js';
7
- export * from './bases.js';
8
- export * from './utils.js';
9
- export * from './project.js';
10
- export * from './prototype.js';
11
- export * from './dictionary.js';
12
- export * from './mysql-driver.js';
13
- export * from './enum-driver.js';
14
- export * from './typebox-driver.js';
15
- export * from './pattern.js';
16
- export * from './patterns/retry.js';
17
- export * from './flow.js';
18
- export * from './action.js';
19
- export * from './event.js';
20
- export * from './component.js';
21
- export * from './convert.js';
22
- export * from './ref.js';
23
- export * from './route.js';
24
- export * from './service.js';
25
- export * from './dao.js';
26
- export * from './page.js';
27
- export * from './curd.js';
28
- export * from './page-flow.js';
29
- export * from './provider.js';
30
- export * from './page-def.js';
31
- export * from './mermaid-driver.js';
32
- export * from './navigation.js';
33
- export * from './popup.js';
1
+ export * from './dsl.js';
2
+ export * from './db.js';
3
+ export * from './mock.js';
4
+ export * from './asset.js';
5
+ export * from './dto.js';
6
+ export * from './db-config.js';
7
+ export * from './bases.js';
8
+ export * from './utils.js';
9
+ export * from './project.js';
10
+ export * from './prototype.js';
11
+ export * from './dictionary.js';
12
+ export * from './mysql-driver.js';
13
+ export * from './enum-driver.js';
14
+ export * from './typebox-driver.js';
15
+ export * from './pattern.js';
16
+ export * from './patterns/retry.js';
17
+ export * from './flow.js';
18
+ export * from './action.js';
19
+ export * from './event.js';
20
+ export * from './component.js';
21
+ export * from './convert.js';
22
+ export * from './ref.js';
23
+ export * from './route.js';
24
+ export * from './service.js';
25
+ export * from './controller.js';
26
+ export * from './endpoint.js';
27
+ export * from './dao.js';
28
+ export * from './third-service.js';
29
+ export * from './field-rule.js';
30
+ export * from './exception.js';
31
+ export * from './page.js';
32
+ export * from './curd.js';
33
+ export * from './page-flow.js';
34
+ export * from './provider.js';
35
+ export * from './page-def.js';
36
+ export * from './mermaid-driver.js';
37
+ export * from './navigation.js';
38
+ export * from './popup.js';
39
+ export * from './method.js';
40
+
41
+ // Naming conversions moved to @pylonts/core; re-exported for compatibility
42
+ // with packages that import them from @pylonts/dsl.
43
+ export { toCamelCase, toPascalCase, toKebabCase } from '@pylonts/core';
@@ -1,85 +1,113 @@
1
- import { FlowEdge, FlowNode, FlowSchema } from './flow.js';
2
- import { Page } from './page.js';
3
- import { PageEdge, PageFlow } from './page-flow.js';
4
-
5
- // Mermaid driver: converts a FlowSchema into a Mermaid flowchart (TD).
6
- // Node ids are hierarchical (n0, n0_0, n0_0_0, ...) so nested sub-flows stay
7
- // globally unique. A node with a sub-flow renders as a subgraph block whose
8
- // internals are rendered recursively. ok edges render as -->, conditional
9
- // edges render as -->|"WHEN"|.
10
-
11
- function escapeLabel(s: string): string {
12
- return s.replace(/"/g, '\\"').replace(/\n/g, '<br/>');
13
- }
14
-
15
- export function renderFlowMermaid(schema: FlowSchema): string {
16
- const lines: string[] = ['flowchart TD'];
17
- const ids = new Map<FlowNode, string>();
18
- renderFlow(schema, 'n', lines, ids);
19
- lines.push('');
20
- lines.push(' classDef start fill:#e6f4ea,stroke:#333,stroke-width:1px;');
21
- lines.push(` class ${ids.get(schema.start)} start;`);
22
- return lines.join('\n');
23
- }
24
-
25
- function renderFlow(schema: FlowSchema, prefix: string, lines: string[], ids: Map<FlowNode, string>): void {
26
- schema.nodes.forEach((n, i) => ids.set(n, `${prefix}${i}`));
27
- for (const n of schema.nodes) {
28
- const id = ids.get(n)!;
29
- if (n.flow) {
30
- lines.push(` subgraph ${id}["${escapeLabel(n.name)}"]`);
31
- renderFlow(n.flow, `${id}_`, lines, ids);
32
- lines.push(' end');
33
- } else {
34
- lines.push(` ${id}["${escapeLabel(n.name)}"]`);
35
- }
36
- }
37
- for (const e of schema.edges) {
38
- lines.push(renderEdge(e, ids));
39
- }
40
- }
41
-
42
- function renderEdge(e: FlowEdge, ids: Map<FlowNode, string>): string {
43
- const label = e.when ? `|"${escapeLabel(e.when)}"|` : '';
44
- return ` ${ids.get(e.start)} -->${label} ${ids.get(e.end)}`;
45
- }
46
-
47
- // Page-driven flow renderer: groups pages by their app into swimlane
48
- // subgraphs, then renders edges across the whole flow.
49
-
50
- export function renderPageFlowMermaid(schema: PageFlow): string {
51
- const lines: string[] = ['flowchart TD'];
52
- const ids = new Map<Page, string>();
53
-
54
- const byApp = new Map<string, Page[]>();
55
- for (const p of schema.pages) {
56
- const list = byApp.get(p.app.name);
57
- if (!list) {
58
- byApp.set(p.app.name, [p]);
59
- } else {
60
- list.push(p);
61
- }
62
- }
63
-
64
- let appIdx = 0;
65
- for (const [appName, pages] of byApp) {
66
- lines.push(` subgraph app${appIdx}["${escapeLabel(appName)}"]`);
67
- pages.forEach((p, i) => ids.set(p, `app${appIdx}_p${i}`));
68
- for (const p of pages) {
69
- const display = p.label ?? p.name;
70
- lines.push(` ${ids.get(p)}["${escapeLabel(display)}"]`);
71
- }
72
- appIdx++;
73
- lines.push(' end');
74
- }
75
-
76
- for (const e of schema.edges) {
77
- const label = e.when ? `|"${escapeLabel(e.when.name)}"|` : '';
78
- lines.push(` ${ids.get(e.start)} -->${label} ${ids.get(e.end)}`);
79
- }
80
-
81
- lines.push('');
82
- lines.push(' classDef start fill:#e6f4ea,stroke:#333,stroke-width:1px;');
83
- lines.push(` class ${ids.get(schema.start)} start;`);
84
- return lines.join('\n');
1
+ import { FlowEdge, FlowNode, FlowSchema } from './flow.js';
2
+ import type { FlowMethodRef } from './flow.js';
3
+ import { Page } from './page.js';
4
+ import { PageEdge, PageFlow } from './page-flow.js';
5
+
6
+ // Mermaid driver: converts a FlowSchema into a Mermaid flowchart (TD).
7
+ // Node ids are hierarchical (n0, n0_0, n0_0_0, ...) so nested sub-flows stay
8
+ // globally unique. A node with a sub-flow renders as a subgraph block whose
9
+ // internals are rendered recursively. ok edges render as -->, conditional
10
+ // edges render as -->|"WHEN"|.
11
+
12
+ function escapeLabel(s: string): string {
13
+ return s.replace(/"/g, '\\"').replace(/\n/g, '<br/>');
14
+ }
15
+
16
+ export function renderFlowMermaid(schema: FlowSchema): string {
17
+ const lines: string[] = ['flowchart TD'];
18
+ const ids = new Map<FlowNode, string>();
19
+ renderFlow(schema, 'n', lines, ids);
20
+ lines.push('');
21
+ lines.push(' classDef start fill:#e6f4ea,stroke:#333,stroke-width:1px;');
22
+ lines.push(` class ${ids.get(schema.start)} start;`);
23
+ return lines.join('\n');
24
+ }
25
+
26
+ function renderFlow(schema: FlowSchema, prefix: string, lines: string[], ids: Map<FlowNode, string>): void {
27
+ schema.nodes.forEach((n, i) => ids.set(n, `${prefix}${i}`));
28
+ const outgoing = new Map<FlowNode, FlowEdge[]>();
29
+ for (const n of schema.nodes) outgoing.set(n, []);
30
+ for (const e of schema.edges) outgoing.get(e.start)!.push(e);
31
+
32
+ for (const n of schema.nodes) {
33
+ const id = ids.get(n)!;
34
+ if (n.flow) {
35
+ lines.push(` subgraph ${id}["${escapeLabel(renderNodeLabel(n))}"]`);
36
+ renderFlow(n.flow, `${id}_`, lines, ids);
37
+ lines.push(' end');
38
+ } else {
39
+ const shape = renderShape(n, schema, outgoing.get(n)!);
40
+ lines.push(` ${id}${shape.open}${escapeLabel(renderNodeLabel(n))}${shape.close}`);
41
+ }
42
+ }
43
+ for (const e of schema.edges) {
44
+ lines.push(renderEdge(e, ids));
45
+ }
46
+ }
47
+
48
+ /** Node label: name on the first line, method references on the second. */
49
+ function renderNodeLabel(n: FlowNode): string {
50
+ if (n.methods === undefined || n.methods.length === 0) return n.name;
51
+ return `${n.name}\n${n.methods.map((m: FlowMethodRef) => renderMethodRef(m)).join(' | ')}`;
52
+ }
53
+
54
+ /** Display form: owner.name for descriptors and container methods, bare name for converts. */
55
+ function renderMethodRef(m: FlowMethodRef): string {
56
+ if ('owner' in m) return `${m.owner}.${m.name}`;
57
+ if ('schema' in m) return `${m.schema.name}.${m.name}`;
58
+ return m.name;
59
+ }
60
+
61
+ /** Shape derived from topology: start and terminals rounded, branching nodes diamond, else rect.
62
+ * Exception edges do not count as branches. */
63
+ function renderShape(n: FlowNode, schema: FlowSchema, outgoing: FlowEdge[]): { open: string; close: string } {
64
+ if (n === schema.start || outgoing.length === 0) return { open: '(["', close: '"])' };
65
+ const normal = outgoing.filter((e) => e.exception !== true).length;
66
+ return normal >= 2 ? { open: '{"', close: '"}' } : { open: '["', close: '"]' };
67
+ }
68
+
69
+ function renderEdge(e: FlowEdge, ids: Map<FlowNode, string>): string {
70
+ const arrow = e.exception === true ? '-.->' : '-->';
71
+ const label = e.when ? `|"${escapeLabel(e.when)}"|` : '';
72
+ return ` ${ids.get(e.start)} ${arrow}${label} ${ids.get(e.end)}`;
73
+ }
74
+
75
+ // Page-driven flow renderer: groups pages by their app into swimlane
76
+ // subgraphs, then renders edges across the whole flow.
77
+
78
+ export function renderPageFlowMermaid(schema: PageFlow): string {
79
+ const lines: string[] = ['flowchart TD'];
80
+ const ids = new Map<Page, string>();
81
+
82
+ const byApp = new Map<string, Page[]>();
83
+ for (const p of schema.pages) {
84
+ const list = byApp.get(p.app.name);
85
+ if (!list) {
86
+ byApp.set(p.app.name, [p]);
87
+ } else {
88
+ list.push(p);
89
+ }
90
+ }
91
+
92
+ let appIdx = 0;
93
+ for (const [appName, pages] of byApp) {
94
+ lines.push(` subgraph app${appIdx}["${escapeLabel(appName)}"]`);
95
+ pages.forEach((p, i) => ids.set(p, `app${appIdx}_p${i}`));
96
+ for (const p of pages) {
97
+ const display = p.label ?? p.name;
98
+ lines.push(` ${ids.get(p)}["${escapeLabel(display)}"]`);
99
+ }
100
+ appIdx++;
101
+ lines.push(' end');
102
+ }
103
+
104
+ for (const e of schema.edges) {
105
+ const label = e.when ? `|"${escapeLabel(e.when.name)}"|` : '';
106
+ lines.push(` ${ids.get(e.start)} -->${label} ${ids.get(e.end)}`);
107
+ }
108
+
109
+ lines.push('');
110
+ lines.push(' classDef start fill:#e6f4ea,stroke:#333,stroke-width:1px;');
111
+ lines.push(` class ${ids.get(schema.start)} start;`);
112
+ return lines.join('\n');
85
113
  }
package/src/method.ts ADDED
@@ -0,0 +1,20 @@
1
+ import type { SchemaBase } from './dsl.js';
2
+
3
+ // A pure descriptor of one method invocation (e.g. payDao.insert).
4
+ // No args/results — the invocation stays natural language for now.
5
+ // SequenceSchema is the ordered list of such invocations.
6
+
7
+ export interface MethodSchema extends SchemaBase {
8
+ /** Owning schema name, e.g. 'payDao'. */
9
+ owner: string;
10
+ }
11
+
12
+ export type SequenceSchema = MethodSchema[];
13
+
14
+ export function defineMethod(options: {
15
+ name: string;
16
+ owner: string;
17
+ description?: string;
18
+ }): MethodSchema {
19
+ return { name: options.name, owner: options.owner, description: options.description };
20
+ }
@@ -36,6 +36,10 @@ function columnType(field: Field): string {
36
36
  return field.enum.valueType === 'integer' ? 'TINYINT' : 'VARCHAR(20)';
37
37
  case 'json':
38
38
  return 'JSON';
39
+ case 'array':
40
+ case 'object':
41
+ // Nested fields are wire-format only (third-party messages); table columns cannot nest.
42
+ throw new Error(`field ${field.name} (${field.type}): nested fields are not supported on table columns`);
39
43
  }
40
44
  }
41
45