openyida 2026.9.12 → 2026.9.14
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/lib/app/canvas-compile.js +66 -30
- package/lib/app/display-page-readback.js +63 -5
- package/lib/app/get-schema.js +158 -5
- package/lib/app/publish.js +127 -5
- package/lib/app/services/canvas-page-compiler.js +3 -3
- package/lib/core/command-manifest.js +2 -2
- package/lib/core/locales/en.js +9 -0
- package/lib/core/locales/zh.js +9 -0
- package/lib/core/utils.js +358 -0
- package/package.json +1 -1
- package/yida-skills/skills/yida-app/workflow/plan/step-4-deliver.md +3 -1
- package/yida-skills/skills/yida-app/workflow/step-2-design.md +2 -2
- package/yida-skills/skills/yida-create-form-page/SKILL.md +1 -0
- package/yida-skills/skills/yida-design/references/ask-human-interaction-contract.md +40 -6
- package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/references/build-plan-schema.md +1 -1
- package/yida-skills/skills/yida-design/workflow/step-4-wireframe-interaction.md +1 -1
- package/yida-skills/skills/yida-integration/SKILL.md +1 -0
- package/yida-skills/skills/yida-nav-shell/SKILL.md +4 -4
- package/yida-skills/skills/yida-prd/workflow/output-prd.md +2 -2
- package/yida-skills/skills/yida-prd/workflow/step-2-information-architecture.md +2 -2
- package/yida-skills/skills/yida-publish-page/SKILL.md +5 -4
- package/yida-skills/skills/yida-requirement-analysis/SKILL.md +1 -1
- package/yida-skills/skills/yida-requirement-analysis/workflow/prepare-brief.md +13 -16
|
@@ -24,12 +24,13 @@
|
|
|
24
24
|
* 3) 第三方依赖以 `window.<别名>` 形式引用(antd→window.antd、react→window.React …),
|
|
25
25
|
* 这些 UMD 依赖由画布运行时依据 importedModules 白名单按需注入。
|
|
26
26
|
*
|
|
27
|
-
* 因此本地编译 = Babel 把 JSX/TS 转成
|
|
28
|
-
* 把 export default 改写成画布入口 `YidaComp` → 正则抽出依赖包名。
|
|
27
|
+
* 因此本地编译 = Babel 把 JSX/TS 转成 JS → 把 import 改写成 window 别名引用、
|
|
28
|
+
* 把 export default 改写成画布入口 `YidaComp` → UglifyJS 压缩 → 正则抽出依赖包名。
|
|
29
29
|
*/
|
|
30
30
|
|
|
31
31
|
const Babel = require('@babel/standalone');
|
|
32
32
|
const globals = require('globals');
|
|
33
|
+
const UglifyJS = require('uglify-js');
|
|
33
34
|
const {
|
|
34
35
|
assertNoEmojiInArtifactName,
|
|
35
36
|
assertNoEmojiInText,
|
|
@@ -877,6 +878,36 @@ function assertCanvasRuntimeParseable(runtimeCode, options = {}) {
|
|
|
877
878
|
}
|
|
878
879
|
}
|
|
879
880
|
|
|
881
|
+
/**
|
|
882
|
+
* 压缩画布运行态代码,并显式保留装配器读取的 YidaComp 入口名。
|
|
883
|
+
*/
|
|
884
|
+
function minifyCanvasRuntime(runtimeCode, options = {}) {
|
|
885
|
+
let result;
|
|
886
|
+
try {
|
|
887
|
+
result = UglifyJS.minify(runtimeCode, {
|
|
888
|
+
compress: true,
|
|
889
|
+
mangle: {
|
|
890
|
+
reserved: ['YidaComp'],
|
|
891
|
+
},
|
|
892
|
+
});
|
|
893
|
+
} catch (error) {
|
|
894
|
+
result = { error };
|
|
895
|
+
}
|
|
896
|
+
if (!result || result.error || typeof result.code !== 'string' || !result.code) {
|
|
897
|
+
const detail = result && result.error && result.error.message
|
|
898
|
+
? result.error.message
|
|
899
|
+
: '压缩结果为空';
|
|
900
|
+
throw new CliError(`Code Canvas runtimeCode 压缩失败: ${detail}`, {
|
|
901
|
+
code: 'OPENYIDA_CANVAS_MINIFY_FAILED',
|
|
902
|
+
details: {
|
|
903
|
+
stage: 'canvas_minify',
|
|
904
|
+
sourcePath: options.sourcePath || '',
|
|
905
|
+
},
|
|
906
|
+
});
|
|
907
|
+
}
|
|
908
|
+
return result.code;
|
|
909
|
+
}
|
|
910
|
+
|
|
880
911
|
/**
|
|
881
912
|
* 本地编译 Code Canvas 源码。
|
|
882
913
|
* @param {string} source 原始 React/JSX/TSX 源码
|
|
@@ -984,11 +1015,12 @@ function compileCanvasLocal(source, options = {}) {
|
|
|
984
1015
|
configFile: false,
|
|
985
1016
|
});
|
|
986
1017
|
|
|
987
|
-
const
|
|
988
|
-
assertNoEmojiInText(
|
|
1018
|
+
const unminifiedRuntimeCode = stage2.code || '';
|
|
1019
|
+
assertNoEmojiInText(unminifiedRuntimeCode, {
|
|
989
1020
|
artifact: options.sourcePath ? options.sourcePath + ' runtime' : 'Code Canvas runtime',
|
|
990
1021
|
code: 'OPENYIDA_CANVAS_SOURCE_EMOJI_FORBIDDEN',
|
|
991
1022
|
});
|
|
1023
|
+
const runtimeCode = minifyCanvasRuntime(unminifiedRuntimeCode, options);
|
|
992
1024
|
assertCanvasRuntimeParseable(runtimeCode, options);
|
|
993
1025
|
assertDependencyManifestConsistent(runtimeCode, importedModules, options);
|
|
994
1026
|
return {
|
|
@@ -1019,43 +1051,47 @@ function compileCanvas(source, options = {}) {
|
|
|
1019
1051
|
try {
|
|
1020
1052
|
resolve(compileCanvasLocal(source, options));
|
|
1021
1053
|
} catch (compileError) {
|
|
1022
|
-
|
|
1023
|
-
reject(compileError);
|
|
1024
|
-
return;
|
|
1025
|
-
}
|
|
1026
|
-
const detail = compileError && compileError.message ? compileError.message : String(compileError);
|
|
1027
|
-
if (
|
|
1028
|
-
compileError &&
|
|
1029
|
-
/^OPENYIDA_/.test(String(compileError.code || '')) &&
|
|
1030
|
-
compileError.details !== undefined
|
|
1031
|
-
) {
|
|
1032
|
-
reject(new CliError(`Code Canvas 本地编译失败: ${detail}`, {
|
|
1033
|
-
code: compileError.code,
|
|
1034
|
-
details: compileError.details,
|
|
1035
|
-
}));
|
|
1036
|
-
return;
|
|
1037
|
-
}
|
|
1038
|
-
reject(new CliError(`Code Canvas 本地编译失败: ${detail}`, {
|
|
1039
|
-
code: 'OPENYIDA_CANVAS_COMPILE_FAILED',
|
|
1040
|
-
details: {
|
|
1041
|
-
stage: 'canvas_compile',
|
|
1042
|
-
sourcePath: options.sourcePath,
|
|
1043
|
-
causeCode: compileError && compileError.code,
|
|
1044
|
-
causeName: compileError && compileError.name,
|
|
1045
|
-
loc: compileError && compileError.loc,
|
|
1046
|
-
},
|
|
1047
|
-
}));
|
|
1054
|
+
reject(normalizeCanvasCompileError(compileError, options));
|
|
1048
1055
|
}
|
|
1049
1056
|
});
|
|
1050
1057
|
}
|
|
1051
1058
|
|
|
1059
|
+
function normalizeCanvasCompileError(compileError, options = {}) {
|
|
1060
|
+
if (isCliError(compileError)) {
|
|
1061
|
+
return compileError;
|
|
1062
|
+
}
|
|
1063
|
+
const detail = compileError && compileError.message ? compileError.message : String(compileError);
|
|
1064
|
+
if (
|
|
1065
|
+
compileError &&
|
|
1066
|
+
/^OPENYIDA_/.test(String(compileError.code || '')) &&
|
|
1067
|
+
compileError.details !== undefined
|
|
1068
|
+
) {
|
|
1069
|
+
return new CliError(`Code Canvas 本地编译失败: ${detail}`, {
|
|
1070
|
+
code: compileError.code,
|
|
1071
|
+
details: compileError.details,
|
|
1072
|
+
});
|
|
1073
|
+
}
|
|
1074
|
+
return new CliError(`Code Canvas 本地编译失败: ${detail}`, {
|
|
1075
|
+
code: 'OPENYIDA_CANVAS_COMPILE_FAILED',
|
|
1076
|
+
details: {
|
|
1077
|
+
stage: 'canvas_compile',
|
|
1078
|
+
sourcePath: options.sourcePath,
|
|
1079
|
+
causeCode: compileError && compileError.code,
|
|
1080
|
+
causeName: compileError && compileError.name,
|
|
1081
|
+
loc: compileError && compileError.loc,
|
|
1082
|
+
},
|
|
1083
|
+
});
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1052
1086
|
module.exports = {
|
|
1053
1087
|
compileCanvas,
|
|
1054
1088
|
compileCanvasLocal,
|
|
1089
|
+
normalizeCanvasCompileError,
|
|
1055
1090
|
extractImportedModules,
|
|
1056
1091
|
resolveWindowAlias,
|
|
1057
1092
|
shouldAllowUnsupportedBareImports,
|
|
1058
1093
|
assertCanvasRuntimeParseable,
|
|
1094
|
+
minifyCanvasRuntime,
|
|
1059
1095
|
findBareDependencyGlobalIssues,
|
|
1060
1096
|
findSelfReferentialDependencyBindingIssues,
|
|
1061
1097
|
findDependencyManifestIssues,
|
|
@@ -23,10 +23,30 @@ function fingerprint(value) {
|
|
|
23
23
|
return crypto.createHash('sha256').update(normalized).digest('hex');
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
+
function rawFingerprint(value) {
|
|
27
|
+
if (typeof value !== 'string' || !value) {
|
|
28
|
+
return '';
|
|
29
|
+
}
|
|
30
|
+
return crypto.createHash('sha256').update(value, 'utf8').digest('hex');
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function positiveSize(value) {
|
|
34
|
+
const size = Number(value);
|
|
35
|
+
return Number.isFinite(size) && size > 0 ? size : 0;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function sha256(value) {
|
|
39
|
+
const digest = String(value || '').toLowerCase();
|
|
40
|
+
return /^[a-f0-9]{64}$/.test(digest) ? digest : '';
|
|
41
|
+
}
|
|
42
|
+
|
|
26
43
|
function createEmptyDisplayInfo() {
|
|
27
44
|
return {
|
|
28
45
|
hasYidaCodeCanvas: false,
|
|
46
|
+
hasCodeBundle: false,
|
|
29
47
|
hasNativeJsx: false,
|
|
48
|
+
codeBundleCount: 0,
|
|
49
|
+
bundleIds: [],
|
|
30
50
|
runtimeCodeBytes: 0,
|
|
31
51
|
sourceCodeBytes: 0,
|
|
32
52
|
compiledCodeBytes: 0,
|
|
@@ -34,6 +54,8 @@ function createEmptyDisplayInfo() {
|
|
|
34
54
|
componentCount: 0,
|
|
35
55
|
canvasRuntimeCode: '',
|
|
36
56
|
canvasSourceCode: '',
|
|
57
|
+
canvasRuntimeSha256: '',
|
|
58
|
+
canvasSourceSha256: '',
|
|
37
59
|
nativeCompiledCode: '',
|
|
38
60
|
nativeSourceCode: '',
|
|
39
61
|
};
|
|
@@ -79,12 +101,37 @@ function traverseDisplayNodes(node, info) {
|
|
|
79
101
|
|
|
80
102
|
if (node.componentName === 'YidaCodeCanvas') {
|
|
81
103
|
const props = node.props || {};
|
|
104
|
+
const codeBundle = props.codeBundle && typeof props.codeBundle === 'object'
|
|
105
|
+
? props.codeBundle
|
|
106
|
+
: null;
|
|
82
107
|
info.hasYidaCodeCanvas = true;
|
|
83
108
|
info.componentCount++;
|
|
84
|
-
|
|
85
|
-
|
|
109
|
+
if (typeof props.runtimeCode === 'string' && props.runtimeCode) {
|
|
110
|
+
info.canvasRuntimeCode = props.runtimeCode;
|
|
111
|
+
}
|
|
112
|
+
if (typeof props.code === 'string' && props.code) {
|
|
113
|
+
info.canvasSourceCode = props.code;
|
|
114
|
+
}
|
|
86
115
|
info.runtimeCodeBytes += codeBytes(props.runtimeCode);
|
|
87
116
|
info.sourceCodeBytes += codeBytes(props.code);
|
|
117
|
+
if (codeBundle) {
|
|
118
|
+
const bundleId = String(codeBundle.bundleId || '');
|
|
119
|
+
const runtime = codeBundle.runtime && typeof codeBundle.runtime === 'object'
|
|
120
|
+
? codeBundle.runtime
|
|
121
|
+
: {};
|
|
122
|
+
const source = codeBundle.source && typeof codeBundle.source === 'object'
|
|
123
|
+
? codeBundle.source
|
|
124
|
+
: {};
|
|
125
|
+
info.hasCodeBundle = true;
|
|
126
|
+
info.codeBundleCount++;
|
|
127
|
+
if (bundleId && !info.bundleIds.includes(bundleId)) {
|
|
128
|
+
info.bundleIds.push(bundleId);
|
|
129
|
+
}
|
|
130
|
+
info.runtimeCodeBytes += positiveSize(runtime.size);
|
|
131
|
+
info.sourceCodeBytes += positiveSize(source.size);
|
|
132
|
+
info.canvasRuntimeSha256 = sha256(runtime.sha256) || info.canvasRuntimeSha256;
|
|
133
|
+
info.canvasSourceSha256 = sha256(source.sha256) || info.canvasSourceSha256;
|
|
134
|
+
}
|
|
88
135
|
addImportedModules(info.importedModules, props.importedModules);
|
|
89
136
|
} else if (node.componentName === 'Jsx') {
|
|
90
137
|
info.hasNativeJsx = true;
|
|
@@ -133,7 +180,9 @@ function hasExpectedDisplayComponent(info, publishMode) {
|
|
|
133
180
|
return false;
|
|
134
181
|
}
|
|
135
182
|
if (publishMode === 'canvas') {
|
|
136
|
-
return info.hasYidaCodeCanvas &&
|
|
183
|
+
return info.hasYidaCodeCanvas && (
|
|
184
|
+
info.runtimeCodeBytes > 0 || !!info.canvasRuntimeSha256
|
|
185
|
+
);
|
|
137
186
|
}
|
|
138
187
|
return info.hasNativeJsx && info.compiledCodeBytes > 0;
|
|
139
188
|
}
|
|
@@ -144,7 +193,10 @@ function summarizeDisplayPublishInfo(info) {
|
|
|
144
193
|
}
|
|
145
194
|
return {
|
|
146
195
|
hasYidaCodeCanvas: info.hasYidaCodeCanvas,
|
|
196
|
+
hasCodeBundle: info.hasCodeBundle,
|
|
147
197
|
hasNativeJsx: info.hasNativeJsx,
|
|
198
|
+
codeBundleCount: info.codeBundleCount,
|
|
199
|
+
bundleIds: info.bundleIds.slice(),
|
|
148
200
|
runtimeCodeBytes: info.runtimeCodeBytes,
|
|
149
201
|
sourceCodeBytes: info.sourceCodeBytes,
|
|
150
202
|
compiledCodeBytes: info.compiledCodeBytes,
|
|
@@ -159,8 +211,13 @@ function verifyPublishedContentMatch(readbackSchema, expectedSchemaContent, publ
|
|
|
159
211
|
const displayComponentPresent = hasExpectedDisplayComponent(readbackInfo, publishMode);
|
|
160
212
|
const readbackArtifact = getPublishArtifact(readbackInfo, publishMode);
|
|
161
213
|
const expectedArtifact = getPublishArtifact(expectedInfo, publishMode);
|
|
162
|
-
const
|
|
163
|
-
const
|
|
214
|
+
const codeBundleReadback = publishMode === 'canvas' && readbackInfo && readbackInfo.hasCodeBundle;
|
|
215
|
+
const readbackFingerprint = codeBundleReadback
|
|
216
|
+
? readbackInfo.canvasRuntimeSha256
|
|
217
|
+
: fingerprint(readbackArtifact);
|
|
218
|
+
const expectedFingerprint = codeBundleReadback
|
|
219
|
+
? rawFingerprint(expectedArtifact)
|
|
220
|
+
: fingerprint(expectedArtifact);
|
|
164
221
|
|
|
165
222
|
return {
|
|
166
223
|
readbackInfo,
|
|
@@ -180,6 +237,7 @@ function verifyPublishedContentMatch(readbackSchema, expectedSchemaContent, publ
|
|
|
180
237
|
module.exports = {
|
|
181
238
|
extractDisplayPublishInfo,
|
|
182
239
|
fingerprint,
|
|
240
|
+
rawFingerprint,
|
|
183
241
|
hasExpectedDisplayComponent,
|
|
184
242
|
parseSchemaContent,
|
|
185
243
|
summarizeDisplayPublishInfo,
|
package/lib/app/get-schema.js
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
'use strict';
|
|
11
11
|
|
|
12
|
+
const crypto = require('crypto');
|
|
12
13
|
const fs = require('fs');
|
|
13
14
|
const path = require('path');
|
|
14
15
|
const {
|
|
@@ -16,6 +17,7 @@ const {
|
|
|
16
17
|
triggerLogin,
|
|
17
18
|
resolveBaseUrl,
|
|
18
19
|
httpGet,
|
|
20
|
+
httpGetCodeBundleText,
|
|
19
21
|
requestWithAutoLogin,
|
|
20
22
|
} = require('../core/utils');
|
|
21
23
|
const { t } = require('../core/i18n');
|
|
@@ -227,6 +229,122 @@ function resolveSchemaContent(schemaResult) {
|
|
|
227
229
|
return parseJsonObject(content);
|
|
228
230
|
}
|
|
229
231
|
|
|
232
|
+
function validateCodeBundleDescriptor(codeBundle) {
|
|
233
|
+
const bundleId = String(codeBundle && codeBundle.bundleId || '');
|
|
234
|
+
const source = codeBundle && codeBundle.source;
|
|
235
|
+
const runtime = codeBundle && codeBundle.runtime;
|
|
236
|
+
const validSha256 = value => /^[a-f0-9]{64}$/.test(String(value || ''));
|
|
237
|
+
const validSize = value => Number.isFinite(Number(value)) && Number(value) > 0
|
|
238
|
+
&& Number(value) <= 5 * 1024 * 1024;
|
|
239
|
+
if (!validSha256(bundleId)
|
|
240
|
+
|| !source || !runtime
|
|
241
|
+
|| !validSha256(source.sha256) || !validSize(source.size)
|
|
242
|
+
|| !validSha256(runtime.sha256) || !validSize(runtime.size)
|
|
243
|
+
|| Number(source.size) + Number(runtime.size) > 5 * 1024 * 1024) {
|
|
244
|
+
throw new Error('YidaCodeCanvas codeBundle 描述不合法');
|
|
245
|
+
}
|
|
246
|
+
return { bundleId, source, runtime };
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
function collectCodeBundleCanvases(content) {
|
|
250
|
+
const canvases = [];
|
|
251
|
+
function traverse(node) {
|
|
252
|
+
if (Array.isArray(node)) {
|
|
253
|
+
node.forEach(traverse);
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
if (!node || typeof node !== 'object') {
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
if (node.componentName === 'YidaCodeCanvas' && node.id && node.props
|
|
260
|
+
&& node.props.codeBundle && typeof node.props.codeBundle === 'object') {
|
|
261
|
+
canvases.push({ props: node.props, descriptor: validateCodeBundleDescriptor(node.props.codeBundle) });
|
|
262
|
+
}
|
|
263
|
+
Object.values(node).forEach(traverse);
|
|
264
|
+
}
|
|
265
|
+
traverse(content);
|
|
266
|
+
return canvases;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
async function downloadCodeBundleArtifact(appType, formUuid, bundleId, artifact, descriptor, authRef) {
|
|
270
|
+
let responseMetadata = null;
|
|
271
|
+
const expectedContentTypes = artifact === 'source'
|
|
272
|
+
? ['text/plain']
|
|
273
|
+
: ['application/javascript', 'text/javascript', 'application/x-javascript'];
|
|
274
|
+
const value = await requestWithAutoLogin((auth) => httpGetCodeBundleText(
|
|
275
|
+
auth.baseUrl,
|
|
276
|
+
`/alibaba/web/${appType}/query/codeBundle/download.json`,
|
|
277
|
+
{ formUuid, bundleId, artifact },
|
|
278
|
+
{
|
|
279
|
+
silentStatus: true,
|
|
280
|
+
maxBytes: 5 * 1024 * 1024,
|
|
281
|
+
expectedContentTypes,
|
|
282
|
+
onResponseMetadata: metadata => {
|
|
283
|
+
responseMetadata = metadata;
|
|
284
|
+
},
|
|
285
|
+
}
|
|
286
|
+
), authRef);
|
|
287
|
+
if (typeof value !== 'string') {
|
|
288
|
+
const message = value && (value.errorMsg || value.message);
|
|
289
|
+
throw new Error(message || `下载 CodeBundle ${artifact} 失败`);
|
|
290
|
+
}
|
|
291
|
+
const size = Buffer.byteLength(value, 'utf8');
|
|
292
|
+
const digest = crypto.createHash('sha256').update(value, 'utf8').digest('hex');
|
|
293
|
+
if (size !== Number(descriptor.size) || digest !== descriptor.sha256) {
|
|
294
|
+
const context = responseMetadata && responseMetadata.context
|
|
295
|
+
? responseMetadata.context
|
|
296
|
+
: `baseUrl=${authRef && authRef.baseUrl || 'unknown'}`;
|
|
297
|
+
const error = new Error(t('common.code_bundle_integrity_failed', artifact, context));
|
|
298
|
+
error.code = 'CODE_BUNDLE_INTEGRITY_MISMATCH';
|
|
299
|
+
error.details = {
|
|
300
|
+
artifact,
|
|
301
|
+
expectedSize: Number(descriptor.size),
|
|
302
|
+
actualSize: size,
|
|
303
|
+
expectedSha256: descriptor.sha256,
|
|
304
|
+
actualSha256: digest,
|
|
305
|
+
...(responseMetadata || {}),
|
|
306
|
+
};
|
|
307
|
+
throw error;
|
|
308
|
+
}
|
|
309
|
+
return value;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
async function resolveCodeBundleSchema(schemaResult, appType, formUuid, authRef) {
|
|
313
|
+
const content = resolveSchemaContent(schemaResult);
|
|
314
|
+
if (!content) {
|
|
315
|
+
return schemaResult;
|
|
316
|
+
}
|
|
317
|
+
const canvases = collectCodeBundleCanvases(content);
|
|
318
|
+
if (canvases.length === 0) {
|
|
319
|
+
return schemaResult;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
const downloaded = new Map();
|
|
323
|
+
for (const canvas of canvases) {
|
|
324
|
+
const { bundleId, source, runtime } = canvas.descriptor;
|
|
325
|
+
let code = downloaded.get(bundleId);
|
|
326
|
+
if (!code) {
|
|
327
|
+
const [sourceCode, runtimeCode] = await Promise.all([
|
|
328
|
+
downloadCodeBundleArtifact(appType, formUuid, bundleId, 'source', source, authRef),
|
|
329
|
+
downloadCodeBundleArtifact(appType, formUuid, bundleId, 'runtime', runtime, authRef),
|
|
330
|
+
]);
|
|
331
|
+
code = { sourceCode, runtimeCode };
|
|
332
|
+
downloaded.set(bundleId, code);
|
|
333
|
+
}
|
|
334
|
+
canvas.props.code = code.sourceCode;
|
|
335
|
+
canvas.props.runtimeCode = code.runtimeCode;
|
|
336
|
+
delete canvas.props.codeBundle;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
if (schemaResult && Object.prototype.hasOwnProperty.call(schemaResult, 'content')) {
|
|
340
|
+
schemaResult.content = typeof schemaResult.content === 'string'
|
|
341
|
+
? JSON.stringify(content)
|
|
342
|
+
: content;
|
|
343
|
+
return schemaResult;
|
|
344
|
+
}
|
|
345
|
+
return content;
|
|
346
|
+
}
|
|
347
|
+
|
|
230
348
|
function addImportedModules(target, value) {
|
|
231
349
|
let modules = value;
|
|
232
350
|
if (typeof modules === 'string') {
|
|
@@ -269,7 +387,10 @@ function extractDisplayPageSummary(schemaResult) {
|
|
|
269
387
|
|
|
270
388
|
const displayPage = {
|
|
271
389
|
hasYidaCodeCanvas: false,
|
|
390
|
+
hasCodeBundle: false,
|
|
272
391
|
hasNativeJsx: false,
|
|
392
|
+
codeBundleCount: 0,
|
|
393
|
+
bundleIds: [],
|
|
273
394
|
runtimeCodeBytes: 0,
|
|
274
395
|
sourceCodeBytes: 0,
|
|
275
396
|
compiledCodeBytes: 0,
|
|
@@ -291,10 +412,29 @@ function extractDisplayPageSummary(schemaResult) {
|
|
|
291
412
|
|
|
292
413
|
if (node.componentName === 'YidaCodeCanvas' && isComponentInstance(node)) {
|
|
293
414
|
const props = node.props || {};
|
|
415
|
+
const codeBundle = props.codeBundle && typeof props.codeBundle === 'object'
|
|
416
|
+
? props.codeBundle
|
|
417
|
+
: null;
|
|
294
418
|
displayPage.hasYidaCodeCanvas = true;
|
|
295
419
|
displayPage.componentCount++;
|
|
296
420
|
displayPage.runtimeCodeBytes += codeBytes(props.runtimeCode);
|
|
297
421
|
displayPage.sourceCodeBytes += codeBytes(props.code);
|
|
422
|
+
if (codeBundle) {
|
|
423
|
+
const source = codeBundle.source && typeof codeBundle.source === 'object'
|
|
424
|
+
? codeBundle.source
|
|
425
|
+
: {};
|
|
426
|
+
const runtime = codeBundle.runtime && typeof codeBundle.runtime === 'object'
|
|
427
|
+
? codeBundle.runtime
|
|
428
|
+
: {};
|
|
429
|
+
const bundleId = String(codeBundle.bundleId || '');
|
|
430
|
+
displayPage.hasCodeBundle = true;
|
|
431
|
+
displayPage.codeBundleCount++;
|
|
432
|
+
displayPage.sourceCodeBytes += Number(source.size) || 0;
|
|
433
|
+
displayPage.runtimeCodeBytes += Number(runtime.size) || 0;
|
|
434
|
+
if (bundleId && !displayPage.bundleIds.includes(bundleId)) {
|
|
435
|
+
displayPage.bundleIds.push(bundleId);
|
|
436
|
+
}
|
|
437
|
+
}
|
|
298
438
|
addImportedModules(displayPage.importedModules, props.importedModules);
|
|
299
439
|
} else if (node.componentName === 'Jsx' && isComponentInstance(node)) {
|
|
300
440
|
displayPage.hasNativeJsx = true;
|
|
@@ -581,12 +721,15 @@ async function mapLimit(items, limit, iterator) {
|
|
|
581
721
|
return results;
|
|
582
722
|
}
|
|
583
723
|
|
|
584
|
-
async function fetchSchemaRecord(appType, form, authRef, retries) {
|
|
724
|
+
async function fetchSchemaRecord(appType, form, authRef, retries, options = {}) {
|
|
585
725
|
let lastError = null;
|
|
586
726
|
for (let attempt = 0; attempt <= retries; attempt++) {
|
|
587
727
|
try {
|
|
588
728
|
const result = await fetchSchema(appType, form.formUuid, authRef);
|
|
589
729
|
if (isSuccessfulSchemaResult(result)) {
|
|
730
|
+
const resolvedResult = options.resolveCodeBundles
|
|
731
|
+
? await resolveCodeBundleSchema(result, appType, form.formUuid, authRef)
|
|
732
|
+
: result;
|
|
590
733
|
const record = {
|
|
591
734
|
formUuid: form.formUuid,
|
|
592
735
|
formName: form.formName,
|
|
@@ -594,10 +737,10 @@ async function fetchSchemaRecord(appType, form, authRef, retries) {
|
|
|
594
737
|
pathName: form.pathName,
|
|
595
738
|
success: true,
|
|
596
739
|
attempts: attempt + 1,
|
|
597
|
-
fieldSummary: extractFieldSummary(
|
|
598
|
-
schema:
|
|
740
|
+
fieldSummary: extractFieldSummary(resolvedResult),
|
|
741
|
+
schema: resolvedResult,
|
|
599
742
|
};
|
|
600
|
-
const displayPage = extractDisplayPageSummary(
|
|
743
|
+
const displayPage = extractDisplayPageSummary(resolvedResult);
|
|
601
744
|
if (displayPage) {
|
|
602
745
|
record.displayPage = displayPage;
|
|
603
746
|
}
|
|
@@ -694,6 +837,10 @@ async function runSingle(parsed, authRef) {
|
|
|
694
837
|
throwCommandError(errorMsg);
|
|
695
838
|
}
|
|
696
839
|
|
|
840
|
+
if (!parsed.field && !parsed.compact && !parsed.summaryJson) {
|
|
841
|
+
result = await resolveCodeBundleSchema(result, parsed.appType, parsed.formUuid, authRef);
|
|
842
|
+
}
|
|
843
|
+
|
|
697
844
|
// 保留既有 --field 返回结构;新 contract 仅由 --compact / --resolve-fields 触发。
|
|
698
845
|
if (parsed.field) {
|
|
699
846
|
const allFieldNodes = collectFieldNodes(result);
|
|
@@ -782,7 +929,9 @@ async function runBatch(parsed, authRef) {
|
|
|
782
929
|
info(` 批量获取 ${forms.length} 个表单 Schema,并发 ${parsed.concurrency},重试 ${parsed.retries}`);
|
|
783
930
|
|
|
784
931
|
const records = await mapLimit(forms, parsed.concurrency, async (form) => {
|
|
785
|
-
const record = await fetchSchemaRecord(parsed.appType, form, authRef, parsed.retries
|
|
932
|
+
const record = await fetchSchemaRecord(parsed.appType, form, authRef, parsed.retries, {
|
|
933
|
+
resolveCodeBundles: !parsed.summaryJson,
|
|
934
|
+
});
|
|
786
935
|
if (record.success && parsed.analysisJson) {
|
|
787
936
|
record.semanticAnalysis = buildSemanticAnalysis(
|
|
788
937
|
parsed.appType,
|
|
@@ -848,5 +997,9 @@ module.exports = {
|
|
|
848
997
|
fetchSchemaRecord,
|
|
849
998
|
collectFieldNodes,
|
|
850
999
|
findFieldNode,
|
|
1000
|
+
validateCodeBundleDescriptor,
|
|
1001
|
+
collectCodeBundleCanvases,
|
|
1002
|
+
downloadCodeBundleArtifact,
|
|
1003
|
+
resolveCodeBundleSchema,
|
|
851
1004
|
run,
|
|
852
1005
|
};
|