best-lowcode-runtime 0.2.5 → 0.2.7

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
@@ -44,6 +44,29 @@ export function CustomerPage() {
44
44
  }
45
45
  ```
46
46
 
47
+ ## 异步字典更新
48
+
49
+ 字典可以在页面初始化后通过 `useBestDictionaryActions` 局部更新,不需要替换完整 Registry:
50
+
51
+ ```tsx
52
+ import { useEffect } from 'react'
53
+ import { useBestDictionaryActions } from 'best-lowcode-runtime'
54
+
55
+ function LoadDictionaries() {
56
+ const { setDictionary } = useBestDictionaryActions()
57
+
58
+ useEffect(() => {
59
+ void fetch('/api/status-options')
60
+ .then((response) => response.json())
61
+ .then((items) => setDictionary('customer.status', items))
62
+ }, [setDictionary])
63
+
64
+ return null
65
+ }
66
+ ```
67
+
68
+ `setDictionary` 只更新指定字典,并触发使用该字典的字段、表格和详情重新渲染。
69
+
47
70
  ## 开发期校验入口
48
71
 
49
72
  ### 通用表单和数据能力
package/dist/dev.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export { getBuiltinCapabilities, validateUnknownCrudPageSchema } from './lowcode/dev';
1
+ export { getBuiltinCapabilities, validateUnknownCrudPageSchema, validateUnknownPageSchema } 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,6BAA6B,EAC7B,yBAAyB,EAC1B,MAAM,eAAe,CAAA"}
package/dist/dev.js CHANGED
@@ -1,6 +1,8 @@
1
1
  // src/lowcode/schema.ts
2
2
  var CRUD_SCHEMA_ID = "https://best.dev/schema/crud/v1";
3
3
  var CRUD_SCHEMA_VERSION = 1;
4
+ var TABBED_PAGE_SCHEMA_ID = "https://best.dev/schema/tabs/v1";
5
+ var TABBED_PAGE_SCHEMA_VERSION = 1;
4
6
 
5
7
  // src/lowcode/validate.ts
6
8
  var fieldComponents = /* @__PURE__ */ new Set([
@@ -252,6 +254,37 @@ function validateCrudPageSchema(schema, registry) {
252
254
  );
253
255
  return { valid: diagnostics.length === 0, diagnostics };
254
256
  }
257
+ function validateTabbedPageSchema(schema, registry) {
258
+ const diagnostics = [];
259
+ if (schema.$schema !== TABBED_PAGE_SCHEMA_ID)
260
+ push(diagnostics, "/$schema", "schema.id", `\u4EC5\u652F\u6301 ${TABBED_PAGE_SCHEMA_ID}`);
261
+ if (schema.version !== TABBED_PAGE_SCHEMA_VERSION)
262
+ push(diagnostics, "/version", "schema.version", `\u4EC5\u652F\u6301\u7248\u672C ${TABBED_PAGE_SCHEMA_VERSION}`);
263
+ if (!schema.id) push(diagnostics, "/id", "page.id", "\u9875\u9762 id \u4E0D\u80FD\u4E3A\u7A7A");
264
+ if (!Array.isArray(schema.tabs) || schema.tabs.length === 0) {
265
+ push(diagnostics, "/tabs", "tabs.required", "\u81F3\u5C11\u9700\u8981\u4E00\u4E2A\u9875\u7B7E");
266
+ return { valid: false, diagnostics };
267
+ }
268
+ const keys = /* @__PURE__ */ new Set();
269
+ schema.tabs.forEach((tab, index) => {
270
+ const path = `/tabs/${index}`;
271
+ if (!tab.key) push(diagnostics, path, "tab.key", "\u9875\u7B7E key \u4E0D\u80FD\u4E3A\u7A7A");
272
+ if (keys.has(tab.key)) push(diagnostics, path, "tab.duplicate", `\u9875\u7B7E key \u91CD\u590D\uFF1A${tab.key}`);
273
+ keys.add(tab.key);
274
+ if (!tab.label) push(diagnostics, path, "tab.label", "\u9875\u7B7E\u6807\u9898\u4E0D\u80FD\u4E3A\u7A7A");
275
+ if (tab.content.type === "crud") {
276
+ const result = validateCrudPageSchema(tab.content.schema, registry);
277
+ diagnostics.push(...result.diagnostics.map((item) => ({ ...item, path: `${path}/content/schema${item.path}` })));
278
+ } else if (tab.content.type === "slot") {
279
+ if (!tab.content.slot) push(diagnostics, path, "tab.slot", "slot \u9875\u7B7E\u5FC5\u987B\u6307\u5B9A slot key");
280
+ if (tab.content.slot && registry && !registry.slots[tab.content.slot])
281
+ push(diagnostics, path, "registry.slot", `\u672A\u6CE8\u518C\u63D2\u69FD\uFF1A${tab.content.slot}`);
282
+ } else {
283
+ push(diagnostics, path, "tab.content", "\u4E0D\u652F\u6301\u7684\u9875\u7B7E\u5185\u5BB9\u7C7B\u578B");
284
+ }
285
+ });
286
+ return { valid: diagnostics.length === 0, diagnostics };
287
+ }
255
288
 
256
289
  // src/lowcode/dev.ts
257
290
  var builtInCapabilities = [
@@ -326,6 +359,15 @@ function toRuntimeSchema(candidate) {
326
359
  meta: candidate.meta
327
360
  };
328
361
  }
362
+ function toRuntimeTabbedSchema(candidate) {
363
+ return {
364
+ $schema: candidate.$schema,
365
+ version: candidate.version,
366
+ id: candidate.id,
367
+ kind: candidate.kind,
368
+ tabs: candidate.tabs
369
+ };
370
+ }
329
371
  function validateUnknownCrudPageSchema(candidate) {
330
372
  const shapeDiagnostics = validateUnknownShape(candidate);
331
373
  if (shapeDiagnostics.length || !isRecord(candidate)) {
@@ -333,11 +375,60 @@ function validateUnknownCrudPageSchema(candidate) {
333
375
  }
334
376
  return validateCrudPageSchema(toRuntimeSchema(candidate));
335
377
  }
378
+ function validateUnknownPageSchema(candidate) {
379
+ if (!isRecord(candidate)) return validateUnknownCrudPageSchema(candidate);
380
+ if (candidate.kind === "crud" || candidate.$schema === CRUD_SCHEMA_ID) {
381
+ return validateUnknownCrudPageSchema(candidate);
382
+ }
383
+ if (candidate.kind !== "tabs" && candidate.$schema !== TABBED_PAGE_SCHEMA_ID)
384
+ return validateUnknownCrudPageSchema(candidate);
385
+ if (!Array.isArray(candidate.tabs) || !candidate.tabs.every(isRecord)) {
386
+ return {
387
+ valid: false,
388
+ diagnostics: [diagnostic("/tabs", "tabs.type", "tabs \u5FC5\u987B\u662F\u5BF9\u8C61\u6570\u7EC4")]
389
+ };
390
+ }
391
+ for (const [index, tab] of candidate.tabs.entries()) {
392
+ const contentPath = `/tabs/${index}/content`;
393
+ if (!isRecord(tab.content)) {
394
+ return {
395
+ valid: false,
396
+ diagnostics: [diagnostic(contentPath, "tabs.content", "tab content \u5FC5\u987B\u662F CRUD \u6216 Slot")]
397
+ };
398
+ }
399
+ if (tab.content.type !== "crud" && tab.content.type !== "slot") {
400
+ return {
401
+ valid: false,
402
+ diagnostics: [diagnostic(`${contentPath}/type`, "tabs.content", "tab content \u5FC5\u987B\u662F CRUD \u6216 Slot")]
403
+ };
404
+ }
405
+ if (tab.content.type === "crud" && !isRecord(tab.content.schema)) {
406
+ return {
407
+ valid: false,
408
+ diagnostics: [diagnostic(`${contentPath}/schema`, "tabs.content", "CRUD tab \u5FC5\u987B\u63D0\u4F9B\u5BF9\u8C61 schema")]
409
+ };
410
+ }
411
+ if (tab.content.type === "crud") {
412
+ const result = validateUnknownCrudPageSchema(tab.content.schema);
413
+ if (!result.valid) {
414
+ return {
415
+ valid: false,
416
+ diagnostics: result.diagnostics.map((item) => ({
417
+ ...item,
418
+ path: `${contentPath}/schema${item.path}`
419
+ }))
420
+ };
421
+ }
422
+ }
423
+ }
424
+ return validateTabbedPageSchema(toRuntimeTabbedSchema(candidate));
425
+ }
336
426
  function getBuiltinCapabilities() {
337
427
  return [...builtInCapabilities];
338
428
  }
339
429
  export {
340
430
  getBuiltinCapabilities,
341
- validateUnknownCrudPageSchema
431
+ validateUnknownCrudPageSchema,
432
+ validateUnknownPageSchema
342
433
  };
343
434
  //# sourceMappingURL=dev.js.map
package/dist/dev.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/lowcode/schema.ts", "../src/lowcode/validate.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\nexport const TABBED_PAGE_SCHEMA_ID = 'https://best.dev/schema/tabs/v1' as const\nexport const TABBED_PAGE_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 fixed?: 'left' | 'right'\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 PageActionButtonType = 'primary' | 'default' | 'link' | 'text' | 'dashed'\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 /** Visual button style; omitted actions use the runtime area default. */\n buttonType?: PageActionButtonType\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\nexport type TabContentSchema =\n | { type: 'crud'; schema: CrudPageSchema }\n | { type: 'slot'; slot: string }\n\nexport type TabSchema = {\n key: string\n label: string\n access?: string\n /** Defaults to true so inactive CRUD pages do not fetch until selected. */\n destroyOnHidden?: boolean\n content: TabContentSchema\n}\n\n/** A page composition schema with runtime-owned tab navigation. */\nexport type TabbedPageSchema = {\n $schema: typeof TABBED_PAGE_SCHEMA_ID\n version: typeof TABBED_PAGE_SCHEMA_VERSION\n id: string\n kind: 'tabs'\n tabs: TabSchema[]\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 TABBED_PAGE_SCHEMA_ID,\n TABBED_PAGE_SCHEMA_VERSION,\n type TabbedPageSchema\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 (!condition || typeof condition !== 'object') {\n push(diagnostics, path, 'condition.type', '\u6761\u4EF6\u5FC5\u987B\u662F\u5BF9\u8C61')\n return\n }\n if (condition.operator === 'equals') {\n if (typeof condition.field !== 'string' || condition.field === '') {\n push(diagnostics, path, 'condition.field', 'equals \u6761\u4EF6\u5FC5\u987B\u6307\u5B9A\u5B57\u6BB5\u540D')\n }\n return\n }\n if (condition.operator === 'notEmpty') {\n if (typeof condition.field !== 'string' || condition.field === '') {\n push(diagnostics, path, 'condition.field', 'notEmpty \u6761\u4EF6\u5FC5\u987B\u6307\u5B9A\u5B57\u6BB5\u540D')\n }\n return\n }\n if (condition.operator === 'modeEquals') {\n return\n }\n if (\n (condition.operator === 'and' || condition.operator === 'or') &&\n !Array.isArray(condition.conditions)\n ) {\n push(diagnostics, path, 'condition.conditions', '\u7EC4\u5408\u6761\u4EF6\u5FC5\u987B\u6307\u5B9A conditions \u6570\u7EC4')\n return\n }\n if (condition.operator === 'and' || condition.operator === 'or') {\n if (condition.conditions.length === 0) {\n push(diagnostics, path, 'condition.empty', '\u7EC4\u5408\u6761\u4EF6\u81F3\u5C11\u9700\u8981\u4E00\u4E2A\u5B50\u6761\u4EF6')\n }\n condition.conditions.forEach((item, index) => {\n validateCondition(item, `${path}/conditions/${index}`, diagnostics)\n })\n return\n }\n if (condition.operator === 'not') {\n if (!condition.condition) {\n push(diagnostics, path, 'condition.missing', 'not \u6761\u4EF6\u5FC5\u987B\u6307\u5B9A condition')\n return\n }\n validateCondition(condition.condition, `${path}/condition`, diagnostics)\n return\n }\n push(diagnostics, path, 'condition.operator', `\u4E0D\u652F\u6301\u7684\u6761\u4EF6\uFF1A${(condition as { operator?: unknown }).operator}`)\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 (field.itemFields?.length)\n validateFields(\n field.itemFields as FieldSchema[],\n `${fieldPath}/itemFields`,\n registry,\n diagnostics\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?.create && registry && !registry.services[schema.dataSource.create]) {\n push(\n diagnostics,\n '/dataSource/create',\n 'registry.service',\n `\u672A\u6CE8\u518C\u670D\u52A1\uFF1A${schema.dataSource.create}`\n )\n }\n if (schema.dataSource?.update && registry && !registry.services[schema.dataSource.update]) {\n push(\n diagnostics,\n '/dataSource/update',\n 'registry.service',\n `\u672A\u6CE8\u518C\u670D\u52A1\uFF1A${schema.dataSource.update}`\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.fixed !== undefined && column.fixed !== 'left' && column.fixed !== 'right') {\n push(\n diagnostics,\n `/table/columns/${index}/fixed`,\n 'column.fixed',\n `\u4E0D\u652F\u6301\u7684\u56FA\u5B9A\u4F4D\u7F6E\uFF1A${column.fixed}`\n )\n }\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 if (schema.detail !== undefined) {\n if (\n !schema.detail ||\n typeof schema.detail !== 'object' ||\n !Array.isArray(schema.detail.fields)\n ) {\n push(diagnostics, '/detail', 'detail.type', 'detail \u5FC5\u987B\u5305\u542B fields \u5BF9\u8C61\u6570\u7EC4')\n } else {\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 }\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\nexport function validateTabbedPageSchema(\n schema: TabbedPageSchema,\n registry?: BestRegistry\n): SchemaValidationResult {\n const diagnostics: SchemaDiagnostic[] = []\n if (schema.$schema !== TABBED_PAGE_SCHEMA_ID)\n push(diagnostics, '/$schema', 'schema.id', `\u4EC5\u652F\u6301 ${TABBED_PAGE_SCHEMA_ID}`)\n if (schema.version !== TABBED_PAGE_SCHEMA_VERSION)\n push(diagnostics, '/version', 'schema.version', `\u4EC5\u652F\u6301\u7248\u672C ${TABBED_PAGE_SCHEMA_VERSION}`)\n if (!schema.id) push(diagnostics, '/id', 'page.id', '\u9875\u9762 id \u4E0D\u80FD\u4E3A\u7A7A')\n if (!Array.isArray(schema.tabs) || schema.tabs.length === 0) {\n push(diagnostics, '/tabs', 'tabs.required', '\u81F3\u5C11\u9700\u8981\u4E00\u4E2A\u9875\u7B7E')\n return { valid: false, diagnostics }\n }\n const keys = new Set<string>()\n schema.tabs.forEach((tab, index) => {\n const path = `/tabs/${index}`\n if (!tab.key) push(diagnostics, path, 'tab.key', '\u9875\u7B7E key \u4E0D\u80FD\u4E3A\u7A7A')\n if (keys.has(tab.key)) push(diagnostics, path, 'tab.duplicate', `\u9875\u7B7E key \u91CD\u590D\uFF1A${tab.key}`)\n keys.add(tab.key)\n if (!tab.label) push(diagnostics, path, 'tab.label', '\u9875\u7B7E\u6807\u9898\u4E0D\u80FD\u4E3A\u7A7A')\n if (tab.content.type === 'crud') {\n const result = validateCrudPageSchema(tab.content.schema, registry)\n diagnostics.push(...result.diagnostics.map((item) => ({ ...item, path: `${path}/content/schema${item.path}` })))\n } else if (tab.content.type === 'slot') {\n if (!tab.content.slot) push(diagnostics, path, 'tab.slot', 'slot \u9875\u7B7E\u5FC5\u987B\u6307\u5B9A slot key')\n if (tab.content.slot && registry && !registry.slots[tab.content.slot])\n push(diagnostics, path, 'registry.slot', `\u672A\u6CE8\u518C\u63D2\u69FD\uFF1A${tab.content.slot}`)\n } else {\n push(diagnostics, path, 'tab.content', '\u4E0D\u652F\u6301\u7684\u9875\u7B7E\u5185\u5BB9\u7C7B\u578B')\n }\n })\n return { valid: diagnostics.length === 0, diagnostics }\n}\n\nexport function assertValidTabbedPageSchema(schema: TabbedPageSchema, registry?: BestRegistry) {\n const result = validateTabbedPageSchema(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.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 [...builtInCapabilities]\n}\n"],
5
- "mappings": "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",
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\nexport const TABBED_PAGE_SCHEMA_ID = 'https://best.dev/schema/tabs/v1' as const\nexport const TABBED_PAGE_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 fixed?: 'left' | 'right'\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 PageActionButtonType = 'primary' | 'default' | 'link' | 'text' | 'dashed'\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 /** Visual button style; omitted actions use the runtime area default. */\n buttonType?: PageActionButtonType\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\nexport type TabContentSchema =\n | { type: 'crud'; schema: CrudPageSchema }\n | { type: 'slot'; slot: string }\n\nexport type TabSchema = {\n key: string\n label: string\n access?: string\n /** Defaults to true so inactive CRUD pages do not fetch until selected. */\n destroyOnHidden?: boolean\n content: TabContentSchema\n}\n\n/** A page composition schema with runtime-owned tab navigation. */\nexport type TabbedPageSchema = {\n $schema: typeof TABBED_PAGE_SCHEMA_ID\n version: typeof TABBED_PAGE_SCHEMA_VERSION\n id: string\n kind: 'tabs'\n tabs: TabSchema[]\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 TABBED_PAGE_SCHEMA_ID,\n TABBED_PAGE_SCHEMA_VERSION,\n type TabbedPageSchema\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 (!condition || typeof condition !== 'object') {\n push(diagnostics, path, 'condition.type', '\u6761\u4EF6\u5FC5\u987B\u662F\u5BF9\u8C61')\n return\n }\n if (condition.operator === 'equals') {\n if (typeof condition.field !== 'string' || condition.field === '') {\n push(diagnostics, path, 'condition.field', 'equals \u6761\u4EF6\u5FC5\u987B\u6307\u5B9A\u5B57\u6BB5\u540D')\n }\n return\n }\n if (condition.operator === 'notEmpty') {\n if (typeof condition.field !== 'string' || condition.field === '') {\n push(diagnostics, path, 'condition.field', 'notEmpty \u6761\u4EF6\u5FC5\u987B\u6307\u5B9A\u5B57\u6BB5\u540D')\n }\n return\n }\n if (condition.operator === 'modeEquals') {\n return\n }\n if (\n (condition.operator === 'and' || condition.operator === 'or') &&\n !Array.isArray(condition.conditions)\n ) {\n push(diagnostics, path, 'condition.conditions', '\u7EC4\u5408\u6761\u4EF6\u5FC5\u987B\u6307\u5B9A conditions \u6570\u7EC4')\n return\n }\n if (condition.operator === 'and' || condition.operator === 'or') {\n if (condition.conditions.length === 0) {\n push(diagnostics, path, 'condition.empty', '\u7EC4\u5408\u6761\u4EF6\u81F3\u5C11\u9700\u8981\u4E00\u4E2A\u5B50\u6761\u4EF6')\n }\n condition.conditions.forEach((item, index) => {\n validateCondition(item, `${path}/conditions/${index}`, diagnostics)\n })\n return\n }\n if (condition.operator === 'not') {\n if (!condition.condition) {\n push(diagnostics, path, 'condition.missing', 'not \u6761\u4EF6\u5FC5\u987B\u6307\u5B9A condition')\n return\n }\n validateCondition(condition.condition, `${path}/condition`, diagnostics)\n return\n }\n push(diagnostics, path, 'condition.operator', `\u4E0D\u652F\u6301\u7684\u6761\u4EF6\uFF1A${(condition as { operator?: unknown }).operator}`)\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 (field.itemFields?.length)\n validateFields(\n field.itemFields as FieldSchema[],\n `${fieldPath}/itemFields`,\n registry,\n diagnostics\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?.create && registry && !registry.services[schema.dataSource.create]) {\n push(\n diagnostics,\n '/dataSource/create',\n 'registry.service',\n `\u672A\u6CE8\u518C\u670D\u52A1\uFF1A${schema.dataSource.create}`\n )\n }\n if (schema.dataSource?.update && registry && !registry.services[schema.dataSource.update]) {\n push(\n diagnostics,\n '/dataSource/update',\n 'registry.service',\n `\u672A\u6CE8\u518C\u670D\u52A1\uFF1A${schema.dataSource.update}`\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.fixed !== undefined && column.fixed !== 'left' && column.fixed !== 'right') {\n push(\n diagnostics,\n `/table/columns/${index}/fixed`,\n 'column.fixed',\n `\u4E0D\u652F\u6301\u7684\u56FA\u5B9A\u4F4D\u7F6E\uFF1A${column.fixed}`\n )\n }\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 if (schema.detail !== undefined) {\n if (\n !schema.detail ||\n typeof schema.detail !== 'object' ||\n !Array.isArray(schema.detail.fields)\n ) {\n push(diagnostics, '/detail', 'detail.type', 'detail \u5FC5\u987B\u5305\u542B fields \u5BF9\u8C61\u6570\u7EC4')\n } else {\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 }\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\nexport function validateTabbedPageSchema(\n schema: TabbedPageSchema,\n registry?: BestRegistry\n): SchemaValidationResult {\n const diagnostics: SchemaDiagnostic[] = []\n if (schema.$schema !== TABBED_PAGE_SCHEMA_ID)\n push(diagnostics, '/$schema', 'schema.id', `\u4EC5\u652F\u6301 ${TABBED_PAGE_SCHEMA_ID}`)\n if (schema.version !== TABBED_PAGE_SCHEMA_VERSION)\n push(diagnostics, '/version', 'schema.version', `\u4EC5\u652F\u6301\u7248\u672C ${TABBED_PAGE_SCHEMA_VERSION}`)\n if (!schema.id) push(diagnostics, '/id', 'page.id', '\u9875\u9762 id \u4E0D\u80FD\u4E3A\u7A7A')\n if (!Array.isArray(schema.tabs) || schema.tabs.length === 0) {\n push(diagnostics, '/tabs', 'tabs.required', '\u81F3\u5C11\u9700\u8981\u4E00\u4E2A\u9875\u7B7E')\n return { valid: false, diagnostics }\n }\n const keys = new Set<string>()\n schema.tabs.forEach((tab, index) => {\n const path = `/tabs/${index}`\n if (!tab.key) push(diagnostics, path, 'tab.key', '\u9875\u7B7E key \u4E0D\u80FD\u4E3A\u7A7A')\n if (keys.has(tab.key)) push(diagnostics, path, 'tab.duplicate', `\u9875\u7B7E key \u91CD\u590D\uFF1A${tab.key}`)\n keys.add(tab.key)\n if (!tab.label) push(diagnostics, path, 'tab.label', '\u9875\u7B7E\u6807\u9898\u4E0D\u80FD\u4E3A\u7A7A')\n if (tab.content.type === 'crud') {\n const result = validateCrudPageSchema(tab.content.schema, registry)\n diagnostics.push(...result.diagnostics.map((item) => ({ ...item, path: `${path}/content/schema${item.path}` })))\n } else if (tab.content.type === 'slot') {\n if (!tab.content.slot) push(diagnostics, path, 'tab.slot', 'slot \u9875\u7B7E\u5FC5\u987B\u6307\u5B9A slot key')\n if (tab.content.slot && registry && !registry.slots[tab.content.slot])\n push(diagnostics, path, 'registry.slot', `\u672A\u6CE8\u518C\u63D2\u69FD\uFF1A${tab.content.slot}`)\n } else {\n push(diagnostics, path, 'tab.content', '\u4E0D\u652F\u6301\u7684\u9875\u7B7E\u5185\u5BB9\u7C7B\u578B')\n }\n })\n return { valid: diagnostics.length === 0, diagnostics }\n}\n\nexport function assertValidTabbedPageSchema(schema: TabbedPageSchema, registry?: BestRegistry) {\n const result = validateTabbedPageSchema(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 {\n CRUD_SCHEMA_ID,\n TABBED_PAGE_SCHEMA_ID\n} from './schema'\nimport type {\n CRUD_SCHEMA_VERSION,\n CrudPageSchema,\n FieldSchema,\n PageActionSchema,\n TABBED_PAGE_SCHEMA_VERSION,\n TabbedPageSchema\n} from './schema'\nimport type { SchemaDiagnostic, SchemaValidationResult } from './validate'\nimport { validateCrudPageSchema, validateTabbedPageSchema } 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.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\nfunction toRuntimeTabbedSchema(candidate: JsonRecord): TabbedPageSchema {\n return {\n $schema: candidate.$schema as typeof TABBED_PAGE_SCHEMA_ID,\n version: candidate.version as typeof TABBED_PAGE_SCHEMA_VERSION,\n id: candidate.id as string,\n kind: candidate.kind as 'tabs',\n tabs: candidate.tabs as TabbedPageSchema['tabs']\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/** Validates every page schema the Runtime can render without importing React. */\nexport function validateUnknownPageSchema(candidate: unknown): SchemaValidationResult {\n if (!isRecord(candidate)) return validateUnknownCrudPageSchema(candidate)\n if (candidate.kind === 'crud' || candidate.$schema === CRUD_SCHEMA_ID) {\n return validateUnknownCrudPageSchema(candidate)\n }\n if (candidate.kind !== 'tabs' && candidate.$schema !== TABBED_PAGE_SCHEMA_ID)\n return validateUnknownCrudPageSchema(candidate)\n if (!Array.isArray(candidate.tabs) || !candidate.tabs.every(isRecord)) {\n return {\n valid: false,\n diagnostics: [diagnostic('/tabs', 'tabs.type', 'tabs \u5FC5\u987B\u662F\u5BF9\u8C61\u6570\u7EC4')]\n }\n }\n for (const [index, tab] of candidate.tabs.entries()) {\n const contentPath = `/tabs/${index}/content`\n if (!isRecord(tab.content)) {\n return {\n valid: false,\n diagnostics: [diagnostic(contentPath, 'tabs.content', 'tab content \u5FC5\u987B\u662F CRUD \u6216 Slot')]\n }\n }\n if (tab.content.type !== 'crud' && tab.content.type !== 'slot') {\n return {\n valid: false,\n diagnostics: [diagnostic(`${contentPath}/type`, 'tabs.content', 'tab content \u5FC5\u987B\u662F CRUD \u6216 Slot')]\n }\n }\n if (tab.content.type === 'crud' && !isRecord(tab.content.schema)) {\n return {\n valid: false,\n diagnostics: [diagnostic(`${contentPath}/schema`, 'tabs.content', 'CRUD tab \u5FC5\u987B\u63D0\u4F9B\u5BF9\u8C61 schema')]\n }\n }\n if (tab.content.type === 'crud') {\n const result = validateUnknownCrudPageSchema(tab.content.schema)\n if (!result.valid) {\n return {\n valid: false,\n diagnostics: result.diagnostics.map((item) => ({\n ...item,\n path: `${contentPath}/schema${item.path}`\n }))\n }\n }\n }\n }\n return validateTabbedPageSchema(toRuntimeTabbedSchema(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
6
  "names": []
7
7
  }
package/dist/index.js CHANGED
@@ -35,11 +35,11 @@ function createBestCrudAdapter(options = {}) {
35
35
  // src/lowcode/BestCrudPage.tsx
36
36
  import { Button as Button4, Modal as Modal2, message } from "antd";
37
37
  import dayjs5 from "dayjs";
38
- import { useCallback, useEffect as useEffect3, useLayoutEffect, useMemo as useMemo5, useRef as useRef3, useState as useState3 } from "react";
38
+ import { useCallback as useCallback2, useEffect as useEffect3, useLayoutEffect, useMemo as useMemo5, useRef as useRef3, useState as useState4 } from "react";
39
39
 
40
40
  // src/runtime/BestProvider.tsx
41
41
  import { ConfigProvider } from "antd";
42
- import { createContext, useContext, useMemo } from "react";
42
+ import { createContext, useCallback, useContext, useMemo, useState } from "react";
43
43
  import { jsx } from "react/jsx-runtime";
44
44
  var emptyRegistry = {
45
45
  listServices: {},
@@ -57,6 +57,7 @@ var defaultTheme = {
57
57
  }
58
58
  };
59
59
  var BestRuntimeContext = createContext(emptyRegistry);
60
+ var BestDictionaryActionsContext = createContext(null);
60
61
  function composeBestRegistry(...layers) {
61
62
  const result = {
62
63
  listServices: {},
@@ -87,12 +88,20 @@ function createBestRegistry(registry = {}) {
87
88
  return composeBestRegistry(registry);
88
89
  }
89
90
  function BestProvider({ children, registry, theme }) {
90
- const value = useMemo(() => createBestRegistry(registry), [registry]);
91
+ const [dictionaryUpdates, setDictionaryUpdates] = useState({});
92
+ const setDictionary = useCallback((key, items) => {
93
+ setDictionaryUpdates((current) => ({ ...current, [key]: items }));
94
+ }, []);
95
+ const value = useMemo(() => {
96
+ const next = createBestRegistry(registry);
97
+ Object.assign(next.dictionaries, dictionaryUpdates);
98
+ return next;
99
+ }, [dictionaryUpdates, registry]);
91
100
  const mergedTheme = useMemo(
92
101
  () => ({ ...defaultTheme, ...theme, token: { ...defaultTheme.token, ...theme?.token } }),
93
102
  [theme]
94
103
  );
95
- return /* @__PURE__ */ jsx(BestRuntimeContext.Provider, { value, children: /* @__PURE__ */ jsx(ConfigProvider, { theme: mergedTheme, children }) });
104
+ return /* @__PURE__ */ jsx(BestRuntimeContext.Provider, { value, children: /* @__PURE__ */ jsx(ConfigProvider, { theme: mergedTheme, children: /* @__PURE__ */ jsx(BestDictionaryActionsContext.Provider, { value: { setDictionary }, children }) }) });
96
105
  }
97
106
  function useBestRegistry() {
98
107
  return useContext(BestRuntimeContext);
@@ -113,6 +122,11 @@ function useBestDictionary(key) {
113
122
  const dictionaries = useBestRegistry().dictionaries;
114
123
  return key ? dictionaries[key] ?? [] : [];
115
124
  }
125
+ function useBestDictionaryActions() {
126
+ const actions = useContext(BestDictionaryActionsContext);
127
+ if (!actions) throw new Error("useBestDictionaryActions \u5FC5\u987B\u5728 BestProvider \u5185\u4F7F\u7528");
128
+ return actions;
129
+ }
116
130
  function useBestAction(key) {
117
131
  const action = useBestRegistry().actions[key];
118
132
  if (!action) throw new Error(`\u672A\u6CE8\u518C\u52A8\u4F5C\uFF1A${key}`);
@@ -121,7 +135,7 @@ function useBestAction(key) {
121
135
 
122
136
  // src/ui/BestBatchInput.tsx
123
137
  import { Input } from "antd";
124
- import { useImperativeHandle, useMemo as useMemo2, useState } from "react";
138
+ import { useImperativeHandle, useMemo as useMemo2, useState as useState2 } from "react";
125
139
  import { jsx as jsx2 } from "react/jsx-runtime";
126
140
  function parse(value, separator) {
127
141
  const escaped = separator.replace(/[\\\]\-^]/g, "\\$&");
@@ -136,7 +150,7 @@ function BestBatchInput({
136
150
  onChange,
137
151
  ...props
138
152
  }) {
139
- const [innerValue, setInnerValue] = useState(String(defaultValue ?? ""));
153
+ const [innerValue, setInnerValue] = useState2(String(defaultValue ?? ""));
140
154
  const currentValue = value == null ? innerValue : String(value);
141
155
  const parsed = useMemo2(() => parse(currentValue, separator), [currentValue, separator]);
142
156
  useImperativeHandle(ref, () => ({ getParsedValue: () => parsed }), [parsed]);
@@ -204,7 +218,7 @@ function BestFilePreview({ files, onDownload }) {
204
218
  // src/ui/BestForm.tsx
205
219
  import { Button as Button2, DatePicker, Form, Input as Input2, InputNumber, Select, Space } from "antd";
206
220
  import dayjs2 from "dayjs";
207
- import { useEffect, useMemo as useMemo3, useRef, useState as useState2 } from "react";
221
+ import { useEffect, useMemo as useMemo3, useRef, useState as useState3 } from "react";
208
222
  import { Fragment, jsx as jsx5, jsxs as jsxs2 } from "react/jsx-runtime";
209
223
  function toNamePath(path) {
210
224
  return path === void 0 ? [] : Array.isArray(path) ? path : [path];
@@ -571,10 +585,10 @@ function RemoteSelect({
571
585
  onChange,
572
586
  registry
573
587
  }) {
574
- const [keywordOptions, setKeywordOptions] = useState2([]);
575
- const [selectedOptions, setSelectedOptions] = useState2([]);
576
- const [loading, setLoading] = useState2(false);
577
- const [keyword, setKeyword] = useState2("");
588
+ const [keywordOptions, setKeywordOptions] = useState3([]);
589
+ const [selectedOptions, setSelectedOptions] = useState3([]);
590
+ const [loading, setLoading] = useState3(false);
591
+ const [keyword, setKeyword] = useState3("");
578
592
  const keywordRequestId = useRef(0);
579
593
  const selectedRequestId = useRef(0);
580
594
  const service = field.remoteService ? registry.services[field.remoteService] : void 0;
@@ -1637,7 +1651,7 @@ function BestCrudPage({ adapter, className, schema }) {
1637
1651
  assertValidCrudPageSchema(schema, registry);
1638
1652
  const registeredListService = useBestListService(schema.dataSource.list);
1639
1653
  if (!registeredListService) throw new Error(`\u672A\u6CE8\u518C\u5217\u8868\u670D\u52A1\uFF1A${schema.dataSource.list}`);
1640
- const listService = useCallback(
1654
+ const listService = useCallback2(
1641
1655
  async (query2, options) => {
1642
1656
  const response = await registeredListService(query2, options);
1643
1657
  return adapter?.fromList ? { ...response, items: adapter.fromList(response.items) } : response;
@@ -1663,17 +1677,17 @@ function BestCrudPage({ adapter, className, schema }) {
1663
1677
  ),
1664
1678
  [searchFields]
1665
1679
  );
1666
- const [query, setQuery] = useState3(searchDefaultValues);
1680
+ const [query, setQuery] = useState4(searchDefaultValues);
1667
1681
  const queryRef = useRef3(searchDefaultValues);
1668
1682
  const queryStateRef = useRef3({
1669
1683
  schemaId: schema.id,
1670
1684
  searchSchemaSignature,
1671
1685
  userTouched: false
1672
1686
  });
1673
- const [drawer, setDrawer] = useState3({ mode: "closed" });
1674
- const [submitting, setSubmitting] = useState3(false);
1687
+ const [drawer, setDrawer] = useState4({ mode: "closed" });
1688
+ const [submitting, setSubmitting] = useState4(false);
1675
1689
  const submittingRef = useRef3(false);
1676
- const handleAction = useCallback(
1690
+ const handleAction = useCallback2(
1677
1691
  async (action, record) => {
1678
1692
  if (action.access && !registry.access(action.access)) return;
1679
1693
  if (action.effect !== "remove" && !await confirmBeforeAction(action.confirm, confirmAction))
@@ -1781,7 +1795,7 @@ function BestCrudPage({ adapter, className, schema }) {
1781
1795
  [listService, schema.title]
1782
1796
  );
1783
1797
  const rowKey = schema.table.rowKey;
1784
- const request = useCallback(
1798
+ const request = useCallback2(
1785
1799
  (params, sort) => pageRequest.request(
1786
1800
  toBestListQuery({ ...params, ...useBestSearch ? queryRef.current : {} }, sort)
1787
1801
  ),
@@ -1804,7 +1818,7 @@ function BestCrudPage({ adapter, className, schema }) {
1804
1818
  };
1805
1819
  }, [schema.id, searchDefaultValues, searchFieldNames, searchSchemaSignature]);
1806
1820
  useEffect3(() => () => pageRequest.abort(), [pageRequest]);
1807
- const submitForm = useCallback(
1821
+ const submitForm = useCallback2(
1808
1822
  async (values) => {
1809
1823
  if (submittingRef.current) return;
1810
1824
  const serviceKey = drawer.mode === "edit" ? schema.dataSource.update : schema.dataSource.create;
@@ -1979,6 +1993,7 @@ export {
1979
1993
  useBestAccess,
1980
1994
  useBestAction,
1981
1995
  useBestDictionary,
1996
+ useBestDictionaryActions,
1982
1997
  useBestListService,
1983
1998
  useBestRegistry,
1984
1999
  useBestService,