@objectql/platform-node 3.0.1 → 4.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +18 -3
- package/README.md +501 -0
- package/dist/driver.d.ts +7 -0
- package/dist/driver.js +7 -0
- package/dist/driver.js.map +1 -1
- package/dist/index.d.ts +7 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -1
- package/dist/loader.d.ts +7 -0
- package/dist/loader.js +7 -0
- package/dist/loader.js.map +1 -1
- package/dist/module.d.ts +7 -0
- package/dist/module.js +7 -0
- package/dist/module.js.map +1 -1
- package/dist/plugin.d.ts +11 -2
- package/dist/plugin.js +29 -10
- package/dist/plugin.js.map +1 -1
- package/jest.config.js +17 -0
- package/package.json +4 -3
- package/src/driver.ts +8 -0
- package/src/index.ts +8 -0
- package/src/loader.ts +9 -1
- package/src/module.ts +8 -0
- package/src/plugin.ts +39 -13
- package/test/__mocks__/@objectstack/runtime.ts +223 -0
- package/test/dynamic.test.ts +8 -0
- package/test/fixtures/project.action.js +8 -0
- package/test/loader.test.ts +8 -0
- package/test/metadata.test.ts +8 -0
- package/test/validation.test.ts +8 -0
- package/tsconfig.tsbuildinfo +1 -1
package/dist/module.js
CHANGED
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* ObjectQL
|
|
4
|
+
* Copyright (c) 2026-present ObjectStack Inc.
|
|
5
|
+
*
|
|
6
|
+
* This source code is licensed under the MIT license found in the
|
|
7
|
+
* LICENSE file in the root directory of this source tree.
|
|
8
|
+
*/
|
|
2
9
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
10
|
if (k2 === undefined) k2 = k;
|
|
4
11
|
var desc = Object.getOwnPropertyDescriptor(m, k);
|
package/dist/module.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"module.js","sourceRoot":"","sources":["../src/module.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"module.js","sourceRoot":"","sources":["../src/module.ts"],"names":[],"mappings":"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"}
|
package/dist/plugin.d.ts
CHANGED
|
@@ -1,2 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* ObjectQL
|
|
3
|
+
* Copyright (c) 2026-present ObjectStack Inc.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*/
|
|
8
|
+
import { System } from '@objectstack/spec';
|
|
9
|
+
type PluginDefinition = System.PluginDefinition;
|
|
10
|
+
export declare function loadPlugin(packageName: string): PluginDefinition;
|
|
11
|
+
export {};
|
package/dist/plugin.js
CHANGED
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* ObjectQL
|
|
4
|
+
* Copyright (c) 2026-present ObjectStack Inc.
|
|
5
|
+
*
|
|
6
|
+
* This source code is licensed under the MIT license found in the
|
|
7
|
+
* LICENSE file in the root directory of this source tree.
|
|
8
|
+
*/
|
|
2
9
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
10
|
exports.loadPlugin = loadPlugin;
|
|
4
11
|
function loadPlugin(packageName) {
|
|
@@ -10,27 +17,39 @@ function loadPlugin(packageName) {
|
|
|
10
17
|
catch (e) {
|
|
11
18
|
throw new Error(`Failed to resolve plugin '${packageName}': ${e}`);
|
|
12
19
|
}
|
|
20
|
+
// Helper to check if candidate is a PluginDefinition
|
|
21
|
+
const isPlugin = (candidate) => {
|
|
22
|
+
return candidate && (
|
|
23
|
+
// Check for any lifecycle method
|
|
24
|
+
typeof candidate.onEnable === 'function' ||
|
|
25
|
+
typeof candidate.onDisable === 'function' ||
|
|
26
|
+
typeof candidate.onInstall === 'function' ||
|
|
27
|
+
typeof candidate.onUninstall === 'function' ||
|
|
28
|
+
typeof candidate.onUpgrade === 'function') && (
|
|
29
|
+
// Note: id is optional in PluginDefinition, so we don't require it
|
|
30
|
+
// The spec allows plugins without id (it just defaults to package name)
|
|
31
|
+
candidate.id === undefined || typeof candidate.id === 'string');
|
|
32
|
+
};
|
|
13
33
|
// Helper to find plugin instance
|
|
14
34
|
const findPlugin = (candidate) => {
|
|
15
35
|
if (!candidate)
|
|
16
36
|
return undefined;
|
|
17
|
-
// 1.
|
|
37
|
+
// 1. Check if it's a PluginDefinition
|
|
38
|
+
if (isPlugin(candidate)) {
|
|
39
|
+
return candidate;
|
|
40
|
+
}
|
|
41
|
+
// 2. Try treating as Class
|
|
18
42
|
if (typeof candidate === 'function') {
|
|
19
43
|
try {
|
|
20
44
|
const inst = new candidate();
|
|
21
|
-
if (inst
|
|
22
|
-
return inst;
|
|
45
|
+
if (isPlugin(inst)) {
|
|
46
|
+
return inst;
|
|
23
47
|
}
|
|
24
48
|
}
|
|
25
49
|
catch (e) {
|
|
26
50
|
// Not a constructor or instantiation failed
|
|
27
51
|
}
|
|
28
52
|
}
|
|
29
|
-
// 2. Try treating as Instance
|
|
30
|
-
if (candidate && typeof candidate.setup === 'function') {
|
|
31
|
-
if (candidate.name)
|
|
32
|
-
return candidate;
|
|
33
|
-
}
|
|
34
53
|
return undefined;
|
|
35
54
|
};
|
|
36
55
|
// Search in default, module root, and all named exports
|
|
@@ -49,8 +68,8 @@ function loadPlugin(packageName) {
|
|
|
49
68
|
return instance;
|
|
50
69
|
}
|
|
51
70
|
else {
|
|
52
|
-
console.error(`[PluginLoader] Failed to find
|
|
53
|
-
throw new Error(`Plugin '${packageName}' must export a
|
|
71
|
+
console.error(`[PluginLoader] Failed to find plugin in '${packageName}'. Exports:`, Object.keys(mod));
|
|
72
|
+
throw new Error(`Plugin '${packageName}' must export a PluginDefinition with lifecycle hooks (onEnable, onDisable, etc.).`);
|
|
54
73
|
}
|
|
55
74
|
}
|
|
56
75
|
//# sourceMappingURL=plugin.js.map
|
package/dist/plugin.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG;;AAKH,gCAmEC;AAnED,SAAgB,UAAU,CAAC,WAAmB;IAC1C,IAAI,GAAQ,CAAC;IACb,IAAI,CAAC;QACD,MAAM,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,KAAK,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;QAC5E,GAAG,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAC9B,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACT,MAAM,IAAI,KAAK,CAAC,6BAA6B,WAAW,MAAM,CAAC,EAAE,CAAC,CAAC;IACvE,CAAC;IAED,qDAAqD;IACrD,MAAM,QAAQ,GAAG,CAAC,SAAc,EAAiC,EAAE;QAC/D,OAAO,SAAS,IAAI;QAChB,iCAAiC;QACjC,OAAO,SAAS,CAAC,QAAQ,KAAK,UAAU;YACxC,OAAO,SAAS,CAAC,SAAS,KAAK,UAAU;YACzC,OAAO,SAAS,CAAC,SAAS,KAAK,UAAU;YACzC,OAAO,SAAS,CAAC,WAAW,KAAK,UAAU;YAC3C,OAAO,SAAS,CAAC,SAAS,KAAK,UAAU,CAC5C,IAAI;QACD,mEAAmE;QACnE,wEAAwE;QACxE,SAAS,CAAC,EAAE,KAAK,SAAS,IAAI,OAAO,SAAS,CAAC,EAAE,KAAK,QAAQ,CACjE,CAAC;IACN,CAAC,CAAC;IAEF,iCAAiC;IACjC,MAAM,UAAU,GAAG,CAAC,SAAc,EAAgC,EAAE;QAC5D,IAAI,CAAC,SAAS;YAAE,OAAO,SAAS,CAAC;QAEjC,sCAAsC;QACtC,IAAI,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;YACtB,OAAO,SAAS,CAAC;QACrB,CAAC;QAED,2BAA2B;QAC3B,IAAI,OAAO,SAAS,KAAK,UAAU,EAAE,CAAC;YAClC,IAAI,CAAC;gBACD,MAAM,IAAI,GAAG,IAAI,SAAS,EAAE,CAAC;gBAC7B,IAAI,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;oBACjB,OAAO,IAAI,CAAC;gBAChB,CAAC;YACL,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACT,4CAA4C;YAChD,CAAC;QACL,CAAC;QAED,OAAO,SAAS,CAAC;IACzB,CAAC,CAAC;IAEF,wDAAwD;IACxD,IAAI,QAAQ,GAAG,UAAU,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,UAAU,CAAC,GAAG,CAAC,CAAC;IAE1D,IAAI,CAAC,QAAQ,IAAI,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;QAC9C,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;YACjC,IAAI,GAAG,KAAK,SAAS;gBAAE,SAAS;YAChC,QAAQ,GAAG,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;YAChC,IAAI,QAAQ;gBAAE,MAAM;QACxB,CAAC;IACL,CAAC;IAED,IAAI,QAAQ,EAAE,CAAC;QACV,QAAgB,CAAC,YAAY,GAAG,WAAW,CAAC;QAC7C,OAAO,QAAQ,CAAC;IACpB,CAAC;SAAM,CAAC;QACJ,OAAO,CAAC,KAAK,CAAC,4CAA4C,WAAW,aAAa,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;QACtG,MAAM,IAAI,KAAK,CAAC,WAAW,WAAW,oFAAoF,CAAC,CAAC;IAChI,CAAC;AACL,CAAC"}
|
package/jest.config.js
CHANGED
|
@@ -1,13 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ObjectQL
|
|
3
|
+
* Copyright (c) 2026-present ObjectStack Inc.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*/
|
|
8
|
+
|
|
1
9
|
module.exports = {
|
|
2
10
|
preset: 'ts-jest',
|
|
3
11
|
testEnvironment: 'node',
|
|
4
12
|
testMatch: ['**/test/**/*.test.ts'],
|
|
5
13
|
moduleNameMapper: {
|
|
14
|
+
'^@objectql/runtime$': '<rootDir>/../../objectstack/runtime/src',
|
|
15
|
+
'^@objectstack/runtime$': '<rootDir>/test/__mocks__/@objectstack/runtime.ts',
|
|
6
16
|
'^@objectql/(.*)$': '<rootDir>/../$1/src',
|
|
7
17
|
},
|
|
8
18
|
transform: {
|
|
9
19
|
'^.+\\.ts$': ['ts-jest', {
|
|
10
20
|
isolatedModules: true,
|
|
21
|
+
tsconfig: {
|
|
22
|
+
esModuleInterop: true,
|
|
23
|
+
allowSyntheticDefaultImports: true,
|
|
24
|
+
}
|
|
11
25
|
}],
|
|
12
26
|
},
|
|
27
|
+
transformIgnorePatterns: [
|
|
28
|
+
'node_modules/(?!(@objectstack))',
|
|
29
|
+
],
|
|
13
30
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@objectql/platform-node",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.1",
|
|
4
4
|
"description": "Node.js platform utilities for ObjectQL - File system integration, YAML loading, and plugin management",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"objectql",
|
|
@@ -16,10 +16,11 @@
|
|
|
16
16
|
"main": "dist/index.js",
|
|
17
17
|
"types": "dist/index.d.ts",
|
|
18
18
|
"dependencies": {
|
|
19
|
+
"@objectstack/spec": "^0.3.1",
|
|
19
20
|
"fast-glob": "^3.3.2",
|
|
20
21
|
"js-yaml": "^4.1.1",
|
|
21
|
-
"@objectql/types": "
|
|
22
|
-
"@objectql/core": "
|
|
22
|
+
"@objectql/types": "4.0.1",
|
|
23
|
+
"@objectql/core": "4.0.1"
|
|
23
24
|
},
|
|
24
25
|
"devDependencies": {
|
|
25
26
|
"typescript": "^5.3.0"
|
package/src/driver.ts
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ObjectQL
|
|
3
|
+
* Copyright (c) 2026-present ObjectStack Inc.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*/
|
|
8
|
+
|
|
1
9
|
import { Driver } from '@objectql/types';
|
|
2
10
|
|
|
3
11
|
export function createDriverFromConnection(connection: string): Driver {
|
package/src/index.ts
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ObjectQL
|
|
3
|
+
* Copyright (c) 2026-present ObjectStack Inc.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*/
|
|
8
|
+
|
|
1
9
|
export * from './loader';
|
|
2
10
|
export * from './plugin';
|
|
3
11
|
export * from './driver';
|
package/src/loader.ts
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ObjectQL
|
|
3
|
+
* Copyright (c) 2026-present ObjectStack Inc.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*/
|
|
8
|
+
|
|
1
9
|
import * as fs from 'fs';
|
|
2
10
|
import * as glob from 'fast-glob';
|
|
3
11
|
import * as path from 'path';
|
|
@@ -290,7 +298,7 @@ function registerObject(registry: MetadataRegistry, obj: any, file: string, pack
|
|
|
290
298
|
// Check for existing object to Merge
|
|
291
299
|
const existing = registry.getEntry('object', obj.name);
|
|
292
300
|
if (existing) {
|
|
293
|
-
const base = existing.content;
|
|
301
|
+
const base = existing.content as ObjectConfig;
|
|
294
302
|
|
|
295
303
|
// Merge Fields: New fields overwrite old ones
|
|
296
304
|
if (obj.fields) {
|
package/src/module.ts
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ObjectQL
|
|
3
|
+
* Copyright (c) 2026-present ObjectStack Inc.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*/
|
|
8
|
+
|
|
1
9
|
import { ObjectLoader } from './loader';
|
|
2
10
|
import * as path from 'path';
|
|
3
11
|
import * as fs from 'fs';
|
package/src/plugin.ts
CHANGED
|
@@ -1,6 +1,15 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* ObjectQL
|
|
3
|
+
* Copyright (c) 2026-present ObjectStack Inc.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*/
|
|
2
8
|
|
|
3
|
-
|
|
9
|
+
import { System } from '@objectstack/spec';
|
|
10
|
+
type PluginDefinition = System.PluginDefinition;
|
|
11
|
+
|
|
12
|
+
export function loadPlugin(packageName: string): PluginDefinition {
|
|
4
13
|
let mod: any;
|
|
5
14
|
try {
|
|
6
15
|
const modulePath = require.resolve(packageName, { paths: [process.cwd()] });
|
|
@@ -9,26 +18,43 @@ export function loadPlugin(packageName: string): ObjectQLPlugin {
|
|
|
9
18
|
throw new Error(`Failed to resolve plugin '${packageName}': ${e}`);
|
|
10
19
|
}
|
|
11
20
|
|
|
21
|
+
// Helper to check if candidate is a PluginDefinition
|
|
22
|
+
const isPlugin = (candidate: any): candidate is PluginDefinition => {
|
|
23
|
+
return candidate && (
|
|
24
|
+
// Check for any lifecycle method
|
|
25
|
+
typeof candidate.onEnable === 'function' ||
|
|
26
|
+
typeof candidate.onDisable === 'function' ||
|
|
27
|
+
typeof candidate.onInstall === 'function' ||
|
|
28
|
+
typeof candidate.onUninstall === 'function' ||
|
|
29
|
+
typeof candidate.onUpgrade === 'function'
|
|
30
|
+
) && (
|
|
31
|
+
// Note: id is optional in PluginDefinition, so we don't require it
|
|
32
|
+
// The spec allows plugins without id (it just defaults to package name)
|
|
33
|
+
candidate.id === undefined || typeof candidate.id === 'string'
|
|
34
|
+
);
|
|
35
|
+
};
|
|
36
|
+
|
|
12
37
|
// Helper to find plugin instance
|
|
13
|
-
const findPlugin = (candidate: any):
|
|
38
|
+
const findPlugin = (candidate: any): PluginDefinition | undefined => {
|
|
14
39
|
if (!candidate) return undefined;
|
|
15
40
|
|
|
16
|
-
// 1.
|
|
41
|
+
// 1. Check if it's a PluginDefinition
|
|
42
|
+
if (isPlugin(candidate)) {
|
|
43
|
+
return candidate;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// 2. Try treating as Class
|
|
17
47
|
if (typeof candidate === 'function') {
|
|
18
48
|
try {
|
|
19
49
|
const inst = new candidate();
|
|
20
|
-
if (inst
|
|
21
|
-
return inst;
|
|
50
|
+
if (isPlugin(inst)) {
|
|
51
|
+
return inst;
|
|
22
52
|
}
|
|
23
53
|
} catch (e) {
|
|
24
54
|
// Not a constructor or instantiation failed
|
|
25
55
|
}
|
|
26
56
|
}
|
|
27
|
-
|
|
28
|
-
// 2. Try treating as Instance
|
|
29
|
-
if (candidate && typeof candidate.setup === 'function') {
|
|
30
|
-
if (candidate.name) return candidate;
|
|
31
|
-
}
|
|
57
|
+
|
|
32
58
|
return undefined;
|
|
33
59
|
};
|
|
34
60
|
|
|
@@ -47,7 +73,7 @@ export function loadPlugin(packageName: string): ObjectQLPlugin {
|
|
|
47
73
|
(instance as any)._packageName = packageName;
|
|
48
74
|
return instance;
|
|
49
75
|
} else {
|
|
50
|
-
console.error(`[PluginLoader] Failed to find
|
|
51
|
-
throw new Error(`Plugin '${packageName}' must export a
|
|
76
|
+
console.error(`[PluginLoader] Failed to find plugin in '${packageName}'. Exports:`, Object.keys(mod));
|
|
77
|
+
throw new Error(`Plugin '${packageName}' must export a PluginDefinition with lifecycle hooks (onEnable, onDisable, etc.).`);
|
|
52
78
|
}
|
|
53
79
|
}
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mock for @objectql/runtime
|
|
3
|
+
* This mock is needed because the npm package has issues with Jest
|
|
4
|
+
* and we want to focus on testing ObjectQL's logic, not the kernel integration.
|
|
5
|
+
*
|
|
6
|
+
* For now, this mock delegates to the legacy driver to maintain backward compatibility
|
|
7
|
+
* during the migration phase.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
// Simple mock implementations of runtime managers
|
|
11
|
+
class MockMetadataRegistry {
|
|
12
|
+
private store = new Map<string, Map<string, any>>();
|
|
13
|
+
|
|
14
|
+
register(type: string, item: any): void {
|
|
15
|
+
if (!this.store.has(type)) {
|
|
16
|
+
this.store.set(type, new Map());
|
|
17
|
+
}
|
|
18
|
+
const typeMap = this.store.get(type)!;
|
|
19
|
+
typeMap.set(item.id || item.name, item);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
get<T = any>(type: string, id: string): T | undefined {
|
|
23
|
+
const typeMap = this.store.get(type);
|
|
24
|
+
const item = typeMap?.get(id);
|
|
25
|
+
return item?.content as T;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
list<T = any>(type: string): T[] {
|
|
29
|
+
const typeMap = this.store.get(type);
|
|
30
|
+
if (!typeMap) return [];
|
|
31
|
+
return Array.from(typeMap.values()).map(item => item.content as T);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
unregister(type: string, id: string): boolean {
|
|
35
|
+
const typeMap = this.store.get(type);
|
|
36
|
+
if (!typeMap) return false;
|
|
37
|
+
return typeMap.delete(id);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
getTypes(): string[] {
|
|
41
|
+
return Array.from(this.store.keys());
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
getEntry(type: string, id: string): any | undefined {
|
|
45
|
+
const typeMap = this.store.get(type);
|
|
46
|
+
return typeMap ? typeMap.get(id) : undefined;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
unregisterPackage(packageName: string): void {
|
|
50
|
+
// Simple implementation - in real runtime this would filter by package
|
|
51
|
+
for (const [type, typeMap] of this.store.entries()) {
|
|
52
|
+
const toDelete: string[] = [];
|
|
53
|
+
for (const [id, item] of typeMap.entries()) {
|
|
54
|
+
if (item.packageName === packageName || item.package === packageName) {
|
|
55
|
+
toDelete.push(id);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
toDelete.forEach(id => typeMap.delete(id));
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
class MockHookManager {
|
|
64
|
+
removePackage(packageName: string): void {
|
|
65
|
+
// Mock implementation
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
clear(): void {
|
|
69
|
+
// Mock implementation
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
class MockActionManager {
|
|
74
|
+
removePackage(packageName: string): void {
|
|
75
|
+
// Mock implementation
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
clear(): void {
|
|
79
|
+
// Mock implementation
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export class ObjectStackKernel {
|
|
84
|
+
public ql: unknown = null;
|
|
85
|
+
public metadata: MockMetadataRegistry;
|
|
86
|
+
public hooks: MockHookManager;
|
|
87
|
+
public actions: MockActionManager;
|
|
88
|
+
private plugins: any[] = [];
|
|
89
|
+
private driver: any = null; // Will be set by the ObjectQL app
|
|
90
|
+
|
|
91
|
+
constructor(plugins: any[] = []) {
|
|
92
|
+
this.plugins = plugins;
|
|
93
|
+
this.metadata = new MockMetadataRegistry();
|
|
94
|
+
this.hooks = new MockHookManager();
|
|
95
|
+
this.actions = new MockActionManager();
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Method to set the driver for delegation during migration
|
|
99
|
+
setDriver(driver: any): void {
|
|
100
|
+
this.driver = driver;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
async start(): Promise<void> {
|
|
104
|
+
// Mock implementation that calls plugin lifecycle methods
|
|
105
|
+
for (const plugin of this.plugins) {
|
|
106
|
+
if (plugin.install) {
|
|
107
|
+
await plugin.install({ engine: this });
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
for (const plugin of this.plugins) {
|
|
111
|
+
if (plugin.onStart) {
|
|
112
|
+
await plugin.onStart({ engine: this });
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
async seed(): Promise<void> {
|
|
118
|
+
// Mock implementation
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
async find(objectName: string, query: any): Promise<{ value: Record<string, any>[]; count: number }> {
|
|
122
|
+
// Delegate to driver during migration phase
|
|
123
|
+
if (this.driver) {
|
|
124
|
+
// Convert QueryAST back to UnifiedQuery format for driver
|
|
125
|
+
const unifiedQuery: any = {};
|
|
126
|
+
|
|
127
|
+
if (query.fields) {
|
|
128
|
+
unifiedQuery.fields = query.fields;
|
|
129
|
+
}
|
|
130
|
+
if (query.filters) {
|
|
131
|
+
unifiedQuery.filters = query.filters;
|
|
132
|
+
}
|
|
133
|
+
if (query.sort) {
|
|
134
|
+
unifiedQuery.sort = query.sort.map((s: any) => [s.field, s.order]);
|
|
135
|
+
}
|
|
136
|
+
if (query.top !== undefined) {
|
|
137
|
+
unifiedQuery.limit = query.top;
|
|
138
|
+
}
|
|
139
|
+
if (query.skip !== undefined) {
|
|
140
|
+
unifiedQuery.skip = query.skip;
|
|
141
|
+
}
|
|
142
|
+
if (query.aggregations) {
|
|
143
|
+
unifiedQuery.aggregate = query.aggregations.map((agg: any) => ({
|
|
144
|
+
func: agg.function,
|
|
145
|
+
field: agg.field,
|
|
146
|
+
alias: agg.alias
|
|
147
|
+
}));
|
|
148
|
+
}
|
|
149
|
+
if (query.groupBy) {
|
|
150
|
+
unifiedQuery.groupBy = query.groupBy;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const results = await this.driver.find(objectName, unifiedQuery, {});
|
|
154
|
+
return { value: results, count: results.length };
|
|
155
|
+
}
|
|
156
|
+
return { value: [], count: 0 };
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
async get(objectName: string, id: string): Promise<Record<string, any>> {
|
|
160
|
+
// Delegate to driver during migration phase
|
|
161
|
+
if (this.driver) {
|
|
162
|
+
return await this.driver.findOne(objectName, id, {}, {});
|
|
163
|
+
}
|
|
164
|
+
return {};
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
async create(objectName: string, data: any): Promise<Record<string, any>> {
|
|
168
|
+
// Delegate to driver during migration phase
|
|
169
|
+
if (this.driver) {
|
|
170
|
+
return await this.driver.create(objectName, data, {});
|
|
171
|
+
}
|
|
172
|
+
return data;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
async update(objectName: string, id: string, data: any): Promise<Record<string, any>> {
|
|
176
|
+
// Delegate to driver during migration phase
|
|
177
|
+
if (this.driver) {
|
|
178
|
+
return await this.driver.update(objectName, id, data, {});
|
|
179
|
+
}
|
|
180
|
+
return data;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
async delete(objectName: string, id: string): Promise<boolean> {
|
|
184
|
+
// Delegate to driver during migration phase
|
|
185
|
+
if (this.driver) {
|
|
186
|
+
await this.driver.delete(objectName, id, {});
|
|
187
|
+
return true;
|
|
188
|
+
}
|
|
189
|
+
return true;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
getMetadata(objectName: string): any {
|
|
193
|
+
return {};
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
getView(objectName: string, viewType?: 'list' | 'form'): any {
|
|
197
|
+
return null;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
export class ObjectStackRuntimeProtocol {}
|
|
202
|
+
|
|
203
|
+
export interface RuntimeContext {
|
|
204
|
+
engine: ObjectStackKernel;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
export interface RuntimePlugin {
|
|
208
|
+
name: string;
|
|
209
|
+
install?: (ctx: RuntimeContext) => void | Promise<void>;
|
|
210
|
+
onStart?: (ctx: RuntimeContext) => void | Promise<void>;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// Export MetadataRegistry
|
|
214
|
+
export { MockMetadataRegistry as MetadataRegistry };
|
|
215
|
+
|
|
216
|
+
export interface MetadataItem {
|
|
217
|
+
type: string;
|
|
218
|
+
id: string;
|
|
219
|
+
content: unknown;
|
|
220
|
+
packageName?: string;
|
|
221
|
+
path?: string;
|
|
222
|
+
package?: string;
|
|
223
|
+
}
|
package/test/dynamic.test.ts
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ObjectQL
|
|
3
|
+
* Copyright (c) 2026-present ObjectStack Inc.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*/
|
|
8
|
+
|
|
1
9
|
import { ObjectQL } from '@objectql/core';
|
|
2
10
|
import { ObjectLoader } from '../src';
|
|
3
11
|
import * as path from 'path';
|
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ObjectQL
|
|
3
|
+
* Copyright (c) 2026-present ObjectStack Inc.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*/
|
|
8
|
+
|
|
1
9
|
module.exports = {
|
|
2
10
|
listenTo: 'project',
|
|
3
11
|
closeProject: {
|
package/test/loader.test.ts
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ObjectQL
|
|
3
|
+
* Copyright (c) 2026-present ObjectStack Inc.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*/
|
|
8
|
+
|
|
1
9
|
import { loadObjectConfigs } from '../src/loader';
|
|
2
10
|
import * as path from 'path';
|
|
3
11
|
|
package/test/metadata.test.ts
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ObjectQL
|
|
3
|
+
* Copyright (c) 2026-present ObjectStack Inc.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*/
|
|
8
|
+
|
|
1
9
|
import { ObjectQL } from '@objectql/core';
|
|
2
10
|
import { ObjectConfig } from '@objectql/types';
|
|
3
11
|
import * as fs from 'fs';
|
package/test/validation.test.ts
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ObjectQL
|
|
3
|
+
* Copyright (c) 2026-present ObjectStack Inc.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*/
|
|
8
|
+
|
|
1
9
|
import { Validator } from '@objectql/core';
|
|
2
10
|
import {
|
|
3
11
|
ValidationContext,
|