@pylonts/dsl 1.1.5 → 1.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/README.md +4 -0
- package/dist/action.d.ts +32 -0
- package/dist/action.js +14 -0
- package/dist/aggregate.d.ts +38 -0
- package/dist/aggregate.js +46 -0
- package/dist/business-flow.d.ts +9 -0
- package/dist/business-flow.js +72 -0
- package/dist/controller.d.ts +35 -0
- package/dist/controller.js +17 -0
- package/dist/convert.d.ts +37 -7
- package/dist/convert.js +23 -2
- package/dist/curd.d.ts +7 -12
- package/dist/curd.js +10 -1
- package/dist/dao.d.ts +140 -3
- package/dist/dao.js +307 -2
- package/dist/db.d.ts +6 -0
- package/dist/db.js +13 -0
- package/dist/domain-event.d.ts +48 -0
- package/dist/domain-event.js +24 -0
- package/dist/dsl.d.ts +32 -2
- package/dist/dsl.js +13 -0
- package/dist/dto.d.ts +8 -2
- package/dist/dto.js +21 -9
- package/dist/endpoint.d.ts +15 -0
- package/dist/endpoint.js +3 -0
- package/dist/entity.d.ts +29 -0
- package/dist/entity.js +13 -0
- package/dist/exception.d.ts +20 -0
- package/dist/exception.js +33 -0
- package/dist/expr.d.ts +45 -0
- package/dist/expr.js +32 -0
- package/dist/field-rule.d.ts +20 -0
- package/dist/field-rule.js +19 -0
- package/dist/filter.d.ts +45 -0
- package/dist/filter.js +21 -0
- package/dist/flow-script.d.ts +108 -0
- package/dist/flow-script.js +505 -0
- package/dist/flow.d.ts +309 -10
- package/dist/flow.js +819 -22
- package/dist/index.d.ts +12 -1
- package/dist/index.js +14 -1
- package/dist/mermaid-driver.js +278 -9
- package/dist/method.d.ts +11 -0
- package/dist/method.js +3 -0
- package/dist/mysql-driver.js +7 -0
- package/dist/project.d.ts +5 -4
- package/dist/project.js +14 -2
- package/dist/provider.d.ts +6 -11
- package/dist/provider.js +2 -2
- package/dist/repository.d.ts +26 -0
- package/dist/repository.js +8 -0
- package/dist/service.d.ts +30 -8
- package/dist/service.js +62 -2
- package/dist/third-service.d.ts +80 -0
- package/dist/third-service.js +97 -0
- package/dist/typebox-driver.d.ts +6 -0
- package/dist/typebox-driver.js +77 -12
- package/dist/utils.d.ts +32 -10
- package/dist/utils.js +32 -11
- package/docs/aggregate.md +110 -0
- package/docs/dao-generation.md +478 -0
- package/docs/ddd-principles.md +75 -0
- package/docs/domain-event.md +137 -0
- package/docs/dto.md +73 -66
- package/docs/keyword-matcher.md +182 -0
- package/docs/third-service.md +122 -0
- package/docs/token.md +327 -0
- package/docs/trans-reentrant.md +85 -0
- package/package.json +27 -5
- package/src/action.ts +51 -10
- package/src/aggregate.ts +104 -0
- package/src/business-flow.ts +80 -0
- package/src/controller.ts +54 -0
- package/src/convert.ts +78 -15
- package/src/curd.ts +104 -93
- package/src/dao.ts +486 -13
- package/src/db.ts +199 -181
- package/src/domain-event.ts +74 -0
- package/src/dsl.ts +48 -2
- package/src/dto.ts +266 -247
- package/src/entity.ts +43 -0
- package/src/exception.ts +53 -0
- package/src/expr.ts +65 -0
- package/src/field-rule.ts +47 -0
- package/src/filter.ts +70 -0
- package/src/flow-script.ts +696 -0
- package/src/flow.ts +1226 -103
- package/src/index.ts +47 -33
- package/src/mermaid-driver.ts +339 -84
- package/src/method.ts +20 -0
- package/src/mysql-driver.ts +7 -0
- package/src/project.ts +114 -97
- package/src/repository.ts +35 -0
- package/src/service.ts +107 -20
- package/src/third-service.ts +192 -0
- package/src/typebox-driver.ts +86 -11
- package/src/utils.ts +74 -26
- package/dist/check-inheritance.d.ts +0 -9
- package/dist/check-inheritance.js +0 -58
- package/src/provider.ts +0 -73
package/src/typebox-driver.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { DtoArrayField, DtoField, DtoMessage, DtoObjectField, ImportBase, ImportRef } from './dto.js';
|
|
2
|
-
import { Field } from './dsl.js';
|
|
2
|
+
import { EnumField, Field } from './dsl.js';
|
|
3
|
+
import type { ThirdMethodSchema } from './third-service.js';
|
|
3
4
|
|
|
4
5
|
// TypeBox driver: renders a DtoMessage into TypeBox TypeScript source.
|
|
5
6
|
// Shape matches the codegen product consumed by fastify v5 TypeBoxTypeProvider:
|
|
@@ -27,6 +28,7 @@ function renderBasic(
|
|
|
27
28
|
pattern: string | undefined,
|
|
28
29
|
defaultValue: unknown,
|
|
29
30
|
resolver: EnumResolver | undefined,
|
|
31
|
+
indent = 0,
|
|
30
32
|
): string {
|
|
31
33
|
if (pattern !== undefined && field.type !== 'string') {
|
|
32
34
|
throw new Error(`pattern is only supported on string fields, got ${field.type} (${field.name})`);
|
|
@@ -77,15 +79,39 @@ function renderBasic(
|
|
|
77
79
|
}
|
|
78
80
|
return `Type.Enum(${ref.name})`;
|
|
79
81
|
}
|
|
82
|
+
case 'aggregate':
|
|
83
|
+
// Aggregate query outputs: count/sum(int) are numbers, everything else
|
|
84
|
+
// arrives as a precision string.
|
|
85
|
+
return field.jsType === 'number' ? 'Type.Number()' : 'Type.String()';
|
|
86
|
+
case 'array':
|
|
87
|
+
return `Type.Array(${renderFieldValue(field.items, indent, resolver)})`;
|
|
88
|
+
case 'object':
|
|
89
|
+
return renderFieldObject(field.properties, indent + 1, resolver);
|
|
80
90
|
default:
|
|
81
91
|
// Field union is exhaustive; this branch is unreachable at runtime.
|
|
82
92
|
throw new Error(`unsupported field type: ${String((field as Field).type)}`);
|
|
83
93
|
}
|
|
84
94
|
}
|
|
85
95
|
|
|
86
|
-
|
|
96
|
+
/** Render a plain Field value (wire-format nested fields), wrapping optional. */
|
|
97
|
+
function renderFieldValue(field: Field, indent: number, resolver: EnumResolver | undefined): string {
|
|
98
|
+
const base = renderBasic(field, undefined, undefined, resolver, indent);
|
|
99
|
+
return field.optional ? `Type.Optional(${base})` : base;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/** Render a plain Field object (wire-format nested object). */
|
|
103
|
+
function renderFieldObject(properties: Record<string, Field>, indent: number, resolver: EnumResolver | undefined): string {
|
|
104
|
+
const pad = ' '.repeat(indent);
|
|
105
|
+
const entries = Object.entries(properties).map(([name, f]) => `${pad}${name}: ${renderFieldValue(f, indent, resolver)}`);
|
|
106
|
+
return `Type.Object({\n${entries.join(',\n')}\n${' '.repeat(indent - 1)}})`;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function renderObject(fields: Record<string, DtoField | Field>, indent: number, resolver: EnumResolver | undefined): string {
|
|
87
110
|
const pad = ' '.repeat(indent);
|
|
88
|
-
const entries = Object.entries(fields).map(([name, f]) =>
|
|
111
|
+
const entries = Object.entries(fields).map(([name, f]) => {
|
|
112
|
+
const rendered = isDtoField(f) ? renderField(f, indent, resolver) : renderFieldValue(f, indent, resolver);
|
|
113
|
+
return `${pad}${name}: ${rendered}`;
|
|
114
|
+
});
|
|
89
115
|
return `Type.Object({\n${entries.join(',\n')}\n${' '.repeat(indent - 1)}})`;
|
|
90
116
|
}
|
|
91
117
|
|
|
@@ -99,7 +125,8 @@ function renderValue(f: DtoField, indent: number, resolver: EnumResolver | undef
|
|
|
99
125
|
const items = f.field.items;
|
|
100
126
|
// Referenced DTO element — render by name (same-file export), not expanded.
|
|
101
127
|
if (isDtoMessage(items)) return `Type.Array(${items.name})`;
|
|
102
|
-
return `Type.Array(${renderField(items, indent + 1, resolver)})`;
|
|
128
|
+
if (isDtoField(items)) return `Type.Array(${renderField(items, indent + 1, resolver)})`;
|
|
129
|
+
return `Type.Array(${renderFieldValue(items, indent, resolver)})`;
|
|
103
130
|
}
|
|
104
131
|
if (f.field.type === 'object') {
|
|
105
132
|
return renderObject(f.field.properties, indent + 1, resolver);
|
|
@@ -107,7 +134,7 @@ function renderValue(f: DtoField, indent: number, resolver: EnumResolver | undef
|
|
|
107
134
|
// DtoField only wraps a database Field; array/object defs live in the subclasses.
|
|
108
135
|
// Only DTO-level defaults (setDefault) are emitted as TypeBox default
|
|
109
136
|
// annotations; DB field defaults are not carried into the API contract.
|
|
110
|
-
return renderBasic(f.field as Field, f.pattern, f.default, resolver);
|
|
137
|
+
return renderBasic(f.field as Field, f.pattern, f.default, resolver, indent);
|
|
111
138
|
}
|
|
112
139
|
|
|
113
140
|
/** Structural check — DtoMessage instances may come from a different module copy, so instanceof is unreliable. */
|
|
@@ -116,6 +143,12 @@ function isDtoMessage(v: unknown): v is DtoMessage {
|
|
|
116
143
|
return (v as Record<string, unknown>).type === 'dto';
|
|
117
144
|
}
|
|
118
145
|
|
|
146
|
+
/** Structural check — a DtoField wraps a Field in a .field property and has no .type of its own. */
|
|
147
|
+
function isDtoField(v: unknown): v is DtoField {
|
|
148
|
+
if (typeof v !== 'object' || v === null) return false;
|
|
149
|
+
return 'field' in v && !('type' in v);
|
|
150
|
+
}
|
|
151
|
+
|
|
119
152
|
function collectEnumImports(
|
|
120
153
|
f: DtoField,
|
|
121
154
|
resolver: EnumResolver | undefined,
|
|
@@ -123,18 +156,45 @@ function collectEnumImports(
|
|
|
123
156
|
): void {
|
|
124
157
|
if (f.field.type === 'array') {
|
|
125
158
|
const items = f.field.items;
|
|
126
|
-
if (
|
|
159
|
+
if (isDtoMessage(items)) return;
|
|
160
|
+
if (isDtoField(items)) {
|
|
161
|
+
collectEnumImports(items, resolver, out);
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
collectFieldEnumImports(items, resolver, out);
|
|
127
165
|
return;
|
|
128
166
|
}
|
|
129
167
|
if (f.field.type === 'object') {
|
|
130
|
-
for (const child of Object.values(f.field.properties))
|
|
168
|
+
for (const child of Object.values(f.field.properties)) {
|
|
169
|
+
if (isDtoField(child)) collectEnumImports(child, resolver, out);
|
|
170
|
+
else collectFieldEnumImports(child, resolver, out);
|
|
171
|
+
}
|
|
131
172
|
return;
|
|
132
173
|
}
|
|
133
|
-
if (f.field.type === 'enum')
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
174
|
+
if (f.field.type === 'enum') collectEnumRef(f.field, resolver, out);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/** Enum import collection over a plain Field (wire-format nested fields). */
|
|
178
|
+
function collectFieldEnumImports(
|
|
179
|
+
field: Field,
|
|
180
|
+
resolver: EnumResolver | undefined,
|
|
181
|
+
out: Map<string, ImportBase>,
|
|
182
|
+
): void {
|
|
183
|
+
if (field.type === 'array') {
|
|
184
|
+
collectFieldEnumImports(field.items, resolver, out);
|
|
185
|
+
return;
|
|
137
186
|
}
|
|
187
|
+
if (field.type === 'object') {
|
|
188
|
+
for (const child of Object.values(field.properties)) collectFieldEnumImports(child, resolver, out);
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
if (field.type === 'enum') collectEnumRef(field, resolver, out);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function collectEnumRef(field: EnumField, resolver: EnumResolver | undefined, out: Map<string, ImportBase>): void {
|
|
195
|
+
const ref = resolver?.(field.enum.jsName);
|
|
196
|
+
if (!ref) throw new Error(`enum field ${field.name}: no import ref for ${field.enum.jsName} — pass an EnumResolver`);
|
|
197
|
+
out.set(`${ref.from}#${ref.name}`, ref);
|
|
138
198
|
}
|
|
139
199
|
|
|
140
200
|
/** Collect all imports needed to render a DTO: include() bases + enum references. */
|
|
@@ -191,4 +251,19 @@ function renderBase(base: ImportRef): string {
|
|
|
191
251
|
if (base.args === undefined || base.args.length === 0) return base.name;
|
|
192
252
|
const args = base.args.map((a) => (typeof a === 'string' ? a : a.name));
|
|
193
253
|
return `${base.name}(${args.join(', ')})`;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/** Render one third-party method message export (const only — pair with
|
|
257
|
+
* renderDtoTypeExport for the Static type). */
|
|
258
|
+
export function renderThirdMethodExport(schema: ThirdMethodSchema, resolver: EnumResolver | undefined): string {
|
|
259
|
+
return `export const ${schema.name} = ${renderFieldObject(schema.fields, 1, resolver)};`;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/** Collect all imports needed to render a third-party method message: enum references. */
|
|
263
|
+
export function collectThirdMethodImports(
|
|
264
|
+
schema: ThirdMethodSchema,
|
|
265
|
+
resolver: EnumResolver | undefined,
|
|
266
|
+
out: Map<string, ImportBase>,
|
|
267
|
+
): void {
|
|
268
|
+
for (const f of Object.values(schema.fields)) collectFieldEnumImports(f, resolver, out);
|
|
194
269
|
}
|
package/src/utils.ts
CHANGED
|
@@ -1,27 +1,75 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
export
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
1
|
+
import type { Field, SchemaBase } from './dsl.js';
|
|
2
|
+
import type { FrontAppSchema, ProjectApiSchema } from './project.js';
|
|
3
|
+
|
|
4
|
+
// Base utility modules — business-agnostic helpers with full method
|
|
5
|
+
// signatures (e.g. DateTimeUtils.format). Called at the service layer;
|
|
6
|
+
// their args/results are own wire types, independent of business schemas.
|
|
7
|
+
|
|
8
|
+
/** A utility method with a full signature. */
|
|
9
|
+
export interface UtilsMethodSchema extends SchemaBase {
|
|
10
|
+
type: 'utilsMethod';
|
|
11
|
+
/** The utility module this method belongs to. */
|
|
12
|
+
schema: UtilsSchema;
|
|
13
|
+
/** Input fields. */
|
|
14
|
+
args: Record<string, Field>;
|
|
15
|
+
/** Output field. */
|
|
16
|
+
result: Field;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** Method input for defineUtils: type/schema/name are set by the builder. */
|
|
20
|
+
export type UtilsMethodDef = Omit<UtilsMethodSchema, 'type' | 'schema' | 'name'>;
|
|
21
|
+
|
|
22
|
+
/** A base utility module (e.g. DateTimeUtils). */
|
|
23
|
+
export interface UtilsSchema extends SchemaBase {
|
|
24
|
+
type: 'utils';
|
|
25
|
+
/** Backend binding — the api module this utils belongs to (shared instance
|
|
26
|
+
* from project.config.ts apis). With `app` it serves that frontend
|
|
27
|
+
* ({api}/{app}/utils/); alone it is the api's public module
|
|
28
|
+
* ({api}/common/utils/). Unset = not backend-side. */
|
|
29
|
+
api?: ProjectApiSchema;
|
|
30
|
+
/** Optional binding — the frontend app this utils serves (shared instance
|
|
31
|
+
* from project.config.ts apps). Empty means a shared public module. */
|
|
32
|
+
app?: FrontAppSchema;
|
|
33
|
+
/** Methods keyed by name — the map key is written back as the method name. */
|
|
34
|
+
methods: Record<string, UtilsMethodSchema>;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function defineUtils(options: {
|
|
38
|
+
name: string;
|
|
39
|
+
api?: ProjectApiSchema;
|
|
40
|
+
app?: FrontAppSchema;
|
|
41
|
+
methods: Record<string, UtilsMethodDef>;
|
|
42
|
+
description?: string;
|
|
43
|
+
}): UtilsSchema {
|
|
44
|
+
if (options.api !== undefined && options.app !== undefined && !options.api.apps.includes(options.app)) {
|
|
45
|
+
throw new Error(`utils ${options.name}: api '${options.api.name}' does not serve app '${options.app.name}'`);
|
|
46
|
+
}
|
|
47
|
+
const schema: UtilsSchema = {
|
|
48
|
+
type: 'utils',
|
|
49
|
+
name: options.name,
|
|
50
|
+
description: options.description,
|
|
51
|
+
api: options.api,
|
|
52
|
+
app: options.app,
|
|
53
|
+
methods: {},
|
|
54
|
+
};
|
|
55
|
+
for (const key of Object.keys(options.methods)) {
|
|
56
|
+
const method = options.methods[key] as UtilsMethodDef;
|
|
57
|
+
const methodSchema: UtilsMethodSchema = {
|
|
58
|
+
type: 'utilsMethod',
|
|
59
|
+
name: key,
|
|
60
|
+
description: method.description,
|
|
61
|
+
schema,
|
|
62
|
+
args: method.args,
|
|
63
|
+
result: method.result,
|
|
64
|
+
};
|
|
65
|
+
for (const argKey of Object.keys(methodSchema.args)) {
|
|
66
|
+
const field = methodSchema.args[argKey] as Field;
|
|
67
|
+
field.name = argKey;
|
|
68
|
+
field.schema = methodSchema;
|
|
69
|
+
}
|
|
70
|
+
methodSchema.result.name = key;
|
|
71
|
+
methodSchema.result.schema = methodSchema;
|
|
72
|
+
schema.methods[key] = methodSchema;
|
|
73
|
+
}
|
|
74
|
+
return schema;
|
|
27
75
|
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
export interface InheritanceIssue {
|
|
2
|
-
file: string;
|
|
3
|
-
container: string;
|
|
4
|
-
field: string;
|
|
5
|
-
/** e.g. ["t_order.order_no"] or ["t_order.id", "t_merchant.id"] when several inferred tables share the name */
|
|
6
|
-
candidates: string[];
|
|
7
|
-
}
|
|
8
|
-
/** Check one loaded DSL module (its exports) for inheritance gaps. */
|
|
9
|
-
export declare function checkInheritance(mod: Record<string, unknown>, file: string): InheritanceIssue[];
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
/** snake_case → camelCase: order_no → orderNo; names without underscores are unchanged */
|
|
2
|
-
function toCamelCase(name) {
|
|
3
|
-
return name.replace(/_([a-z])/g, (_, c) => c.toUpperCase());
|
|
4
|
-
}
|
|
5
|
-
function isDtoMessage(v) {
|
|
6
|
-
if (typeof v !== 'object' || v === null)
|
|
7
|
-
return false;
|
|
8
|
-
const o = v;
|
|
9
|
-
return o.type === 'dto' && typeof o.name === 'string' && typeof o.fields === 'object' && o.fields !== null;
|
|
10
|
-
}
|
|
11
|
-
function collectFields(mod) {
|
|
12
|
-
const out = [];
|
|
13
|
-
for (const [name, v] of Object.entries(mod)) {
|
|
14
|
-
if (isDtoMessage(v)) {
|
|
15
|
-
const container = v;
|
|
16
|
-
for (const [fname, f] of Object.entries(container.fields)) {
|
|
17
|
-
out.push({ name: fname, field: f.field, container: name });
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
return out;
|
|
22
|
-
}
|
|
23
|
-
/** Check one loaded DSL module (its exports) for inheritance gaps. */
|
|
24
|
-
export function checkInheritance(mod, file) {
|
|
25
|
-
const fields = collectFields(mod);
|
|
26
|
-
if (fields.length === 0)
|
|
27
|
-
return [];
|
|
28
|
-
// Infer the tables this file is about from the referenced fields' schema identity.
|
|
29
|
-
const tables = new Map(); // table -> camelCol -> origCol
|
|
30
|
-
for (const f of fields) {
|
|
31
|
-
const schema = f.field.schema;
|
|
32
|
-
if (schema?.type !== 'table')
|
|
33
|
-
continue;
|
|
34
|
-
const table = schema;
|
|
35
|
-
if (!tables.has(table.name))
|
|
36
|
-
tables.set(table.name, new Map());
|
|
37
|
-
tables.get(table.name).set(toCamelCase(f.name), f.name);
|
|
38
|
-
}
|
|
39
|
-
if (tables.size === 0)
|
|
40
|
-
return [];
|
|
41
|
-
const issues = [];
|
|
42
|
-
for (const f of fields) {
|
|
43
|
-
if (f.field.schema?.type === 'table')
|
|
44
|
-
continue;
|
|
45
|
-
if (f.field.semantic !== undefined || f.field.type === 'enum')
|
|
46
|
-
continue;
|
|
47
|
-
const candidates = [];
|
|
48
|
-
for (const [t, cols] of tables) {
|
|
49
|
-
const orig = cols.get(f.name);
|
|
50
|
-
if (orig !== undefined)
|
|
51
|
-
candidates.push(`${t}.${orig}`);
|
|
52
|
-
}
|
|
53
|
-
if (candidates.length > 0) {
|
|
54
|
-
issues.push({ file, container: f.container, field: f.name, candidates });
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
return issues;
|
|
58
|
-
}
|
package/src/provider.ts
DELETED
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
import type { ImportBase } from './import-base.js';
|
|
2
|
-
import type { ImportableSchemaBase } from './dsl.js';
|
|
3
|
-
import type { DtoField, DtoMessage, DtoArrayField, DtoObjectField } from './dto.js';
|
|
4
|
-
import type { ActionSchema } from './action.js';
|
|
5
|
-
import type { RefSchema } from './ref.js';
|
|
6
|
-
import type { ConvertSchema } from './convert.js';
|
|
7
|
-
|
|
8
|
-
// ProviderSchema: an API function signature (args DTO + results DTO).
|
|
9
|
-
|
|
10
|
-
/** Parameter data source for a call argument. */
|
|
11
|
-
export type DataRef =
|
|
12
|
-
| { type: 'route'; key: string }
|
|
13
|
-
| { type: 'data'; key: string }
|
|
14
|
-
| { type: 'value'; value: unknown };
|
|
15
|
-
|
|
16
|
-
/** Create a route-parameter reference. */
|
|
17
|
-
export function route(key: string): DataRef {
|
|
18
|
-
return { type: 'route', key };
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/** Create a page-data reference. */
|
|
22
|
-
export function data(key: string): DataRef {
|
|
23
|
-
return { type: 'data', key };
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export interface CallAction extends ActionSchema {
|
|
27
|
-
type: 'call';
|
|
28
|
-
func: ProviderSchema;
|
|
29
|
-
args?: Record<string, DtoField | DtoMessage | DtoArrayField | DtoObjectField | RefSchema | string>;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
export function call(func: ProviderSchema, args?: Record<string, DtoField | DtoMessage | DtoArrayField | DtoObjectField | RefSchema | string>): CallAction {
|
|
34
|
-
return { name: func.name, type: 'call', func, args };
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/** Provider function signature. The generated API client exposes one function
|
|
38
|
-
* per endpoint; ProviderSchema gives that function a name and types. */
|
|
39
|
-
export interface ProviderSchema extends ImportableSchemaBase {
|
|
40
|
-
isAsync: boolean;
|
|
41
|
-
/** Input DTO (buildInput / buildQuery / buildPk result). */
|
|
42
|
-
args: DtoMessage;
|
|
43
|
-
/** Output DTO (buildOutput result) or primitive. */
|
|
44
|
-
results: DtoMessage | number | boolean | string;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/** Define a provider function. */
|
|
48
|
-
export function defineProvider(
|
|
49
|
-
name: string,
|
|
50
|
-
schema: {
|
|
51
|
-
isAsync: boolean;
|
|
52
|
-
args: DtoMessage;
|
|
53
|
-
results: DtoMessage | number | boolean | string;
|
|
54
|
-
description?: string;
|
|
55
|
-
importRef?: ImportBase;
|
|
56
|
-
},
|
|
57
|
-
): ProviderSchema {
|
|
58
|
-
return { name, ...schema };
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/** Assign a call's result to a page data field.
|
|
62
|
-
* React: setState({ [field]: await ... }). Mini-program: this.setData({ [field]: ... }). */
|
|
63
|
-
export interface SetDataAction extends ActionSchema {
|
|
64
|
-
type: 'setData';
|
|
65
|
-
call: CallAction;
|
|
66
|
-
field: DtoField;
|
|
67
|
-
/** Optional field-level transform before assignment. */
|
|
68
|
-
convert?: ConvertSchema;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
export function setData(call: CallAction, field: DtoField, convert?: ConvertSchema): SetDataAction {
|
|
72
|
-
return { name: 'setData', type: 'setData', call, field, convert };
|
|
73
|
-
}
|