@pylonts/dsl 1.0.5 → 1.1.1

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 (78) hide show
  1. package/README.md +2 -1
  2. package/dist/asset.d.ts +48 -0
  3. package/dist/asset.js +31 -0
  4. package/dist/bases.d.ts +6 -2
  5. package/dist/bases.js +10 -6
  6. package/dist/check-inheritance.js +1 -4
  7. package/dist/curd.d.ts +60 -0
  8. package/dist/curd.js +31 -0
  9. package/dist/db-config.d.ts +8 -0
  10. package/dist/db-config.js +1 -0
  11. package/dist/db.d.ts +52 -0
  12. package/dist/db.js +91 -0
  13. package/dist/dictionary.d.ts +26 -5
  14. package/dist/dictionary.js +21 -8
  15. package/dist/dsl.d.ts +5 -49
  16. package/dist/dsl.js +12 -103
  17. package/dist/dto.d.ts +14 -9
  18. package/dist/dto.js +28 -38
  19. package/dist/enum-driver.d.ts +1 -1
  20. package/dist/enum-driver.js +1 -4
  21. package/dist/flow.d.ts +1 -1
  22. package/dist/flow.js +3 -8
  23. package/dist/import-base.d.ts +15 -0
  24. package/dist/import-base.js +1 -0
  25. package/dist/index.d.ts +21 -17
  26. package/dist/index.js +21 -33
  27. package/dist/mermaid-driver.d.ts +2 -2
  28. package/dist/mermaid-driver.js +2 -6
  29. package/dist/mock.d.ts +30 -0
  30. package/dist/mock.js +18 -0
  31. package/dist/mysql-driver.d.ts +1 -1
  32. package/dist/mysql-driver.js +20 -10
  33. package/dist/page-flow.d.ts +2 -2
  34. package/dist/page-flow.js +2 -6
  35. package/dist/page.d.ts +6 -6
  36. package/dist/page.js +3 -8
  37. package/dist/pattern.js +2 -6
  38. package/dist/patterns/retry.d.ts +1 -1
  39. package/dist/patterns/retry.js +2 -6
  40. package/dist/project.d.ts +18 -13
  41. package/dist/project.js +41 -6
  42. package/dist/prototype.d.ts +1 -1
  43. package/dist/prototype.js +1 -4
  44. package/dist/typebox-driver.d.ts +3 -3
  45. package/dist/typebox-driver.js +28 -24
  46. package/dist/utils.d.ts +2 -0
  47. package/dist/utils.js +5 -4
  48. package/docs/curd.md +111 -0
  49. package/docs/dictionary.md +42 -31
  50. package/docs/driver.md +42 -42
  51. package/docs/dto.md +66 -66
  52. package/docs/enum.md +24 -24
  53. package/docs/project.md +2 -2
  54. package/docs/table.md +50 -15
  55. package/package.json +6 -4
  56. package/src/asset.ts +63 -0
  57. package/src/bases.ts +12 -2
  58. package/src/curd.ts +92 -0
  59. package/src/db-config.ts +8 -0
  60. package/src/db.ts +142 -0
  61. package/src/dictionary.ts +45 -19
  62. package/src/dsl.ts +182 -281
  63. package/src/dto.ts +247 -234
  64. package/src/enum-driver.ts +1 -1
  65. package/src/flow.ts +1 -1
  66. package/src/import-base.ts +15 -0
  67. package/src/index.ts +21 -17
  68. package/src/mermaid-driver.ts +3 -3
  69. package/src/mock.ts +45 -0
  70. package/src/mysql-driver.ts +19 -6
  71. package/src/page-flow.ts +3 -3
  72. package/src/page.ts +7 -7
  73. package/src/patterns/retry.ts +1 -1
  74. package/src/project.ts +90 -54
  75. package/src/prototype.ts +1 -1
  76. package/src/typebox-driver.ts +192 -183
  77. package/src/utils.ts +5 -0
  78. package/src/check-inheritance.ts +0 -86
@@ -1,4 +1,5 @@
1
- import { Field, ForeignKey, Index, TableSchema } from './dsl';
1
+ import { Field } from './dsl.js';
2
+ import { ForeignKey, Index, TableSchema } from './db.js';
2
3
 
3
4
  // MySQL driver: converts a TableSchema into a CREATE TABLE statement.
4
5
 
@@ -31,11 +32,23 @@ function columnType(field: Field): string {
31
32
  }
32
33
  }
33
34
 
