@nocobase/flow-engine 2.0.0-alpha.67 → 2.0.0-alpha.69

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.
Files changed (89) hide show
  1. package/lib/BlockScopedFlowEngine.js +0 -1
  2. package/lib/ViewScopedFlowEngine.js +3 -0
  3. package/lib/components/variables/VariableInput.js +8 -2
  4. package/lib/data-source/index.js +3 -0
  5. package/lib/flowContext.d.ts +64 -0
  6. package/lib/flowContext.js +138 -64
  7. package/lib/flowEngine.d.ts +21 -0
  8. package/lib/flowEngine.js +38 -0
  9. package/lib/index.d.ts +5 -1
  10. package/lib/index.js +18 -0
  11. package/lib/models/flowModel.js +12 -1
  12. package/lib/provider.js +5 -5
  13. package/lib/resources/baseRecordResource.d.ts +5 -0
  14. package/lib/resources/baseRecordResource.js +24 -0
  15. package/lib/resources/multiRecordResource.d.ts +1 -0
  16. package/lib/resources/multiRecordResource.js +11 -4
  17. package/lib/resources/singleRecordResource.js +2 -0
  18. package/lib/resources/sqlResource.d.ts +1 -0
  19. package/lib/resources/sqlResource.js +8 -3
  20. package/lib/runjs-context/contexts/FormJSFieldItemRunJSContext.js +12 -2
  21. package/lib/runjs-context/contexts/JSBlockRunJSContext.js +2 -2
  22. package/lib/runjs-context/contexts/JSEditableFieldRunJSContext.d.ts +16 -0
  23. package/lib/runjs-context/contexts/JSEditableFieldRunJSContext.js +125 -0
  24. package/lib/runjs-context/contexts/JSItemRunJSContext.js +12 -2
  25. package/lib/runjs-context/contexts/base.js +691 -23
  26. package/lib/runjs-context/contributions.d.ts +33 -0
  27. package/lib/runjs-context/contributions.js +88 -0
  28. package/lib/runjs-context/setup.js +6 -0
  29. package/lib/runjs-context/snippets/index.d.ts +11 -1
  30. package/lib/runjs-context/snippets/index.js +61 -40
  31. package/lib/runjsLibs.d.ts +13 -0
  32. package/lib/runjsLibs.js +309 -0
  33. package/lib/utils/createCollectionContextMeta.js +1 -0
  34. package/lib/utils/index.d.ts +1 -0
  35. package/lib/utils/index.js +5 -0
  36. package/lib/utils/resolveModuleUrl.d.ts +58 -0
  37. package/lib/utils/resolveModuleUrl.js +65 -0
  38. package/lib/utils/runjsModuleLoader.d.ts +58 -0
  39. package/lib/utils/runjsModuleLoader.js +422 -0
  40. package/lib/utils/safeGlobals.d.ts +5 -9
  41. package/lib/utils/safeGlobals.js +129 -17
  42. package/lib/views/useDialog.js +7 -1
  43. package/lib/views/useDrawer.js +7 -1
  44. package/lib/views/usePage.js +10 -1
  45. package/lib/views/viewEvents.d.ts +17 -0
  46. package/lib/views/viewEvents.js +90 -0
  47. package/package.json +4 -4
  48. package/src/BlockScopedFlowEngine.ts +2 -5
  49. package/src/ViewScopedFlowEngine.ts +4 -0
  50. package/src/__tests__/flowContext.test.ts +12 -0
  51. package/src/__tests__/flowEngine.dataSourceDirty.test.ts +63 -0
  52. package/src/__tests__/runjsContext.test.ts +4 -1
  53. package/src/__tests__/runjsExternalLibs.test.ts +242 -0
  54. package/src/__tests__/runjsLocales.test.ts +4 -1
  55. package/src/components/variables/VariableInput.tsx +8 -2
  56. package/src/data-source/index.ts +3 -0
  57. package/src/flowContext.ts +226 -65
  58. package/src/flowEngine.ts +41 -0
  59. package/src/index.ts +12 -1
  60. package/src/models/flowModel.tsx +13 -1
  61. package/src/provider.tsx +7 -6
  62. package/src/resources/__tests__/multiRecordResource.test.ts +44 -0
  63. package/src/resources/__tests__/sqlResource.test.ts +60 -0
  64. package/src/resources/baseRecordResource.ts +31 -0
  65. package/src/resources/multiRecordResource.ts +11 -4
  66. package/src/resources/singleRecordResource.ts +3 -0
  67. package/src/resources/sqlResource.ts +8 -3
  68. package/src/runjs-context/contexts/FormJSFieldItemRunJSContext.ts +10 -0
  69. package/src/runjs-context/contexts/JSBlockRunJSContext.ts +6 -2
  70. package/src/runjs-context/contexts/JSEditableFieldRunJSContext.ts +106 -0
  71. package/src/runjs-context/contexts/JSItemRunJSContext.ts +10 -0
  72. package/src/runjs-context/contexts/base.ts +698 -30
  73. package/src/runjs-context/contributions.ts +88 -0
  74. package/src/runjs-context/setup.ts +6 -0
  75. package/src/runjs-context/snippets/index.ts +75 -41
  76. package/src/runjsLibs.ts +404 -0
  77. package/src/utils/__tests__/runjsRequireAsyncAutoWhitelist.test.ts +38 -0
  78. package/src/utils/__tests__/safeGlobals.test.ts +49 -2
  79. package/src/utils/createCollectionContextMeta.ts +1 -0
  80. package/src/utils/index.ts +3 -0
  81. package/src/utils/resolveModuleUrl.ts +91 -0
  82. package/src/utils/runjsModuleLoader.ts +553 -0
  83. package/src/utils/safeGlobals.ts +133 -16
  84. package/src/views/__tests__/useDialog.closeDestroy.test.tsx +35 -4
  85. package/src/views/__tests__/viewEvents.resolveOpenerEngine.test.ts +28 -0
  86. package/src/views/useDialog.tsx +8 -0
  87. package/src/views/useDrawer.tsx +8 -0
  88. package/src/views/usePage.tsx +13 -0
  89. package/src/views/viewEvents.ts +55 -0
