openxiangda 1.0.0

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 (121) hide show
  1. package/README.md +58 -0
  2. package/bin/openxiangda.js +11 -0
  3. package/lib/cli.js +2423 -0
  4. package/lib/config.js +121 -0
  5. package/lib/http.js +47 -0
  6. package/lib/skills.js +371 -0
  7. package/lib/utils.js +87 -0
  8. package/lib/workspace-init.js +139 -0
  9. package/openxiangda-skills/SKILL.md +128 -0
  10. package/openxiangda-skills/references/architecture-patterns.md +242 -0
  11. package/openxiangda-skills/references/automation-v3.md +129 -0
  12. package/openxiangda-skills/references/component-guide.md +198 -0
  13. package/openxiangda-skills/references/forms/component-registry.md +53 -0
  14. package/openxiangda-skills/references/forms/form-schema.md +109 -0
  15. package/openxiangda-skills/references/forms/layout-and-rules.md +24 -0
  16. package/openxiangda-skills/references/openxiangda-api.md +466 -0
  17. package/openxiangda-skills/references/pages/page-sdk.md +13 -0
  18. package/openxiangda-skills/references/pages/publish-flow.md +36 -0
  19. package/openxiangda-skills/references/pages/workspace-structure.md +38 -0
  20. package/openxiangda-skills/references/permissions-settings.md +147 -0
  21. package/openxiangda-skills/references/platform-data-model.md +305 -0
  22. package/openxiangda-skills/references/style-system.md +492 -0
  23. package/openxiangda-skills/references/troubleshooting.md +246 -0
  24. package/openxiangda-skills/references/workflow-v3.md +105 -0
  25. package/openxiangda-skills/references/workspace-state.md +45 -0
  26. package/openxiangda-skills/skills/openxiangda-app/SKILL.md +64 -0
  27. package/openxiangda-skills/skills/openxiangda-core/SKILL.md +143 -0
  28. package/openxiangda-skills/skills/openxiangda-form/SKILL.md +76 -0
  29. package/openxiangda-skills/skills/openxiangda-inspect/SKILL.md +40 -0
  30. package/openxiangda-skills/skills/openxiangda-page/SKILL.md +62 -0
  31. package/openxiangda-skills/skills/openxiangda-permission-settings/SKILL.md +95 -0
  32. package/openxiangda-skills/skills/openxiangda-workflow-automation/SKILL.md +97 -0
  33. package/package.json +126 -0
  34. package/packages/sdk/bin/lowcode-workspace.mjs +4 -0
  35. package/packages/sdk/dist/build/index.cjs +33 -0
  36. package/packages/sdk/dist/build/index.cjs.map +1 -0
  37. package/packages/sdk/dist/build/index.d.mts +40 -0
  38. package/packages/sdk/dist/build/index.d.ts +40 -0
  39. package/packages/sdk/dist/build/index.mjs +8 -0
  40. package/packages/sdk/dist/build/index.mjs.map +1 -0
  41. package/packages/sdk/dist/components/index.cjs +18700 -0
  42. package/packages/sdk/dist/components/index.cjs.map +1 -0
  43. package/packages/sdk/dist/components/index.d.mts +2094 -0
  44. package/packages/sdk/dist/components/index.d.ts +2094 -0
  45. package/packages/sdk/dist/components/index.mjs +18649 -0
  46. package/packages/sdk/dist/components/index.mjs.map +1 -0
  47. package/packages/sdk/dist/runtime/index.cjs +1469 -0
  48. package/packages/sdk/dist/runtime/index.cjs.map +1 -0
  49. package/packages/sdk/dist/runtime/index.d.mts +831 -0
  50. package/packages/sdk/dist/runtime/index.d.ts +831 -0
  51. package/packages/sdk/dist/runtime/index.mjs +1420 -0
  52. package/packages/sdk/dist/runtime/index.mjs.map +1 -0
  53. package/packages/sdk/dist/styles/antd-theme.cjs +60 -0
  54. package/packages/sdk/dist/styles/antd-theme.cjs.map +1 -0
  55. package/packages/sdk/dist/styles/antd-theme.d.mts +5 -0
  56. package/packages/sdk/dist/styles/antd-theme.d.ts +5 -0
  57. package/packages/sdk/dist/styles/antd-theme.mjs +35 -0
  58. package/packages/sdk/dist/styles/antd-theme.mjs.map +1 -0
  59. package/packages/sdk/dist/styles/tailwind-preset.cjs +2641 -0
  60. package/packages/sdk/dist/styles/tailwind-preset.cjs.map +1 -0
  61. package/packages/sdk/dist/styles/tailwind-preset.d.mts +75 -0
  62. package/packages/sdk/dist/styles/tailwind-preset.d.ts +75 -0
  63. package/packages/sdk/dist/styles/tailwind-preset.mjs +2618 -0
  64. package/packages/sdk/dist/styles/tailwind-preset.mjs.map +1 -0
  65. package/packages/sdk/dist/styles/tokens.css +73 -0
  66. package/packages/sdk/src/build-source/README.md +9 -0
  67. package/packages/sdk/src/build-source/bin/lowcode-workspace.mjs +7 -0
  68. package/packages/sdk/src/build-source/package.json +34 -0
  69. package/packages/sdk/src/build-source/scripts/build-forms.mjs +824 -0
  70. package/packages/sdk/src/build-source/scripts/build-forms.runtime-entry.test.ts +18 -0
  71. package/packages/sdk/src/build-source/scripts/build-pages.mjs +793 -0
  72. package/packages/sdk/src/build-source/scripts/build-workspace.mjs +64 -0
  73. package/packages/sdk/src/build-source/scripts/publish-all.mjs +127 -0
  74. package/packages/sdk/src/build-source/scripts/publish-oss.mjs +149 -0
  75. package/packages/sdk/src/build-source/scripts/register-bundle.mjs +1 -0
  76. package/packages/sdk/src/build-source/scripts/register.mjs +329 -0
  77. package/packages/sdk/src/build-source/scripts/sync-schema.mjs +301 -0
  78. package/packages/sdk/src/build-source/scripts/utils/form-api.mjs +639 -0
  79. package/packages/sdk/src/build-source/scripts/utils/form-api.test.ts +244 -0
  80. package/packages/sdk/src/build-source/scripts/utils/form-runtime-assets.mjs +57 -0
  81. package/packages/sdk/src/build-source/scripts/utils/form-runtime-assets.test.ts +135 -0
  82. package/packages/sdk/src/build-source/scripts/utils/incremental.mjs +210 -0
  83. package/packages/sdk/src/build-source/scripts/utils/load-config.mjs +257 -0
  84. package/packages/sdk/src/build-source/scripts/utils/load-config.test.ts +44 -0
  85. package/packages/sdk/src/build-source/scripts/utils/mime-types.mjs +70 -0
  86. package/packages/sdk/src/build-source/scripts/utils/namespace-css.mjs +61 -0
  87. package/packages/sdk/src/build-source/scripts/utils/oss-client.mjs +128 -0
  88. package/packages/sdk/src/build-source/scripts/utils/pages.mjs +80 -0
  89. package/packages/sdk/src/build-source/scripts/utils/progress.mjs +57 -0
  90. package/packages/sdk/src/build-source/scripts/utils/register-payload.mjs +89 -0
  91. package/packages/sdk/src/build-source/scripts/utils/register-payload.test.ts +76 -0
  92. package/packages/sdk/src/build-source/scripts/utils/runtime-css-check.mjs +44 -0
  93. package/packages/sdk/src/build-source/scripts/utils/runtime-css-check.test.ts +54 -0
  94. package/packages/sdk/src/build-source/scripts/utils/schema-transform.mjs +130 -0
  95. package/packages/sdk/src/build-source/scripts/utils/schema-transform.test.ts +141 -0
  96. package/packages/sdk/src/build-source/scripts/utils/tailwind-config.mjs +227 -0
  97. package/packages/sdk/src/build-source/scripts/utils/tailwind-config.test.ts +187 -0
  98. package/packages/sdk/src/build-source/src/cli.mjs +679 -0
  99. package/templates/sy-lowcode-app-workspace/app-workspace.config.ts +34 -0
  100. package/templates/sy-lowcode-app-workspace/examples/forms/customer/page.tsx +1 -0
  101. package/templates/sy-lowcode-app-workspace/examples/forms/customer/schema.ts +35 -0
  102. package/templates/sy-lowcode-app-workspace/index.html +12 -0
  103. package/templates/sy-lowcode-app-workspace/package.json +49 -0
  104. package/templates/sy-lowcode-app-workspace/postcss.config.cjs +6 -0
  105. package/templates/sy-lowcode-app-workspace/scripts/build-js-code.mjs +100 -0
  106. package/templates/sy-lowcode-app-workspace/src/dev/App.tsx +26 -0
  107. package/templates/sy-lowcode-app-workspace/src/forms/.gitkeep +1 -0
  108. package/templates/sy-lowcode-app-workspace/src/forms/README.md +48 -0
  109. package/templates/sy-lowcode-app-workspace/src/index.css +28 -0
  110. package/templates/sy-lowcode-app-workspace/src/js-code-nodes/.gitkeep +1 -0
  111. package/templates/sy-lowcode-app-workspace/src/js-code-nodes/types.d.ts +3 -0
  112. package/templates/sy-lowcode-app-workspace/src/main.tsx +36 -0
  113. package/templates/sy-lowcode-app-workspace/src/pages/.gitkeep +1 -0
  114. package/templates/sy-lowcode-app-workspace/src/shared/form-schema.ts +128 -0
  115. package/templates/sy-lowcode-app-workspace/src/types/app-workspace.types.ts +31 -0
  116. package/templates/sy-lowcode-app-workspace/tailwind.config.cjs +30 -0
  117. package/templates/sy-lowcode-app-workspace/tsconfig.app.json +24 -0
  118. package/templates/sy-lowcode-app-workspace/tsconfig.js-code-nodes.json +15 -0
  119. package/templates/sy-lowcode-app-workspace/tsconfig.json +7 -0
  120. package/templates/sy-lowcode-app-workspace/tsconfig.node.json +10 -0
  121. package/templates/sy-lowcode-app-workspace/vite.config.ts +32 -0
