openyida 2026.5.20 → 2026.5.21-beta.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.
- package/README.md +4 -0
- package/bin/yida.js +52 -12
- package/lib/app/publish.js +298 -65
- package/lib/auth/qr-login.js +119 -8
- package/lib/bridge/bridge.js +883 -0
- package/lib/core/command-manifest.js +8 -0
- package/lib/core/locales/ar.js +8 -2
- package/lib/core/locales/de.js +8 -2
- package/lib/core/locales/en.js +8 -2
- package/lib/core/locales/es.js +8 -2
- package/lib/core/locales/fr.js +8 -2
- package/lib/core/locales/hi.js +8 -2
- package/lib/core/locales/ja.js +8 -2
- package/lib/core/locales/ko.js +8 -2
- package/lib/core/locales/pt.js +8 -2
- package/lib/core/locales/vi.js +8 -2
- package/lib/core/locales/zh-HK.js +8 -2
- package/lib/core/locales/zh.js +8 -2
- package/lib/core/utils.js +28 -1
- package/lib/feedback/feedback.js +1012 -0
- package/package.json +1 -1
- package/project/pages/src/demo-agent-chatbox.oyd.jsx +7836 -0
- package/project/pages/src/demo-dingtalk-ai-solution-center.oyd.jsx +1158 -187
- package/yida-skills/skills/yida-publish-page/SKILL.md +7 -0
package/README.md
CHANGED
|
@@ -323,6 +323,8 @@ For overseas apps, pass `--locale en_US` or `--locale ja_JP` on creation command
|
|
|
323
323
|
| `openyida publish <sourceFile> <appType> <formUuid> [--compat] [--health-check] [--force] [--open\|--no-open]` | Compile and publish a custom display page; by default the target must be `formType=display` |
|
|
324
324
|
| `openyida update-form-config <appType> <formUuid> <isRenderNav> <title> [--locale zh_CN\|en_US\|ja_JP]` | Update page/form display configuration |
|
|
325
325
|
|
|
326
|
+
`openyida publish` preserves existing custom page data sources by default. Before saving the new compiled JSX Schema, it reads the current page Schema and merges the Page-level `dataSource` with the built-in `urlParams` and `timestamp` sources, so manually configured data sources are not deleted during republish.
|
|
327
|
+
|
|
326
328
|
### Data, Permissions, and Sharing
|
|
327
329
|
|
|
328
330
|
| Command | Description |
|
|
@@ -364,10 +366,12 @@ For overseas apps, pass `--locale en_US` or `--locale ja_JP` on creation command
|
|
|
364
366
|
|---------|-------------|
|
|
365
367
|
| `openyida copy [--force]` | Initialize the local `project/` workspace |
|
|
366
368
|
| `openyida sample [--list]` | Emit sample templates |
|
|
369
|
+
| `openyida bridge start [--port 6736] [--open]` | Start the local OpenYida web bridge for `https://demo.aliwork.com/s/openyida` |
|
|
367
370
|
| `openyida doctor [--fix]` | Diagnose and repair environment issues |
|
|
368
371
|
| `openyida formula evaluate <formula\|file> [--schema file]` | Static-check formula syntax and field references |
|
|
369
372
|
| `openyida update` | Update OpenYida through npm |
|
|
370
373
|
| `openyida export-conversation [options]` | Export AI conversation history |
|
|
374
|
+
| `openyida feedback <setup\|url\|dismiss\|status>` | Create a public Yida feedback form, generate privacy-safe feedback links, and manage local reminder snooze state |
|
|
371
375
|
| `openyida flash-to-prd --file <path> --name "<project>"` | Convert flash notes or meeting notes into a PRD prompt |
|
|
372
376
|
| `openyida ai text --prompt "..."` | Call Yida's text generation AI API |
|
|
373
377
|
| `openyida ai image --file <image> --app-type APP_XXX` | Upload an image and call the image recognition connector |
|
package/bin/yida.js
CHANGED
|
@@ -206,6 +206,8 @@ function handleFirstRunGuide() {
|
|
|
206
206
|
}
|
|
207
207
|
|
|
208
208
|
function printLoginResult(result) {
|
|
209
|
+
noteLoginCommandResult(result);
|
|
210
|
+
|
|
209
211
|
if (result && (result.status === 'need_qr_scan' || result.status === 'need_corp_selection')) {
|
|
210
212
|
console.log(JSON.stringify(result));
|
|
211
213
|
return;
|
|
@@ -248,6 +250,41 @@ function printLoginResult(result) {
|
|
|
248
250
|
console.log(JSON.stringify(summary));
|
|
249
251
|
}
|
|
250
252
|
|
|
253
|
+
function noteLoginCommandResult(result) {
|
|
254
|
+
try {
|
|
255
|
+
const { recordLoginEvent, printLoginLoopFeedbackHint } = require('../lib/feedback/feedback');
|
|
256
|
+
let status = 'failed';
|
|
257
|
+
let reason = 'login_failed';
|
|
258
|
+
|
|
259
|
+
if (result && (result.csrf_token || (result.status === 'ok' && result.can_auto_use))) {
|
|
260
|
+
status = 'success';
|
|
261
|
+
reason = 'login_ok';
|
|
262
|
+
} else if (result && result.status === 'need_qr_scan') {
|
|
263
|
+
status = 'need_qr_scan';
|
|
264
|
+
reason = 'need_qr_scan';
|
|
265
|
+
} else if (result && result.status === 'need_codex_browser_login') {
|
|
266
|
+
status = 'need_browser_login';
|
|
267
|
+
reason = 'need_browser_login';
|
|
268
|
+
} else if (result && result.status === 'need_corp_selection') {
|
|
269
|
+
status = 'success';
|
|
270
|
+
reason = 'need_corp_selection';
|
|
271
|
+
} else if (result && result.status) {
|
|
272
|
+
reason = result.status;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
const loopStatus = recordLoginEvent(status, {
|
|
276
|
+
mode: args.join(' ') || 'default',
|
|
277
|
+
reason,
|
|
278
|
+
command: 'openyida login',
|
|
279
|
+
});
|
|
280
|
+
if (status !== 'success') {
|
|
281
|
+
printLoginLoopFeedbackHint(loopStatus);
|
|
282
|
+
}
|
|
283
|
+
} catch {
|
|
284
|
+
// Login feedback tracking is best-effort and must not affect CLI output.
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
251
288
|
function isAgentConversationEnvironment() {
|
|
252
289
|
const { detectActiveTool } = require('../lib/core/utils');
|
|
253
290
|
return !!detectActiveTool();
|
|
@@ -370,6 +407,12 @@ async function main() {
|
|
|
370
407
|
break;
|
|
371
408
|
}
|
|
372
409
|
|
|
410
|
+
case 'bridge': {
|
|
411
|
+
const { run } = require('../lib/bridge/bridge');
|
|
412
|
+
await run(args);
|
|
413
|
+
break;
|
|
414
|
+
}
|
|
415
|
+
|
|
373
416
|
case 'env': {
|
|
374
417
|
if (shouldUseEnvManagement(args)) {
|
|
375
418
|
const { run } = require('../lib/core/env-cmd');
|
|
@@ -428,7 +471,7 @@ async function main() {
|
|
|
428
471
|
} else if (loginArgs.includes('--qr')) {
|
|
429
472
|
const { qrLogin } = require('../lib/auth/qr-login');
|
|
430
473
|
const result = await qrLogin({ corpId: getArgValue(loginArgs, '--corp-id') });
|
|
431
|
-
|
|
474
|
+
printLoginResult(result);
|
|
432
475
|
} else if (shouldUseAgentLogin(loginArgs)) {
|
|
433
476
|
const cachedResult = checkLoginOnly({ includeSecrets: true });
|
|
434
477
|
if (cachedResult.status === 'ok') {
|
|
@@ -473,7 +516,7 @@ async function main() {
|
|
|
473
516
|
}
|
|
474
517
|
const { qrLogin } = require('../lib/auth/qr-login');
|
|
475
518
|
const result = await qrLogin({ corpId: getArgValue(loginArgs, '--corp-id') });
|
|
476
|
-
|
|
519
|
+
printLoginResult(result);
|
|
477
520
|
}
|
|
478
521
|
break;
|
|
479
522
|
}
|
|
@@ -629,24 +672,15 @@ async function main() {
|
|
|
629
672
|
}
|
|
630
673
|
|
|
631
674
|
case 'publish': {
|
|
632
|
-
// 参数顺序:<源文件路径> <appType> <formUuid>
|
|
633
|
-
// publish.js 内部读取顺序:argv[2]=appType, argv[3]=formUuid, argv[4]=sourceFile
|
|
634
675
|
const passThroughFlags = new Set(['--skip-lint', '--health-check', '--check', '--open', '--no-open', '--compat', '--modern', '--force']);
|
|
635
|
-
const forwardedFlags = args.filter(arg => passThroughFlags.has(arg));
|
|
636
676
|
const filteredArgs = args.filter(arg => !passThroughFlags.has(arg));
|
|
637
677
|
if (filteredArgs.length < 3) {
|
|
638
678
|
warn(t('cli.publish_usage'));
|
|
639
679
|
warn(t('cli.publish_example'));
|
|
640
680
|
process.exit(1);
|
|
641
681
|
}
|
|
642
|
-
const [sourceFile, appType, formUuid] = filteredArgs;
|
|
643
|
-
process.argv = [
|
|
644
|
-
process.argv[0], process.argv[1],
|
|
645
|
-
appType, formUuid, sourceFile,
|
|
646
|
-
...forwardedFlags
|
|
647
|
-
];
|
|
648
682
|
const publishMain = require('../lib/app/publish');
|
|
649
|
-
await publishMain();
|
|
683
|
+
await publishMain(args);
|
|
650
684
|
break;
|
|
651
685
|
}
|
|
652
686
|
|
|
@@ -1007,6 +1041,12 @@ async function main() {
|
|
|
1007
1041
|
break;
|
|
1008
1042
|
}
|
|
1009
1043
|
|
|
1044
|
+
case 'feedback': {
|
|
1045
|
+
const { run: runFeedback } = require('../lib/feedback/feedback');
|
|
1046
|
+
await runFeedback(args);
|
|
1047
|
+
break;
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1010
1050
|
case 'task-center': {
|
|
1011
1051
|
const { run: runTaskCenter } = require('../lib/core/task-center');
|
|
1012
1052
|
await runTaskCenter(args);
|
package/lib/app/publish.js
CHANGED
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
* publish.js - 宜搭自定义页面发布工具(Node.js 版)
|
|
4
4
|
*
|
|
5
5
|
* 用法:
|
|
6
|
-
* openyida publish <appType> <formUuid>
|
|
6
|
+
* openyida publish <源文件路径> <appType> <formUuid>
|
|
7
7
|
*
|
|
8
8
|
* 示例:
|
|
9
|
-
* openyida publish APP_XXX FORM-XXX
|
|
9
|
+
* openyida publish pages/xxx.js APP_XXX FORM-XXX
|
|
10
10
|
*
|
|
11
11
|
* 流程:
|
|
12
12
|
* 1. 读取源文件,通过内置 babel-transform 编译 + UglifyJS 压缩
|
|
@@ -20,7 +20,16 @@ const path = require('path');
|
|
|
20
20
|
const https = require('https');
|
|
21
21
|
const http = require('http');
|
|
22
22
|
const querystring = require('querystring');
|
|
23
|
-
const {
|
|
23
|
+
const {
|
|
24
|
+
findProjectRoot,
|
|
25
|
+
isLoginExpired,
|
|
26
|
+
isCsrfTokenExpired,
|
|
27
|
+
loadCookieData,
|
|
28
|
+
triggerLogin,
|
|
29
|
+
refreshCsrfToken,
|
|
30
|
+
httpGet,
|
|
31
|
+
requestWithAutoLogin,
|
|
32
|
+
} = require('../core/utils');
|
|
24
33
|
const { t } = require('../core/i18n');
|
|
25
34
|
const { banner, step, label, success, fail, warn, info, error, result, usage, hint } = require('../core/chalk');
|
|
26
35
|
const { compileSource } = require('./page-compiler');
|
|
@@ -38,8 +47,34 @@ const PREFIX = '_view';
|
|
|
38
47
|
|
|
39
48
|
// ── 参数解析 ─────────────────────────────────────────
|
|
40
49
|
|
|
41
|
-
function
|
|
42
|
-
|
|
50
|
+
function looksLikeAppType(value) {
|
|
51
|
+
return /^APP_[A-Z0-9]+$/i.test(value || '');
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function looksLikeFormUuid(value) {
|
|
55
|
+
return /^FORM-[A-Z0-9]+$/i.test(value || '');
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function normalizePublishArgs(positionals) {
|
|
59
|
+
const [first, second, third] = positionals;
|
|
60
|
+
|
|
61
|
+
if (looksLikeAppType(first) && looksLikeFormUuid(second)) {
|
|
62
|
+
return {
|
|
63
|
+
appType: first,
|
|
64
|
+
formUuid: second,
|
|
65
|
+
sourceFile: third,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return {
|
|
70
|
+
sourceFile: first,
|
|
71
|
+
appType: second,
|
|
72
|
+
formUuid: third,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function parseArgs(argv = process.argv.slice(2)) {
|
|
77
|
+
const openOption = parseOpenOption(argv);
|
|
43
78
|
const args = openOption.args;
|
|
44
79
|
const skipLint = args.includes('--skip-lint');
|
|
45
80
|
const healthCheck = args.includes('--health-check') || args.includes('--check');
|
|
@@ -51,10 +86,11 @@ function parseArgs() {
|
|
|
51
86
|
usage(t('publish.usage'), t('publish.example'));
|
|
52
87
|
process.exit(1);
|
|
53
88
|
}
|
|
89
|
+
const { appType, formUuid, sourceFile } = normalizePublishArgs(filteredArgs);
|
|
54
90
|
return {
|
|
55
|
-
appType
|
|
56
|
-
formUuid
|
|
57
|
-
sourceFile
|
|
91
|
+
appType,
|
|
92
|
+
formUuid,
|
|
93
|
+
sourceFile,
|
|
58
94
|
skipLint,
|
|
59
95
|
healthCheck,
|
|
60
96
|
compat,
|
|
@@ -88,16 +124,240 @@ function generateSuffix() {
|
|
|
88
124
|
|
|
89
125
|
// ── 2. 构建 Schema ──────────────────────────────────
|
|
90
126
|
|
|
91
|
-
function
|
|
127
|
+
function getGlobalDataSourceFitConfig() {
|
|
128
|
+
const fitCompiled = "'use strict';\n\nvar __preParser__ = function fit(response) {\n var content = response.content !== undefined ? response.content : response;\n var error = {\n message: response.errorMsg || response.errors && response.errors[0] && response.errors[0].msg || response.content || '远程数据源请求出错,success is false'\n };\n var success = true;\n if (response.success !== undefined) {\n success = response.success;\n } else if (response.hasError !== undefined) {\n success = !response.hasError;\n }\n return {\n content: content,\n success: success,\n error: error\n };\n};";
|
|
129
|
+
const fitSource = "function fit(response) {\r\n const content = (response.content !== undefined) ? response.content : response;\r\n const error = {\r\n message: response.errorMsg ||\r\n (response.errors && response.errors[0] && response.errors[0].msg) ||\r\n response.content || '远程数据源请求出错,success is false',\r\n };\r\n let success = true;\r\n if (response.success !== undefined) {\r\n success = response.success;\r\n } else if (response.hasError !== undefined) {\r\n success = !response.hasError;\r\n }\r\n return {\r\n content,\r\n success,\r\n error,\r\n };\r\n}";
|
|
130
|
+
|
|
131
|
+
return {
|
|
132
|
+
fit: {
|
|
133
|
+
compiled: fitCompiled,
|
|
134
|
+
source: fitSource,
|
|
135
|
+
type: 'js',
|
|
136
|
+
error: {},
|
|
137
|
+
},
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function buildDefaultPageDataSource(formUuid) {
|
|
142
|
+
const urlParamsDataSource = {
|
|
143
|
+
id: 'VCB660714833IBHEOXK376TA7XJH2AXUWR8MMW',
|
|
144
|
+
name: 'urlParams',
|
|
145
|
+
description: '当前页面地址的参数:如 aliwork.com/APP_XXX/workbench?id=1&name=宜搭,可通过 this.state.urlParams.name 获取到宜搭',
|
|
146
|
+
formUuid: formUuid,
|
|
147
|
+
protocal: 'URI',
|
|
148
|
+
isReadonly: true,
|
|
149
|
+
};
|
|
150
|
+
const timestampDataSource = {
|
|
151
|
+
id: '',
|
|
152
|
+
name: 'timestamp',
|
|
153
|
+
description: '',
|
|
154
|
+
formUuid: formUuid,
|
|
155
|
+
protocal: 'VALUE',
|
|
156
|
+
initialData: '',
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
return {
|
|
160
|
+
offline: [],
|
|
161
|
+
globalConfig: getGlobalDataSourceFitConfig(),
|
|
162
|
+
online: [urlParamsDataSource, timestampDataSource],
|
|
163
|
+
list: [urlParamsDataSource, timestampDataSource],
|
|
164
|
+
sync: true,
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function cloneJson(value) {
|
|
169
|
+
if (value === undefined || value === null) {
|
|
170
|
+
return value;
|
|
171
|
+
}
|
|
172
|
+
return JSON.parse(JSON.stringify(value));
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function getDataSourceIdentity(item) {
|
|
176
|
+
if (!item || typeof item !== 'object') {
|
|
177
|
+
return '';
|
|
178
|
+
}
|
|
179
|
+
if (isBuiltInPageDataSource(item)) {
|
|
180
|
+
return 'builtin:' + item.name;
|
|
181
|
+
}
|
|
182
|
+
if (item.id) {
|
|
183
|
+
return 'id:' + item.id;
|
|
184
|
+
}
|
|
185
|
+
if (item.name && item.protocal) {
|
|
186
|
+
return 'name:' + item.name + '|protocal:' + item.protocal;
|
|
187
|
+
}
|
|
188
|
+
if (item.name) {
|
|
189
|
+
return 'name:' + item.name;
|
|
190
|
+
}
|
|
191
|
+
return JSON.stringify(item);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function mergeDataSourceArray(existingItems, generatedItems) {
|
|
195
|
+
const merged = Array.isArray(existingItems) ? cloneJson(existingItems) : [];
|
|
196
|
+
const seen = new Set(merged.map(getDataSourceIdentity).filter(Boolean));
|
|
197
|
+
|
|
198
|
+
(Array.isArray(generatedItems) ? generatedItems : []).forEach((item) => {
|
|
199
|
+
const identity = getDataSourceIdentity(item);
|
|
200
|
+
if (!identity || !seen.has(identity)) {
|
|
201
|
+
merged.push(cloneJson(item));
|
|
202
|
+
if (identity) {
|
|
203
|
+
seen.add(identity);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
return merged;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function mergePageDataSource(existingDataSource, generatedDataSource) {
|
|
212
|
+
if (!existingDataSource || typeof existingDataSource !== 'object') {
|
|
213
|
+
return cloneJson(generatedDataSource);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const existing = cloneJson(existingDataSource);
|
|
217
|
+
const generated = cloneJson(generatedDataSource || {});
|
|
218
|
+
const merged = Object.assign({}, generated, existing);
|
|
219
|
+
|
|
220
|
+
merged.offline = mergeDataSourceArray(existing.offline, generated.offline);
|
|
221
|
+
merged.online = mergeDataSourceArray(existing.online, generated.online);
|
|
222
|
+
merged.list = mergeDataSourceArray(existing.list, generated.list);
|
|
223
|
+
merged.globalConfig = Object.assign(
|
|
224
|
+
{},
|
|
225
|
+
generated.globalConfig || {},
|
|
226
|
+
existing.globalConfig || {}
|
|
227
|
+
);
|
|
228
|
+
merged.sync = existing.sync !== undefined ? existing.sync : generated.sync;
|
|
229
|
+
|
|
230
|
+
return merged;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
function extractSchemaContent(schemaResult) {
|
|
234
|
+
if (!schemaResult) {
|
|
235
|
+
return null;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
let content = schemaResult.content !== undefined ? schemaResult.content : schemaResult;
|
|
239
|
+
if (typeof content === 'string') {
|
|
240
|
+
try {
|
|
241
|
+
content = JSON.parse(content);
|
|
242
|
+
} catch {
|
|
243
|
+
return null;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
if (content && typeof content === 'object' && content.pages) {
|
|
248
|
+
return content;
|
|
249
|
+
}
|
|
250
|
+
if (schemaResult.pages) {
|
|
251
|
+
return schemaResult;
|
|
252
|
+
}
|
|
253
|
+
return null;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
function extractPageDataSource(schema) {
|
|
257
|
+
if (!schema || !Array.isArray(schema.pages)) {
|
|
258
|
+
return null;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
function findPageDataSource(node) {
|
|
262
|
+
if (!node || typeof node !== 'object') {
|
|
263
|
+
return null;
|
|
264
|
+
}
|
|
265
|
+
if (node.componentName === 'Page' && node.dataSource) {
|
|
266
|
+
return node.dataSource;
|
|
267
|
+
}
|
|
268
|
+
const children = Array.isArray(node.children) ? node.children : [];
|
|
269
|
+
for (const child of children) {
|
|
270
|
+
const dataSource = findPageDataSource(child);
|
|
271
|
+
if (dataSource) {
|
|
272
|
+
return dataSource;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
return null;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
for (const page of schema.pages) {
|
|
279
|
+
const tree = page && Array.isArray(page.componentsTree) ? page.componentsTree : [];
|
|
280
|
+
for (const component of tree) {
|
|
281
|
+
const dataSource = findPageDataSource(component);
|
|
282
|
+
if (dataSource) {
|
|
283
|
+
return dataSource;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
return null;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
function isBuiltInPageDataSource(item) {
|
|
291
|
+
return !!(item && (item.name === 'urlParams' || item.name === 'timestamp'));
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
function countCustomPageDataSources(dataSource) {
|
|
295
|
+
if (!dataSource || typeof dataSource !== 'object') {
|
|
296
|
+
return 0;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
const identities = new Set();
|
|
300
|
+
['offline', 'online', 'list'].forEach((key) => {
|
|
301
|
+
(Array.isArray(dataSource[key]) ? dataSource[key] : []).forEach((item) => {
|
|
302
|
+
if (!isBuiltInPageDataSource(item)) {
|
|
303
|
+
const identity = getDataSourceIdentity(item);
|
|
304
|
+
if (identity) {
|
|
305
|
+
identities.add(identity);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
});
|
|
309
|
+
});
|
|
310
|
+
return identities.size;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
async function fetchExistingSchemaContent(appType, formUuid, authRef) {
|
|
314
|
+
const result = await requestWithAutoLogin((auth) => {
|
|
315
|
+
return httpGet(
|
|
316
|
+
auth.baseUrl,
|
|
317
|
+
`/alibaba/web/${appType}/${PREFIX}/query/formdesign/getFormSchema.json`,
|
|
318
|
+
{ formUuid, schemaVersion: SCHEMA_VERSION },
|
|
319
|
+
auth.cookies
|
|
320
|
+
);
|
|
321
|
+
}, authRef);
|
|
322
|
+
|
|
323
|
+
if (!result || result.success === false || result.__needLogin || result.__csrfExpired) {
|
|
324
|
+
const errorMsg = result ? result.errorMsg || t('common.unknown_error') : t('common.request_failed');
|
|
325
|
+
throw new Error(errorMsg);
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
const schema = extractSchemaContent(result);
|
|
329
|
+
if (!schema) {
|
|
330
|
+
throw new Error(t('create_form.schema_parse_failed'));
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
return schema;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
async function readExistingPageDataSource(appType, formUuid, authRef) {
|
|
337
|
+
info(t('publish.data_source_fetching'));
|
|
338
|
+
const existingSchema = await fetchExistingSchemaContent(appType, formUuid, authRef);
|
|
339
|
+
const dataSource = extractPageDataSource(existingSchema);
|
|
340
|
+
const customCount = countCustomPageDataSources(dataSource);
|
|
341
|
+
|
|
342
|
+
if (customCount > 0) {
|
|
343
|
+
success(t('publish.data_source_preserved', String(customCount)));
|
|
344
|
+
} else {
|
|
345
|
+
info(t('publish.data_source_none'));
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
return dataSource;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
function buildSchemaContent(sourceCode, compiledCode, formUuid, options = {}) {
|
|
92
352
|
info(t('publish.building_schema'));
|
|
93
353
|
const nextNodeId = createNodeIdGenerator();
|
|
94
354
|
|
|
95
355
|
// 构造函数代码(固定模板)
|
|
96
356
|
const constructorCode = "function constructor() {\nvar module = { exports: {} };\nvar _this = this;\nthis.__initMethods__(module.exports, module);\nObject.keys(module.exports).forEach(function(item) {\n if(typeof module.exports[item] === 'function'){\n _this[item] = module.exports[item];\n }\n});\n\n}";
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
357
|
+
const pageDataSource = mergePageDataSource(
|
|
358
|
+
options.existingDataSource,
|
|
359
|
+
buildDefaultPageDataSource(formUuid)
|
|
360
|
+
);
|
|
101
361
|
|
|
102
362
|
const schema = {
|
|
103
363
|
schemaType: 'superform',
|
|
@@ -156,54 +416,7 @@ function buildSchemaContent(sourceCode, compiledCode, formUuid) {
|
|
|
156
416
|
compiled: 'function (exports, module) { /*set actions code here*/ }',
|
|
157
417
|
},
|
|
158
418
|
},
|
|
159
|
-
dataSource:
|
|
160
|
-
offline: [],
|
|
161
|
-
globalConfig: {
|
|
162
|
-
fit: {
|
|
163
|
-
compiled: fitCompiled,
|
|
164
|
-
source: fitSource,
|
|
165
|
-
type: 'js',
|
|
166
|
-
error: {},
|
|
167
|
-
},
|
|
168
|
-
},
|
|
169
|
-
online: [
|
|
170
|
-
{
|
|
171
|
-
id: 'VCB660714833IBHEOXK376TA7XJH2AXUWR8MMW',
|
|
172
|
-
name: 'urlParams',
|
|
173
|
-
description: '当前页面地址的参数:如 aliwork.com/APP_XXX/workbench?id=1&name=宜搭,可通过 this.state.urlParams.name 获取到宜搭',
|
|
174
|
-
formUuid: formUuid,
|
|
175
|
-
protocal: 'URI',
|
|
176
|
-
isReadonly: true,
|
|
177
|
-
},
|
|
178
|
-
{
|
|
179
|
-
id: '',
|
|
180
|
-
name: 'timestamp',
|
|
181
|
-
description: '',
|
|
182
|
-
formUuid: formUuid,
|
|
183
|
-
protocal: 'VALUE',
|
|
184
|
-
initialData: '',
|
|
185
|
-
},
|
|
186
|
-
],
|
|
187
|
-
list: [
|
|
188
|
-
{
|
|
189
|
-
id: 'VCB660714833IBHEOXK376TA7XJH2AXUWR8MMW',
|
|
190
|
-
name: 'urlParams',
|
|
191
|
-
description: '当前页面地址的参数:如 aliwork.com/APP_XXX/workbench?id=1&name=宜搭,可通过 this.state.urlParams.name 获取到宜搭',
|
|
192
|
-
formUuid: formUuid,
|
|
193
|
-
protocal: 'URI',
|
|
194
|
-
isReadonly: true,
|
|
195
|
-
},
|
|
196
|
-
{
|
|
197
|
-
id: '',
|
|
198
|
-
name: 'timestamp',
|
|
199
|
-
description: '',
|
|
200
|
-
formUuid: formUuid,
|
|
201
|
-
protocal: 'VALUE',
|
|
202
|
-
initialData: '',
|
|
203
|
-
},
|
|
204
|
-
],
|
|
205
|
-
sync: true,
|
|
206
|
-
},
|
|
419
|
+
dataSource: pageDataSource,
|
|
207
420
|
lifeCycles: {
|
|
208
421
|
constructor: {
|
|
209
422
|
type: 'js',
|
|
@@ -647,8 +860,8 @@ function sendHealthCheckRequest(pageUrl, cookies) {
|
|
|
647
860
|
|
|
648
861
|
// ── 主流程 ────────────────────────────────────────────
|
|
649
862
|
|
|
650
|
-
async function main() {
|
|
651
|
-
const { appType, formUuid, sourceFile, skipLint, healthCheck, compat, force, browserOpenMode } = parseArgs();
|
|
863
|
+
async function main(argv) {
|
|
864
|
+
const { appType, formUuid, sourceFile, skipLint, healthCheck, compat, force, browserOpenMode } = parseArgs(argv);
|
|
652
865
|
|
|
653
866
|
let sourcePath = path.resolve(sourceFile);
|
|
654
867
|
if (!fs.existsSync(sourcePath)) {
|
|
@@ -687,8 +900,6 @@ async function main() {
|
|
|
687
900
|
|
|
688
901
|
step(1, t('publish.step_compile'));
|
|
689
902
|
const { sourceCode, compiledCode } = compileSource(sourcePath);
|
|
690
|
-
const schemaContent = buildSchemaContent(sourceCode, compiledCode, formUuid);
|
|
691
|
-
success(t('publish.schema_built'));
|
|
692
903
|
|
|
693
904
|
step(2, t('common.step_login', 2));
|
|
694
905
|
let cookieData = loadCookieData();
|
|
@@ -709,6 +920,20 @@ async function main() {
|
|
|
709
920
|
cookies = authRef.cookies;
|
|
710
921
|
baseUrl = authRef.baseUrl;
|
|
711
922
|
|
|
923
|
+
let existingDataSource = null;
|
|
924
|
+
try {
|
|
925
|
+
existingDataSource = await readExistingPageDataSource(appType, formUuid, authRef);
|
|
926
|
+
} catch (dataSourceError) {
|
|
927
|
+
fail(t('publish.data_source_fetch_failed', dataSourceError.message));
|
|
928
|
+
process.exit(1);
|
|
929
|
+
}
|
|
930
|
+
csrfToken = authRef.csrfToken;
|
|
931
|
+
cookies = authRef.cookies;
|
|
932
|
+
baseUrl = authRef.baseUrl;
|
|
933
|
+
|
|
934
|
+
const schemaContent = buildSchemaContent(sourceCode, compiledCode, formUuid, { existingDataSource });
|
|
935
|
+
success(t('publish.schema_built'));
|
|
936
|
+
|
|
712
937
|
banner(t('publish.title'));
|
|
713
938
|
label('Base URL:', baseUrl);
|
|
714
939
|
label('App Type:', appType);
|
|
@@ -825,10 +1050,18 @@ if (require.main === module) {
|
|
|
825
1050
|
} else {
|
|
826
1051
|
// 如果作为模块被 require,导出 main 函数
|
|
827
1052
|
module.exports = main;
|
|
1053
|
+
module.exports.parseArgs = parseArgs;
|
|
1054
|
+
module.exports.normalizePublishArgs = normalizePublishArgs;
|
|
828
1055
|
module.exports.findDuplicateSourceMismatches = findDuplicateSourceMismatches;
|
|
829
1056
|
module.exports.sendHealthCheckRequest = sendHealthCheckRequest;
|
|
830
1057
|
module.exports.normalizeFormType = normalizeFormType;
|
|
831
1058
|
module.exports.findPublishTarget = findPublishTarget;
|
|
832
1059
|
module.exports.isCustomPageTarget = isCustomPageTarget;
|
|
833
1060
|
module.exports.verifyPublishTarget = verifyPublishTarget;
|
|
1061
|
+
module.exports.buildDefaultPageDataSource = buildDefaultPageDataSource;
|
|
1062
|
+
module.exports.mergePageDataSource = mergePageDataSource;
|
|
1063
|
+
module.exports.extractSchemaContent = extractSchemaContent;
|
|
1064
|
+
module.exports.extractPageDataSource = extractPageDataSource;
|
|
1065
|
+
module.exports.countCustomPageDataSources = countCustomPageDataSources;
|
|
1066
|
+
module.exports.buildSchemaContent = buildSchemaContent;
|
|
834
1067
|
}
|