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 +19 -0
- package/dist/dev.d.ts +1 -1
- package/dist/dev.d.ts.map +1 -1
- package/dist/dev.js +33 -3
- package/dist/dev.js.map +4 -4
- package/dist/index.js +182 -11
- package/dist/index.js.map +4 -4
- package/dist/lowcode/BestCrudPage.d.ts.map +1 -1
- package/dist/lowcode/adapter.d.ts +11 -0
- package/dist/lowcode/adapter.d.ts.map +1 -0
- package/dist/lowcode/capabilities.d.ts +19 -0
- package/dist/lowcode/capabilities.d.ts.map +1 -0
- package/dist/lowcode/dev.d.ts +1 -0
- package/dist/lowcode/dev.d.ts.map +1 -1
- package/dist/lowcode/index.d.ts +2 -0
- package/dist/lowcode/index.d.ts.map +1 -1
- package/dist/lowcode/schema.d.ts +8 -1
- package/dist/lowcode/schema.d.ts.map +1 -1
- package/dist/lowcode/validate.d.ts.map +1 -1
- package/dist/ui/BestForm.d.ts +19 -1
- package/dist/ui/BestForm.d.ts.map +1 -1
- package/dist/ui/BestSearch.d.ts.map +1 -1
- package/dist/ui/index.d.ts +1 -1
- package/dist/ui/index.d.ts.map +1 -1
- package/dist/ui/types.d.ts +18 -5
- package/dist/ui/types.d.ts.map +1 -1
- package/package.json +1 -1
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,
|
|
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
|
|
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
|
|
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(
|
|
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}` }] :
|
|
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] =
|
|
896
|
-
const [drawer, setDrawer] =
|
|
897
|
-
const [submitting, setSubmitting] =
|
|
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)
|
|
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,
|