35
+ function renderDefault(field: Field): string {
36
+ if (field.default === undefined) return '';
37
+ // CURRENT_TIMESTAMP is a MySQL function keyword, not a string literal.
38
+ if (field.default === 'CURRENT_TIMESTAMP') return ' DEFAULT CURRENT_TIMESTAMP';
39
+ // Numeric columns take a bare literal, not a quoted one.
40
+ if (field.type === 'integer' || field.type === 'bigint' || field.type === 'decimal' || field.type === 'boolean') {
41
+ return ` DEFAULT ${field.default}`;
42
+ }
43
+ return ` DEFAULT '${field.default}'`;
44
+ }
45
+
34
46
  function columnDef(field: Field, autoIncrement?: Field): string {
35
47
  const parts = [field.name, columnType(field)];
36
48
  if (field.optional === false) parts.push('NOT NULL');
37
- if (field.default !== undefined) parts.push(`DEFAULT '${field.default}'`);
49
+ parts.push(renderDefault(field));
38
50
  if (field === autoIncrement) parts.push('AUTO_INCREMENT');
51
+ if (field.description) parts.push(`COMMENT '${field.description.replace(/'/g, "\\'")}'`);
39
52
  return parts.join(' ');
40
53
  }
41
54
 
@@ -46,14 +59,14 @@ function primaryKeyClause(schema: TableSchema): string | null {
46
59
  }
47
60
 
48
61
  function indexClause(index: Index): string {
49
- const fields = Array.isArray(index.fields) ? index.fields : [index.fields];
62
+ const fields = Array.isArray(index.columns) ? index.columns : [index.columns];
50
63
  const kind = index.unique ? 'UNIQUE KEY' : 'KEY';
51
64
  const name = index.name ?? fields.map((f) => f.name).join('_');
52
65
  return `${kind} ${name} (${fields.map((f) => f.name).join(', ')})`;
53
66
  }
54
67
 
55
68
  function foreignKeyClause(name: string, fk: ForeignKey): string {
56
- const fields = Array.isArray(fk.fields) ? fk.fields : [fk.fields];
69
+ const fields = Array.isArray(fk.columns) ? fk.columns : [fk.columns];
57
70
  const refs = Array.isArray(fk.references) ? fk.references : [fk.references];
58
71
  const refTable = refs[0].schema?.name;
59
72
  if (!refTable) throw new Error(`foreign key ${name}: references field has no schema`);
@@ -68,7 +81,7 @@ export interface BuildCreateTableSqlOptions {
68
81
  }
69
82
 
70
83
  export function buildCreateTableSql(schema: TableSchema, options: BuildCreateTableSqlOptions = {}): string {
71
- const lines = Object.values(schema.fields).map((field) => columnDef(field, schema.autoIncrement));
84
+ const lines = Object.values(schema.columns).map((field) => columnDef(field, schema.autoIncrement));
72
85
  const pk = primaryKeyClause(schema);
73
86
  if (pk) lines.push(pk);
74
87
  for (const index of schema.indexes ?? []) lines.push(indexClause(index));
@@ -77,5 +90,5 @@ export function buildCreateTableSql(schema: TableSchema, options: BuildCreateTab
77
90
  lines.push(foreignKeyClause(name, fk));
78
91
  }
79
92
  }
80
- return `CREATE TABLE \`${schema.name}\` (\n ${lines.join(',\n ')}\n);`;
93
+ return `CREATE TABLE IF NOT EXISTS \`${schema.name}\` (\n ${lines.join(',\n ')}\n);`;
81
94
  }
package/src/page-flow.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { SchemaBase } from './dsl';
2
- import { ActionSchema, Page } from './page';
1
+ import { SchemaBase } from './dsl.js';
2
+ import { ActionSchema, Page } from './page.js';
3
3
 
4
4
  // Page-driven flow: every node is a page, and a page belongs to an app.
5
5
  // Leaf nodes are pages too — a journey starts at a page and ends at a page.
@@ -49,4 +49,4 @@ export function definePageFlow(
49
49
  pages.push(schema.start);
50
50
  }
51
51
  return { name, description: schema.description, start: schema.start, pages, edges: schema.edges };
52
- }
52
+ }
package/src/page.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { SchemaBase } from './dsl';
2
- import { FrontApp } from './project';
1
+ import { SchemaBase } from './dsl.js';
2
+ import { FrontAppSchema } from './project.js';
3
3
 
4
4
  // Page definitions: standalone page schemas and the page node type used by
