@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.
- package/dist/controller.d.ts +27 -0
- package/dist/controller.js +11 -0
- package/dist/convert.d.ts +18 -6
- package/dist/convert.js +12 -2
- package/dist/curd.d.ts +0 -2
- package/dist/curd.js +7 -0
- package/dist/dao.d.ts +111 -2
- package/dist/dao.js +28 -2
- package/dist/db.js +3 -0
- package/dist/dsl.d.ts +16 -1
- package/dist/dsl.js +6 -0
- package/dist/dto.d.ts +6 -2
- package/dist/dto.js +20 -9
- package/dist/endpoint.d.ts +15 -0
- package/dist/endpoint.js +3 -0
- package/dist/exception.d.ts +14 -0
- package/dist/exception.js +9 -0
- package/dist/field-rule.d.ts +20 -0
- package/dist/field-rule.js +19 -0
- package/dist/flow.d.ts +24 -2
- package/dist/flow.js +16 -4
- package/dist/index.d.ts +7 -0
- package/dist/index.js +9 -0
- package/dist/mermaid-driver.js +32 -3
- package/dist/method.d.ts +11 -0
- package/dist/method.js +3 -0
- package/dist/mysql-driver.js +4 -0
- package/dist/provider.d.ts +6 -11
- package/dist/provider.js +2 -2
- package/dist/service.d.ts +16 -6
- package/dist/service.js +13 -2
- package/dist/third-service.d.ts +75 -0
- package/dist/third-service.js +96 -0
- package/dist/typebox-driver.d.ts +6 -0
- package/dist/typebox-driver.js +73 -12
- package/dist/utils.d.ts +25 -10
- package/dist/utils.js +28 -11
- package/docs/dto.md +73 -66
- package/docs/third-service.md +122 -0
- package/package.json +4 -1
- package/src/controller.ts +40 -0
- package/src/convert.ts +42 -15
- package/src/curd.ts +98 -93
- package/src/dao.ts +172 -13
- package/src/db.ts +186 -181
- package/src/dsl.ts +26 -1
- package/src/dto.ts +263 -247
- package/src/endpoint.ts +18 -0
- package/src/exception.ts +28 -0
- package/src/field-rule.ts +47 -0
- package/src/flow.ts +143 -103
- package/src/index.ts +43 -33
- package/src/mermaid-driver.ts +112 -84
- package/src/method.ts +20 -0
- package/src/mysql-driver.ts +4 -0
- package/src/provider.ts +67 -72
- package/src/service.ts +42 -20
- package/src/third-service.ts +186 -0
- package/src/typebox-driver.ts +82 -11
- package/src/utils.ts +63 -26
- package/dist/check-inheritance.d.ts +0 -9
- package/dist/check-inheritance.js +0 -58
package/src/flow.ts
CHANGED
|
@@ -1,104 +1,144 @@
|
|
|
1
|
-
import { SchemaBase } from './dsl.js';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
//
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
for (const
|
|
92
|
-
if (!
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
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 './
|
|
26
|
-
export * from './
|
|
27
|
-
export * from './
|
|
28
|
-
export * from './
|
|
29
|
-
export * from './
|
|
30
|
-
export * from './
|
|
31
|
-
export * from './
|
|
32
|
-
export * from './
|
|
33
|
-
export * from './
|
|
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';
|
package/src/mermaid-driver.ts
CHANGED
|
@@ -1,85 +1,113 @@
|
|
|
1
|
-
import { FlowEdge, FlowNode, FlowSchema } from './flow.js';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
// edges render as
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
lines.push('
|
|
21
|
-
lines.push(
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
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
|
+
}
|
package/src/mysql-driver.ts
CHANGED
|
@@ -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
|
|