best-lowcode-runtime 0.1.0 → 0.1.1

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 CHANGED
@@ -46,6 +46,25 @@ export function CustomerPage() {
46
46
 
47
47
  ## 开发期校验入口
48
48
 
49
+ ### 通用表单和数据能力
50
+
51
+ Schema 支持 `remoteSelect`,通过 Registry Service 提供防抖搜索数据:
52
+
53
+ ```ts
54
+ {
55
+ field: 'owner',
56
+ label: '负责人',
57
+ component: 'remoteSelect',
58
+ remoteService: 'user.search',
59
+ searchField: 'keyword',
60
+ labelField: 'name',
61
+ valueField: 'id'
62
+ }
63
+ ```
64
+
65
+ 字段可声明 `required`、`type`、`min`、`max`、`minLength`、`maxLength`、`pattern` 等通用规则。
66
+ `createBestCrudAdapter` 和 `normalizeBestValues` 可用于统一清理空字符串、转换创建/更新 payload,提交期间 Runtime 会自动显示 loading 并防止重复提交。
67
+
49
68
  CLI 或工具链可从 `best-lowcode-runtime/dev` 导入不依赖页面渲染的能力:
50
69
 
51
70
  ```ts
package/dist/dev.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export { getBuiltinCapabilities, validateUnknownCrudPageSchema } from './lowcode/dev';
1
+ export { getBuiltinCapabilities, getBuiltinCapabilityDefinitions, validateUnknownCrudPageSchema } from './lowcode/dev';
2
2
  //# sourceMappingURL=dev.d.ts.map
package/dist/dev.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"dev.d.ts","sourceRoot":"","sources":["../src/dev.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,6BAA6B,EAAE,MAAM,eAAe,CAAA"}
1
+ {"version":3,"file":"dev.d.ts","sourceRoot":"","sources":["../src/dev.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,sBAAsB,EACtB,+BAA+B,EAC/B,6BAA6B,EAC9B,MAAM,eAAe,CAAA"}
package/dist/dev.js CHANGED
@@ -7,6 +7,7 @@ var fieldComponents = /* @__PURE__ */ new Set([
7
7
  "input",
8
8
  "number",
9
9
  "select",
10
+ "remoteSelect",
10
11
  "date",
11
12
  "dateRange",
12
13
  "textarea",
@@ -50,6 +51,10 @@ function validateFields(fields, path, registry, diagnostics) {
50
51
  if (field.dict && registry && !registry.dictionaries[field.dict]) {
51
52
  push(diagnostics, fieldPath, "registry.dictionary", `\u672A\u6CE8\u518C\u5B57\u5178\uFF1A${field.dict}`);
52
53
  }
54
+ if (field.component === "remoteSelect" && !field.remoteService)
55
+ push(diagnostics, fieldPath, "field.remoteService", "remoteSelect \u5FC5\u987B\u6307\u5B9A remoteService");
56
+ if (field.remoteService && registry && !registry.services[field.remoteService])
57
+ push(diagnostics, fieldPath, "registry.service", `\u672A\u6CE8\u518C\u670D\u52A1\uFF1A${field.remoteService}`);
53
58
  if (field.component === "slot" && !field.slot)
54
59
  push(diagnostics, fieldPath, "field.slot", "slot \u7EC4\u4EF6\u5FC5\u987B\u6307\u5B9A slot key");
55
60
  if (field.component === "repeatable" && !field.itemFields?.length)
@@ -180,6 +185,26 @@ function validateCrudPageSchema(schema, registry) {
180
185
  return { valid: diagnostics.length === 0, diagnostics };
181
186
  }
182
187
 
188
+ // src/lowcode/capabilities.ts
189
+ var builtinCapabilityDefinitions = [
190
+ { id: "builtin.field.input", kind: "field", description: "\u5355\u884C\u6587\u672C\u8F93\u5165", status: "supported", schema: { component: "input" } },
191
+ { id: "builtin.field.number", kind: "field", description: "\u6570\u5B57\u8F93\u5165", status: "supported", schema: { component: "number" } },
192
+ { id: "builtin.field.select", kind: "field", description: "\u9759\u6001\u9009\u9879\u4E0B\u62C9\u9009\u62E9", status: "supported", schema: { component: "select" } },
193
+ { id: "builtin.field.remoteSelect", kind: "field", description: "\u5E26\u9632\u6296\u548C\u8BF7\u6C42\u53D6\u6D88\u7684\u8FDC\u7A0B\u641C\u7D22\u4E0B\u62C9", status: "supported", schema: { component: "remoteSelect", required: ["remoteService"] }, registry: { required: ["services"] }, examples: ["\u4EBA\u5458\u9009\u62E9", "\u5BA2\u6237\u9009\u62E9"] },
194
+ { id: "builtin.field.repeatable", kind: "field", description: "\u652F\u6301\u52A8\u6001\u589E\u5220\u7684\u91CD\u590D\u5BF9\u8C61\u5B57\u6BB5", status: "supported", schema: { component: "repeatable", required: ["itemFields"] }, examples: ["\u9636\u68AF\u4EF7\u683C", "\u89C4\u5219\u5217\u8868"] },
195
+ { id: "builtin.field.slot", kind: "field", description: "\u6CE8\u518C\u4E1A\u52A1\u81EA\u5B9A\u4E49\u5B57\u6BB5\u6E32\u67D3\u5668", status: "supported", schema: { component: "slot", required: ["slot"] }, registry: { required: ["slots"] } },
196
+ { id: "builtin.effect.openCreate", kind: "effect", description: "\u6253\u5F00\u65B0\u5EFA\u8868\u5355", status: "supported", schema: { effect: "openCreate" } },
197
+ { id: "builtin.effect.openEdit", kind: "effect", description: "\u6253\u5F00\u7F16\u8F91\u8868\u5355", status: "supported", schema: { effect: "openEdit" } },
198
+ { id: "builtin.effect.openDetail", kind: "effect", description: "\u6253\u5F00\u8BE6\u60C5\u62BD\u5C49", status: "supported", schema: { effect: "openDetail" } },
199
+ { id: "builtin.effect.runAction", kind: "effect", description: "\u8C03\u7528 Registry Action \u5E76\u5237\u65B0\u5217\u8868", status: "supported", schema: { effect: "runAction" }, registry: { required: ["actions"] } },
200
+ { id: "builtin.format.date", kind: "format", description: "\u65E5\u671F\u683C\u5F0F\u5316", status: "supported", schema: { format: "date" } },
201
+ { id: "builtin.format.datetime", kind: "format", description: "\u65E5\u671F\u65F6\u95F4\u683C\u5F0F\u5316", status: "supported", schema: { format: "datetime" } },
202
+ { id: "builtin.format.money", kind: "format", description: "\u91D1\u989D\u683C\u5F0F\u5316", status: "supported", schema: { format: "money" } }
203
+ ];
204
+ function getBuiltinCapabilities() {
205
+ return builtinCapabilityDefinitions.map((item) => item.id);
206
+ }
207
+
183
208
  // src/lowcode/dev.ts
184
209
  var builtInCapabilities = [
185
210
  "builtin.effect.openCreate",
@@ -195,6 +220,7 @@ var builtInCapabilities = [
195
220
  "builtin.field.input",
196
221
  "builtin.field.number",
197
222
  "builtin.field.select",
223
+ "builtin.field.remoteSelect",
198
224
  "builtin.field.date",
199
225
  "builtin.field.dateRange",
200
226
  "builtin.field.textarea",
@@ -259,11 +285,15 @@ function validateUnknownCrudPageSchema(candidate) {
259
285
  }
260
286
  return validateCrudPageSchema(toRuntimeSchema(candidate));
261
287
  }
262
- function getBuiltinCapabilities() {
263
- return [...builtInCapabilities];
288
+ function getBuiltinCapabilities2() {
289
+ return [.../* @__PURE__ */ new Set([...builtInCapabilities, ...getBuiltinCapabilities()])];
290
+ }
291
+ function getBuiltinCapabilityDefinitions() {
292
+ return builtinCapabilityDefinitions;
264
293
  }
265
294
  export {
266
- getBuiltinCapabilities,
295
+ getBuiltinCapabilities2 as getBuiltinCapabilities,
296
+ getBuiltinCapabilityDefinitions,
267
297
  validateUnknownCrudPageSchema
268
298
  };
269
299
  //# sourceMappingURL=dev.js.map
package/dist/dev.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../src/lowcode/schema.ts", "../src/lowcode/validate.ts", "../src/lowcode/dev.ts"],
4
- "sourcesContent": ["import type { BestFieldComponent } from '../ui/types'\n\nexport const CRUD_SCHEMA_ID = 'https://best.dev/schema/crud/v1' as const\nexport const CRUD_SCHEMA_VERSION = 1 as const\n\nexport type Condition =\n | { operator: 'equals'; field: string; value: string | number | boolean | null }\n | { operator: 'notEmpty'; field: string }\n | { operator: 'modeEquals'; value: FormMode }\n | { operator: 'and' | 'or'; conditions: Condition[] }\n | { operator: 'not'; condition: Condition }\n\nexport type FormMode = 'create' | 'edit' | 'detail'\n\nexport type FieldSchema = {\n field: string\n label: string\n component: BestFieldComponent\n placeholder?: string\n dict?: string\n required?: boolean\n disabled?: boolean\n hidden?: boolean\n maxDate?: 'today'\n span?: number\n defaultValue?: string | number | boolean | null\n /** Application-specific form control registered in the BestProvider registry. */\n slot?: string\n visibleWhen?: Condition\n disabledWhen?: Condition\n /** Clears stale dependent values when this field becomes hidden. */\n clearWhenHidden?: boolean\n /** Repeated object fields, for rules such as tiered pricing. */\n itemFields?: Omit<FieldSchema, 'itemFields'>[]\n minItems?: number\n maxItems?: number\n}\n\nexport type TableColumnSchema = {\n field: string\n title: string\n dict?: string\n width?: number\n format?: 'date' | 'datetime' | 'money' | 'text'\n slot?: string\n}\n\nexport type DetailFieldSchema = {\n field: string\n label: string\n dict?: string\n span?: number\n slot?: string\n}\n\nexport type PageActionSchema = {\n id: string\n label: string\n effect: 'openCreate' | 'openDetail' | 'openEdit' | 'remove' | 'runAction' | 'slot'\n action?: string\n slot?: string\n access?: string\n confirm?: string\n}\n\nexport type CrudPageSchema = {\n $schema: typeof CRUD_SCHEMA_ID\n version: typeof CRUD_SCHEMA_VERSION\n id: string\n kind: 'crud'\n title: string\n dataSource: {\n list: string\n detail?: string\n create?: string\n update?: string\n remove?: string\n }\n search?: FieldSchema[]\n searchMode?: 'proTable' | 'bestSearch'\n form?: FieldSchema[]\n table: {\n rowKey: string | string[]\n columns: TableColumnSchema[]\n actions?: PageActionSchema[]\n scrollX?: number\n pageSize?: number\n }\n detail?: { fields: DetailFieldSchema[] }\n toolbar?: PageActionSchema[]\n meta?: {\n generatedBy?: string\n generatedAt?: string\n }\n}\n", "import type { BestRegistry } from '../runtime'\nimport {\n type Condition,\n CRUD_SCHEMA_ID,\n CRUD_SCHEMA_VERSION,\n type CrudPageSchema,\n type FieldSchema,\n type PageActionSchema\n} from './schema'\n\nexport type SchemaDiagnostic = {\n path: string\n code: string\n message: string\n}\n\nexport type SchemaValidationResult = {\n valid: boolean\n diagnostics: SchemaDiagnostic[]\n}\n\nconst fieldComponents = new Set([\n 'input',\n 'number',\n 'select',\n 'date',\n 'dateRange',\n 'textarea',\n 'slot',\n 'repeatable'\n])\nconst builtInEffects = new Set([\n 'openCreate',\n 'openDetail',\n 'openEdit',\n 'remove',\n 'runAction',\n 'slot'\n])\nconst columnFormats = new Set(['date', 'datetime', 'money', 'text'])\n\nfunction push(diagnostics: SchemaDiagnostic[], path: string, code: string, message: string) {\n diagnostics.push({ path, code, message })\n}\n\nfunction validateCondition(condition: Condition, path: string, diagnostics: SchemaDiagnostic[]) {\n if (\n (condition.operator === 'and' || condition.operator === 'or') &&\n condition.conditions.length === 0\n ) {\n push(diagnostics, path, 'condition.empty', '\u7EC4\u5408\u6761\u4EF6\u81F3\u5C11\u9700\u8981\u4E00\u4E2A\u5B50\u6761\u4EF6')\n }\n if (condition.operator === 'and' || condition.operator === 'or') {\n condition.conditions.forEach((item, index) => {\n validateCondition(item, `${path}/conditions/${index}`, diagnostics)\n })\n }\n if (condition.operator === 'not')\n validateCondition(condition.condition, `${path}/condition`, diagnostics)\n}\n\nfunction validateFields(\n fields: FieldSchema[] | undefined,\n path: string,\n registry: BestRegistry | undefined,\n diagnostics: SchemaDiagnostic[]\n) {\n const seen = new Set<string>()\n fields?.forEach((field, index) => {\n const fieldPath = `${path}/${index}`\n if (!field.field) push(diagnostics, fieldPath, 'field.missing', '\u5B57\u6BB5\u540D\u4E0D\u80FD\u4E3A\u7A7A')\n if (seen.has(field.field))\n push(diagnostics, fieldPath, 'field.duplicate', `\u5B57\u6BB5\u91CD\u590D\uFF1A${field.field}`)\n seen.add(field.field)\n if (!fieldComponents.has(field.component))\n push(diagnostics, fieldPath, 'field.component', `\u4E0D\u652F\u6301\u7684\u7EC4\u4EF6\uFF1A${field.component}`)\n if (field.dict && registry && !registry.dictionaries[field.dict]) {\n push(diagnostics, fieldPath, 'registry.dictionary', `\u672A\u6CE8\u518C\u5B57\u5178\uFF1A${field.dict}`)\n }\n if (field.component === 'slot' && !field.slot)\n push(diagnostics, fieldPath, 'field.slot', 'slot \u7EC4\u4EF6\u5FC5\u987B\u6307\u5B9A slot key')\n if (field.component === 'repeatable' && !field.itemFields?.length)\n push(\n diagnostics,\n fieldPath,\n 'field.repeatable',\n 'repeatable \u7EC4\u4EF6\u81F3\u5C11\u9700\u8981\u4E00\u4E2A itemFields \u5B57\u6BB5'\n )\n if (\n field.minItems !== undefined &&\n field.maxItems !== undefined &&\n field.minItems > field.maxItems\n )\n push(diagnostics, fieldPath, 'field.repeatable.range', 'minItems \u4E0D\u80FD\u5927\u4E8E maxItems')\n if (field.slot && registry && !registry.slots[field.slot])\n push(diagnostics, fieldPath, 'registry.slot', `\u672A\u6CE8\u518C\u63D2\u69FD\uFF1A${field.slot}`)\n if (field.visibleWhen)\n validateCondition(field.visibleWhen, `${fieldPath}/visibleWhen`, diagnostics)\n if (field.disabledWhen)\n validateCondition(field.disabledWhen, `${fieldPath}/disabledWhen`, diagnostics)\n })\n}\n\nfunction validateActions(\n actions: PageActionSchema[] | undefined,\n path: string,\n registry: BestRegistry | undefined,\n hasRemoveService: boolean,\n diagnostics: SchemaDiagnostic[]\n) {\n actions?.forEach((action, index) => {\n const actionPath = `${path}/${index}`\n if (!action.id) push(diagnostics, actionPath, 'action.missing', '\u52A8\u4F5C id \u4E0D\u80FD\u4E3A\u7A7A')\n if (!builtInEffects.has(action.effect))\n push(diagnostics, actionPath, 'action.effect', `\u4E0D\u652F\u6301\u7684\u52A8\u4F5C\uFF1A${action.effect}`)\n if (action.effect === 'runAction' && !action.action)\n push(diagnostics, actionPath, 'action.key', 'runAction \u5FC5\u987B\u6307\u5B9A action key')\n if (action.effect === 'remove' && !hasRemoveService)\n push(diagnostics, actionPath, 'action.removeService', 'remove \u52A8\u4F5C\u5FC5\u987B\u914D\u7F6E dataSource.remove')\n if (action.effect === 'slot' && !action.slot)\n push(diagnostics, actionPath, 'action.slot', 'slot \u52A8\u4F5C\u5FC5\u987B\u6307\u5B9A slot key')\n if (action.action && registry && !registry.actions[action.action]) {\n push(diagnostics, actionPath, 'registry.action', `\u672A\u6CE8\u518C\u52A8\u4F5C\uFF1A${action.action}`)\n }\n if (action.slot && registry && !registry.slots[action.slot]) {\n push(diagnostics, actionPath, 'registry.slot', `\u672A\u6CE8\u518C\u63D2\u69FD\uFF1A${action.slot}`)\n }\n })\n}\n\nexport function validateCrudPageSchema(\n schema: CrudPageSchema,\n registry?: BestRegistry\n): SchemaValidationResult {\n const diagnostics: SchemaDiagnostic[] = []\n if (schema.$schema !== CRUD_SCHEMA_ID)\n push(diagnostics, '/$schema', 'schema.id', `\u4EC5\u652F\u6301 ${CRUD_SCHEMA_ID}`)\n if (schema.version !== CRUD_SCHEMA_VERSION)\n push(diagnostics, '/version', 'schema.version', `\u4EC5\u652F\u6301\u7248\u672C ${CRUD_SCHEMA_VERSION}`)\n if (!schema.id) push(diagnostics, '/id', 'page.id', '\u9875\u9762 id \u4E0D\u80FD\u4E3A\u7A7A')\n if (!schema.title) push(diagnostics, '/title', 'page.title', '\u9875\u9762\u6807\u9898\u4E0D\u80FD\u4E3A\u7A7A')\n if (!schema.dataSource?.list)\n push(diagnostics, '/dataSource/list', 'service.list', '\u5217\u8868\u670D\u52A1\u4E0D\u80FD\u4E3A\u7A7A')\n if (schema.dataSource?.list && registry && !registry.listServices[schema.dataSource.list]) {\n push(\n diagnostics,\n '/dataSource/list',\n 'registry.service',\n `\u672A\u6CE8\u518C\u670D\u52A1\uFF1A${schema.dataSource.list}`\n )\n }\n if (schema.dataSource?.detail && registry && !registry.services[schema.dataSource.detail]) {\n push(\n diagnostics,\n '/dataSource/detail',\n 'registry.service',\n `\u672A\u6CE8\u518C\u670D\u52A1\uFF1A${schema.dataSource.detail}`\n )\n }\n if (schema.dataSource?.remove && registry && !registry.services[schema.dataSource.remove]) {\n push(\n diagnostics,\n '/dataSource/remove',\n 'registry.service',\n `\u672A\u6CE8\u518C\u670D\u52A1\uFF1A${schema.dataSource.remove}`\n )\n }\n validateFields(schema.search, '/search', registry, diagnostics)\n validateFields(schema.form, '/form', registry, diagnostics)\n if (!schema.table?.rowKey) push(diagnostics, '/table/rowKey', 'table.rowKey', 'rowKey \u4E0D\u80FD\u4E3A\u7A7A')\n if (!schema.table?.columns?.length)\n push(diagnostics, '/table/columns', 'table.columns', '\u81F3\u5C11\u9700\u8981\u4E00\u5217')\n schema.table?.columns?.forEach((column, index) => {\n if (column.format && !columnFormats.has(column.format)) {\n push(\n diagnostics,\n `/table/columns/${index}/format`,\n 'column.format',\n `\u4E0D\u652F\u6301\u7684\u683C\u5F0F\uFF1A${column.format}`\n )\n }\n if (column.dict && registry && !registry.dictionaries[column.dict]) {\n push(\n diagnostics,\n `/table/columns/${index}/dict`,\n 'registry.dictionary',\n `\u672A\u6CE8\u518C\u5B57\u5178\uFF1A${column.dict}`\n )\n }\n if (column.slot && registry && !registry.slots[column.slot]) {\n push(\n diagnostics,\n `/table/columns/${index}/slot`,\n 'registry.slot',\n `\u672A\u6CE8\u518C\u63D2\u69FD\uFF1A${column.slot}`\n )\n }\n })\n schema.detail?.fields.forEach((field, index) => {\n if (field.slot && registry && !registry.slots[field.slot])\n push(\n diagnostics,\n `/detail/fields/${index}/slot`,\n 'registry.slot',\n `\u672A\u6CE8\u518C\u63D2\u69FD\uFF1A${field.slot}`\n )\n })\n validateActions(\n schema.table?.actions,\n '/table/actions',\n registry,\n Boolean(schema.dataSource?.remove),\n diagnostics\n )\n validateActions(\n schema.toolbar,\n '/toolbar',\n registry,\n Boolean(schema.dataSource?.remove),\n diagnostics\n )\n return { valid: diagnostics.length === 0, diagnostics }\n}\n\nexport function assertValidCrudPageSchema(schema: CrudPageSchema, registry?: BestRegistry) {\n const result = validateCrudPageSchema(schema, registry)\n if (!result.valid) {\n const message = result.diagnostics.map((item) => `${item.path}: ${item.message}`).join('\\n')\n throw new Error(`Schema \u6821\u9A8C\u5931\u8D25\uFF1A\\n${message}`)\n }\n}\n", "import type {\n CRUD_SCHEMA_ID,\n CRUD_SCHEMA_VERSION,\n CrudPageSchema,\n FieldSchema,\n PageActionSchema\n} from './schema'\nimport type { SchemaDiagnostic, SchemaValidationResult } from './validate'\nimport { validateCrudPageSchema } from './validate'\n\nconst builtInCapabilities = [\n 'builtin.effect.openCreate',\n 'builtin.effect.openDetail',\n 'builtin.effect.openEdit',\n 'builtin.effect.remove',\n 'builtin.effect.runAction',\n 'builtin.effect.slot',\n 'builtin.format.date',\n 'builtin.format.datetime',\n 'builtin.format.money',\n 'builtin.format.text',\n 'builtin.field.input',\n 'builtin.field.number',\n 'builtin.field.select',\n 'builtin.field.date',\n 'builtin.field.dateRange',\n 'builtin.field.textarea',\n 'builtin.field.slot',\n 'builtin.field.repeatable'\n] as const\n\ntype JsonRecord = Record<string, unknown>\n\nfunction isRecord(value: unknown): value is JsonRecord {\n return !!value && typeof value === 'object' && !Array.isArray(value)\n}\n\nfunction arrayOfRecords(value: unknown): JsonRecord[] | undefined {\n return Array.isArray(value) && value.every(isRecord) ? value : undefined\n}\n\nfunction diagnostic(path: string, code: string, message: string): SchemaDiagnostic {\n return { path, code, message }\n}\n\nfunction validateUnknownShape(candidate: unknown): SchemaDiagnostic[] {\n if (!isRecord(candidate)) return [diagnostic('', 'schema.type', 'Schema \u5FC5\u987B\u662F JSON \u5BF9\u8C61')]\n const diagnostics: SchemaDiagnostic[] = []\n if (!isRecord(candidate.dataSource))\n diagnostics.push(diagnostic('/dataSource', 'dataSource.type', 'dataSource \u5FC5\u987B\u662F\u5BF9\u8C61'))\n if (!isRecord(candidate.table))\n diagnostics.push(diagnostic('/table', 'table.type', 'table \u5FC5\u987B\u662F\u5BF9\u8C61'))\n for (const key of ['search', 'form'] as const) {\n if (candidate[key] !== undefined && !arrayOfRecords(candidate[key])) {\n diagnostics.push(diagnostic(`/${key}`, 'field.list', `${key} \u5FC5\u987B\u662F\u5BF9\u8C61\u6570\u7EC4`))\n }\n }\n if (isRecord(candidate.table)) {\n if (!arrayOfRecords(candidate.table.columns)) {\n diagnostics.push(diagnostic('/table/columns', 'column.list', 'columns \u5FC5\u987B\u662F\u5BF9\u8C61\u6570\u7EC4'))\n }\n if (candidate.table.actions !== undefined && !arrayOfRecords(candidate.table.actions)) {\n diagnostics.push(diagnostic('/table/actions', 'action.list', 'actions \u5FC5\u987B\u662F\u5BF9\u8C61\u6570\u7EC4'))\n }\n }\n if (candidate.toolbar !== undefined && !arrayOfRecords(candidate.toolbar)) {\n diagnostics.push(diagnostic('/toolbar', 'action.list', 'toolbar \u5FC5\u987B\u662F\u5BF9\u8C61\u6570\u7EC4'))\n }\n return diagnostics\n}\n\nfunction toRuntimeSchema(candidate: JsonRecord): CrudPageSchema {\n return {\n $schema: candidate.$schema as typeof CRUD_SCHEMA_ID,\n version: candidate.version as typeof CRUD_SCHEMA_VERSION,\n id: candidate.id as string,\n kind: candidate.kind as 'crud',\n title: candidate.title as string,\n dataSource: candidate.dataSource as CrudPageSchema['dataSource'],\n search: candidate.search as FieldSchema[] | undefined,\n searchMode: candidate.searchMode as CrudPageSchema['searchMode'],\n form: candidate.form as FieldSchema[] | undefined,\n table: candidate.table as CrudPageSchema['table'],\n detail: candidate.detail as CrudPageSchema['detail'],\n toolbar: candidate.toolbar as PageActionSchema[] | undefined,\n meta: candidate.meta as CrudPageSchema['meta']\n }\n}\n\n/**\n * Server-safe development entry. It accepts unknown JSON from CLI/MCP before delegating to the\n * runtime validator, so untrusted candidates cannot trigger assumptions in typed runtime code.\n */\nexport function validateUnknownCrudPageSchema(candidate: unknown): SchemaValidationResult {\n const shapeDiagnostics = validateUnknownShape(candidate)\n if (shapeDiagnostics.length || !isRecord(candidate)) {\n return { valid: false, diagnostics: shapeDiagnostics }\n }\n return validateCrudPageSchema(toRuntimeSchema(candidate))\n}\n\n/** Serializable capabilities supplied by the current runtime without application Manifest entries. */\nexport function getBuiltinCapabilities(): string[] {\n return [...builtInCapabilities]\n}\n"],
5
- "mappings": "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",
6
- "names": []
3
+ "sources": ["../src/lowcode/schema.ts", "../src/lowcode/validate.ts", "../src/lowcode/capabilities.ts", "../src/lowcode/dev.ts"],
4
+ "sourcesContent": ["import type { BestFieldComponent, BestFieldRule } from '../ui/types'\n\nexport const CRUD_SCHEMA_ID = 'https://best.dev/schema/crud/v1' as const\nexport const CRUD_SCHEMA_VERSION = 1 as const\n\nexport type Condition =\n | { operator: 'equals'; field: string; value: string | number | boolean | null }\n | { operator: 'notEmpty'; field: string }\n | { operator: 'modeEquals'; value: FormMode }\n | { operator: 'and' | 'or'; conditions: Condition[] }\n | { operator: 'not'; condition: Condition }\n\nexport type FormMode = 'create' | 'edit' | 'detail'\n\nexport type FieldSchema = {\n field: string\n label: string\n component: BestFieldComponent\n placeholder?: string\n dict?: string\n required?: boolean\n disabled?: boolean\n hidden?: boolean\n maxDate?: 'today'\n span?: number\n defaultValue?: string | number | boolean | null\n rules?: BestFieldRule[]\n /** Application-specific form control registered in the BestProvider registry. */\n slot?: string\n remoteService?: string\n searchField?: string\n labelField?: string\n valueField?: string\n debounceMs?: number\n pageSize?: number\n visibleWhen?: Condition\n disabledWhen?: Condition\n /** Clears stale dependent values when this field becomes hidden. */\n clearWhenHidden?: boolean\n /** Repeated object fields, for rules such as tiered pricing. */\n itemFields?: Omit<FieldSchema, 'itemFields'>[]\n minItems?: number\n maxItems?: number\n}\n\nexport type TableColumnSchema = {\n field: string\n title: string\n dict?: string\n width?: number\n format?: 'date' | 'datetime' | 'money' | 'text'\n slot?: string\n}\n\nexport type DetailFieldSchema = {\n field: string\n label: string\n dict?: string\n span?: number\n slot?: string\n}\n\nexport type PageActionSchema = {\n id: string\n label: string\n effect: 'openCreate' | 'openDetail' | 'openEdit' | 'remove' | 'runAction' | 'slot'\n action?: string\n slot?: string\n access?: string\n confirm?: string\n}\n\nexport type CrudPageSchema = {\n $schema: typeof CRUD_SCHEMA_ID\n version: typeof CRUD_SCHEMA_VERSION\n id: string\n kind: 'crud'\n title: string\n dataSource: {\n list: string\n detail?: string\n create?: string\n update?: string\n remove?: string\n }\n search?: FieldSchema[]\n searchMode?: 'proTable' | 'bestSearch'\n form?: FieldSchema[]\n table: {\n rowKey: string | string[]\n columns: TableColumnSchema[]\n actions?: PageActionSchema[]\n scrollX?: number\n pageSize?: number\n }\n detail?: { fields: DetailFieldSchema[] }\n toolbar?: PageActionSchema[]\n meta?: {\n generatedBy?: string\n generatedAt?: string\n }\n}\n", "import type { BestRegistry } from '../runtime'\nimport {\n type Condition,\n CRUD_SCHEMA_ID,\n CRUD_SCHEMA_VERSION,\n type CrudPageSchema,\n type FieldSchema,\n type PageActionSchema\n} from './schema'\n\nexport type SchemaDiagnostic = {\n path: string\n code: string\n message: string\n}\n\nexport type SchemaValidationResult = {\n valid: boolean\n diagnostics: SchemaDiagnostic[]\n}\n\nconst fieldComponents = new Set([\n 'input',\n 'number',\n 'select',\n 'remoteSelect',\n 'date',\n 'dateRange',\n 'textarea',\n 'slot',\n 'repeatable'\n])\nconst builtInEffects = new Set([\n 'openCreate',\n 'openDetail',\n 'openEdit',\n 'remove',\n 'runAction',\n 'slot'\n])\nconst columnFormats = new Set(['date', 'datetime', 'money', 'text'])\n\nfunction push(diagnostics: SchemaDiagnostic[], path: string, code: string, message: string) {\n diagnostics.push({ path, code, message })\n}\n\nfunction validateCondition(condition: Condition, path: string, diagnostics: SchemaDiagnostic[]) {\n if (\n (condition.operator === 'and' || condition.operator === 'or') &&\n condition.conditions.length === 0\n ) {\n push(diagnostics, path, 'condition.empty', '\u7EC4\u5408\u6761\u4EF6\u81F3\u5C11\u9700\u8981\u4E00\u4E2A\u5B50\u6761\u4EF6')\n }\n if (condition.operator === 'and' || condition.operator === 'or') {\n condition.conditions.forEach((item, index) => {\n validateCondition(item, `${path}/conditions/${index}`, diagnostics)\n })\n }\n if (condition.operator === 'not')\n validateCondition(condition.condition, `${path}/condition`, diagnostics)\n}\n\nfunction validateFields(\n fields: FieldSchema[] | undefined,\n path: string,\n registry: BestRegistry | undefined,\n diagnostics: SchemaDiagnostic[]\n) {\n const seen = new Set<string>()\n fields?.forEach((field, index) => {\n const fieldPath = `${path}/${index}`\n if (!field.field) push(diagnostics, fieldPath, 'field.missing', '\u5B57\u6BB5\u540D\u4E0D\u80FD\u4E3A\u7A7A')\n if (seen.has(field.field))\n push(diagnostics, fieldPath, 'field.duplicate', `\u5B57\u6BB5\u91CD\u590D\uFF1A${field.field}`)\n seen.add(field.field)\n if (!fieldComponents.has(field.component))\n push(diagnostics, fieldPath, 'field.component', `\u4E0D\u652F\u6301\u7684\u7EC4\u4EF6\uFF1A${field.component}`)\n if (field.dict && registry && !registry.dictionaries[field.dict]) {\n push(diagnostics, fieldPath, 'registry.dictionary', `\u672A\u6CE8\u518C\u5B57\u5178\uFF1A${field.dict}`)\n }\n if (field.component === 'remoteSelect' && !field.remoteService)\n push(diagnostics, fieldPath, 'field.remoteService', 'remoteSelect \u5FC5\u987B\u6307\u5B9A remoteService')\n if (field.remoteService && registry && !registry.services[field.remoteService])\n push(diagnostics, fieldPath, 'registry.service', `\u672A\u6CE8\u518C\u670D\u52A1\uFF1A${field.remoteService}`)\n if (field.component === 'slot' && !field.slot)\n push(diagnostics, fieldPath, 'field.slot', 'slot \u7EC4\u4EF6\u5FC5\u987B\u6307\u5B9A slot key')\n if (field.component === 'repeatable' && !field.itemFields?.length)\n push(\n diagnostics,\n fieldPath,\n 'field.repeatable',\n 'repeatable \u7EC4\u4EF6\u81F3\u5C11\u9700\u8981\u4E00\u4E2A itemFields \u5B57\u6BB5'\n )\n if (\n field.minItems !== undefined &&\n field.maxItems !== undefined &&\n field.minItems > field.maxItems\n )\n push(diagnostics, fieldPath, 'field.repeatable.range', 'minItems \u4E0D\u80FD\u5927\u4E8E maxItems')\n if (field.slot && registry && !registry.slots[field.slot])\n push(diagnostics, fieldPath, 'registry.slot', `\u672A\u6CE8\u518C\u63D2\u69FD\uFF1A${field.slot}`)\n if (field.visibleWhen)\n validateCondition(field.visibleWhen, `${fieldPath}/visibleWhen`, diagnostics)\n if (field.disabledWhen)\n validateCondition(field.disabledWhen, `${fieldPath}/disabledWhen`, diagnostics)\n })\n}\n\nfunction validateActions(\n actions: PageActionSchema[] | undefined,\n path: string,\n registry: BestRegistry | undefined,\n hasRemoveService: boolean,\n diagnostics: SchemaDiagnostic[]\n) {\n actions?.forEach((action, index) => {\n const actionPath = `${path}/${index}`\n if (!action.id) push(diagnostics, actionPath, 'action.missing', '\u52A8\u4F5C id \u4E0D\u80FD\u4E3A\u7A7A')\n if (!builtInEffects.has(action.effect))\n push(diagnostics, actionPath, 'action.effect', `\u4E0D\u652F\u6301\u7684\u52A8\u4F5C\uFF1A${action.effect}`)\n if (action.effect === 'runAction' && !action.action)\n push(diagnostics, actionPath, 'action.key', 'runAction \u5FC5\u987B\u6307\u5B9A action key')\n if (action.effect === 'remove' && !hasRemoveService)\n push(diagnostics, actionPath, 'action.removeService', 'remove \u52A8\u4F5C\u5FC5\u987B\u914D\u7F6E dataSource.remove')\n if (action.effect === 'slot' && !action.slot)\n push(diagnostics, actionPath, 'action.slot', 'slot \u52A8\u4F5C\u5FC5\u987B\u6307\u5B9A slot key')\n if (action.action && registry && !registry.actions[action.action]) {\n push(diagnostics, actionPath, 'registry.action', `\u672A\u6CE8\u518C\u52A8\u4F5C\uFF1A${action.action}`)\n }\n if (action.slot && registry && !registry.slots[action.slot]) {\n push(diagnostics, actionPath, 'registry.slot', `\u672A\u6CE8\u518C\u63D2\u69FD\uFF1A${action.slot}`)\n }\n })\n}\n\nexport function validateCrudPageSchema(\n schema: CrudPageSchema,\n registry?: BestRegistry\n): SchemaValidationResult {\n const diagnostics: SchemaDiagnostic[] = []\n if (schema.$schema !== CRUD_SCHEMA_ID)\n push(diagnostics, '/$schema', 'schema.id', `\u4EC5\u652F\u6301 ${CRUD_SCHEMA_ID}`)\n if (schema.version !== CRUD_SCHEMA_VERSION)\n push(diagnostics, '/version', 'schema.version', `\u4EC5\u652F\u6301\u7248\u672C ${CRUD_SCHEMA_VERSION}`)\n if (!schema.id) push(diagnostics, '/id', 'page.id', '\u9875\u9762 id \u4E0D\u80FD\u4E3A\u7A7A')\n if (!schema.title) push(diagnostics, '/title', 'page.title', '\u9875\u9762\u6807\u9898\u4E0D\u80FD\u4E3A\u7A7A')\n if (!schema.dataSource?.list)\n push(diagnostics, '/dataSource/list', 'service.list', '\u5217\u8868\u670D\u52A1\u4E0D\u80FD\u4E3A\u7A7A')\n if (schema.dataSource?.list && registry && !registry.listServices[schema.dataSource.list]) {\n push(\n diagnostics,\n '/dataSource/list',\n 'registry.service',\n `\u672A\u6CE8\u518C\u670D\u52A1\uFF1A${schema.dataSource.list}`\n )\n }\n if (schema.dataSource?.detail && registry && !registry.services[schema.dataSource.detail]) {\n push(\n diagnostics,\n '/dataSource/detail',\n 'registry.service',\n `\u672A\u6CE8\u518C\u670D\u52A1\uFF1A${schema.dataSource.detail}`\n )\n }\n if (schema.dataSource?.remove && registry && !registry.services[schema.dataSource.remove]) {\n push(\n diagnostics,\n '/dataSource/remove',\n 'registry.service',\n `\u672A\u6CE8\u518C\u670D\u52A1\uFF1A${schema.dataSource.remove}`\n )\n }\n validateFields(schema.search, '/search', registry, diagnostics)\n validateFields(schema.form, '/form', registry, diagnostics)\n if (!schema.table?.rowKey) push(diagnostics, '/table/rowKey', 'table.rowKey', 'rowKey \u4E0D\u80FD\u4E3A\u7A7A')\n if (!schema.table?.columns?.length)\n push(diagnostics, '/table/columns', 'table.columns', '\u81F3\u5C11\u9700\u8981\u4E00\u5217')\n schema.table?.columns?.forEach((column, index) => {\n if (column.format && !columnFormats.has(column.format)) {\n push(\n diagnostics,\n `/table/columns/${index}/format`,\n 'column.format',\n `\u4E0D\u652F\u6301\u7684\u683C\u5F0F\uFF1A${column.format}`\n )\n }\n if (column.dict && registry && !registry.dictionaries[column.dict]) {\n push(\n diagnostics,\n `/table/columns/${index}/dict`,\n 'registry.dictionary',\n `\u672A\u6CE8\u518C\u5B57\u5178\uFF1A${column.dict}`\n )\n }\n if (column.slot && registry && !registry.slots[column.slot]) {\n push(\n diagnostics,\n `/table/columns/${index}/slot`,\n 'registry.slot',\n `\u672A\u6CE8\u518C\u63D2\u69FD\uFF1A${column.slot}`\n )\n }\n })\n schema.detail?.fields.forEach((field, index) => {\n if (field.slot && registry && !registry.slots[field.slot])\n push(\n diagnostics,\n `/detail/fields/${index}/slot`,\n 'registry.slot',\n `\u672A\u6CE8\u518C\u63D2\u69FD\uFF1A${field.slot}`\n )\n })\n validateActions(\n schema.table?.actions,\n '/table/actions',\n registry,\n Boolean(schema.dataSource?.remove),\n diagnostics\n )\n validateActions(\n schema.toolbar,\n '/toolbar',\n registry,\n Boolean(schema.dataSource?.remove),\n diagnostics\n )\n return { valid: diagnostics.length === 0, diagnostics }\n}\n\nexport function assertValidCrudPageSchema(schema: CrudPageSchema, registry?: BestRegistry) {\n const result = validateCrudPageSchema(schema, registry)\n if (!result.valid) {\n const message = result.diagnostics.map((item) => `${item.path}: ${item.message}`).join('\\n')\n throw new Error(`Schema \u6821\u9A8C\u5931\u8D25\uFF1A\\n${message}`)\n }\n}\n", "export type BuiltinCapabilityDefinition = {\n id: string\n kind: 'field' | 'effect' | 'format'\n description: string\n status: 'supported'\n schema?: { component?: string; effect?: string; format?: string; required?: string[] }\n registry?: { required?: string[] }\n examples?: string[]\n}\n\nexport const builtinCapabilityDefinitions: BuiltinCapabilityDefinition[] = [\n { id: 'builtin.field.input', kind: 'field', description: '\u5355\u884C\u6587\u672C\u8F93\u5165', status: 'supported', schema: { component: 'input' } },\n { id: 'builtin.field.number', kind: 'field', description: '\u6570\u5B57\u8F93\u5165', status: 'supported', schema: { component: 'number' } },\n { id: 'builtin.field.select', kind: 'field', description: '\u9759\u6001\u9009\u9879\u4E0B\u62C9\u9009\u62E9', status: 'supported', schema: { component: 'select' } },\n { id: 'builtin.field.remoteSelect', kind: 'field', description: '\u5E26\u9632\u6296\u548C\u8BF7\u6C42\u53D6\u6D88\u7684\u8FDC\u7A0B\u641C\u7D22\u4E0B\u62C9', status: 'supported', schema: { component: 'remoteSelect', required: ['remoteService'] }, registry: { required: ['services'] }, examples: ['\u4EBA\u5458\u9009\u62E9', '\u5BA2\u6237\u9009\u62E9'] },\n { id: 'builtin.field.repeatable', kind: 'field', description: '\u652F\u6301\u52A8\u6001\u589E\u5220\u7684\u91CD\u590D\u5BF9\u8C61\u5B57\u6BB5', status: 'supported', schema: { component: 'repeatable', required: ['itemFields'] }, examples: ['\u9636\u68AF\u4EF7\u683C', '\u89C4\u5219\u5217\u8868'] },\n { id: 'builtin.field.slot', kind: 'field', description: '\u6CE8\u518C\u4E1A\u52A1\u81EA\u5B9A\u4E49\u5B57\u6BB5\u6E32\u67D3\u5668', status: 'supported', schema: { component: 'slot', required: ['slot'] }, registry: { required: ['slots'] } },\n { id: 'builtin.effect.openCreate', kind: 'effect', description: '\u6253\u5F00\u65B0\u5EFA\u8868\u5355', status: 'supported', schema: { effect: 'openCreate' } },\n { id: 'builtin.effect.openEdit', kind: 'effect', description: '\u6253\u5F00\u7F16\u8F91\u8868\u5355', status: 'supported', schema: { effect: 'openEdit' } },\n { id: 'builtin.effect.openDetail', kind: 'effect', description: '\u6253\u5F00\u8BE6\u60C5\u62BD\u5C49', status: 'supported', schema: { effect: 'openDetail' } },\n { id: 'builtin.effect.runAction', kind: 'effect', description: '\u8C03\u7528 Registry Action \u5E76\u5237\u65B0\u5217\u8868', status: 'supported', schema: { effect: 'runAction' }, registry: { required: ['actions'] } },\n { id: 'builtin.format.date', kind: 'format', description: '\u65E5\u671F\u683C\u5F0F\u5316', status: 'supported', schema: { format: 'date' } },\n { id: 'builtin.format.datetime', kind: 'format', description: '\u65E5\u671F\u65F6\u95F4\u683C\u5F0F\u5316', status: 'supported', schema: { format: 'datetime' } },\n { id: 'builtin.format.money', kind: 'format', description: '\u91D1\u989D\u683C\u5F0F\u5316', status: 'supported', schema: { format: 'money' } }\n]\n\nexport function getBuiltinCapabilities() {\n return builtinCapabilityDefinitions.map((item) => item.id)\n}\n", "import type {\n CRUD_SCHEMA_ID,\n CRUD_SCHEMA_VERSION,\n CrudPageSchema,\n FieldSchema,\n PageActionSchema\n} from './schema'\nimport type { SchemaDiagnostic, SchemaValidationResult } from './validate'\nimport { validateCrudPageSchema } from './validate'\nimport { builtinCapabilityDefinitions, getBuiltinCapabilities as getCatalogCapabilities } from './capabilities'\n\nconst builtInCapabilities = [\n 'builtin.effect.openCreate',\n 'builtin.effect.openDetail',\n 'builtin.effect.openEdit',\n 'builtin.effect.remove',\n 'builtin.effect.runAction',\n 'builtin.effect.slot',\n 'builtin.format.date',\n 'builtin.format.datetime',\n 'builtin.format.money',\n 'builtin.format.text',\n 'builtin.field.input',\n 'builtin.field.number',\n 'builtin.field.select',\n 'builtin.field.remoteSelect',\n 'builtin.field.date',\n 'builtin.field.dateRange',\n 'builtin.field.textarea',\n 'builtin.field.slot',\n 'builtin.field.repeatable'\n] as const\n\ntype JsonRecord = Record<string, unknown>\n\nfunction isRecord(value: unknown): value is JsonRecord {\n return !!value && typeof value === 'object' && !Array.isArray(value)\n}\n\nfunction arrayOfRecords(value: unknown): JsonRecord[] | undefined {\n return Array.isArray(value) && value.every(isRecord) ? value : undefined\n}\n\nfunction diagnostic(path: string, code: string, message: string): SchemaDiagnostic {\n return { path, code, message }\n}\n\nfunction validateUnknownShape(candidate: unknown): SchemaDiagnostic[] {\n if (!isRecord(candidate)) return [diagnostic('', 'schema.type', 'Schema \u5FC5\u987B\u662F JSON \u5BF9\u8C61')]\n const diagnostics: SchemaDiagnostic[] = []\n if (!isRecord(candidate.dataSource))\n diagnostics.push(diagnostic('/dataSource', 'dataSource.type', 'dataSource \u5FC5\u987B\u662F\u5BF9\u8C61'))\n if (!isRecord(candidate.table))\n diagnostics.push(diagnostic('/table', 'table.type', 'table \u5FC5\u987B\u662F\u5BF9\u8C61'))\n for (const key of ['search', 'form'] as const) {\n if (candidate[key] !== undefined && !arrayOfRecords(candidate[key])) {\n diagnostics.push(diagnostic(`/${key}`, 'field.list', `${key} \u5FC5\u987B\u662F\u5BF9\u8C61\u6570\u7EC4`))\n }\n }\n if (isRecord(candidate.table)) {\n if (!arrayOfRecords(candidate.table.columns)) {\n diagnostics.push(diagnostic('/table/columns', 'column.list', 'columns \u5FC5\u987B\u662F\u5BF9\u8C61\u6570\u7EC4'))\n }\n if (candidate.table.actions !== undefined && !arrayOfRecords(candidate.table.actions)) {\n diagnostics.push(diagnostic('/table/actions', 'action.list', 'actions \u5FC5\u987B\u662F\u5BF9\u8C61\u6570\u7EC4'))\n }\n }\n if (candidate.toolbar !== undefined && !arrayOfRecords(candidate.toolbar)) {\n diagnostics.push(diagnostic('/toolbar', 'action.list', 'toolbar \u5FC5\u987B\u662F\u5BF9\u8C61\u6570\u7EC4'))\n }\n return diagnostics\n}\n\nfunction toRuntimeSchema(candidate: JsonRecord): CrudPageSchema {\n return {\n $schema: candidate.$schema as typeof CRUD_SCHEMA_ID,\n version: candidate.version as typeof CRUD_SCHEMA_VERSION,\n id: candidate.id as string,\n kind: candidate.kind as 'crud',\n title: candidate.title as string,\n dataSource: candidate.dataSource as CrudPageSchema['dataSource'],\n search: candidate.search as FieldSchema[] | undefined,\n searchMode: candidate.searchMode as CrudPageSchema['searchMode'],\n form: candidate.form as FieldSchema[] | undefined,\n table: candidate.table as CrudPageSchema['table'],\n detail: candidate.detail as CrudPageSchema['detail'],\n toolbar: candidate.toolbar as PageActionSchema[] | undefined,\n meta: candidate.meta as CrudPageSchema['meta']\n }\n}\n\n/**\n * Server-safe development entry. It accepts unknown JSON from CLI/MCP before delegating to the\n * runtime validator, so untrusted candidates cannot trigger assumptions in typed runtime code.\n */\nexport function validateUnknownCrudPageSchema(candidate: unknown): SchemaValidationResult {\n const shapeDiagnostics = validateUnknownShape(candidate)\n if (shapeDiagnostics.length || !isRecord(candidate)) {\n return { valid: false, diagnostics: shapeDiagnostics }\n }\n return validateCrudPageSchema(toRuntimeSchema(candidate))\n}\n\n/** Serializable capabilities supplied by the current runtime without application Manifest entries. */\nexport function getBuiltinCapabilities(): string[] {\n return [...new Set([...builtInCapabilities, ...getCatalogCapabilities()])]\n}\n\nexport function getBuiltinCapabilityDefinitions() {\n return builtinCapabilityDefinitions\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["getBuiltinCapabilities"]
7
7
  }
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  // src/lowcode/BestCrudPage.tsx
2
2
  import { Button as Button4, Modal as Modal2, message } from "antd";
3
3
  import dayjs3 from "dayjs";
4
- import { useCallback, useEffect as useEffect3, useMemo as useMemo3, useRef, useState as useState2 } from "react";
4
+ import { useCallback, useEffect as useEffect3, useMemo as useMemo3, useRef, useState as useState3 } from "react";
5
5
 
6
6
  // src/runtime/BestProvider.tsx
7
7
  import { ConfigProvider } from "antd";
@@ -141,7 +141,7 @@ function BestFilePreview({ files, onDownload }) {
141
141
 
142
142
  // src/ui/BestForm.tsx
143
143
  import { Button as Button2, DatePicker, Form, Input as Input2, InputNumber, Select, Space } from "antd";
144
- import { useEffect } from "react";
144
+ import { useEffect, useState as useState2 } from "react";
145
145
  import { Fragment, jsx as jsx5, jsxs as jsxs2 } from "react/jsx-runtime";
146
146
  function FormControl({
147
147
  field,
@@ -150,6 +150,7 @@ function FormControl({
150
150
  form,
151
151
  ...controlProps
152
152
  }) {
153
+ const registry = useBestRegistry();
153
154
  switch (field.component) {
154
155
  case "select":
155
156
  return /* @__PURE__ */ jsx5(
@@ -161,6 +162,18 @@ function FormControl({
161
162
  placeholder: field.placeholder
162
163
  }
163
164
  );
165
+ case "remoteSelect":
166
+ return /* @__PURE__ */ jsx5(
167
+ RemoteSelect,
168
+ {
169
+ field,
170
+ value: values[field.field],
171
+ disabled: field.disabled,
172
+ placeholder: field.placeholder,
173
+ onChange: (value) => form.setFieldValue(field.field, value),
174
+ registry
175
+ }
176
+ );
164
177
  case "number":
165
178
  return /* @__PURE__ */ jsx5(
166
179
  InputNumber,
@@ -208,7 +221,7 @@ function FormControl({
208
221
  {
209
222
  label: itemField.label,
210
223
  name: [item.name, itemField.field],
211
- rules: itemField.rules,
224
+ rules: toAntRules(itemField.rules),
212
225
  children: /* @__PURE__ */ jsx5(FormControl, { field: itemField, form, mode, values })
213
226
  },
214
227
  itemField.field
@@ -259,9 +272,88 @@ function FormFields({ fields, form, initialValues, mode = "create" }) {
259
272
  },
260
273
  field.field
261
274
  );
262
- return field.component === "repeatable" ? /* @__PURE__ */ jsx5(Form.Item, { label: field.label, children: control }, field.field) : /* @__PURE__ */ jsx5(Form.Item, { label: field.label, name: field.field, rules: field.rules, children: control }, field.field);
275
+ return field.component === "repeatable" ? /* @__PURE__ */ jsx5(Form.Item, { label: field.label, children: control }, field.field) : /* @__PURE__ */ jsx5(
276
+ Form.Item,
277
+ {
278
+ label: field.label,
279
+ name: field.field,
280
+ rules: toAntRules(field.rules),
281
+ children: control
282
+ },
283
+ field.field
284
+ );
263
285
  }) });
264
286
  }
287
+ function toAntRules(rules) {
288
+ return rules?.map((rule) => ({
289
+ required: rule.required,
290
+ type: rule.type === "string" ? void 0 : rule.type,
291
+ min: rule.min ?? rule.minLength,
292
+ max: rule.max ?? rule.maxLength,
293
+ pattern: rule.pattern ? new RegExp(rule.pattern) : void 0,
294
+ message: rule.message,
295
+ validator: rule.type === "integer" ? async (_, value) => {
296
+ if (value === void 0 || value === null || value === "") return;
297
+ if (!Number.isInteger(Number(value))) throw new Error(rule.message ?? "\u8BF7\u8F93\u5165\u6574\u6570");
298
+ } : void 0
299
+ }));
300
+ }
301
+ function RemoteSelect({
302
+ field,
303
+ value,
304
+ disabled,
305
+ placeholder,
306
+ onChange,
307
+ registry
308
+ }) {
309
+ const [options, setOptions] = useState2([]);
310
+ const [loading, setLoading] = useState2(false);
311
+ const [keyword, setKeyword] = useState2("");
312
+ const service = field.remoteService ? registry.services[field.remoteService] : void 0;
313
+ const labelField = field.labelField ?? "label";
314
+ const valueField = field.valueField ?? "value";
315
+ const searchField = field.searchField ?? "keyword";
316
+ const debounceMs = field.debounceMs ?? 300;
317
+ useEffect(() => {
318
+ if (!service) return;
319
+ const controller = new AbortController();
320
+ const timer = window.setTimeout(async () => {
321
+ setLoading(true);
322
+ try {
323
+ const response = await service(
324
+ { [searchField]: keyword, page: 1, pageSize: field.pageSize ?? 20 },
325
+ { signal: controller.signal }
326
+ );
327
+ const raw = Array.isArray(response) ? response : response?.items ?? response?.list ?? [];
328
+ setOptions(
329
+ raw.filter((item) => !!item && typeof item === "object").map((item) => ({ label: String(item[labelField] ?? ""), value: item[valueField] }))
330
+ );
331
+ } catch {
332
+ setOptions([]);
333
+ } finally {
334
+ if (!controller.signal.aborted) setLoading(false);
335
+ }
336
+ }, debounceMs);
337
+ return () => {
338
+ window.clearTimeout(timer);
339
+ controller.abort();
340
+ };
341
+ }, [debounceMs, field.pageSize, keyword, labelField, searchField, service, valueField]);
342
+ return /* @__PURE__ */ jsx5(
343
+ Select,
344
+ {
345
+ showSearch: true,
346
+ filterOption: false,
347
+ loading,
348
+ value,
349
+ options,
350
+ disabled,
351
+ placeholder,
352
+ onSearch: setKeyword,
353
+ onChange
354
+ }
355
+ );
356
+ }
265
357
  function BestForm({
266
358
  fields,
267
359
  initialValues,
@@ -342,6 +434,7 @@ import dayjs from "dayjs";
342
434
  import { useEffect as useEffect2 } from "react";
343
435
  import { jsx as jsx8, jsxs as jsxs3 } from "react/jsx-runtime";
344
436
  function FieldControl({ field }) {
437
+ const registry = useBestRegistry();
345
438
  switch (field.component) {
346
439
  case "select":
347
440
  return /* @__PURE__ */ jsx8(
@@ -362,6 +455,16 @@ function FieldControl({ field }) {
362
455
  style: { width: "100%" }
363
456
  }
364
457
  );
458
+ case "remoteSelect":
459
+ return /* @__PURE__ */ jsx8(
460
+ RemoteSelect,
461
+ {
462
+ field,
463
+ value: void 0,
464
+ onChange: () => void 0,
465
+ registry
466
+ }
467
+ );
365
468
  case "date":
366
469
  return /* @__PURE__ */ jsx8(
367
470
  DatePicker2,
@@ -413,7 +516,7 @@ function BestSearch({
413
516
  onValuesChange: (_, values) => onChange?.(values),
414
517
  style: { marginBottom: 16 },
415
518
  children: /* @__PURE__ */ jsxs3(Row, { gutter: 16, align: "bottom", children: [
416
- fields.filter((field) => !field.hidden).map((field) => /* @__PURE__ */ jsx8(Col, { span: field.span ?? 6, children: /* @__PURE__ */ jsx8(Form2.Item, { label: field.label, name: field.field, rules: field.rules, children: /* @__PURE__ */ jsx8(FieldControl, { field }) }) }, field.field)),
519
+ fields.filter((field) => !field.hidden).map((field) => /* @__PURE__ */ jsx8(Col, { span: field.span ?? 6, children: /* @__PURE__ */ jsx8(Form2.Item, { label: field.label, name: field.field, rules: toAntRules(field.rules), children: /* @__PURE__ */ jsx8(FieldControl, { field }) }) }, field.field)),
417
520
  /* @__PURE__ */ jsx8(Col, { children: /* @__PURE__ */ jsxs3(Form2.Item, { children: [
418
521
  /* @__PURE__ */ jsx8(Button3, { htmlType: "submit", loading, type: "primary", children: submitText }),
419
522
  /* @__PURE__ */ jsx8(
@@ -593,6 +696,7 @@ var fieldComponents = /* @__PURE__ */ new Set([
593
696
  "input",
594
697
  "number",
595
698
  "select",
699
+ "remoteSelect",
596
700
  "date",
597
701
  "dateRange",
598
702
  "textarea",
@@ -636,6 +740,10 @@ function validateFields(fields, path, registry, diagnostics) {
636
740
  if (field.dict && registry && !registry.dictionaries[field.dict]) {
637
741
  push(diagnostics, fieldPath, "registry.dictionary", `\u672A\u6CE8\u518C\u5B57\u5178\uFF1A${field.dict}`);
638
742
  }
743
+ if (field.component === "remoteSelect" && !field.remoteService)
744
+ push(diagnostics, fieldPath, "field.remoteService", "remoteSelect \u5FC5\u987B\u6307\u5B9A remoteService");
745
+ if (field.remoteService && registry && !registry.services[field.remoteService])
746
+ push(diagnostics, fieldPath, "registry.service", `\u672A\u6CE8\u518C\u670D\u52A1\uFF1A${field.remoteService}`);
639
747
  if (field.component === "slot" && !field.slot)
640
748
  push(diagnostics, fieldPath, "field.slot", "slot \u7EC4\u4EF6\u5FC5\u987B\u6307\u5B9A slot key");
641
749
  if (field.component === "repeatable" && !field.itemFields?.length)
@@ -784,6 +892,12 @@ function toFieldDefinition(field, options, slots) {
784
892
  component: field.component,
785
893
  placeholder: field.placeholder,
786
894
  options,
895
+ remoteService: field.remoteService,
896
+ searchField: field.searchField,
897
+ labelField: field.labelField,
898
+ valueField: field.valueField,
899
+ debounceMs: field.debounceMs,
900
+ pageSize: field.pageSize,
787
901
  required: field.required,
788
902
  disabled: field.disabled,
789
903
  hidden: field.hidden,
@@ -796,7 +910,7 @@ function toFieldDefinition(field, options, slots) {
796
910
  minItems: field.minItems,
797
911
  maxItems: field.maxItems,
798
912
  render: slot ? (context) => slots[slot]?.(context) : void 0,
799
- rules: field.required ? [{ required: true, message: `\u8BF7\u586B\u5199${field.label}` }] : void 0
913
+ rules: field.required ? [{ required: true, message: `\u8BF7\u586B\u5199${field.label}` }, ...field.rules ?? []] : field.rules
800
914
  };
801
915
  }
802
916
  function useFields(fields = []) {
@@ -892,9 +1006,9 @@ function BestCrudPage({ adapter, className, schema }) {
892
1006
  const formFields = useFields(schema.form);
893
1007
  const actionRef = useRef(void 0);
894
1008
  const pageRequestRef = useRef(void 0);
895
- const [query, setQuery] = useState2({});
896
- const [drawer, setDrawer] = useState2({ mode: "closed" });
897
- const [submitting, setSubmitting] = useState2(false);
1009
+ const [query, setQuery] = useState3({});
1010
+ const [drawer, setDrawer] = useState3({ mode: "closed" });
1011
+ const [submitting, setSubmitting] = useState3(false);
898
1012
  const handleAction = useCallback(
899
1013
  async (action, record) => {
900
1014
  if (action.access && !registry.access(action.access)) return;
@@ -996,8 +1110,12 @@ function BestCrudPage({ adapter, className, schema }) {
996
1110
  const rowKey = schema.table.rowKey;
997
1111
  const submitForm = useCallback(
998
1112
  async (values) => {
1113
+ if (submitting) return;
999
1114
  const serviceKey = drawer.mode === "edit" ? schema.dataSource.update : schema.dataSource.create;
1000
- if (!serviceKey) return;
1115
+ if (!serviceKey) {
1116
+ message.error(`${drawer.mode === "edit" ? "\u66F4\u65B0" : "\u521B\u5EFA"}\u670D\u52A1\u672A\u914D\u7F6E`);
1117
+ return;
1118
+ }
1001
1119
  const record = drawer.mode === "closed" ? void 0 : drawer.record;
1002
1120
  setSubmitting(true);
1003
1121
  try {
@@ -1013,7 +1131,7 @@ function BestCrudPage({ adapter, className, schema }) {
1013
1131
  setSubmitting(false);
1014
1132
  }
1015
1133
  },
1016
- [adapter, drawer, registry.services, schema.dataSource.create, schema.dataSource.update]
1134
+ [adapter, drawer, registry.services, schema.dataSource.create, schema.dataSource.update, submitting]
1017
1135
  );
1018
1136
  return /* @__PURE__ */ jsxs4(Fragment2, { children: [
1019
1137
  useBestSearch && searchFields.length ? /* @__PURE__ */ jsx11(
@@ -1100,6 +1218,55 @@ function BestCrudPage({ adapter, className, schema }) {
1100
1218
  );
1101
1219
  }
1102
1220
  }
1221
+
1222
+ // src/lowcode/adapter.ts
1223
+ function normalizeBestValues(values, normalize = defaultNormalize) {
1224
+ return Object.fromEntries(
1225
+ Object.entries(values).map(([field, value]) => [field, normalizeNested(value, normalize, field)])
1226
+ );
1227
+ }
1228
+ function normalizeNested(value, normalize, field) {
1229
+ if (Array.isArray(value)) return value.map((item) => normalizeNested(item, normalize, field));
1230
+ if (value && typeof value === "object" && !(value instanceof Date)) {
1231
+ return Object.fromEntries(
1232
+ Object.entries(value).map(([key, item]) => [key, normalizeNested(item, normalize, key)])
1233
+ );
1234
+ }
1235
+ return normalize(value, field);
1236
+ }
1237
+ function defaultNormalize(value) {
1238
+ if (typeof value === "string") return value.trim() === "" ? void 0 : value.trim();
1239
+ return value;
1240
+ }
1241
+ function createBestCrudAdapter(options = {}) {
1242
+ const normalize = options.normalize ?? defaultNormalize;
1243
+ return {
1244
+ fromList: options.fromList,
1245
+ fromDetail: options.fromDetail,
1246
+ toCreatePayload: (values) => options.toCreatePayload?.(normalizeBestValues(values, normalize)) ?? normalizeBestValues(values, normalize),
1247
+ toUpdatePayload: (values, record) => options.toUpdatePayload?.(normalizeBestValues(values, normalize), record) ?? normalizeBestValues(values, normalize)
1248
+ };
1249
+ }
1250
+
1251
+ // src/lowcode/capabilities.ts
1252
+ var builtinCapabilityDefinitions = [
1253
+ { id: "builtin.field.input", kind: "field", description: "\u5355\u884C\u6587\u672C\u8F93\u5165", status: "supported", schema: { component: "input" } },
1254
+ { id: "builtin.field.number", kind: "field", description: "\u6570\u5B57\u8F93\u5165", status: "supported", schema: { component: "number" } },
1255
+ { id: "builtin.field.select", kind: "field", description: "\u9759\u6001\u9009\u9879\u4E0B\u62C9\u9009\u62E9", status: "supported", schema: { component: "select" } },
1256
+ { id: "builtin.field.remoteSelect", kind: "field", description: "\u5E26\u9632\u6296\u548C\u8BF7\u6C42\u53D6\u6D88\u7684\u8FDC\u7A0B\u641C\u7D22\u4E0B\u62C9", status: "supported", schema: { component: "remoteSelect", required: ["remoteService"] }, registry: { required: ["services"] }, examples: ["\u4EBA\u5458\u9009\u62E9", "\u5BA2\u6237\u9009\u62E9"] },
1257
+ { id: "builtin.field.repeatable", kind: "field", description: "\u652F\u6301\u52A8\u6001\u589E\u5220\u7684\u91CD\u590D\u5BF9\u8C61\u5B57\u6BB5", status: "supported", schema: { component: "repeatable", required: ["itemFields"] }, examples: ["\u9636\u68AF\u4EF7\u683C", "\u89C4\u5219\u5217\u8868"] },
1258
+ { id: "builtin.field.slot", kind: "field", description: "\u6CE8\u518C\u4E1A\u52A1\u81EA\u5B9A\u4E49\u5B57\u6BB5\u6E32\u67D3\u5668", status: "supported", schema: { component: "slot", required: ["slot"] }, registry: { required: ["slots"] } },
1259
+ { id: "builtin.effect.openCreate", kind: "effect", description: "\u6253\u5F00\u65B0\u5EFA\u8868\u5355", status: "supported", schema: { effect: "openCreate" } },
1260
+ { id: "builtin.effect.openEdit", kind: "effect", description: "\u6253\u5F00\u7F16\u8F91\u8868\u5355", status: "supported", schema: { effect: "openEdit" } },
1261
+ { id: "builtin.effect.openDetail", kind: "effect", description: "\u6253\u5F00\u8BE6\u60C5\u62BD\u5C49", status: "supported", schema: { effect: "openDetail" } },
1262
+ { id: "builtin.effect.runAction", kind: "effect", description: "\u8C03\u7528 Registry Action \u5E76\u5237\u65B0\u5217\u8868", status: "supported", schema: { effect: "runAction" }, registry: { required: ["actions"] } },
1263
+ { id: "builtin.format.date", kind: "format", description: "\u65E5\u671F\u683C\u5F0F\u5316", status: "supported", schema: { format: "date" } },
1264
+ { id: "builtin.format.datetime", kind: "format", description: "\u65E5\u671F\u65F6\u95F4\u683C\u5F0F\u5316", status: "supported", schema: { format: "datetime" } },
1265
+ { id: "builtin.format.money", kind: "format", description: "\u91D1\u989D\u683C\u5F0F\u5316", status: "supported", schema: { format: "money" } }
1266
+ ];
1267
+ function getBuiltinCapabilities() {
1268
+ return builtinCapabilityDefinitions.map((item) => item.id);
1269
+ }
1103
1270
  export {
1104
1271
  BestBatchInput,
1105
1272
  BestCrudPage,
@@ -1118,7 +1285,11 @@ export {
1118
1285
  CRUD_SCHEMA_ID,
1119
1286
  CRUD_SCHEMA_VERSION,
1120
1287
  assertValidCrudPageSchema,
1288
+ builtinCapabilityDefinitions,
1289
+ createBestCrudAdapter,
1121
1290
  createBestRegistry,
1291
+ getBuiltinCapabilities as getCapabilityIds,
1292
+ normalizeBestValues,
1122
1293
  useBestAccess,
1123
1294
  useBestAction,
1124
1295
  useBestDictionary,