@nocobase/flow-engine 2.0.0-alpha.4 → 2.0.0-alpha.5
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/lib/data-source/index.js +4 -2
- package/lib/data-source/sortCollectionsByInherits.d.ts +10 -0
- package/lib/data-source/sortCollectionsByInherits.js +71 -0
- package/package.json +2 -2
- package/src/data-source/__tests__/sortCollectionsByInherits.test.ts +125 -0
- package/src/data-source/index.ts +4 -2
- package/src/data-source/sortCollectionsByInherits.ts +61 -0
package/lib/data-source/index.js
CHANGED
|
@@ -49,6 +49,7 @@ module.exports = __toCommonJS(data_source_exports);
|
|
|
49
49
|
var import_reactive = require("@formily/reactive");
|
|
50
50
|
var import_lodash = __toESM(require("lodash"));
|
|
51
51
|
var import_jioToJoiSchema = require("./jioToJoiSchema");
|
|
52
|
+
var import_sortCollectionsByInherits = require("./sortCollectionsByInherits");
|
|
52
53
|
const _DataSourceManager = class _DataSourceManager {
|
|
53
54
|
dataSources;
|
|
54
55
|
flowEngine;
|
|
@@ -220,7 +221,7 @@ const _CollectionManager = class _CollectionManager {
|
|
|
220
221
|
return this.getCollection(options.name);
|
|
221
222
|
}
|
|
222
223
|
upsertCollections(collections) {
|
|
223
|
-
for (const collection of
|
|
224
|
+
for (const collection of (0, import_sortCollectionsByInherits.sortCollectionsByInherits)(collections)) {
|
|
224
225
|
if (this.collections.has(collection.name)) {
|
|
225
226
|
this.updateCollection(collection);
|
|
226
227
|
} else {
|
|
@@ -368,7 +369,8 @@ const _Collection = class _Collection {
|
|
|
368
369
|
for (const inherit of this.options.inherits || []) {
|
|
369
370
|
const collection = this.collectionManager.getCollection(inherit);
|
|
370
371
|
if (!collection) {
|
|
371
|
-
|
|
372
|
+
console.warn(`Warning: Collection ${inherit} not found for collection ${this.name}`);
|
|
373
|
+
continue;
|
|
372
374
|
}
|
|
373
375
|
this.inherits.set(inherit, collection);
|
|
374
376
|
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
import { CollectionOptions } from '.';
|
|
10
|
+
export declare function sortCollectionsByInherits(collections: CollectionOptions[]): CollectionOptions[];
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
var __defProp = Object.defineProperty;
|
|
11
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
12
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
13
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
14
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
15
|
+
var __export = (target, all) => {
|
|
16
|
+
for (var name in all)
|
|
17
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
18
|
+
};
|
|
19
|
+
var __copyProps = (to, from, except, desc) => {
|
|
20
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
21
|
+
for (let key of __getOwnPropNames(from))
|
|
22
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
23
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
24
|
+
}
|
|
25
|
+
return to;
|
|
26
|
+
};
|
|
27
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
28
|
+
var sortCollectionsByInherits_exports = {};
|
|
29
|
+
__export(sortCollectionsByInherits_exports, {
|
|
30
|
+
sortCollectionsByInherits: () => sortCollectionsByInherits
|
|
31
|
+
});
|
|
32
|
+
module.exports = __toCommonJS(sortCollectionsByInherits_exports);
|
|
33
|
+
function sortCollectionsByInherits(collections) {
|
|
34
|
+
const sorted = [];
|
|
35
|
+
const visited = /* @__PURE__ */ new Set();
|
|
36
|
+
const visiting = /* @__PURE__ */ new Set();
|
|
37
|
+
const map = /* @__PURE__ */ new Map();
|
|
38
|
+
collections.forEach((col) => {
|
|
39
|
+
map.set(col.name, col);
|
|
40
|
+
});
|
|
41
|
+
const addToSorted = /* @__PURE__ */ __name((col) => {
|
|
42
|
+
if (visiting.has(col.name)) {
|
|
43
|
+
throw new Error(`Circular dependency detected: ${col.name} inherits from itself through a chain`);
|
|
44
|
+
}
|
|
45
|
+
if (visited.has(col.name)) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
visiting.add(col.name);
|
|
49
|
+
const inherits = col.inherits || [];
|
|
50
|
+
for (const inheritName of inherits) {
|
|
51
|
+
const inheritCol = map.get(inheritName);
|
|
52
|
+
if (!inheritCol) {
|
|
53
|
+
console.warn(`Warning: Collection ${inheritName}, inherited by ${col.name}, not found.`);
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
addToSorted(inheritCol);
|
|
57
|
+
}
|
|
58
|
+
visiting.delete(col.name);
|
|
59
|
+
visited.add(col.name);
|
|
60
|
+
sorted.push(col);
|
|
61
|
+
}, "addToSorted");
|
|
62
|
+
for (const col of collections) {
|
|
63
|
+
addToSorted(col);
|
|
64
|
+
}
|
|
65
|
+
return sorted;
|
|
66
|
+
}
|
|
67
|
+
__name(sortCollectionsByInherits, "sortCollectionsByInherits");
|
|
68
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
69
|
+
0 && (module.exports = {
|
|
70
|
+
sortCollectionsByInherits
|
|
71
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nocobase/flow-engine",
|
|
3
|
-
"version": "2.0.0-alpha.
|
|
3
|
+
"version": "2.0.0-alpha.5",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "A standalone flow engine for NocoBase, managing workflows, models, and actions.",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -33,5 +33,5 @@
|
|
|
33
33
|
],
|
|
34
34
|
"author": "NocoBase Team",
|
|
35
35
|
"license": "AGPL-3.0",
|
|
36
|
-
"gitHead": "
|
|
36
|
+
"gitHead": "943e035bbec27f9ecfe8ce8857955945f20976f3"
|
|
37
37
|
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { describe, expect, it } from 'vitest';
|
|
11
|
+
import { sortCollectionsByInherits } from '../sortCollectionsByInherits';
|
|
12
|
+
|
|
13
|
+
describe('sortCollectionsByInherits', () => {
|
|
14
|
+
it('should sort collections by their inherits in correct order', () => {
|
|
15
|
+
const collections = [
|
|
16
|
+
{ name: 'posts', inherits: [] },
|
|
17
|
+
{ name: 'comments', inherits: ['posts'] },
|
|
18
|
+
{ name: 'users', inherits: ['comments'] },
|
|
19
|
+
];
|
|
20
|
+
const sorted = sortCollectionsByInherits(collections);
|
|
21
|
+
expect(sorted.map((c) => c.name)).toEqual(['posts', 'comments', 'users']);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('should handle collections with no inherits', () => {
|
|
25
|
+
const collections = [
|
|
26
|
+
{ name: 'users', inherits: [] },
|
|
27
|
+
{ name: 'posts', inherits: [] },
|
|
28
|
+
];
|
|
29
|
+
const sorted = sortCollectionsByInherits(collections);
|
|
30
|
+
expect(sorted.map((c) => c.name)).toEqual(['users', 'posts']);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it('should handle collections with undefined inherits', () => {
|
|
34
|
+
const collections = [{ name: 'users' }, { name: 'posts' }];
|
|
35
|
+
const sorted = sortCollectionsByInherits(collections);
|
|
36
|
+
expect(sorted.map((c) => c.name)).toEqual(['users', 'posts']);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('should handle complex inheritance chains', () => {
|
|
40
|
+
const collections = [
|
|
41
|
+
{ name: 'base', inherits: [] },
|
|
42
|
+
{ name: 'middle', inherits: ['base'] },
|
|
43
|
+
{ name: 'top', inherits: ['middle'] },
|
|
44
|
+
{ name: 'independent', inherits: [] },
|
|
45
|
+
];
|
|
46
|
+
const sorted = sortCollectionsByInherits(collections);
|
|
47
|
+
expect(sorted.map((c) => c.name)).toEqual(['base', 'middle', 'top', 'independent']);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('should handle multiple inheritance', () => {
|
|
51
|
+
const collections = [
|
|
52
|
+
{ name: 'user', inherits: [] },
|
|
53
|
+
{ name: 'post', inherits: [] },
|
|
54
|
+
{ name: 'comment', inherits: ['user', 'post'] },
|
|
55
|
+
];
|
|
56
|
+
const sorted = sortCollectionsByInherits(collections);
|
|
57
|
+
expect(sorted.map((c) => c.name)).toEqual(['user', 'post', 'comment']);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('should throw error for circular dependencies', () => {
|
|
61
|
+
const collections = [
|
|
62
|
+
{ name: 'a', inherits: ['b'] },
|
|
63
|
+
{ name: 'b', inherits: ['a'] },
|
|
64
|
+
];
|
|
65
|
+
expect(() => sortCollectionsByInherits(collections)).toThrow('Circular dependency detected');
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it('should gracefully handle missing inherit collections', () => {
|
|
69
|
+
const collections = [
|
|
70
|
+
{ name: 'posts', inherits: ['nonexistent'] },
|
|
71
|
+
{ name: 'users', inherits: [] },
|
|
72
|
+
];
|
|
73
|
+
const sorted = sortCollectionsByInherits(collections);
|
|
74
|
+
expect(sorted.map((c) => c.name)).toEqual(['posts', 'users']);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it('should handle self-inheritance circular dependency', () => {
|
|
78
|
+
const collections = [{ name: 'posts', inherits: ['posts'] }];
|
|
79
|
+
expect(() => sortCollectionsByInherits(collections)).toThrow('Circular dependency detected');
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it('should maintain order for collections without dependencies', () => {
|
|
83
|
+
const collections = [
|
|
84
|
+
{ name: 'z', inherits: [] },
|
|
85
|
+
{ name: 'a', inherits: [] },
|
|
86
|
+
{ name: 'm', inherits: [] },
|
|
87
|
+
];
|
|
88
|
+
const sorted = sortCollectionsByInherits(collections);
|
|
89
|
+
expect(sorted.map((c) => c.name)).toEqual(['z', 'a', 'm']);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it('should handle empty collections array', () => {
|
|
93
|
+
const sorted = sortCollectionsByInherits([]);
|
|
94
|
+
expect(sorted).toEqual([]);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it('should handle collections with multiple missing inherits', () => {
|
|
98
|
+
const collections = [
|
|
99
|
+
{ name: 'posts', inherits: ['missing1', 'missing2'] },
|
|
100
|
+
{ name: 'users', inherits: ['missing3'] },
|
|
101
|
+
{ name: 'comments', inherits: ['posts', 'missing4'] },
|
|
102
|
+
];
|
|
103
|
+
const sorted = sortCollectionsByInherits(collections);
|
|
104
|
+
expect(sorted.map((c) => c.name)).toEqual(['posts', 'users', 'comments']);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it('should handle mixed existing and missing inherits', () => {
|
|
108
|
+
const collections = [
|
|
109
|
+
{ name: 'base', inherits: [] },
|
|
110
|
+
{ name: 'middle', inherits: ['base', 'missing'] },
|
|
111
|
+
{ name: 'top', inherits: ['middle'] },
|
|
112
|
+
];
|
|
113
|
+
const sorted = sortCollectionsByInherits(collections);
|
|
114
|
+
expect(sorted.map((c) => c.name)).toEqual(['base', 'middle', 'top']);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it('should handle all inherits missing', () => {
|
|
118
|
+
const collections = [
|
|
119
|
+
{ name: 'posts', inherits: ['missing1', 'missing2'] },
|
|
120
|
+
{ name: 'users', inherits: ['missing3'] },
|
|
121
|
+
];
|
|
122
|
+
const sorted = sortCollectionsByInherits(collections);
|
|
123
|
+
expect(sorted.map((c) => c.name)).toEqual(['posts', 'users']);
|
|
124
|
+
});
|
|
125
|
+
});
|
package/src/data-source/index.ts
CHANGED
|
@@ -11,6 +11,7 @@ import { observable } from '@formily/reactive';
|
|
|
11
11
|
import _ from 'lodash';
|
|
12
12
|
import { FlowEngine } from '../flowEngine';
|
|
13
13
|
import { jioToJoiSchema } from './jioToJoiSchema';
|
|
14
|
+
import { sortCollectionsByInherits } from './sortCollectionsByInherits';
|
|
14
15
|
export interface DataSourceOptions extends Record<string, any> {
|
|
15
16
|
key: string;
|
|
16
17
|
displayName?: string;
|
|
@@ -227,7 +228,7 @@ export class CollectionManager {
|
|
|
227
228
|
}
|
|
228
229
|
|
|
229
230
|
upsertCollections(collections: CollectionOptions[]) {
|
|
230
|
-
for (const collection of
|
|
231
|
+
for (const collection of sortCollectionsByInherits(collections)) {
|
|
231
232
|
if (this.collections.has(collection.name)) {
|
|
232
233
|
this.updateCollection(collection);
|
|
233
234
|
} else {
|
|
@@ -400,7 +401,8 @@ export class Collection {
|
|
|
400
401
|
for (const inherit of this.options.inherits || []) {
|
|
401
402
|
const collection = this.collectionManager.getCollection(inherit);
|
|
402
403
|
if (!collection) {
|
|
403
|
-
|
|
404
|
+
console.warn(`Warning: Collection ${inherit} not found for collection ${this.name}`);
|
|
405
|
+
continue;
|
|
404
406
|
}
|
|
405
407
|
this.inherits.set(inherit, collection);
|
|
406
408
|
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { CollectionOptions } from '.';
|
|
11
|
+
|
|
12
|
+
export function sortCollectionsByInherits(collections: CollectionOptions[]): CollectionOptions[] {
|
|
13
|
+
const sorted: CollectionOptions[] = [];
|
|
14
|
+
const visited = new Set<string>();
|
|
15
|
+
const visiting = new Set<string>();
|
|
16
|
+
const map = new Map<string, CollectionOptions>();
|
|
17
|
+
|
|
18
|
+
// Create a map for O(1) lookup
|
|
19
|
+
collections.forEach((col) => {
|
|
20
|
+
map.set(col.name, col);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
const addToSorted = (col: CollectionOptions): void => {
|
|
24
|
+
// Check for circular dependency
|
|
25
|
+
if (visiting.has(col.name)) {
|
|
26
|
+
throw new Error(`Circular dependency detected: ${col.name} inherits from itself through a chain`);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Skip if already processed
|
|
30
|
+
if (visited.has(col.name)) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Mark as currently being processed
|
|
35
|
+
visiting.add(col.name);
|
|
36
|
+
|
|
37
|
+
// Process inherits first (dependencies)
|
|
38
|
+
const inherits = col.inherits || [];
|
|
39
|
+
for (const inheritName of inherits) {
|
|
40
|
+
const inheritCol = map.get(inheritName);
|
|
41
|
+
if (!inheritCol) {
|
|
42
|
+
console.warn(`Warning: Collection ${inheritName}, inherited by ${col.name}, not found.`);
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
addToSorted(inheritCol);
|
|
46
|
+
// Silently skip missing inherit collections
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Mark as processed and add to sorted array
|
|
50
|
+
visiting.delete(col.name);
|
|
51
|
+
visited.add(col.name);
|
|
52
|
+
sorted.push(col);
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
// Process all collections
|
|
56
|
+
for (const col of collections) {
|
|
57
|
+
addToSorted(col);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return sorted;
|
|
61
|
+
}
|