openyida 2026.7.23-1 → 2026.7.23

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.
@@ -95,11 +95,7 @@ function parseOpenOption(inputArgs) {
95
95
  const OPTION_FIELD_TYPES = ['RadioField', 'SelectField', 'CheckboxField', 'MultiSelectField'];
96
96
 
97
97
  function throwCreateFormError(message, code, details) {
98
- throw createCreateFormError(message, code, details);
99
- }
100
-
101
- function createCreateFormError(message, code, details) {
102
- return new CliError(message, {
98
+ throw new CliError(message, {
103
99
  code: code || 'CREATE_FORM_FAILED',
104
100
  details,
105
101
  });
@@ -214,28 +210,6 @@ const FIELD_TYPE_ALIAS = {
214
210
  serialnumberfield: 'SerialNumberField',
215
211
  };
216
212
 
217
- const SUPPORTED_BUSINESS_FIELD_TYPES = [
218
- 'TextField',
219
- 'TextareaField',
220
- 'RadioField',
221
- 'SelectField',
222
- 'CheckboxField',
223
- 'MultiSelectField',
224
- 'NumberField',
225
- 'RateField',
226
- 'DateField',
227
- 'CascadeDateField',
228
- 'EmployeeField',
229
- 'DepartmentSelectField',
230
- 'CountrySelectField',
231
- 'AddressField',
232
- 'AttachmentField',
233
- 'ImageField',
234
- 'TableField',
235
- 'AssociationFormField',
236
- 'SerialNumberField',
237
- ];
238
-
239
213
  const FORM_PRESENTATION_TYPE_ALIAS = {
240
214
  Divider: 'Divider',
241
215
  divider: 'Divider',
@@ -288,28 +262,11 @@ function normalizeComponentAlias(field) {
288
262
  return String(rawAlias).trim();
289
263
  }
290
264
 
291
- function readFormDefinitionType(field) {
292
- if (!field || typeof field !== 'object' || Array.isArray(field)) {
293
- return '';
294
- }
295
- if (field.type !== undefined && field.type !== null && field.type !== '') {
296
- return String(field.type).trim();
297
- }
298
- if (field.componentName !== undefined && field.componentName !== null && field.componentName !== '') {
299
- return String(field.componentName).trim();
300
- }
301
- if (field.componentType !== undefined && field.componentType !== null && field.componentType !== '') {
302
- return String(field.componentType).trim();
303
- }
304
- return '';
305
- }
306
-
307
265
  function normalizeFormDefinitionType(field) {
308
- const rawType = readFormDefinitionType(field);
309
- if (!rawType) {
266
+ if (!field || !field.type) {
310
267
  return '';
311
268
  }
312
- return FORM_PRESENTATION_TYPE_ALIAS[rawType] || FIELD_TYPE_ALIAS[rawType] || rawType;
269
+ return FORM_PRESENTATION_TYPE_ALIAS[field.type] || FIELD_TYPE_ALIAS[field.type] || field.type;
313
270
  }
314
271
 
315
272
  function isFormPresentationComponent(componentName) {
@@ -320,194 +277,6 @@ function isFormPresentationDefinition(field) {
320
277
  return isFormPresentationComponent(normalizeFormDefinitionType(field));
321
278
  }
322
279
 
323
- function isSupportedBusinessFieldType(componentName) {
324
- return SUPPORTED_BUSINESS_FIELD_TYPES.indexOf(componentName) !== -1;
325
- }
326
-
327
- function getDefinitionDisplayName(field) {
328
- if (!field || typeof field !== 'object') {
329
- return '';
330
- }
331
- return field.label || field.title || readFormDefinitionType(field) || '';
332
- }
333
-
334
- function buildInvalidFieldDefinitionDetails(field, fieldPath, extra) {
335
- const details = Object.assign({
336
- path: fieldPath || 'fields',
337
- label: field && typeof field === 'object' ? field.label : undefined,
338
- title: field && typeof field === 'object' ? field.title : undefined,
339
- type: readFormDefinitionType(field),
340
- }, extra || {});
341
- Object.keys(details).forEach(function (key) {
342
- if (details[key] === undefined || details[key] === '') {
343
- delete details[key];
344
- }
345
- });
346
- return details;
347
- }
348
-
349
- function throwInvalidFieldDefinition(message, code, field, fieldPath, extra) {
350
- throwCreateFormError(
351
- message,
352
- code || 'CREATE_FORM_INVALID_FIELD_DEFINITION',
353
- buildInvalidFieldDefinitionDetails(field, fieldPath, extra)
354
- );
355
- }
356
-
357
- function validatePlainFieldObject(field, fieldPath) {
358
- if (!field || typeof field !== 'object' || Array.isArray(field)) {
359
- throwInvalidFieldDefinition(
360
- '字段定义必须是对象: ' + fieldPath,
361
- 'CREATE_FORM_INVALID_FIELD_DEFINITION',
362
- field,
363
- fieldPath
364
- );
365
- }
366
- }
367
-
368
- function validateContainerChildrenArray(field, fieldPath, componentName) {
369
- if (field.children === undefined || field.children === null) {
370
- return [];
371
- }
372
- if (!Array.isArray(field.children)) {
373
- throwInvalidFieldDefinition(
374
- componentName + '.children 必须是数组: ' + fieldPath,
375
- 'CREATE_FORM_INVALID_CONTAINER_CHILDREN',
376
- field,
377
- fieldPath,
378
- { componentName }
379
- );
380
- }
381
- return field.children;
382
- }
383
-
384
- function validateFieldDefinition(field, fieldPath, options) {
385
- const validationOptions = options || {};
386
- validatePlainFieldObject(field, fieldPath);
387
-
388
- const componentName = normalizeFormDefinitionType(field);
389
- if (!componentName) {
390
- throwInvalidFieldDefinition(
391
- '字段定义缺少 type/componentName/componentType: ' + fieldPath,
392
- 'CREATE_FORM_FIELD_TYPE_MISSING',
393
- field,
394
- fieldPath
395
- );
396
- }
397
-
398
- if (isFormPresentationComponent(componentName)) {
399
- if (validationOptions.disallowPresentation) {
400
- throwInvalidFieldDefinition(
401
- 'TableField.children 不支持展示布局组件: ' + componentName,
402
- 'CREATE_FORM_TABLE_CHILD_PRESENTATION_UNSUPPORTED',
403
- field,
404
- fieldPath,
405
- { componentName }
406
- );
407
- }
408
- if (componentName === 'Column' && !validationOptions.allowColumn) {
409
- throwInvalidFieldDefinition(
410
- 'Column 只能作为 ColumnContainer.children 的 Column 对象使用: ' + fieldPath,
411
- 'CREATE_FORM_COLUMN_OUTSIDE_COLUMNS_LAYOUT',
412
- field,
413
- fieldPath,
414
- { componentName }
415
- );
416
- }
417
- if (componentName === 'ColumnsLayout') {
418
- validateColumnsLayoutDefinition(field, fieldPath);
419
- } else if (componentName === 'PageSection') {
420
- validateContainerChildrenArray(field, fieldPath, componentName).forEach(function (child, childIndex) {
421
- validateFieldDefinition(child, fieldPath + '.children[' + childIndex + ']');
422
- });
423
- } else if (componentName === 'Column') {
424
- validateContainerChildrenArray(field, fieldPath, componentName).forEach(function (child, childIndex) {
425
- validateFieldDefinition(child, fieldPath + '.children[' + childIndex + ']');
426
- });
427
- }
428
- return componentName;
429
- }
430
-
431
- if (!isSupportedBusinessFieldType(componentName)) {
432
- throwInvalidFieldDefinition(
433
- '不支持的字段类型: ' + componentName,
434
- 'CREATE_FORM_UNSUPPORTED_FIELD_TYPE',
435
- field,
436
- fieldPath,
437
- { componentName }
438
- );
439
- }
440
-
441
- if (componentName === 'TableField') {
442
- validateTableFieldChildren(field, fieldPath, validationOptions);
443
- }
444
-
445
- return componentName;
446
- }
447
-
448
- function validateColumnsLayoutDefinition(field, fieldPath) {
449
- const columns = validateContainerChildrenArray(field, fieldPath, 'ColumnsLayout');
450
- columns.forEach(function (columnDefinition, columnIndex) {
451
- const columnPath = fieldPath + '.children[' + columnIndex + ']';
452
- if (Array.isArray(columnDefinition)) {
453
- columnDefinition.forEach(function (child, childIndex) {
454
- validateFieldDefinition(child, columnPath + '[' + childIndex + ']');
455
- });
456
- return;
457
- }
458
- if (
459
- columnDefinition &&
460
- typeof columnDefinition === 'object' &&
461
- !Array.isArray(columnDefinition) &&
462
- normalizeFormDefinitionType(columnDefinition) === 'Column'
463
- ) {
464
- validateFieldDefinition(columnDefinition, columnPath, { allowColumn: true });
465
- return;
466
- }
467
- throwInvalidFieldDefinition(
468
- 'ColumnContainer.children 只能包含二维字段数组或 Column 对象: ' + columnPath,
469
- 'CREATE_FORM_INVALID_COLUMNS_LAYOUT_CHILDREN',
470
- columnDefinition,
471
- columnPath,
472
- { componentName: normalizeFormDefinitionType(columnDefinition) || readFormDefinitionType(columnDefinition) }
473
- );
474
- });
475
- }
476
-
477
- function validateTableFieldChildren(field, fieldPath, options) {
478
- if (field.children === undefined || field.children === null) {
479
- return;
480
- }
481
- if (!Array.isArray(field.children)) {
482
- throwInvalidFieldDefinition(
483
- 'TableField.children 必须是字段数组: ' + fieldPath,
484
- 'CREATE_FORM_INVALID_TABLE_CHILDREN',
485
- field,
486
- fieldPath,
487
- { componentName: 'TableField' }
488
- );
489
- }
490
- field.children.forEach(function (child, childIndex) {
491
- validateFieldDefinition(child, fieldPath + '.children[' + childIndex + ']', Object.assign({}, options, {
492
- disallowPresentation: true,
493
- }));
494
- });
495
- }
496
-
497
- function validateFormFieldDefinitions(fields, rootPath) {
498
- if (!Array.isArray(fields)) {
499
- throwInvalidFieldDefinition(
500
- '字段定义必须是数组',
501
- 'CREATE_FORM_INVALID_FIELD_DEFINITION',
502
- null,
503
- rootPath || 'fields'
504
- );
505
- }
506
- fields.forEach(function (field, index) {
507
- validateFieldDefinition(field, (rootPath || 'fields') + '[' + index + ']');
508
- });
509
- }
510
-
511
280
  function normalizeI18nValue(value, fallback) {
512
281
  if (value && typeof value === 'object') {
513
282
  return value;
@@ -696,16 +465,7 @@ function buildFormNodeComponents(fields) {
696
465
  // ── 生成字段组件 ─────────────────────────────────────
697
466
 
698
467
  function buildFieldComponent(field) {
699
- const componentName = normalizeFormDefinitionType(field);
700
- if (!isSupportedBusinessFieldType(componentName)) {
701
- throwInvalidFieldDefinition(
702
- componentName ? '不支持的字段类型: ' + componentName : '字段定义缺少 type/componentName/componentType',
703
- componentName ? 'CREATE_FORM_UNSUPPORTED_FIELD_TYPE' : 'CREATE_FORM_FIELD_TYPE_MISSING',
704
- field,
705
- 'field',
706
- { componentName }
707
- );
708
- }
468
+ const componentName = FIELD_TYPE_ALIAS[field.type] || field.type;
709
469
  const fieldId = generateFieldId(componentName);
710
470
  const nodeId = nextNodeId();
711
471
 
@@ -4076,14 +3836,20 @@ function ensureComponentsMapForComponent(schema, component) {
4076
3836
  }
4077
3837
  }
4078
3838
 
3839
+ function getDefinitionDisplayName(field) {
3840
+ if (!field || typeof field !== 'object') {
3841
+ return '';
3842
+ }
3843
+ return field.label || field.title || field.type || '';
3844
+ }
3845
+
4079
3846
  function countDataFieldDefinitions(fields) {
4080
3847
  let count = 0;
4081
3848
  (fields || []).forEach(function (field) {
4082
3849
  if (!field || typeof field !== 'object' || Array.isArray(field)) {
4083
3850
  return;
4084
3851
  }
4085
- const componentName = normalizeFormDefinitionType(field);
4086
- if (isSupportedBusinessFieldType(componentName)) {
3852
+ if (!isFormPresentationDefinition(field)) {
4087
3853
  count++;
4088
3854
  }
4089
3855
  if (Array.isArray(field.children)) {
@@ -4115,12 +3881,11 @@ function applyChangesToSchema(schema, changes) {
4115
3881
  const actionDesc = t('create_form.action_label', changeIndex + 1, change.action);
4116
3882
 
4117
3883
  if (change.action === 'add') {
4118
- if (!change.field || !normalizeFormDefinitionType(change.field) || (!change.field.label && !change.field.title && !isFormPresentationDefinition(change.field))) {
3884
+ if (!change.field || !change.field.type || (!change.field.label && !change.field.title && !isFormPresentationDefinition(change.field))) {
4119
3885
  warn(actionDesc + t('create_form.add_missing_field'));
4120
3886
  return;
4121
3887
  }
4122
3888
 
4123
- validateFormFieldDefinitions([change.field], 'changes[' + changeIndex + '].field');
4124
3889
  const newComponent = buildFormNodeComponent(change.field);
4125
3890
  ensureComponentsMapForComponent(schema, newComponent);
4126
3891
  const displayName = getDefinitionDisplayName(change.field);
@@ -4292,54 +4057,12 @@ function requireSchemaServerRevision(serverRevision, details) {
4292
4057
  return serverRevision;
4293
4058
  }
4294
4059
 
4295
- function sanitizeFailureResult(result) {
4296
- if (!result || typeof result !== 'object') {
4297
- return result || null;
4298
- }
4299
- const sanitized = {};
4300
- ['success', 'errorMsg', 'errorCode', 'code', 'message', '__httpStatus', '__needLogin', '__csrfExpired'].forEach(function (key) {
4301
- if (Object.prototype.hasOwnProperty.call(result, key)) {
4302
- sanitized[key] = result[key];
4303
- }
4304
- });
4305
- return sanitized;
4306
- }
4307
-
4308
- function buildCreateFormPostCreateFailurePayload(context) {
4309
- const errorObject = context && context.error;
4310
- const payload = {
4311
- success: false,
4312
- appType: context.appType,
4313
- formTitle: context.formTitle,
4314
- formUuid: context.formUuid,
4315
- stage: context.stage || 'postCreate',
4316
- error: errorObject && errorObject.message ? errorObject.message : String(errorObject || 'request failed'),
4317
- errorCode: errorObject && errorObject.code ? errorObject.code : (context.errorCode || 'CREATE_FORM_POST_CREATE_FAILED'),
4318
- retryAdvice: t('create_form.create_post_failure_retry_advice', context.appType, context.formTitle),
4319
- };
4320
- if (context.fieldCount !== undefined) {
4321
- payload.fieldCount = context.fieldCount;
4322
- }
4323
- return payload;
4324
- }
4325
-
4326
- function emitCreateFormPostCreateFailure(context) {
4327
- const errorObject = context && context.error;
4328
- if (errorObject && errorObject.__openyidaPostCreateFailureEmitted) {
4329
- return;
4330
- }
4331
- console.log(JSON.stringify(buildCreateFormPostCreateFailurePayload(context)));
4332
- if (errorObject && typeof errorObject === 'object') {
4333
- errorObject.__openyidaPostCreateFailureEmitted = true;
4334
- }
4335
- }
4336
-
4337
4060
  // ── 保存 Schema 并更新表单配置(create/update 共用)──
4338
4061
  //
4339
4062
  // 封装了 saveFormSchema + updateFormConfig 两步,以及各自的 302 自动重登录重试。
4340
4063
  // 返回 { saveResult, configResult }。
4341
4064
 
4342
- async function saveSchemaAndUpdateConfig(authRef, appType, formUuid, schema, version, stepOffset, failureContext) {
4065
+ async function saveSchemaAndUpdateConfig(authRef, appType, formUuid, schema, version, stepOffset) {
4343
4066
  const saveStep = stepOffset || 4;
4344
4067
  const configStep = saveStep + 1;
4345
4068
 
@@ -4369,20 +4092,12 @@ async function saveSchemaAndUpdateConfig(authRef, appType, formUuid, schema, ver
4369
4092
  if (saveResult && !saveResult.__needLogin) {
4370
4093
  hint(t('common.response_detail', JSON.stringify(saveResult, null, 2)));
4371
4094
  }
4372
- const saveError = createCreateFormError(saveErrorMsg, 'CREATE_FORM_SAVE_SCHEMA_FAILED', {
4095
+ console.log(JSON.stringify({ success: false, formUuid: formUuid, error: saveErrorMsg }));
4096
+ throwCreateFormError(saveErrorMsg, 'CREATE_FORM_SAVE_SCHEMA_FAILED', {
4373
4097
  appType,
4374
4098
  formUuid,
4375
- result: sanitizeFailureResult(saveResult),
4099
+ result: saveResult,
4376
4100
  });
4377
- if (failureContext) {
4378
- emitCreateFormPostCreateFailure(Object.assign({}, failureContext, {
4379
- stage: 'saveFormSchema',
4380
- error: saveError,
4381
- }));
4382
- } else {
4383
- console.log(JSON.stringify({ success: false, formUuid: formUuid, error: saveErrorMsg }));
4384
- }
4385
- throw saveError;
4386
4101
  }
4387
4102
 
4388
4103
  success(t('create_form.schema_saved'));
@@ -4412,7 +4127,6 @@ async function mainCreate(parsedArgs, authRef) {
4412
4127
 
4413
4128
  step(2, t('create_form.step_read_fields', 2));
4414
4129
  const { fields, columns, validations } = readFieldsDefinition(fieldsJsonOrFile);
4415
- validateFormFieldDefinitions(fields);
4416
4130
  const fieldCount = countDataFieldDefinitions(fields);
4417
4131
  success(t('create_form.fields_loaded', fieldCount));
4418
4132
  label('Columns:', String(columns));
@@ -4444,62 +4158,30 @@ async function mainCreate(parsedArgs, authRef) {
4444
4158
 
4445
4159
  const formUuid = createResult.content.formUuid || createResult.content;
4446
4160
  success(t('create_form.blank_created', formUuid));
4447
- let configResult;
4448
- let postCreateStage = 'getFormSchema';
4449
- try {
4450
- const shellSchemaResult = await requestWithAutoLogin(function (auth) {
4451
- return sendGetRequest(
4452
- auth.baseUrl,
4453
- buildApiPath(appType, 'getFormSchema', { prefix: '_view', namespace: 'alibaba' }),
4454
- { formUuid: formUuid, schemaVersion: 'V5' }
4455
- );
4456
- }, authRef);
4457
- if (!shellSchemaResult || shellSchemaResult.success === false || shellSchemaResult.__needLogin || shellSchemaResult.__csrfExpired) {
4458
- const schemaErrorMsg = shellSchemaResult
4459
- ? shellSchemaResult.errorMsg || shellSchemaResult.message || t('common.unknown_error')
4460
- : t('common.request_failed');
4461
- throwCreateFormError(schemaErrorMsg, 'CREATE_FORM_GET_SCHEMA_FAILED', {
4462
- appType,
4463
- formUuid,
4464
- result: sanitizeFailureResult(shellSchemaResult),
4465
- });
4466
- }
4467
- const serverRevision = extractSchemaServerRevision(shellSchemaResult);
4161
+ const shellSchemaResult = await requestWithAutoLogin(function (auth) {
4162
+ return sendGetRequest(
4163
+ auth.baseUrl,
4164
+ buildApiPath(appType, 'getFormSchema', { prefix: '_view', namespace: 'alibaba' }),
4165
+ { formUuid: formUuid, schemaVersion: 'V5' }
4166
+ );
4167
+ }, authRef);
4168
+ const serverRevision = extractSchemaServerRevision(shellSchemaResult);
4468
4169
 
4469
- // Step 4 & 5: 生成 Schema 并保存,然后更新表单配置
4470
- const corpId = resolveCorpId(authRef.authData);
4471
- if (!corpId) {
4472
- warn(t('create_form.no_corp_id_warning'));
4473
- } else {
4474
- info(t('create_form.corp_id_ok', corpId));
4475
- }
4170
+ // Step 4 & 5: 生成 Schema 并保存,然后更新表单配置
4171
+ const corpId = resolveCorpId(authRef.authData);
4172
+ if (!corpId) {
4173
+ warn(t('create_form.no_corp_id_warning'));
4174
+ } else {
4175
+ info(t('create_form.corp_id_ok', corpId));
4176
+ }
4476
4177
 
4477
- postCreateStage = 'buildFormSchema';
4478
- const schema = buildFormSchema(formTitle, fields, formUuid, corpId, appType, layout, theme, labelAlign);
4479
- const createValidationRules = collectSmartValidationRulesFromFields(fields).concat(validations || []);
4480
- if (createValidationRules.length > 0) {
4481
- const appliedValidations = applySmartValidations(schema, createValidationRules);
4482
- info('已为创建表单写入 ' + appliedValidations.appliedRules.length + ' 条字段校验');
4483
- }
4484
- postCreateStage = 'saveSchemaAndUpdateConfig';
4485
- const saveAndConfigResult = await saveSchemaAndUpdateConfig(authRef, appType, formUuid, schema, serverRevision, 4, {
4486
- appType,
4487
- formTitle,
4488
- formUuid,
4489
- fieldCount,
4490
- });
4491
- configResult = saveAndConfigResult.configResult;
4492
- } catch (err) {
4493
- emitCreateFormPostCreateFailure({
4494
- appType,
4495
- formTitle,
4496
- formUuid,
4497
- fieldCount,
4498
- stage: postCreateStage,
4499
- error: err,
4500
- });
4501
- throw err;
4178
+ const schema = buildFormSchema(formTitle, fields, formUuid, corpId, appType, layout, theme, labelAlign);
4179
+ const createValidationRules = collectSmartValidationRulesFromFields(fields).concat(validations || []);
4180
+ if (createValidationRules.length > 0) {
4181
+ const appliedValidations = applySmartValidations(schema, createValidationRules);
4182
+ info('已为创建表单写入 ' + appliedValidations.appliedRules.length + ' 条字段校验');
4502
4183
  }
4184
+ const { configResult } = await saveSchemaAndUpdateConfig(authRef, appType, formUuid, schema, serverRevision, 4);
4503
4185
 
4504
4186
  // 输出结果
4505
4187
  const formUrl = authRef.baseUrl + '/' + appType + '/workbench/' + formUuid;
@@ -4521,25 +4203,11 @@ async function mainCreate(parsedArgs, authRef) {
4521
4203
  ['URL', formUrl],
4522
4204
  ]);
4523
4205
  hint(t('create_form.schema_ok_config_failed'));
4524
- const configError = createCreateFormError(configErrorMsg, 'CREATE_FORM_UPDATE_CONFIG_FAILED', {
4525
- appType,
4526
- formUuid,
4527
- result: sanitizeFailureResult(configResult),
4528
- });
4529
- console.log(JSON.stringify(Object.assign(
4530
- buildCreateFormPostCreateFailurePayload({
4531
- appType,
4532
- formTitle,
4533
- formUuid,
4534
- fieldCount,
4535
- stage: 'updateFormConfig',
4536
- error: configError,
4537
- }),
4538
- {
4539
- url: formUrl,
4540
- schemaSaved: true,
4541
- configWarning: configErrorMsg,
4542
- }
4206
+ console.log(JSON.stringify(withBrowserHandoff(
4207
+ { success: true, formUuid, formTitle, appType, fieldCount, url: formUrl, configWarning: configErrorMsg },
4208
+ formUrl,
4209
+ { stage: 'create_form_success', title: formTitle },
4210
+ parsedArgs.browserOpenMode
4543
4211
  )));
4544
4212
  }
4545
4213
  }
@@ -4560,7 +4228,6 @@ async function createFormForLegacyProcess(context, input) {
4560
4228
 
4561
4229
  const { appType, formTitle, fieldsJsonOrFile, layout, theme, labelAlign } = parsedArgs;
4562
4230
  const { fields, validations } = readFieldsDefinition(fieldsJsonOrFile);
4563
- validateFormFieldDefinitions(fields);
4564
4231
  const fieldCount = countDataFieldDefinitions(fields);
4565
4232
  const createResult = await requestWithAutoLogin(function (auth) {
4566
4233
  return sendPostRequest(
@@ -5526,8 +5193,6 @@ module.exports = {
5526
5193
  buildFormNodeComponent,
5527
5194
  countDataFieldDefinitions,
5528
5195
  collectComponentNames,
5529
- normalizeFormDefinitionType,
5530
- validateFormFieldDefinitions,
5531
5196
  ensureDividerThemeAction,
5532
5197
  applyChangesToSchema,
5533
5198
  },
@@ -514,40 +514,6 @@ function getCanvasDistPath(outputPath) {
514
514
  return path.posix.join(distDir, distName);
515
515
  }
516
516
 
517
- function isOpenYidaProjectCwd(cwd) {
518
- const currentDir = cwd || process.cwd();
519
- return path.basename(currentDir) === 'project' && (
520
- fs.existsSync(path.join(currentDir, 'config.json')) ||
521
- fs.existsSync(path.join(currentDir, 'pages'))
522
- );
523
- }
524
-
525
- function normalizeOutputPathForProjectCwd(output, options = {}) {
526
- const cwd = options.cwd || process.cwd();
527
- const rawOutput = String(output || '');
528
- if (!rawOutput || path.isAbsolute(rawOutput)) {
529
- return {
530
- outputPath: path.resolve(cwd, rawOutput),
531
- strippedProjectPrefix: false,
532
- requestedOutput: rawOutput,
533
- normalizedOutput: rawOutput,
534
- };
535
- }
536
-
537
- const slashOutput = rawOutput.replace(/\\/g, '/').replace(/^\.\//, '');
538
- const shouldStrip = isOpenYidaProjectCwd(cwd) && (
539
- slashOutput.startsWith('project/pages/') ||
540
- slashOutput.startsWith('project/.cache/')
541
- );
542
- const normalizedOutput = shouldStrip ? slashOutput.slice('project/'.length) : rawOutput;
543
- return {
544
- outputPath: path.resolve(cwd, normalizedOutput),
545
- strippedProjectPrefix: shouldStrip,
546
- requestedOutput: rawOutput,
547
- normalizedOutput,
548
- };
549
- }
550
-
551
517
  async function run(args) {
552
518
  const options = parseArgs(args || []);
553
519
  const spec = loadSpec(options.spec);
@@ -567,10 +533,7 @@ async function run(args) {
567
533
  error(t('generate_page.template_not_found', templateFile));
568
534
  }
569
535
 
570
- const outputResolution = normalizeOutputPathForProjectCwd(
571
- options.output || spec.output || (mode === 'canvas' ? templateConfig.defaultCanvasOutput : templateConfig.defaultNativeOutput)
572
- );
573
- const outputPath = outputResolution.outputPath;
536
+ const outputPath = path.resolve(options.output || spec.output || (mode === 'canvas' ? templateConfig.defaultCanvasOutput : templateConfig.defaultNativeOutput));
574
537
  const manifestPath = getManifestPath(outputPath);
575
538
  const templateSource = fs.readFileSync(templateFile, 'utf-8');
576
539
  const ir = normalizePageSpec(spec, {
@@ -598,9 +561,6 @@ async function run(args) {
598
561
  fs.writeFileSync(outputPath, outputSource, 'utf-8');
599
562
  fs.writeFileSync(manifestPath, `${JSON.stringify(ir, null, 2)}\n`, 'utf-8');
600
563
 
601
- if (outputResolution.strippedProjectPrefix) {
602
- warn(t('generate_page.output_project_prefix_stripped', outputResolution.requestedOutput, outputResolution.normalizedOutput));
603
- }
604
564
  success(t('generate_page.done', outputPath));
605
565
  hint(t('generate_page.hint'));
606
566
  reportMaterialStatus(materialPrecheck);
@@ -681,7 +641,6 @@ module.exports = {
681
641
  escapeJsStringValue,
682
642
  getManifestPath,
683
643
  getCanvasDistPath,
684
- normalizeOutputPathForProjectCwd,
685
644
  inferMode,
686
645
  inferTemplateName,
687
646
  };
@@ -509,9 +509,6 @@ const SUPPORTED_FIELD_TYPES = Object.freeze([
509
509
  ]);
510
510
 
511
511
  function normalizeFieldType(fieldType) {
512
- if (fieldType === undefined || fieldType === null || fieldType === '') {
513
- return '';
514
- }
515
512
  return FIELD_TYPE_ALIAS[fieldType] || fieldType;
516
513
  }
517
514
 
@@ -523,57 +520,6 @@ function isOptionFieldType(fieldType) {
523
520
  return OPTION_FIELD_TYPES.indexOf(normalizeFieldType(fieldType)) !== -1;
524
521
  }
525
522
 
526
- function readFieldDefinitionType(field) {
527
- if (!field || typeof field !== 'object' || Array.isArray(field)) {
528
- return '';
529
- }
530
- if (field.type !== undefined && field.type !== null && field.type !== '') {
531
- return String(field.type).trim();
532
- }
533
- if (field.componentType !== undefined && field.componentType !== null && field.componentType !== '') {
534
- return String(field.componentType).trim();
535
- }
536
- if (field.componentName !== undefined && field.componentName !== null && field.componentName !== '') {
537
- return String(field.componentName).trim();
538
- }
539
- return '';
540
- }
541
-
542
- function assertSupportedFieldDefinition(field, details) {
543
- if (!field || typeof field !== 'object' || Array.isArray(field)) {
544
- throw createFormCompilerError(
545
- '字段定义必须是对象',
546
- 'FORM_COMPILER_INVALID_DEFINITION',
547
- details
548
- );
549
- }
550
- const rawType = readFieldDefinitionType(field);
551
- const componentName = normalizeFieldType(rawType);
552
- if (!componentName) {
553
- throw createFormCompilerError(
554
- '字段定义缺少 type/componentType/componentName',
555
- 'FORM_COMPILER_FIELD_TYPE_MISSING',
556
- Object.assign({
557
- label: field.label,
558
- title: field.title,
559
- }, details)
560
- );
561
- }
562
- if (!isSupportedFieldType(componentName)) {
563
- throw createFormCompilerError(
564
- '不支持的字段类型: ' + componentName,
565
- 'FORM_COMPILER_UNSUPPORTED_FIELD_TYPE',
566
- Object.assign({
567
- label: field.label,
568
- title: field.title,
569
- type: rawType,
570
- componentName,
571
- }, details)
572
- );
573
- }
574
- return componentName;
575
- }
576
-
577
523
  const COMPONENT_ALIAS_META = Symbol('openyida.componentAlias');
578
524
 
579
525
  function normalizeComponentAlias(field) {
@@ -598,9 +544,7 @@ function normalizeComponentAlias(field) {
598
544
 
599
545
  function buildFieldComponent(field, options) {
600
546
  const compilerOptions = createCompilerOptions(options);
601
- const componentName = assertSupportedFieldDefinition(field, {
602
- semanticPath: compilerOptions.semanticPath,
603
- });
547
+ const componentName = normalizeFieldType(field.type);
604
548
  const semanticKey = normalizeSemanticKey(field);
605
549
  if (semanticKey && compilerOptions.requireParentSemanticPath && !compilerOptions.semanticPath) {
606
550
  throw createFormCompilerError(
@@ -1195,16 +1139,10 @@ function buildFieldComponent(field, options) {
1195
1139
  function collectComponentNames(fields) {
1196
1140
  const names = new Set(['Page', 'RootHeader', 'RootContent', 'RootFooter', 'FooterYida', 'FormContainer']);
1197
1141
  fields.forEach(function (field) {
1198
- const componentName = normalizeFieldType(readFieldDefinitionType(field));
1199
- if (componentName) {
1200
- names.add(componentName);
1201
- }
1202
- if (componentName === 'TableField' && field.children) {
1142
+ names.add(field.type);
1143
+ if (field.type === 'TableField' && field.children) {
1203
1144
  field.children.forEach(function (child) {
1204
- const childComponentName = normalizeFieldType(readFieldDefinitionType(child));
1205
- if (childComponentName) {
1206
- names.add(childComponentName);
1207
- }
1145
+ names.add(child.type);
1208
1146
  });
1209
1147
  }
1210
1148
  });
@@ -721,7 +721,6 @@ Examples:
721
721
  config_failed: ' ⚠️ Config update failed: {0}',
722
722
  schema_ok_config_failed: ' Schema saved, but config update failed',
723
723
  schema_saved_config_failed: ' Schema saved, but config update failed',
724
- create_post_failure_retry_advice: 'Do not repeat create directly. First run openyida list-forms {0} --keyword "{1}" to check for an existing same-title form; if this run already created a blank/existing form, prefer create-form update or a future --resume-form-uuid flow.',
725
724
  error: '\n❌ Error: {0}',
726
725
  usage_create: 'Usage: openyida create-form create <appType> <formTitle> <fieldsJsonFile>',
727
726
  example_create: 'Example: openyida create-form create "APP_XXX" "Employee Info" .cache/openyida/forms/employee-fields.json',
@@ -1074,7 +1073,6 @@ Examples:
1074
1073
  unknown_template: 'Unknown page template: {0}',
1075
1074
  available_templates: 'Available templates: {0}',
1076
1075
  template_not_found: 'Template file not found: {0}',
1077
- output_project_prefix_stripped: 'Current directory is already an OpenYida project; output path was adjusted from {0} to {1} to avoid project/project.',
1078
1076
  done: 'Page generated: {0}',
1079
1077
  hint: 'Next run openyida compile <file>, or pass --compile to compile immediately.',
1080
1078
  success: 'Page generation complete',
@@ -693,7 +693,6 @@ openyida - 宜搭命令行工具
693
693
  config_failed: ' ⚠️ 配置更新失败: {0}',
694
694
  schema_ok_config_failed: ' Schema 已保存,但配置更新失败',
695
695
  schema_saved_config_failed: ' Schema 已保存,但配置更新失败',
696
- create_post_failure_retry_advice: '不要直接重复 create。先运行 openyida list-forms {0} --keyword "{1}" 确认同名表单;若是本轮创建的空白/已有表单,优先使用 create-form update 或后续 --resume-form-uuid 复用。',
697
696
  error: '\n❌ 错误: {0}',
698
697
  usage_create: '用法: openyida create-form create <appType> <formTitle> <fieldsJsonFile>',
699
698
  example_create: '示例:openyida create-form create "APP_XXX" "员工信息登记" .cache/openyida/forms/employee-fields.json',
@@ -1068,7 +1067,6 @@ openyida - 宜搭命令行工具
1068
1067
  unknown_template: '未知页面模板:{0}',
1069
1068
  available_templates: '可用模板:{0}',
1070
1069
  template_not_found: '模板文件不存在:{0}',
1071
- output_project_prefix_stripped: '检测到当前目录已是 OpenYida project,已将输出路径从 {0} 调整为 {1},避免生成 project/project。',
1072
1070
  done: '页面已生成:{0}',
1073
1071
  hint: '建议继续运行 openyida compile <file> 或使用 --compile 直接编译校验。',
1074
1072
  success: '页面生成完成',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openyida",
3
- "version": "2026.7.23-1",
3
+ "version": "2026.7.23",
4
4
  "description": "OpenYida CLI - 宜搭低代码 AI 开发工具(安装即用,零配置)",
5
5
  "bin": {
6
6
  "openyida": "bin/yida.js",
@@ -231,7 +231,6 @@ schema-managed create/update 必须等待用户对当前 `planId` 显式批准
231
231
  4. **页面源码修改必须发布闭环**:只要本轮 Write/Edit/Create 了页面源码 `project/pages/src/*.{canvas.jsx,canvas.tsx,oyd.jsx,jsx,tsx}`(含完整搭建、补齐、已有页面 update path、单点优化),final 前必须看到成功的 `openyida publish <source> <appType> <displayPageFormUuid>` 命令结果;本地文件编辑、diff、本地校验或编译只证明源码可发布,不等于远端页面已更新。若没有 publish 成功证据,final 只能说“源码已修改,尚未发布”,禁止说“页面已更新 / 已重新发布 / 已上线”。
232
232
  5. **命令输入文件禁止 shell 写入**:当 OpenYida 命令需要 JSON/YAML/CSV/config/script 文件参数时,先使用当前 agent 运行时提供的结构化文件写入工具(如 create_file / Write / file edit tool)创建文件,再把路径传给命令;禁止用 shell heredoc、`cat`/`echo`/`printf`/`tee` 加输出重定向,或把命令 stdout 重定向成业务文件。
233
233
  6. **读文件少用 Bash 噪声**:读取或定位 workspace 文件优先用宿主的 Read / Glob / Grep;OpenYida CLI 已返回成功 JSON、URL 或 `formUuid/appType` 时,不要再用 Bash `cat`/`ls` 做无意义复核。
234
- 7. **OpenYida CLI 不吞诊断**:不要给 `openyida` 命令加 `2>/dev/null`;失败时保留 stdout/stderr(必要时用 `2>&1` 合并诊断)。遇到 DENIED 或同一命令重复失败,先换策略、改输入或重做只读确认,不要盲目微调后重跑。
235
234
 
236
235
  ### 重要规则(IMPORTANT,影响质量/性能/可维护性)
237
236
 
@@ -279,7 +279,6 @@ UI 不是独立替代主流程的步骤,而是按模式插入到页面生成
279
279
  ## 错误处理
280
280
 
281
281
  - 不编造 `appType`、`formUuid`、`fieldId`、`reportId`。
282
- - OpenYida CLI 不要加 `2>/dev/null`;失败时保留 stdout/stderr 诊断。遇到 DENIED 或同一命令重复失败,先换策略、修改输入文件/参数/登录态/组织或重新只读取证,再重试。
283
282
  - 同一命令失败后,必须改变登录态、组织、参数、输入文件或字段 ID 后才能重试;禁止无修改连续重试。
284
283
  - corpId 与目标组织不一致时先停下,让用户选择重新登录或在当前组织继续。
285
284
  - 已有目标 app/page/form/process 时默认复用;只有用户明确要求新建另一个同类资源,或目标缺失且本次意图允许创建时,才加载 create 类子技能。
@@ -24,7 +24,6 @@ description: 表单页面创建与更新,支持 19 种业务字段和 Divider
24
24
  - 不要在 update / patch / rule / validation / bind-datasource 模式中使用猜测的 fieldId,必须先用 `yida-get-schema` 获取
25
25
  - 不要用此命令操作数据记录(增删改查),应使用 `yida-data-management`
26
26
  - 不要用 shell heredoc、`cat`/`echo`/`printf`/`tee` 或重定向生成字段、变更、补丁、规则、数据源 JSON 文件
27
- - OpenYida CLI 不要加 `2>/dev/null`;失败时保留 stdout/stderr 诊断,遇到 DENIED 或重复失败必须换策略
28
27
  - 已有目标表单且用户是改字段/联动/属性时,不要创建新表单;必须走 update/patch/rule/bind-datasource。
29
28
  - 不要用 `GroupContainer` / `PageSection` 承载普通业务分组;普通分组必须优先用 `Divider`
30
29
 
@@ -121,15 +120,6 @@ openyida create-form create <appType> <formTitle> <fieldsJsonOrFile> [--layout d
121
120
  {"success":true,"formUuid":"FORM-XXX","formTitle":"用户信息表","appType":"APP_xxx","fieldCount":4,"url":"{base_url}/APP_xxx/workbench/FORM-XXX"}
122
121
  ```
123
122
 
124
- ### create 失败恢复决策树
125
-
126
- create 命令失败后,不要立刻重复同一条 create:
127
-
128
- 1. 先确认字段 JSON 文件存在,且内容是结构化写入后的最终字段数组/对象,不是半截 JSON、update changes 或 shell 拼接残留。
129
- 2. 运行 `openyida list-forms <appType> --keyword "<表单名>"` 查同名表单;若本轮刚创建过空白表单或已有同名目标表单,优先走 `create-form update` / `patch` / 后续显式 resume 能力复用,不再 create。
130
- 3. 只有确认远端没有同名目标表单,并且已经修改输入文件、参数、登录态或组织后,才重试 create。
131
- 4. 同一 create 命令最多重试 2 次;仍失败时停止并带上完整 stdout/stderr、字段文件路径、appType、表单名和已发现的 formUuid 给用户。
132
-
133
123
  ## update 模式
134
124
 
135
125
  已有 `formUuid` / 表单 URL / bound form 时优先使用本模式;修改字段前必须用 `openyida get-schema` 确认字段 ID 和当前结构。