@@ -37,7 +37,6 @@ function createBlockScopedEngine(parent) {
37
37
  local.setModelRepository(parent.modelRepository);
38
38
  }
39
39
  local.context.addDelegate(parent.context);
40
- const originalUnlink = local.unlinkFromStack.bind(local);
41
40
  local.unlinkFromStack = function() {
42
41
  const prev = local._previousEngine;
43
42
  const next = local._nextEngine;
@@ -31,8 +31,10 @@ __export(ViewScopedFlowEngine_exports, {
31
31
  });
32
32
  module.exports = __toCommonJS(ViewScopedFlowEngine_exports);
33
33
  var import_flowEngine = require("./flowEngine");
34
+ var import_viewEvents = require("./views/viewEvents");
34
35
  function createViewScopedEngine(parent) {
35
36
  const local = new import_flowEngine.FlowEngine();
37
+ Object.defineProperty(local, import_viewEvents.ENGINE_SCOPE_KEY, { value: import_viewEvents.VIEW_ENGINE_SCOPE, configurable: true });
36
38
  if (parent.modelRepository) {
37
39
  local.setModelRepository(parent.modelRepository);
38
40
  }
@@ -48,6 +50,7 @@ function createViewScopedEngine(parent) {
48
50
  "_applyFlowCache",
49
51
  "executor",
50
52
  "context",
53
+ import_viewEvents.ENGINE_SCOPE_KEY,
51
54
  "previousEngine",
52
55
  "nextEngine",
53
56
  // 调度器与事件总线局部化
@@ -230,12 +230,18 @@ const VariableInputComponent = /* @__PURE__ */ __name(({
230
230
  );
231
231
  const handleVariableSelect = (0, import_react.useCallback)(
232
232
  (variableValue, metaTreeNode) => {
233
+ if (!metaTreeNode && variableValue === "") {
234
+ const cleared = clearValue !== void 0 ? clearValue : null;
235
+ setInnerValue(cleared);
236
+ emitChange(cleared);
237
+ return;
238
+ }
233
239
  setCurrentMetaTreeNode(metaTreeNode);
234
240
  const finalValue = (resolveValueFromPath == null ? void 0 : resolveValueFromPath(metaTreeNode)) || variableValue;
235
241
  setInnerValue(finalValue);
236
242
  emitChange(finalValue, metaTreeNode);
237
243
  },
238
- [emitChange, resolveValueFromPath]
244
+ [emitChange, resolveValueFromPath, clearValue]
239
245
  );
240
246
  const { disabled } = restProps;
241
247
  const handleClear = (0, import_react.useCallback)(() => {
@@ -265,7 +271,7 @@ const VariableInputComponent = /* @__PURE__ */ __name(({
265
271
  }, [restProps]);
266
272
  const inputProps = (0, import_react.useMemo)(() => {
267
273
  const baseProps = {
268
- value: innerValue ?? "",
274
+ value: ValueComponent === import_antd.Input ? innerValue ?? "" : innerValue,
269
275
  onChange: handleInputChange,
270
276
  disabled
271
277
  };
@@ -400,6 +400,9 @@ const _Collection = class _Collection {
400
400
  if (typeof this.filterTargetKey === "string") {
401
401
  return record[this.filterTargetKey];
402
402
  }
403
+ if (Array.isArray(this.filterTargetKey) && this.filterTargetKey.length === 1) {
404
+ return record[this.filterTargetKey[0]];
405
+ }
403
406
  return import_lodash.default.pick(record, this.filterTargetKey);
404
407
  }
405
408
  get titleableFields() {
@@ -31,6 +31,7 @@ export interface MetaTreeNode {
31
31
  title: string;
32
32
  type: string;
33
33
  interface?: string;
34
+ options?: any;
34
35
  uiSchema?: ISchema;
35
36
  render?: (props: any) => JSX.Element;
36
37
  paths: string[];
@@ -44,6 +45,7 @@ export interface PropertyMeta {
44
45
  type: string;
45
46
  title: string;
46
47
  interface?: string;
48
+ options?: any;
47
49
  uiSchema?: ISchema;
48
50
  render?: (props: any) => JSX.Element;
49
51
  sort?: number;
@@ -141,6 +143,29 @@ export declare class FlowContext {
141
143
  * @returns 属性定义选项,或 undefined(未定义)
142
144
  */
143
145
  getPropertyOptions(key: string): PropertyOptions | undefined;
146
+ /**
147
+ * 获取当前上下文可用的顶层 API 信息(主要用于编辑器补全/工具)。
148
+ *
149
+ * 注意:
150
+ * - 目前返回值以“尽量可用”为目标,允许不完整。
151
+ * - 该方法不会展开变量 meta(变量结构应由 `getPropertyMetaTree()`/VariableInput 等机制负责)。
152
+ */
153
+ getApiInfos(options?: {
154
+ version?: string;
155
+ }): Promise<Record<string, any>>;
156
+ /**
157
+ * 变量结构信息(保留给编辑器/工具使用)。
158
+ * 当前实现为保底空对象,避免 RunJS doc 中补全到该方法时调用报错。
159
+ */
160
+ getVarInfos(_options?: {
161
+ path?: string | string[];
162
+ maxDepth?: number;
163
+ }): Promise<Record<string, any>>;
164
+ /**
165
+ * 运行时环境信息(保留给编辑器/工具使用)。
166
+ * 当前实现为保底空对象,避免 RunJS doc 中补全到该方法时调用报错。
167
+ */
168
+ getEnvInfos(): Promise<Record<string, any>>;
144
169
  }
145
170
  declare class BaseFlowEngineContext extends FlowContext {
146
171
  router: Router;
@@ -156,6 +181,7 @@ declare class BaseFlowEngineContext extends FlowContext {
156
181
  */
157
182
  renderJson: (template: JSONValue) => Promise<any>;
158
183
  resolveJsonTemplate: (template: JSONValue) => Promise<any>;
184
+ getVar: (path: string) => Promise<any>;
159
185
  runjs: (code: string, variables?: Record<string, any>, options?: JSRunnerOptions) => Promise<any>;
160
186
  getAction: <TModel extends FlowModel = FlowModel, TCtx extends FlowContext = FlowContext>(name: string) => ActionDefinition<TModel, TCtx> | undefined;
161
187
  getActions: <TModel extends FlowModel = FlowModel, TCtx extends FlowContext = FlowContext>() => Map<string, ActionDefinition<TModel, TCtx>>;
@@ -217,22 +243,60 @@ export declare class FlowRuntimeContext<TModel extends FlowModel = FlowModel, TM
217
243
  get mode(): TMode;
218
244
  }
219
245
  export type FlowSettingsContext<TModel extends FlowModel = FlowModel> = FlowRuntimeContext<TModel, 'settings'>;
246
+ export type FlowContextDocRef = string | {
247
+ url: string;
248
+ title?: string;
249
+ };
250
+ export type FlowDeprecationDoc = boolean | {
251
+ message?: string;
252
+ replacedBy?: string | string[];
253
+ since?: string;
254
+ removedIn?: string;
255
+ ref?: FlowContextDocRef;
256
+ };
257
+ export type FlowContextDocParam = {
258
+ name: string;
259
+ description?: string;
260
+ type?: string;
261
+ optional?: boolean;
262
+ default?: JSONValue;
263
+ };
264
+ export type FlowContextDocReturn = {
265
+ description?: string;
266
+ type?: string;
267
+ };
220
268
  export type RunJSDocCompletionDoc = {
221
269
  insertText?: string;
222
270
  };
271
+ export type RunJSDocHiddenDoc = boolean | ((ctx: any) => boolean | Promise<boolean>);
272
+ export type RunJSDocHiddenOrPathsDoc = boolean | string[] | ((ctx: any) => boolean | string[] | Promise<boolean | string[]>);
223
273
  export type RunJSDocPropertyDoc = string | {
224
274
  description?: string;
225
275
  detail?: string;
226
276
  type?: string;
227
277
  examples?: string[];
228
278
  completion?: RunJSDocCompletionDoc;
279
+ ref?: FlowContextDocRef;
280
+ deprecated?: FlowDeprecationDoc;
281
+ params?: FlowContextDocParam[];
282
+ returns?: FlowContextDocReturn;
229
283
  properties?: Record<string, RunJSDocPropertyDoc>;
284
+ hidden?: RunJSDocHiddenOrPathsDoc;
285
+ disabled?: boolean | ((ctx: any) => boolean | Promise<boolean>);
286
+ disabledReason?: string | ((ctx: any) => string | undefined | Promise<string | undefined>);
230
287
  };
231
288
  export type RunJSDocMethodDoc = string | {
232
289
  description?: string;
233
290
  detail?: string;
234
291
  examples?: string[];
235
292
  completion?: RunJSDocCompletionDoc;
293
+ ref?: FlowContextDocRef;
294
+ deprecated?: FlowDeprecationDoc;
295
+ params?: FlowContextDocParam[];
296
+ returns?: FlowContextDocReturn;
297
+ hidden?: RunJSDocHiddenDoc;
298
+ disabled?: boolean | ((ctx: any) => boolean | Promise<boolean>);
299
+ disabledReason?: string | ((ctx: any) => string | undefined | Promise<string | undefined>);
236
300
  };
237
301
  export type RunJSDocMeta = {
238
302
  label?: string;
@@ -78,6 +78,7 @@ var import_registry = require("./runjs-context/registry");
78
78
  var import_createEphemeralContext = require("./utils/createEphemeralContext");
79
79
  var import_dayjs = __toESM(require("dayjs"));
80
80
  var import_runjsLibs = require("./runjsLibs");
81
+ var import_runjsModuleLoader = require("./utils/runjsModuleLoader");
81
82
  var _proxy, _FlowContext_instances, createChildNodes_fn, findMetaByPath_fn, findMetaInDelegatesDeep_fn, findMetaInProperty_fn, resolvePathInMeta_fn, resolvePathInMetaAsync_fn, buildParentTitles_fn, toTreeNode_fn;
82
83
  function isRecordRefLike(val) {
83
84
  return !!(val && typeof val === "object" && "collection" in val && "filterByTk" in val);
@@ -468,6 +469,73 @@ const _FlowContext = class _FlowContext {
468
469
  }
469
470
  return this._findPropertyInDelegates(this._delegates, key);
470
471
  }
472
+ /**
473
+ * 获取当前上下文可用的顶层 API 信息(主要用于编辑器补全/工具)。
474
+ *
475
+ * 注意:
476
+ * - 目前返回值以“尽量可用”为目标,允许不完整。
477
+ * - 该方法不会展开变量 meta(变量结构应由 `getPropertyMetaTree()`/VariableInput 等机制负责)。
478
+ */
479
+ async getApiInfos(options = {}) {
480
+ var _a, _b, _c, _d, _e;
481
+ const version = (options == null ? void 0 : options.version) || "v1";
482
+ const modelClass = (0, import_registry.getModelClassName)(this);
483
+ const Ctor = import_registry.RunJSContextRegistry.resolve(version, modelClass) || import_registry.RunJSContextRegistry.resolve(version, "*");
484
+ const locale = ((_b = (_a = this == null ? void 0 : this.api) == null ? void 0 : _a.auth) == null ? void 0 : _b.locale) || ((_c = this == null ? void 0 : this.i18n) == null ? void 0 : _c.language) || (this == null ? void 0 : this.locale);
485
+ let doc = {};
486
+ try {
487
+ if ((_d = Ctor == null ? void 0 : Ctor.getDoc) == null ? void 0 : _d.length) doc = Ctor.getDoc(locale) || {};
488
+ else doc = ((_e = Ctor == null ? void 0 : Ctor.getDoc) == null ? void 0 : _e.call(Ctor)) || {};
489
+ } catch (_2) {
490
+ doc = {};
491
+ }
492
+ const isPrivateKey = /* @__PURE__ */ __name((key) => typeof key === "string" && key.startsWith("_"), "isPrivateKey");
493
+ const out = {};
494
+ const visited = /* @__PURE__ */ new WeakSet();
495
+ const walk = /* @__PURE__ */ __name((ctx) => {
496
+ if (!ctx || visited.has(ctx)) return;
497
+ visited.add(ctx);
498
+ try {
499
+ for (const key of Object.keys(ctx._props || {})) {
500
+ if (isPrivateKey(key)) continue;
501
+ if (typeof out[key] === "undefined") out[key] = { type: "property" };
502
+ }
503
+ } catch (_2) {
504
+ }
505
+ try {
506
+ for (const key of Object.keys(ctx._methods || {})) {
507
+ if (isPrivateKey(key)) continue;
508
+ if (typeof out[key] === "undefined") out[key] = { type: "function" };
509
+ }
510
+ } catch (_2) {
511
+ }
512
+ try {
513
+ const delegates = Array.isArray(ctx._delegates) ? ctx._delegates : [];
514
+ for (const d of delegates) walk(d);
515
+ } catch (_2) {
516
+ }
517
+ }, "walk");
518
+ walk(this);
519
+ return {
520
+ ...out,
521
+ ...(doc == null ? void 0 : doc.properties) || {},
522
+ ...(doc == null ? void 0 : doc.methods) || {}
523
+ };
524
+ }
525
+ /**
526
+ * 变量结构信息(保留给编辑器/工具使用)。
527
+ * 当前实现为保底空对象,避免 RunJS doc 中补全到该方法时调用报错。
528
+ */
529
+ async getVarInfos(_options = {}) {
530
+ return {};
531
+ }
532
+ /**
533
+ * 运行时环境信息(保留给编辑器/工具使用)。
534
+ * 当前实现为保底空对象,避免 RunJS doc 中补全到该方法时调用报错。
535
+ */
536
+ async getEnvInfos() {
537
+ return {};
538
+ }
471
539
  };
472
540
  _proxy = new WeakMap();
473
541
  _FlowContext_instances = new WeakSet();
@@ -652,6 +720,7 @@ toTreeNode_fn = /* @__PURE__ */ __name(function(name, metaOrFactory, paths = [na
652
720
  type: "object",
653
721
  // 初始类型
654
722
  interface: void 0,
723
+ options: void 0,
655
724
  uiSchema: void 0,
656
725
  paths,
657
726
  parentTitles: parentTitles.length > 0 ? parentTitles : void 0,
@@ -680,6 +749,7 @@ toTreeNode_fn = /* @__PURE__ */ __name(function(name, metaOrFactory, paths = [na
680
749
  node.title = finalTitle;
681
750
  node.type = meta == null ? void 0 : meta.type;
682
751
  node.interface = meta == null ? void 0 : meta.interface;
752
+ node.options = meta == null ? void 0 : meta.options;
683
753
  node.uiSchema = meta == null ? void 0 : meta.uiSchema;
684
754
  if (!(meta == null ? void 0 : meta.properties)) return [];
685
755
  const childNodes = __privateMethod(this, _FlowContext_instances, createChildNodes_fn).call(this, meta.properties, paths, [...parentTitles, finalTitle], meta);
@@ -700,6 +770,7 @@ toTreeNode_fn = /* @__PURE__ */ __name(function(name, metaOrFactory, paths = [na
700
770
  title: nodeTitle,
701
771
  type: metaOrFactory.type,
702
772
  interface: metaOrFactory.interface,
773
+ options: metaOrFactory.options,
703
774
  uiSchema: metaOrFactory.uiSchema,
704
775
  paths,
705
776
  parentTitles: parentTitles.length > 0 ? parentTitles : void 0,
@@ -911,6 +982,19 @@ const _FlowEngineContext = class _FlowEngineContext extends BaseFlowEngineContex
911
982
  }
912
983
  return (0, import_utils.resolveExpressions)(serverResolved, this);
913
984
  });
985
+ this.defineMethod(
986
+ "getVar",
987
+ async function(varPath) {
988
+ const raw = typeof varPath === "string" ? varPath : String(varPath ?? "");
989
+ const s = raw.trim();
990
+ if (!s) return void 0;
991
+ if (s !== "ctx" && !s.startsWith("ctx.")) {
992
+ throw new Error(`ctx.getVar(path) expects an expression starting with "ctx.", got: "${s}"`);
993
+ }
994
+ return this.resolveJsonTemplate(`{{ ${s} }}`);
995
+ },
996
+ 'Resolve a ctx expression value by path (expression starts with "ctx.").'
997
+ );
914
998
  this.defineProperty("requirejs", {
915
999
  get: /* @__PURE__ */ __name(() => {
916
1000
  var _a, _b;
@@ -1000,7 +1084,8 @@ const _FlowEngineContext = class _FlowEngineContext extends BaseFlowEngineContex
1000
1084
  user: this.user
1001
1085
  }), "get")
1002
1086
  });
1003
- this.defineMethod("loadCSS", async (url) => {
1087
+ this.defineMethod("loadCSS", async (href) => {
1088
+ const url = (0, import_utils.resolveModuleUrl)(href);
1004
1089
  return new Promise((resolve, reject) => {
1005
1090
  const existingLink = document.querySelector(`link[href="${url}"]`);
1006
1091
  if (existingLink) {
@@ -1016,51 +1101,14 @@ const _FlowEngineContext = class _FlowEngineContext extends BaseFlowEngineContex
1016
1101
  });
1017
1102
  });
1018
1103
  this.defineMethod("requireAsync", async (url) => {
1019
- return new Promise((resolve, reject) => {
1020
- if (!this.requirejs) {
1021
- reject(new Error("requirejs is not available"));
1022
- return;
1023
- }
1024
- this.requirejs(
1025
- [url],
1026
- (...args) => {
1027
- resolve(args[0]);
1028
- },
1029
- reject
1030
- );
1031
- });
1104
+ const u = (0, import_utils.resolveModuleUrl)(url, { raw: true });
1105
+ return await (0, import_runjsModuleLoader.runjsRequireAsync)(this.requirejs, u);
1032
1106
  });
1033
- this.defineMethod("importAsync", async (url) => {
1034
- if (!url || typeof url !== "string") {
1035
- throw new Error("invalid url");
1107
+ this.defineMethod("importAsync", async function(url) {
1108
+ if ((0, import_utils.isCssFile)(url)) {
1109
+ return this.loadCSS(url);
1036
1110
  }
1037
- const u = url.trim();
1038
- const g = globalThis;
1039
- g.__nocobaseImportAsyncCache = g.__nocobaseImportAsyncCache || /* @__PURE__ */ new Map();
1040
- const cache = g.__nocobaseImportAsyncCache;
1041
- if (cache.has(u)) return cache.get(u);
1042
- const nativeImport = /* @__PURE__ */ __name(() => import(
1043
- /* @vite-ignore */
1044
- /* webpackIgnore: true */
1045
- u
1046
- ), "nativeImport");
1047
- const evalImport = /* @__PURE__ */ __name(() => {
1048
- const importer = (0, eval)("u => import(u)");
1049
- return importer(u);
1050
- }, "evalImport");
1051
- const p = (async () => {
1052
- try {
1053
- return await nativeImport();
1054
- } catch (err) {
1055
- try {
1056
- return await evalImport();
1057
- } catch (err2) {
1058
- throw err2 || err;
1059
- }
1060
- }
1061
- })();
1062
- cache.set(u, p);
1063
- return p;
1111
+ return await (0, import_runjsModuleLoader.runjsImportModule)(this, url, { importer: import_runjsModuleLoader.runjsImportAsync });
1064
1112
  });
1065
1113
  this.defineMethod("createJSRunner", async function(options) {
1066
1114
  try {
@@ -1389,6 +1437,7 @@ const _FlowRunJSContext = class _FlowRunJSContext extends FlowContext {
1389
1437
  return this.engine.reactView.createRoot(realContainer, options);
1390
1438
  }, "createRoot")
1391
1439
  };
1440
+ ReactDOMShim.__nbRunjsInternalShim = true;
1392
1441
  this.defineProperty("ReactDOM", { value: ReactDOMShim });
1393
1442
  (0, import_runjsLibs.setupRunJSLibs)(this);
1394
1443
  this.defineMethod(
@@ -1400,39 +1449,64 @@ const _FlowRunJSContext = class _FlowRunJSContext extends FlowContext {
1400
1449
  const globalRef = globalThis;
1401
1450
  globalRef.__nbRunjsRoots = globalRef.__nbRunjsRoots || /* @__PURE__ */ new WeakMap();
1402
1451
  const rootMap = globalRef.__nbRunjsRoots;
1403
- if (typeof vnode === "string") {
1404
- const existingRoot = rootMap.get(containerEl);
1405
- if (existingRoot && typeof existingRoot.unmount === "function") {
1452
+ const disposeEntry = /* @__PURE__ */ __name((entry2) => {
1453
+ if (!entry2) return;
1454
+ if (entry2.disposeTheme && typeof entry2.disposeTheme === "function") {
1406
1455
  try {
1407
- existingRoot.unmount();
1408
- } finally {
1409
- rootMap.delete(containerEl);
1456
+ entry2.disposeTheme();
1457
+ } catch (_2) {
1458
+ }
1459
+ entry2.disposeTheme = void 0;
1460
+ }
1461
+ const root = entry2.root || entry2;
1462
+ if (root && typeof root.unmount === "function") {
1463
+ try {
1464
+ root.unmount();
1465
+ } catch (_2) {
1410
1466
  }
1411
1467
  }
1468
+ }, "disposeEntry");
1469
+ const unmountContainerRoot = /* @__PURE__ */ __name(() => {
1470
+ const existing = rootMap.get(containerEl);
1471
+ if (existing) {
1472
+ disposeEntry(existing);
1473
+ rootMap.delete(containerEl);
1474
+ }
1475
+ }, "unmountContainerRoot");
1476
+ if (typeof vnode === "string") {
1477
+ unmountContainerRoot();
1412
1478
  const proxy = new import_ElementProxy.ElementProxy(containerEl);
1413
1479
  proxy.innerHTML = String(vnode ?? "");
1414
1480
  return null;
1415
1481
  }
1416
1482
  if (vnode && vnode.nodeType && (vnode.nodeType === 1 || vnode.nodeType === 3 || vnode.nodeType === 11)) {
1417
- const existingRoot = rootMap.get(containerEl);
1418
- if (existingRoot && typeof existingRoot.unmount === "function") {
1419
- try {
1420
- existingRoot.unmount();
1421
- } finally {
1422
- rootMap.delete(containerEl);
1423
- }
1424
- }
1483
+ unmountContainerRoot();
1425
1484
  while (containerEl.firstChild) containerEl.removeChild(containerEl.firstChild);
1426
1485
  containerEl.appendChild(vnode);
1427
1486
  return null;
1428
1487
  }
1429
- let root = rootMap.get(containerEl);
1430
- if (!root) {
1431
- root = this.ReactDOM.createRoot(containerEl);
1432
- rootMap.set(containerEl, root);
1488
+ const rendererKey = this.ReactDOM;
1489
+ const ownerKey = this;
1490
+ let entry = rootMap.get(containerEl);
1491
+ if (!entry || entry.rendererKey !== rendererKey || entry.ownerKey !== ownerKey) {
1492
+ if (entry) {
1493
+ disposeEntry(entry);
1494
+ rootMap.delete(containerEl);
1495
+ }
1496
+ const root = this.ReactDOM.createRoot(containerEl);
1497
+ entry = { rendererKey, ownerKey, root, disposeTheme: void 0, lastVnode: void 0 };
1498
+ rootMap.set(containerEl, entry);
1433
1499
  }
1434
- root.render(vnode);
1435
- return root;
1500
+ return (0, import_runjsLibs.externalReactRender)({
1501
+ ctx: this,
1502
+ entry,
1503
+ vnode,
1504
+ containerEl,
1505
+ rootMap,
1506
+ unmountContainerRoot,
1507
+ internalReact: import_react.default,
1508
+ internalAntd: antd
1509
+ });
1436
1510
  }
1437
1511
  );
1438
1512
  }
@@ -84,6 +84,17 @@ export declare class FlowEngine {
84
84
  private _previousEngine?;
85
85
  private _nextEngine?;
86
86
  private _resources;
87
+ /**
88
+ * Data change registry used to coordinate "refresh on active" across view-scoped engines.
89
+ *
90
+ * Keyed by: dataSourceKey -> resourceName -> version.
91
+ * - mark: increments version
92
+ * - get: returns current version (default 0)
93
+ *
94
+ * NOTE: ViewScopedFlowEngine proxies delegate non-local fields/methods to parents, so this
95
+ * registry naturally lives on the root engine instance and is shared across the whole view stack.
96
+ */
97
+ private _dataSourceDirtyVersions;
87
98
  /**
88
99
  * 引擎事件总线(目前用于模型生命周期等事件)。
89
100
  * ViewScopedFlowEngine 持有自己的实例,实现作用域隔离。
@@ -116,6 +127,16 @@ export declare class FlowEngine {
116
127
  getScheduler(): ModelOperationScheduler;
117
128
  /** 释放并清理当前引擎本地调度器(若存在) */
118
129
  disposeScheduler(): void;
130
+ /**
131
+ * Mark a data source resource as "dirty" (changed).
132
+ * This is used by data blocks to decide whether to refresh when a view becomes active.
133
+ */
134
+ markDataSourceDirty(dataSourceKey: string, resourceName: string): number;
135
+ /**
136
+ * Get current dirty version for a data source resource.
137
+ * Returns 0 when no writes have been recorded.
138
+ */
139
+ getDataSourceDirtyVersion(dataSourceKey: string, resourceName: string): number;
119
140
  /** 在目标模型生命周期达成时执行操作(仅在 View 引擎本地存储计划) */
120
141
  scheduleModelOperation(fromModelOrUid: FlowModel | string, toUid: string, fn: (model: FlowModel) => Promise<void> | void, options?: ScheduleOptions): ScheduledCancel;
121
142
  /** 上一个引擎(根引擎为 undefined) */
package/lib/flowEngine.js CHANGED
@@ -120,6 +120,17 @@ const _FlowEngine = class _FlowEngine {
120
120
  __publicField(this, "_previousEngine");
121
121
  __publicField(this, "_nextEngine");
122
122
  __publicField(this, "_resources", /* @__PURE__ */ new Map());
123
+ /**
124
+ * Data change registry used to coordinate "refresh on active" across view-scoped engines.
125
+ *
126
+ * Keyed by: dataSourceKey -> resourceName -> version.
127
+ * - mark: increments version
128
+ * - get: returns current version (default 0)
129
+ *
130
+ * NOTE: ViewScopedFlowEngine proxies delegate non-local fields/methods to parents, so this
131
+ * registry naturally lives on the root engine instance and is shared across the whole view stack.
132
+ */
133
+ __publicField(this, "_dataSourceDirtyVersions", /* @__PURE__ */ new Map());
123
134
  /**
124
135
  * 引擎事件总线(目前用于模型生命周期等事件)。
125
136
  * ViewScopedFlowEngine 持有自己的实例,实现作用域隔离。
@@ -187,6 +198,33 @@ const _FlowEngine = class _FlowEngine {
187
198
  }
188
199
  }
189
200
  }
201
+ /**
202
+ * Mark a data source resource as "dirty" (changed).
203
+ * This is used by data blocks to decide whether to refresh when a view becomes active.
204
+ */
205
+ markDataSourceDirty(dataSourceKey, resourceName) {
206
+ const dsKey = String(dataSourceKey || "main");
207
+ const resName = String(resourceName || "");
208
+ if (!resName) return this.getDataSourceDirtyVersion(dsKey, resName);
209
+ const ds = this._dataSourceDirtyVersions.get(dsKey) || /* @__PURE__ */ new Map();
210
+ if (!this._dataSourceDirtyVersions.has(dsKey)) {
211
+ this._dataSourceDirtyVersions.set(dsKey, ds);
212
+ }
213
+ const next = (ds.get(resName) || 0) + 1;
214
+ ds.set(resName, next);
215
+ return next;
216
+ }
217
+ /**
218
+ * Get current dirty version for a data source resource.
219
+ * Returns 0 when no writes have been recorded.
220
+ */
221
+ getDataSourceDirtyVersion(dataSourceKey, resourceName) {
222
+ var _a;
223
+ const dsKey = String(dataSourceKey || "main");
224
+ const resName = String(resourceName || "");
225
+ if (!resName) return 0;
226
+ return ((_a = this._dataSourceDirtyVersions.get(dsKey)) == null ? void 0 : _a.get(resName)) || 0;
227
+ }
190
228
  /** 在目标模型生命周期达成时执行操作(仅在 View 引擎本地存储计划) */
191
229
  scheduleModelOperation(fromModelOrUid, toUid, fn, options) {
192
230
  return this.getScheduler().schedule(fromModelOrUid, toUid, fn, options);
package/lib/index.d.ts CHANGED
@@ -27,8 +27,12 @@ export * from './JSRunner';
27
27
  export { getRunJSDocFor, createJSRunnerWithVersion, getRunJSScenesForModel, getRunJSScenesForContext, } from './runjs-context/helpers';
28
28
  export { RunJSContextRegistry, getModelClassName } from './runjs-context/registry';
29
29
  export { setupRunJSContexts } from './runjs-context/setup';
30
- export { getSnippetBody, listSnippetsForContext } from './runjs-context/snippets';
30
+ export type { RunJSContextContribution, RunJSContextContributionApi } from './runjs-context/contributions';
31
+ export { registerRunJSContextContribution } from './runjs-context/contributions';
32
+ export type { RunJSSnippetLoader } from './runjs-context/snippets';
33
+ export { getSnippetBody, listSnippetsForContext, registerRunJSSnippet } from './runjs-context/snippets';
31
34
  export * from './views';
35
+ export { DATA_SOURCE_DIRTY_EVENT, ENGINE_SCOPE_KEY, getEmitterViewActivatedVersion, VIEW_ACTIVATED_EVENT, VIEW_ACTIVATED_VERSION, VIEW_ENGINE_SCOPE, } from './views/viewEvents';
32
36
  export * from './FlowDefinition';
33
37
  export { createViewScopedEngine } from './ViewScopedFlowEngine';
34
38
  export { createBlockScopedEngine } from './BlockScopedFlowEngine';
package/lib/index.js CHANGED
@@ -27,18 +27,26 @@ var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "defau
27
27
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
28
28
  var src_exports = {};
29
29
  __export(src_exports, {
30
+ DATA_SOURCE_DIRTY_EVENT: () => import_viewEvents.DATA_SOURCE_DIRTY_EVENT,
31
+ ENGINE_SCOPE_KEY: () => import_viewEvents.ENGINE_SCOPE_KEY,
30
32
  RunJSContextRegistry: () => import_registry.RunJSContextRegistry,
33
+ VIEW_ACTIVATED_EVENT: () => import_viewEvents.VIEW_ACTIVATED_EVENT,
34
+ VIEW_ACTIVATED_VERSION: () => import_viewEvents.VIEW_ACTIVATED_VERSION,
35
+ VIEW_ENGINE_SCOPE: () => import_viewEvents.VIEW_ENGINE_SCOPE,
31
36
  compileRunJs: () => import_jsxTransform.compileRunJs,
32
37
  createBlockScopedEngine: () => import_BlockScopedFlowEngine.createBlockScopedEngine,
33
38
  createJSRunnerWithVersion: () => import_helpers.createJSRunnerWithVersion,
34
39
  createViewScopedEngine: () => import_ViewScopedFlowEngine.createViewScopedEngine,
40
+ getEmitterViewActivatedVersion: () => import_viewEvents.getEmitterViewActivatedVersion,
35
41
  getModelClassName: () => import_registry.getModelClassName,
36
42
  getRunJSDocFor: () => import_helpers.getRunJSDocFor,
37
43
  getRunJSScenesForContext: () => import_helpers.getRunJSScenesForContext,
38
44
  getRunJSScenesForModel: () => import_helpers.getRunJSScenesForModel,
39
45
  getSnippetBody: () => import_snippets.getSnippetBody,
40
46
  listSnippetsForContext: () => import_snippets.listSnippetsForContext,
47
+ registerRunJSContextContribution: () => import_contributions.registerRunJSContextContribution,
41
48
  registerRunJSLib: () => import_runjsLibs.registerRunJSLib,
49
+ registerRunJSSnippet: () => import_snippets.registerRunJSSnippet,
42
50
  setupRunJSContexts: () => import_setup.setupRunJSContexts
43
51
  });
44
52
  module.exports = __toCommonJS(src_exports);
@@ -62,25 +70,35 @@ __reExport(src_exports, require("./JSRunner"), module.exports);
62
70
  var import_helpers = require("./runjs-context/helpers");
63
71
  var import_registry = require("./runjs-context/registry");
64
72
  var import_setup = require("./runjs-context/setup");
73
+ var import_contributions = require("./runjs-context/contributions");
65
74
  var import_snippets = require("./runjs-context/snippets");
66
75
  __reExport(src_exports, require("./views"), module.exports);
76
+ var import_viewEvents = require("./views/viewEvents");
67
77
  __reExport(src_exports, require("./FlowDefinition"), module.exports);
68
78
  var import_ViewScopedFlowEngine = require("./ViewScopedFlowEngine");
69
79
  var import_BlockScopedFlowEngine = require("./BlockScopedFlowEngine");
70
80
  // Annotate the CommonJS export names for ESM import in node:
71
81
  0 && (module.exports = {
82
+ DATA_SOURCE_DIRTY_EVENT,
83
+ ENGINE_SCOPE_KEY,
72
84
  RunJSContextRegistry,
85
+ VIEW_ACTIVATED_EVENT,
86
+ VIEW_ACTIVATED_VERSION,
87
+ VIEW_ENGINE_SCOPE,
73
88
  compileRunJs,
74
89
  createBlockScopedEngine,
75
90
  createJSRunnerWithVersion,
76
91
  createViewScopedEngine,
92
+ getEmitterViewActivatedVersion,
77
93
  getModelClassName,
78
94
  getRunJSDocFor,
79
95
  getRunJSScenesForContext,
80
96
  getRunJSScenesForModel,
81
97
  getSnippetBody,
82
98
  listSnippetsForContext,
99
+ registerRunJSContextContribution,
83
100
  registerRunJSLib,
101
+ registerRunJSSnippet,
84
102
  setupRunJSContexts,
85
103
  ...require("./types"),
86
104
  ...require("./utils"),
@@ -353,7 +353,18 @@ const _FlowModel = class _FlowModel {
353
353
  const meta = Cls.meta;
354
354
  const metaCreate = meta == null ? void 0 : meta.createModelOptions;
355
355
  if (metaCreate && typeof metaCreate === "object" && metaCreate.subModels) {
356
- mergedSubModels = import_lodash.default.merge({}, import_lodash.default.cloneDeep(metaCreate.subModels || {}), import_lodash.default.cloneDeep(subModels || {}));
356
+ const replaceArrays = /* @__PURE__ */ __name((objValue, srcValue) => {
357
+ if (Array.isArray(objValue) && Array.isArray(srcValue)) {
358
+ return srcValue;
359
+ }
360
+ return void 0;
361
+ }, "replaceArrays");
362
+ mergedSubModels = import_lodash.default.mergeWith(
363
+ {},
364
+ import_lodash.default.cloneDeep(metaCreate.subModels || {}),
365
+ import_lodash.default.cloneDeep(subModels || {}),
366
+ replaceArrays
367
+ );
357
368
  }
358
369
  } catch (e) {
359
370
  }