5
5
  // page-driven flows. Kept separate from page-flow.ts (the flow graph itself).
@@ -8,7 +8,7 @@ import { FrontApp } from './project';
8
8
  * the actions a user can perform, and belongs to exactly one frontend app. */
9
9
  export interface PageSchema extends SchemaBase {
10
10
  /** The frontend app this page belongs to (shared instance from project.config). */
11
- app: FrontApp;
11
+ app: FrontAppSchema;
12
12
  /** Actions a user can perform on this page (e.g. submit, approve, reject). */
13
13
  actions: ActionSchema[];
14
14
  }
@@ -23,7 +23,7 @@ export function defineAction(name: string, description?: string): ActionSchema {
23
23
  export function definePage(schema: {
24
24
  name: string;
25
25
  description?: string;
26
- app: FrontApp;
26
+ app: FrontAppSchema;
27
27
  actions: ActionSchema[];
28
28
  }): PageSchema {
29
29
  return { ...schema };
@@ -32,9 +32,9 @@ export function definePage(schema: {
32
32
  /** A page node in a page-driven flow: every node is a page, and a page belongs to an app. */
33
33
  export interface Page extends SchemaBase {
34
34
  /** The frontend app this page belongs to (shared instance from project.config). */
35
- app: FrontApp;
35
+ app: FrontAppSchema;
36
36
  }
37
37
 
38
- export function page(app: FrontApp, name: string, description?: string): Page {
38
+ export function page(app: FrontAppSchema, name: string, description?: string): Page {
39
39
  return { name, app, description };
40
- }
40
+ }
@@ -1,4 +1,4 @@
1
- import { PatternDef } from '../pattern';
1
+ import { PatternDef } from '../pattern.js';
2
2
 
3
3
  // Retry pattern: blind mechanical retry for read-only operations.
4
4
  // Valid because a read-only action is idempotent by nature: clicking a query
package/src/project.ts CHANGED
@@ -1,55 +1,91 @@
1
- import { SchemaBase } from './dsl';
2
-
3
- // Project topology definitions: describe the applications (frontends) and
4
- // backend APIs of a repository, and which frontends each API serves.
5
-
6
- /** Frontend form factor. Closed enum, extend when new form factors appear. */
7
- export type FrontType = 'admin' | 'wxmini';
8
-
9
- /** A frontend application (e.g. admin console, wechat mini program). */
10
- export interface FrontApp extends SchemaBase {
11
- type: FrontType;
12
- /** Source directory relative to project root, e.g. 'web-admin/'. */
13
- dir: string;
14
- }
15
-
16
- /** A backend API service. apps references shared FrontApp instances. */
17
- export interface ProjectApi extends SchemaBase {
18
- /** Source directory relative to project root, e.g. 'api/'. */
19
- dir: string;
20
- /** Frontends this API serves. Direct instance references (see defineProject). */
21
- apps: FrontApp[];
22
- /** API base URL prefix shared by all apps it serves, e.g. '/mall'. '' = no prefix. */
23
- contextPath?: string;
24
- }
25
-
26
- /** A third-party system (e.g. wechat pay, unionpay). Owns its own
27
- * implementation dir and contract (controller_types), just like an API,
28
- * but is not part of this repo's served surface. */
29
- export interface ThirdApi extends SchemaBase {
30
- /** Source directory relative to project root, e.g. 'wechat/'. */
31
- dir: string;
32
- }
33
-
34
- export interface ProjectSchema extends SchemaBase {
35
- apps: FrontApp[];
36
- apis: ProjectApi[];
37
- thirdApis: ThirdApi[];
38
- }
39
-
40
- /**
41
- * Defines the project topology. FrontApp instances are shared value objects:
42
- * api.apps references the same instances from project.apps, so an app served
43
- * by multiple APIs is defined once and referenced many times.
44
- */
45
- export function defineProject(
46
- name: string,
47
- schema: {
48
- description?: string;
49
- apps: FrontApp[];
50
- apis: ProjectApi[];
51
- thirdApis?: ThirdApi[];
52
- },
53
- ): ProjectSchema {
54
- return { name, ...schema, thirdApis: schema.thirdApis ?? [] };
1
+ import { SchemaBase } from './dsl.js';
2
+
3
+ // Project topology definitions: describe the applications (frontends) and
4
+ // backend APIs of a repository, and which frontends each API serves.
5
+
6
+ /** Frontend form factor. Closed enum, extend when new form factors appear. */
7
+ export type FrontType = 'admin' | 'wxmini';
8
+
9
+ /** A frontend application (e.g. admin console, wechat mini program). */
10
+ export interface FrontAppSchema extends SchemaBase {
11
+ type: FrontType;
12
+ /** Source directory relative to project root, e.g. 'web-admin/'. */
13
+ dir: string;
14
+ }
15
+
16
+ /** A backend API service. apps references shared FrontAppSchema instances. */
17
+ export interface ProjectApiSchema extends SchemaBase {
18
+ /** Source directory relative to project root, e.g. 'api/'. */
19
+ dir: string;
20
+ /** Frontends this API serves. Direct instance references (see defineProject). */
21
+ apps: FrontAppSchema[];
22
+ /** API base URL prefix shared by all apps it serves, e.g. '/mall'. '' = no prefix. */
23
+ contextPath?: string;
24
+ /** API service base URL for node clients, e.g. 'http://127.0.0.1:3000'. */
25
+ baseUrl?: string;
26
+ }
27
+
28
+ /** A third-party system (e.g. wechat pay, unionpay). Owns its own
29
+ * implementation dir and contract (controller_types), just like an API,
30
+ * but is not part of this repo's served surface. */
31
+ export interface ThirdApiSchema extends SchemaBase {
32
+ /** Source directory relative to project root, e.g. 'wechat/'. */
33
+ dir: string;
34
+ }
35
+
36
+ export interface ProjectSchema extends SchemaBase {
37
+ apps: FrontAppSchema[];
38
+ apis: ProjectApiSchema[];
39
+ thirdApis: ThirdApiSchema[];
40
+ }
41
+
42
+ /**
43
+ * Defines the project topology. FrontAppSchema instances are shared value objects:
44
+ * api.apps references the same instances from project.apps, so an app served
45
+ * by multiple APIs is defined once and referenced many times.
46
+ *
47
+ * Runtime-validates app type whitelist, unique names and api.apps reference
48
+ * integrity (same style as defineTable/defineCurd).
49
+ */
50
+ export function defineProject(
51
+ name: string,
52
+ schema: {
53
+ description?: string;
54
+ apps: FrontAppSchema[];
55
+ apis: ProjectApiSchema[];
56
+ thirdApis?: ThirdApiSchema[];
57
+ },
58
+ ): ProjectSchema {
59
+ const project: ProjectSchema = { name, ...schema, thirdApis: schema.thirdApis ?? [] };
60
+
61
+ const appNames = new Set<string>();
62
+ for (const app of project.apps) {
63
+ if (!app.name) throw new Error(`project ${name}: app name is required`);
64
+ if (appNames.has(app.name)) throw new Error(`project ${name}: duplicate app name '${app.name}'`);
65
+ appNames.add(app.name);
66
+ if (app.type !== 'admin' && app.type !== 'wxmini') {
67
+ throw new Error(`project ${name}: app '${app.name}' must be type 'admin' or 'wxmini' (got '${app.type}')`);
68
+ }
69
+ if (!app.dir) throw new Error(`project ${name}: app '${app.name}' dir is required`);
70
+ }
71
+
72
+ const apiNames = new Set<string>();
73
+ for (const api of project.apis) {
74
+ if (!api.name) throw new Error(`project ${name}: api name is required`);
75
+ if (apiNames.has(api.name)) throw new Error(`project ${name}: duplicate api name '${api.name}'`);
76
+ apiNames.add(api.name);
77
+ if (!api.dir) throw new Error(`project ${name}: api '${api.name}' dir is required`);
78
+ for (const ref of api.apps) {
79
+ if (!project.apps.includes(ref)) {
80
+ throw new Error(`project ${name}: api '${api.name}' references app '${ref.name}' that is not a shared instance in project.apps (define once and reference it)`);
81
+ }
82
+ }
83
+ }
84
+
85
+ for (const third of project.thirdApis) {
86
+ if (!third.name) throw new Error(`project ${name}: thirdApi name is required`);
87
+ if (!third.dir) throw new Error(`project ${name}: thirdApi '${third.name}' dir is required`);
88
+ }
89
+
90
+ return project;
55
91
  }
package/src/prototype.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { SchemaBase } from './dsl';
1
+ import { SchemaBase } from './dsl.js';
2
2
 
3
3
  // Prototype definitions: high-level design of a page. A prototype lists only
4
4
  // the fields a page needs — no types, no bindings to apps/APIs/tables. Field