openyida 2026.5.21 → 2026.5.25
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 +5 -1
- package/bin/yida.js +7 -1
- package/lib/app/app-list.js +20 -1
- package/lib/app/check-page.js +2 -2
- package/lib/app/compile.js +3 -2
- package/lib/app/externalize-form.js +642 -0
- package/lib/app/import-app.js +39 -11
- package/lib/app/page-compat.js +258 -2
- package/lib/app/page-compiler.js +4 -1
- package/lib/app/page-linter.js +271 -0
- package/lib/app/publish.js +3 -2
- package/lib/auth/cdp-browser-login.js +7 -3
- package/lib/auth/login.js +2 -3
- package/lib/core/command-manifest.js +3 -0
- package/lib/core/copy.js +50 -8
- package/lib/core/env-manager.js +24 -16
- package/lib/core/locales/ar.js +7 -0
- package/lib/core/locales/de.js +7 -0
- package/lib/core/locales/en.js +7 -0
- package/lib/core/locales/es.js +7 -0
- package/lib/core/locales/fr.js +7 -0
- package/lib/core/locales/hi.js +7 -0
- package/lib/core/locales/ja.js +7 -0
- package/lib/core/locales/ko.js +7 -0
- package/lib/core/locales/pt.js +7 -0
- package/lib/core/locales/vi.js +7 -0
- package/lib/core/locales/zh-HK.js +7 -0
- package/lib/core/locales/zh.js +7 -0
- package/lib/core/utils.js +2 -2
- package/lib/process/configure-process.js +552 -20
- package/package.json +1 -1
- package/project/pages/src/demo-agent-chatbox.oyd.jsx +78 -3
- package/scripts/e2e-real/full-runner.js +257 -8
- package/scripts/e2e-real/skill-coverage.js +2 -2
- package/yida-skills/SKILL.md +1 -1
- package/yida-skills/skills/yida-chart/SKILL.md +1 -1
- package/yida-skills/skills/yida-create-process/SKILL.md +3 -2
- package/yida-skills/skills/yida-custom-page/SKILL.md +7 -2
- package/yida-skills/skills/yida-custom-page/examples/attachment-upload.js +14 -12
- package/yida-skills/skills/yida-custom-page/references/attachment-upload-guide.md +3 -1
- package/yida-skills/skills/yida-custom-page/references/coding-guide.md +4 -0
- package/yida-skills/skills/yida-custom-page/references/component-jsx-guide.md +31 -22
- package/yida-skills/skills/yida-dashboard/SKILL.md +10 -9
- package/yida-skills/skills/yida-dashboard/references/interaction-patterns.md +2 -0
- package/yida-skills/skills/yida-dashboard/references/pitfalls.md +13 -4
- package/yida-skills/skills/yida-dashboard/references/structure-and-layout.md +1 -1
- package/yida-skills/skills/yida-ppt-slider/SKILL.md +47 -37
- package/yida-skills/skills/yida-ppt-slider/references/examples.md +5 -4
- package/yida-skills/skills/yida-process-rule/SKILL.md +93 -3
- package/yida-skills/skills/yida-process-rule/references/official-component-nodes.md +93 -0
- package/yida-skills/skills/yida-publish-page/SKILL.md +6 -4
package/lib/app/import-app.js
CHANGED
|
@@ -52,15 +52,26 @@ async function createApp(appName, authRef) {
|
|
|
52
52
|
return result.content; // appType
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
|
|
55
|
+
function normalizeImportFormType(formType) {
|
|
56
|
+
const normalized = String(formType || '').trim().toLowerCase();
|
|
57
|
+
if (!normalized || normalized === 'form') {
|
|
58
|
+
return 'receipt';
|
|
59
|
+
}
|
|
60
|
+
return normalized;
|
|
61
|
+
}
|
|
56
62
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
_csrf_token:
|
|
60
|
-
formType:
|
|
63
|
+
function buildCreateFormPostData(csrfToken, formTitle, formType = 'receipt') {
|
|
64
|
+
return querystring.stringify({
|
|
65
|
+
_csrf_token: csrfToken,
|
|
66
|
+
formType: normalizeImportFormType(formType),
|
|
61
67
|
title: JSON.stringify(buildYidaI18n(formTitle, { en_US: formTitle, ja_JP: formTitle })),
|
|
62
68
|
});
|
|
69
|
+
}
|
|
63
70
|
|
|
71
|
+
// ── 创建空白表单/页面/报表 ──────────────────────────────
|
|
72
|
+
|
|
73
|
+
async function createBlankForm(appType, formTitle, authRef, formType = 'receipt') {
|
|
74
|
+
const postData = buildCreateFormPostData(authRef.csrfToken, formTitle, formType);
|
|
64
75
|
const result = await requestWithAutoLogin((auth) => {
|
|
65
76
|
return httpPost(
|
|
66
77
|
auth.baseUrl,
|
|
@@ -80,14 +91,18 @@ async function createBlankForm(appType, formTitle, authRef) {
|
|
|
80
91
|
|
|
81
92
|
// ── 保存表单 Schema ───────────────────────────────────
|
|
82
93
|
|
|
83
|
-
async function saveFormSchema(appType, formUuid, schema, authRef) {
|
|
84
|
-
const
|
|
94
|
+
async function saveFormSchema(appType, formUuid, schema, authRef, formType = 'receipt') {
|
|
95
|
+
const payload = {
|
|
85
96
|
_csrf_token: authRef.csrfToken,
|
|
86
97
|
appType,
|
|
87
98
|
formUuid,
|
|
88
99
|
content: JSON.stringify(schema),
|
|
89
100
|
schemaVersion: 'V5',
|
|
90
|
-
}
|
|
101
|
+
};
|
|
102
|
+
if (normalizeImportFormType(formType) === 'report') {
|
|
103
|
+
payload.importSchema = 'true';
|
|
104
|
+
}
|
|
105
|
+
const postData = querystring.stringify(payload);
|
|
91
106
|
|
|
92
107
|
const result = await requestWithAutoLogin((auth) => {
|
|
93
108
|
return httpPost(
|
|
@@ -234,12 +249,13 @@ async function run(args) {
|
|
|
234
249
|
|
|
235
250
|
for (const form of forms) {
|
|
236
251
|
const { formUuid: oldFormUuid, name: formName, schema: formSchemaResult } = form;
|
|
252
|
+
const formType = normalizeImportFormType(form.formType);
|
|
237
253
|
info(t('import.migrating', formName, oldFormUuid));
|
|
238
254
|
|
|
239
255
|
// 4.1 创建空白表单
|
|
240
256
|
let newFormUuid;
|
|
241
257
|
try {
|
|
242
|
-
newFormUuid = await createBlankForm(newAppType, formName, authRef);
|
|
258
|
+
newFormUuid = await createBlankForm(newAppType, formName, authRef, formType);
|
|
243
259
|
success(t('import.blank_form_created', newFormUuid));
|
|
244
260
|
} catch (err) {
|
|
245
261
|
fail(t('import.create_form_failed', err.message));
|
|
@@ -247,6 +263,7 @@ async function run(args) {
|
|
|
247
263
|
oldFormUuid,
|
|
248
264
|
newFormUuid: null,
|
|
249
265
|
name: formName,
|
|
266
|
+
formType,
|
|
250
267
|
status: 'failed',
|
|
251
268
|
error: err.message,
|
|
252
269
|
});
|
|
@@ -262,6 +279,7 @@ async function run(args) {
|
|
|
262
279
|
oldFormUuid,
|
|
263
280
|
newFormUuid,
|
|
264
281
|
name: formName,
|
|
282
|
+
formType,
|
|
265
283
|
status: 'skipped',
|
|
266
284
|
error: t('import.schema_empty_msg'),
|
|
267
285
|
});
|
|
@@ -279,7 +297,7 @@ async function run(args) {
|
|
|
279
297
|
);
|
|
280
298
|
|
|
281
299
|
// 4.3 保存 Schema
|
|
282
|
-
const saveResult = await saveFormSchema(newAppType, newFormUuid, adaptedSchema, authRef);
|
|
300
|
+
const saveResult = await saveFormSchema(newAppType, newFormUuid, adaptedSchema, authRef, formType);
|
|
283
301
|
if (!saveResult || !saveResult.success) {
|
|
284
302
|
const errorMsg = saveResult ? saveResult.errorMsg || t('common.unknown_error') : t('common.request_failed');
|
|
285
303
|
fail(t('import.save_schema_failed', errorMsg));
|
|
@@ -287,6 +305,7 @@ async function run(args) {
|
|
|
287
305
|
oldFormUuid,
|
|
288
306
|
newFormUuid,
|
|
289
307
|
name: formName,
|
|
308
|
+
formType,
|
|
290
309
|
status: 'failed',
|
|
291
310
|
error: t('import.save_schema_failed', errorMsg),
|
|
292
311
|
});
|
|
@@ -308,6 +327,7 @@ async function run(args) {
|
|
|
308
327
|
oldFormUuid,
|
|
309
328
|
newFormUuid,
|
|
310
329
|
name: formName,
|
|
330
|
+
formType,
|
|
311
331
|
status: 'success',
|
|
312
332
|
});
|
|
313
333
|
successCount++;
|
|
@@ -352,4 +372,12 @@ async function run(args) {
|
|
|
352
372
|
);
|
|
353
373
|
}
|
|
354
374
|
|
|
355
|
-
module.exports = {
|
|
375
|
+
module.exports = {
|
|
376
|
+
run,
|
|
377
|
+
__test__: {
|
|
378
|
+
normalizeImportFormType,
|
|
379
|
+
buildCreateFormPostData,
|
|
380
|
+
adaptSerialNumberFormulas,
|
|
381
|
+
extractSchemaContent,
|
|
382
|
+
},
|
|
383
|
+
};
|
package/lib/app/page-compat.js
CHANGED
|
@@ -30,6 +30,37 @@ const SUPPORTED_REMOVABLE_IMPORTS = new Set([
|
|
|
30
30
|
]);
|
|
31
31
|
|
|
32
32
|
const SUPPORTED_HOOKS = new Set(['useState', 'useEffect']);
|
|
33
|
+
const REQUIRED_RUNTIME_EXPORTS = {
|
|
34
|
+
getCustomState: [
|
|
35
|
+
'export function getCustomState(key) {',
|
|
36
|
+
' if (typeof _customState === "undefined") {',
|
|
37
|
+
' return key ? undefined : {};',
|
|
38
|
+
' }',
|
|
39
|
+
' if (key) {',
|
|
40
|
+
' return _customState[key];',
|
|
41
|
+
' }',
|
|
42
|
+
' return Object.assign({}, _customState);',
|
|
43
|
+
'}',
|
|
44
|
+
].join('\n'),
|
|
45
|
+
setCustomState: [
|
|
46
|
+
'export function setCustomState(newState) {',
|
|
47
|
+
' if (typeof _customState === "undefined") {',
|
|
48
|
+
' return;',
|
|
49
|
+
' }',
|
|
50
|
+
' Object.keys(newState || {}).forEach(function(key) {',
|
|
51
|
+
' _customState[key] = newState[key];',
|
|
52
|
+
' });',
|
|
53
|
+
' this.forceUpdate();',
|
|
54
|
+
'}',
|
|
55
|
+
].join('\n'),
|
|
56
|
+
forceUpdate: [
|
|
57
|
+
'export function forceUpdate() {',
|
|
58
|
+
' this.setState({ timestamp: new Date().getTime() });',
|
|
59
|
+
'}',
|
|
60
|
+
].join('\n'),
|
|
61
|
+
didMount: 'export function didMount() {}',
|
|
62
|
+
didUnmount: 'export function didUnmount() {}',
|
|
63
|
+
};
|
|
33
64
|
|
|
34
65
|
function parseSource(sourceCode) {
|
|
35
66
|
return parser.parse(sourceCode, PARSER_OPTIONS);
|
|
@@ -53,11 +84,21 @@ function hasYidaRenderExport(ast) {
|
|
|
53
84
|
});
|
|
54
85
|
}
|
|
55
86
|
|
|
87
|
+
function sourceHasYidaRenderExport(sourceCode) {
|
|
88
|
+
return /export\s+function\s+renderJsx\s*\(/.test(sourceCode || '');
|
|
89
|
+
}
|
|
90
|
+
|
|
56
91
|
function isAuthoringPath(sourcePath) {
|
|
57
92
|
return /\.oyd\.(jsx?|tsx?)$/i.test(sourcePath || '') ||
|
|
58
93
|
/\.openyida\.(jsx?|tsx?)$/i.test(sourcePath || '');
|
|
59
94
|
}
|
|
60
95
|
|
|
96
|
+
function shouldBuildPageSource(sourceCode, sourcePath = '', options = {}) {
|
|
97
|
+
return options.modern === true ||
|
|
98
|
+
isAuthoringPath(sourcePath) ||
|
|
99
|
+
(!sourceHasYidaRenderExport(sourceCode) && /export\s+default\b/.test(sourceCode || ''));
|
|
100
|
+
}
|
|
101
|
+
|
|
61
102
|
function isSupportedRemovableImport(sourceValue) {
|
|
62
103
|
return SUPPORTED_REMOVABLE_IMPORTS.has(String(sourceValue || '').toLowerCase());
|
|
63
104
|
}
|
|
@@ -324,6 +365,73 @@ function removeSupportedImports(ast, fixes, errors) {
|
|
|
324
365
|
});
|
|
325
366
|
}
|
|
326
367
|
|
|
368
|
+
function collectExportedFunctionNames(ast) {
|
|
369
|
+
const names = new Set();
|
|
370
|
+
ast.program.body.forEach((statement) => {
|
|
371
|
+
if (
|
|
372
|
+
statement.type === 'ExportNamedDeclaration' &&
|
|
373
|
+
statement.declaration &&
|
|
374
|
+
statement.declaration.type === 'FunctionDeclaration' &&
|
|
375
|
+
statement.declaration.id
|
|
376
|
+
) {
|
|
377
|
+
names.add(statement.declaration.id.name);
|
|
378
|
+
}
|
|
379
|
+
});
|
|
380
|
+
return names;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
function hasTopLevelCustomState(ast) {
|
|
384
|
+
return ast.program.body.some((statement) => {
|
|
385
|
+
return statement.type === 'VariableDeclaration' &&
|
|
386
|
+
statement.declarations.some((declarator) => {
|
|
387
|
+
return declarator.id &&
|
|
388
|
+
declarator.id.type === 'Identifier' &&
|
|
389
|
+
declarator.id.name === '_customState';
|
|
390
|
+
});
|
|
391
|
+
});
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
function ensureYidaRuntimeContract(sourceCode) {
|
|
395
|
+
const ast = parseSource(sourceCode);
|
|
396
|
+
const exportedNames = collectExportedFunctionNames(ast);
|
|
397
|
+
const fixes = [];
|
|
398
|
+
const prepend = [];
|
|
399
|
+
const append = [];
|
|
400
|
+
const needsStateHelper = !exportedNames.has('getCustomState') || !exportedNames.has('setCustomState');
|
|
401
|
+
|
|
402
|
+
if (needsStateHelper && !hasTopLevelCustomState(ast)) {
|
|
403
|
+
prepend.push('var _customState = {};');
|
|
404
|
+
fixes.push({
|
|
405
|
+
rule: 'runtime-custom-state',
|
|
406
|
+
message: 'Inserted default _customState store for Yida runtime helpers',
|
|
407
|
+
});
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
Object.keys(REQUIRED_RUNTIME_EXPORTS).forEach((name) => {
|
|
411
|
+
if (!exportedNames.has(name)) {
|
|
412
|
+
append.push(REQUIRED_RUNTIME_EXPORTS[name]);
|
|
413
|
+
fixes.push({
|
|
414
|
+
rule: 'runtime-export-' + name,
|
|
415
|
+
message: `Inserted missing export function ${name} for Yida runtime contract`,
|
|
416
|
+
});
|
|
417
|
+
}
|
|
418
|
+
});
|
|
419
|
+
|
|
420
|
+
if (prepend.length === 0 && append.length === 0) {
|
|
421
|
+
return { code: sourceCode, fixes };
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
return {
|
|
425
|
+
code: [
|
|
426
|
+
prepend.join('\n'),
|
|
427
|
+
sourceCode.trimEnd(),
|
|
428
|
+
append.join('\n\n'),
|
|
429
|
+
'',
|
|
430
|
+
].filter(Boolean).join('\n\n'),
|
|
431
|
+
fixes,
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
|
|
327
435
|
function fixYidaSource(sourceCode) {
|
|
328
436
|
const ast = parseSource(sourceCode);
|
|
329
437
|
const fixes = [];
|
|
@@ -335,9 +443,11 @@ function fixYidaSource(sourceCode) {
|
|
|
335
443
|
fixVariableDeclarations(ast, fixes);
|
|
336
444
|
fixRenderTimestamp(ast, fixes);
|
|
337
445
|
|
|
446
|
+
const runtimeResult = ensureYidaRuntimeContract(generateCode(ast));
|
|
447
|
+
|
|
338
448
|
return {
|
|
339
|
-
code:
|
|
340
|
-
fixes,
|
|
449
|
+
code: runtimeResult.code,
|
|
450
|
+
fixes: fixes.concat(runtimeResult.fixes),
|
|
341
451
|
errors,
|
|
342
452
|
mode: 'yida-source',
|
|
343
453
|
};
|
|
@@ -529,6 +639,132 @@ function replaceStateSettersInStatement(statement, stateSetters) {
|
|
|
529
639
|
return wrapper.program.body[0];
|
|
530
640
|
}
|
|
531
641
|
|
|
642
|
+
function addBindingNames(pattern, names) {
|
|
643
|
+
if (!pattern) {
|
|
644
|
+
return;
|
|
645
|
+
}
|
|
646
|
+
if (pattern.type === 'Identifier') {
|
|
647
|
+
names.add(pattern.name);
|
|
648
|
+
return;
|
|
649
|
+
}
|
|
650
|
+
if (pattern.type === 'ArrayPattern') {
|
|
651
|
+
pattern.elements.forEach(element => addBindingNames(element, names));
|
|
652
|
+
return;
|
|
653
|
+
}
|
|
654
|
+
if (pattern.type === 'ObjectPattern') {
|
|
655
|
+
pattern.properties.forEach((property) => {
|
|
656
|
+
addBindingNames(property.value || property.argument || property.key, names);
|
|
657
|
+
});
|
|
658
|
+
return;
|
|
659
|
+
}
|
|
660
|
+
if (pattern.type === 'RestElement') {
|
|
661
|
+
addBindingNames(pattern.argument, names);
|
|
662
|
+
return;
|
|
663
|
+
}
|
|
664
|
+
if (pattern.type === 'AssignmentPattern') {
|
|
665
|
+
addBindingNames(pattern.left, names);
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
function collectComponentBindingNames(componentBody) {
|
|
670
|
+
const names = new Set();
|
|
671
|
+
componentBody.forEach((statement) => {
|
|
672
|
+
if (statement.type === 'VariableDeclaration') {
|
|
673
|
+
statement.declarations.forEach(declarator => addBindingNames(declarator.id, names));
|
|
674
|
+
} else if ((statement.type === 'FunctionDeclaration' || statement.type === 'ClassDeclaration') && statement.id) {
|
|
675
|
+
names.add(statement.id.name);
|
|
676
|
+
}
|
|
677
|
+
});
|
|
678
|
+
return names;
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
function collectUseStateSetterNames(componentBody) {
|
|
682
|
+
const names = new Set();
|
|
683
|
+
componentBody.forEach((statement) => {
|
|
684
|
+
if (statement.type !== 'VariableDeclaration') {
|
|
685
|
+
return;
|
|
686
|
+
}
|
|
687
|
+
statement.declarations.forEach((declarator) => {
|
|
688
|
+
if (isUseStateDeclarator(declarator)) {
|
|
689
|
+
names.add(declarator.id.elements[1].name);
|
|
690
|
+
}
|
|
691
|
+
});
|
|
692
|
+
});
|
|
693
|
+
return names;
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
function collectReferencedIdentifiersFromStatements(statements) {
|
|
697
|
+
const names = new Set();
|
|
698
|
+
if (!statements || statements.length === 0) {
|
|
699
|
+
return names;
|
|
700
|
+
}
|
|
701
|
+
const wrapper = t.file(t.program(statements.map(statement => t.cloneNode(statement))));
|
|
702
|
+
traverse(wrapper, {
|
|
703
|
+
Identifier(pathRef) {
|
|
704
|
+
if (typeof pathRef.isReferencedIdentifier === 'function') {
|
|
705
|
+
if (!pathRef.isReferencedIdentifier()) {
|
|
706
|
+
return;
|
|
707
|
+
}
|
|
708
|
+
} else if (
|
|
709
|
+
pathRef.parent.type === 'MemberExpression' &&
|
|
710
|
+
pathRef.parent.property === pathRef.node &&
|
|
711
|
+
!pathRef.parent.computed
|
|
712
|
+
) {
|
|
713
|
+
return;
|
|
714
|
+
}
|
|
715
|
+
names.add(pathRef.node.name);
|
|
716
|
+
},
|
|
717
|
+
});
|
|
718
|
+
return names;
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
function collectStatementBindingNames(statements) {
|
|
722
|
+
const names = new Set();
|
|
723
|
+
(statements || []).forEach((statement) => {
|
|
724
|
+
if (statement.type === 'VariableDeclaration') {
|
|
725
|
+
statement.declarations.forEach(declarator => addBindingNames(declarator.id, names));
|
|
726
|
+
} else if ((statement.type === 'FunctionDeclaration' || statement.type === 'ClassDeclaration') && statement.id) {
|
|
727
|
+
names.add(statement.id.name);
|
|
728
|
+
}
|
|
729
|
+
});
|
|
730
|
+
return names;
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
function addUnsupportedEffectLocalReferenceErrors(effect, componentBindings, allowedBindings, errors, reportedNames, line) {
|
|
734
|
+
const referencedNames = collectReferencedIdentifiersFromStatements(effect.mount.concat(effect.unmount));
|
|
735
|
+
referencedNames.forEach((name) => {
|
|
736
|
+
if (!componentBindings.has(name) || allowedBindings.has(name) || reportedNames.has(name)) {
|
|
737
|
+
return;
|
|
738
|
+
}
|
|
739
|
+
reportedNames.add(name);
|
|
740
|
+
errors.push({
|
|
741
|
+
code: 'UNSUPPORTED_EFFECT_LOCAL_REFERENCE',
|
|
742
|
+
message: `useEffect(..., []) references local component binding "${name}", which would be undefined inside Yida didMount/didUnmount. Move the logic inline, use a supported state setter functional update, or write native export function didMount().`,
|
|
743
|
+
line,
|
|
744
|
+
});
|
|
745
|
+
});
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
function addUnsupportedEffectCleanupReferenceErrors(effect, errors, reportedNames, line) {
|
|
749
|
+
const mountBindings = collectStatementBindingNames(effect.mount);
|
|
750
|
+
if (mountBindings.size === 0 || effect.unmount.length === 0) {
|
|
751
|
+
return;
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
const cleanupRefs = collectReferencedIdentifiersFromStatements(effect.unmount);
|
|
755
|
+
cleanupRefs.forEach((name) => {
|
|
756
|
+
if (!mountBindings.has(name) || reportedNames.has(name)) {
|
|
757
|
+
return;
|
|
758
|
+
}
|
|
759
|
+
reportedNames.add(name);
|
|
760
|
+
errors.push({
|
|
761
|
+
code: 'UNSUPPORTED_EFFECT_CLEANUP_REFERENCE',
|
|
762
|
+
message: `useEffect cleanup references effect-local binding "${name}", which would be undefined inside Yida didUnmount. Store it on this (for native didMount/didUnmount) or avoid cleanup-local captures in authoring mode.`,
|
|
763
|
+
line,
|
|
764
|
+
});
|
|
765
|
+
});
|
|
766
|
+
}
|
|
767
|
+
|
|
532
768
|
function statementContainsUseEffect(statement) {
|
|
533
769
|
return statement.type === 'ExpressionStatement' &&
|
|
534
770
|
statement.expression &&
|
|
@@ -539,6 +775,10 @@ function statementContainsUseEffect(statement) {
|
|
|
539
775
|
function splitComponentBody(componentBody, errors) {
|
|
540
776
|
const stateItems = [];
|
|
541
777
|
const stateSetters = new Map();
|
|
778
|
+
const componentBindings = collectComponentBindingNames(componentBody);
|
|
779
|
+
const allowedEffectBindings = collectUseStateSetterNames(componentBody);
|
|
780
|
+
const reportedEffectRefs = new Set();
|
|
781
|
+
const reportedCleanupRefs = new Set();
|
|
542
782
|
const renderStatements = [];
|
|
543
783
|
const didMountStatements = [];
|
|
544
784
|
const didUnmountStatements = [];
|
|
@@ -573,6 +813,20 @@ function splitComponentBody(componentBody, errors) {
|
|
|
573
813
|
if (statementContainsUseEffect(statement)) {
|
|
574
814
|
const effect = extractEffect(statement.expression, errors);
|
|
575
815
|
if (effect) {
|
|
816
|
+
addUnsupportedEffectLocalReferenceErrors(
|
|
817
|
+
effect,
|
|
818
|
+
componentBindings,
|
|
819
|
+
allowedEffectBindings,
|
|
820
|
+
errors,
|
|
821
|
+
reportedEffectRefs,
|
|
822
|
+
statement.loc && statement.loc.start ? statement.loc.start.line : undefined
|
|
823
|
+
);
|
|
824
|
+
addUnsupportedEffectCleanupReferenceErrors(
|
|
825
|
+
effect,
|
|
826
|
+
errors,
|
|
827
|
+
reportedCleanupRefs,
|
|
828
|
+
statement.loc && statement.loc.start ? statement.loc.start.line : undefined
|
|
829
|
+
);
|
|
576
830
|
didMountStatements.push(...effect.mount);
|
|
577
831
|
didUnmountStatements.push(...effect.unmount);
|
|
578
832
|
}
|
|
@@ -801,7 +1055,9 @@ function buildPageFile(sourcePath, options = {}) {
|
|
|
801
1055
|
module.exports = {
|
|
802
1056
|
buildPageSource,
|
|
803
1057
|
buildPageFile,
|
|
1058
|
+
ensureYidaRuntimeContract,
|
|
804
1059
|
fixYidaSource,
|
|
805
1060
|
getCompatOutputPath,
|
|
806
1061
|
isAuthoringPath,
|
|
1062
|
+
shouldBuildPageSource,
|
|
807
1063
|
};
|
package/lib/app/page-compiler.js
CHANGED
|
@@ -7,6 +7,7 @@ const { default: babelTransform } = require('../core/babel-transform');
|
|
|
7
7
|
const { findProjectRoot } = require('../core/utils');
|
|
8
8
|
const { t } = require('../core/i18n');
|
|
9
9
|
const { info, success, error } = require('../core/chalk');
|
|
10
|
+
const { ensureYidaRuntimeContract } = require('./page-compat');
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* 编译宜搭自定义页面 JSX/JS 源码。
|
|
@@ -20,7 +21,9 @@ function compileSource(sourcePath) {
|
|
|
20
21
|
const compiledPath = path.join(findProjectRoot(), 'pages', 'dist', compiledFileName);
|
|
21
22
|
|
|
22
23
|
info(t('publish.reading_source', sourceFileName));
|
|
23
|
-
const
|
|
24
|
+
const rawSourceCode = fs.readFileSync(sourcePath, 'utf-8');
|
|
25
|
+
const runtimeResult = ensureYidaRuntimeContract(rawSourceCode);
|
|
26
|
+
const sourceCode = runtimeResult.code;
|
|
24
27
|
|
|
25
28
|
info(t('publish.compiling', sourceFileName));
|
|
26
29
|
const babelResult = babelTransform(sourceCode, {}, false, { RE_VERSION: '7.4.0' });
|