@@ -0,0 +1,301 @@
1
+ /**
2
+ * sync-schema.mjs - 将 form schema 同步到后端 API
3
+ *
4
+ * 扫描 src/forms/{form}/schema.ts 中的 defineFormSchema,
5
+ * 转换为后端 updateFormSchema API 格式并发送请求。
6
+ *
7
+ * 用法:
8
+ * tsx scripts/sync-schema.mjs [options]
9
+ *
10
+ * 选项:
11
+ * --dry-run 只打印 JSON,不发送请求
12
+ * --form <name> 只同步指定表单(目录名)
13
+ * --help 显示帮助信息
14
+ */
15
+
16
+ import fs from "node:fs";
17
+ import path from "node:path";
18
+ import { pathToFileURL } from "node:url";
19
+ import { buildSync } from "esbuild";
20
+ import { loadConfig, getApiBaseUrl, rootDir } from "./utils/load-config.mjs";
21
+ import {
22
+ ensureSchemaFormUuid,
23
+ getOpenApiAccessToken,
24
+ isOpenXiangdaMode,
25
+ } from "./utils/form-api.mjs";
26
+ import {
27
+ assertSchemaSyncResult,
28
+ transformToApiFormat,
29
+ } from "./utils/schema-transform.mjs";
30
+
31
+ const formsDir = path.join(rootDir, "src/forms");
32
+
33
+ // ---------- CLI 参数解析 ----------
34
+
35
+ function parseArgs(argv) {
36
+ const result = {
37
+ dryRun: false,
38
+ form: "",
39
+ help: false,
40
+ };
41
+
42
+ for (let i = 0; i < argv.length; i++) {
43
+ const arg = argv[i];
44
+
45
+ if (arg === "--help" || arg === "-h") {
46
+ result.help = true;
47
+ continue;
48
+ }
49
+ if (arg === "--dry-run") {
50
+ result.dryRun = true;
51
+ continue;
52
+ }
53
+ if (arg === "--form" && argv[i + 1]) {
54
+ result.form = argv[i + 1];
55
+ i++;
56
+ continue;
57
+ }
58
+ }
59
+
60
+ return result;
61
+ }
62
+
63
+ function printHelp() {
64
+ console.log(`
65
+ sync-schema - 将表单 Schema 同步到后端 API
66
+
67
+ 用法:
68
+ tsx scripts/sync-schema.mjs [options]
69
+
70
+ 选项:
71
+ --dry-run 只打印转换后的 JSON,不发送 API 请求
72
+ --form <name> 只同步指定表单(src/forms/ 下的目录名)
73
+ --help, -h 显示帮助信息
74
+
75
+ 示例:
76
+ tsx scripts/sync-schema.mjs --dry-run
77
+ tsx scripts/sync-schema.mjs --form customer-info
78
+ tsx scripts/sync-schema.mjs --form customer-info --dry-run
79
+ `);
80
+ }
81
+
82
+ // ---------- 表单发现 ----------
83
+
84
+ function discoverForms(filterName) {
85
+ if (!fs.existsSync(formsDir)) {
86
+ console.error(`错误: 找不到表单目录 ${formsDir}`);
87
+ process.exit(1);
88
+ }
89
+
90
+ const entries = fs.readdirSync(formsDir, { withFileTypes: true });
91
+ const formDirs = entries
92
+ .filter((entry) => entry.isDirectory())
93
+ .filter((entry) => {
94
+ if (filterName) return entry.name === filterName;
95
+ return true;
96
+ })
97
+ .filter((entry) => {
98
+ const schemaPath = path.join(formsDir, entry.name, "schema.ts");
99
+ return fs.existsSync(schemaPath);
100
+ });
101
+
102
+ return formDirs.map((entry) => ({
103
+ name: entry.name,
104
+ schemaPath: path.join(formsDir, entry.name, "schema.ts"),
105
+ }));
106
+ }
107
+
108
+ // ---------- Schema 加载 ----------
109
+
110
+ async function loadSchema(schemaPath) {
111
+ const tmpFile = schemaPath.replace(/\.ts$/, ".tmp.mjs");
112
+ try {
113
+ // 使用 esbuild 将 .ts 打包为单文件 .mjs(解析所有依赖),再动态 import
114
+ const result = buildSync({
115
+ entryPoints: [schemaPath],
116
+ bundle: true,
117
+ format: "esm",
118
+ platform: "node",
119
+ target: "node18",
120
+ write: false,
121
+ outfile: "out.mjs",
122
+ });
123
+ const code = result.outputFiles[0].text;
124
+ fs.writeFileSync(tmpFile, code, "utf-8");
125
+ const module = await import(pathToFileURL(tmpFile).href);
126
+ return module.default || module;
127
+ } catch (error) {
128
+ console.error(`错误: 无法加载 schema 文件 ${schemaPath}`);
129
+ console.error(` ${error.message}`);
130
+ return null;
131
+ } finally {
132
+ if (fs.existsSync(tmpFile)) {
133
+ fs.unlinkSync(tmpFile);
134
+ }
135
+ }
136
+ }
137
+
138
+ // ---------- API 发送 ----------
139
+
140
+ async function sendToApi(apiPayload, config, accessToken) {
141
+ const apiBase = getApiBaseUrl(config);
142
+ const targetAppType = apiPayload.appType || config.appType;
143
+ const url = isOpenXiangdaMode(config)
144
+ ? `${apiBase}/openxiangda-api/v1/apps/${encodeURIComponent(targetAppType)}/forms/${encodeURIComponent(apiPayload.formUuid)}/schema`
145
+ : `${apiBase}/dingtalk-api/v1.0/forms/updateFormSchema`;
146
+
147
+ console.log(` 发送请求到: ${url}`);
148
+
149
+ const response = await fetch(url, {
150
+ method: isOpenXiangdaMode(config) ? "PUT" : "POST",
151
+ headers: {
152
+ "Content-Type": "application/json",
153
+ ...(isOpenXiangdaMode(config)
154
+ ? { Authorization: `Bearer ${accessToken}` }
155
+ : { "x-acs-dingtalk-access-token": accessToken }),
156
+ },
157
+ body: JSON.stringify(
158
+ isOpenXiangdaMode(config)
159
+ ? {
160
+ schema: apiPayload.schema,
161
+ packages: apiPayload.packages,
162
+ }
163
+ : {
164
+ userId: config.userId,
165
+ appType: targetAppType,
166
+ formUuid: apiPayload.formUuid,
167
+ schema: apiPayload.schema,
168
+ packages: apiPayload.packages,
169
+ },
170
+ ),
171
+ });
172
+
173
+ let body = null;
174
+ try {
175
+ body = await response.json();
176
+ } catch {
177
+ body = null;
178
+ }
179
+
180
+ if (!response.ok) {
181
+ throw new Error(`API 请求失败: ${response.status} ${response.statusText}`);
182
+ }
183
+ assertSchemaSyncResult(body, apiPayload.fieldCount);
184
+
185
+ return body;
186
+ }
187
+
188
+ // ---------- 主流程 ----------
189
+
190
+ async function main() {
191
+ const args = parseArgs(process.argv.slice(2));
192
+
193
+ if (args.help) {
194
+ printHelp();
195
+ process.exit(0);
196
+ }
197
+
198
+ console.log("🔍 扫描表单 Schema...\n");
199
+
200
+ const forms = discoverForms(args.form);
201
+
202
+ if (forms.length === 0) {
203
+ if (args.form) {
204
+ console.error(`错误: 找不到表单 "${args.form}"`);
205
+ console.error(` 请确认 src/forms/${args.form}/schema.ts 存在`);
206
+ } else {
207
+ console.error("错误: 未发现任何表单 schema 文件");
208
+ }
209
+ process.exit(1);
210
+ }
211
+
212
+ console.log(`发现 ${forms.length} 个表单:\n`);
213
+ forms.forEach((f) => console.log(` - ${f.name}`));
214
+ console.log("");
215
+
216
+ const config = await loadConfig();
217
+ const results = [];
218
+ const createdForms = new Set();
219
+ let accessToken = null;
220
+
221
+ for (const form of forms) {
222
+ console.log(`📋 处理: ${form.name}`);
223
+
224
+ const schema = await loadSchema(form.schemaPath);
225
+ if (!schema) {
226
+ results.push({ name: form.name, success: false, error: "加载失败" });
227
+ continue;
228
+ }
229
+
230
+ try {
231
+ if (!args.dryRun && !accessToken) {
232
+ accessToken = await getOpenApiAccessToken(config);
233
+ }
234
+
235
+ const ensured = await ensureSchemaFormUuid({
236
+ config,
237
+ schemaPath: form.schemaPath,
238
+ formName: form.name,
239
+ accessToken,
240
+ dryRun: args.dryRun,
241
+ });
242
+ schema.formMeta.formUuid = ensured.formUuid;
243
+ schema.formMeta.appType = ensured.appType || schema.formMeta.appType;
244
+ if (ensured.created || ensured.dryRunCreated) {
245
+ createdForms.add(form.name);
246
+ }
247
+ } catch (error) {
248
+ console.error(` ❌ 自动创建表单失败: ${error.message}`);
249
+ results.push({
250
+ name: form.name,
251
+ success: false,
252
+ error: error.message,
253
+ });
254
+ console.log("");
255
+ continue;
256
+ }
257
+
258
+ let apiPayload;
259
+ try {
260
+ apiPayload = transformToApiFormat(schema, form.name);
261
+ } catch (error) {
262
+ console.error(` ❌ Schema 校验失败: ${error.message}`);
263
+ results.push({ name: form.name, success: false, error: error.message });
264
+ console.log("");
265
+ continue;
266
+ }
267
+
268
+ if (args.dryRun) {
269
+ console.log(` [dry-run] 转换结果:`);
270
+ console.log(JSON.stringify(apiPayload, null, 2));
271
+ results.push({ name: form.name, success: true, dryRun: true });
272
+ } else {
273
+ try {
274
+ const response = await sendToApi(apiPayload, config, accessToken);
275
+ console.log(` ✅ 同步成功,tableName=${response.data.tableName}`);
276
+ results.push({ name: form.name, success: true, response });
277
+ } catch (error) {
278
+ console.error(` ❌ 同步失败: ${error.message}`);
279
+ results.push({ name: form.name, success: false, error: error.message });
280
+ }
281
+ }
282
+
283
+ console.log("");
284
+ }
285
+
286
+ // 汇总
287
+ const succeeded = results.filter((r) => r.success).length;
288
+ const created = createdForms.size;
289
+ const failed = results.filter((r) => !r.success).length;
290
+
291
+ console.log("---");
292
+ console.log(
293
+ `完成: ${succeeded} 成功, ${created} 自动创建, ${failed} 失败${args.dryRun ? " (dry-run 模式)" : ""}`,
294
+ );
295
+
296
+ if (failed > 0) {
297
+ process.exit(1);
298
+ }
299
+ }
300
+
301
+ await main();