@principal-ai/principal-view-core 0.5.6
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 +126 -0
- package/dist/ConfigurationLoader.d.ts +76 -0
- package/dist/ConfigurationLoader.d.ts.map +1 -0
- package/dist/ConfigurationLoader.js +144 -0
- package/dist/ConfigurationLoader.js.map +1 -0
- package/dist/ConfigurationValidator.d.ts +31 -0
- package/dist/ConfigurationValidator.d.ts.map +1 -0
- package/dist/ConfigurationValidator.js +242 -0
- package/dist/ConfigurationValidator.js.map +1 -0
- package/dist/EventProcessor.d.ts +49 -0
- package/dist/EventProcessor.d.ts.map +1 -0
- package/dist/EventProcessor.js +215 -0
- package/dist/EventProcessor.js.map +1 -0
- package/dist/EventRecorderService.d.ts +305 -0
- package/dist/EventRecorderService.d.ts.map +1 -0
- package/dist/EventRecorderService.js +463 -0
- package/dist/EventRecorderService.js.map +1 -0
- package/dist/LibraryLoader.d.ts +63 -0
- package/dist/LibraryLoader.d.ts.map +1 -0
- package/dist/LibraryLoader.js +188 -0
- package/dist/LibraryLoader.js.map +1 -0
- package/dist/PathBasedEventProcessor.d.ts +90 -0
- package/dist/PathBasedEventProcessor.d.ts.map +1 -0
- package/dist/PathBasedEventProcessor.js +239 -0
- package/dist/PathBasedEventProcessor.js.map +1 -0
- package/dist/SessionManager.d.ts +194 -0
- package/dist/SessionManager.d.ts.map +1 -0
- package/dist/SessionManager.js +299 -0
- package/dist/SessionManager.js.map +1 -0
- package/dist/ValidationEngine.d.ts +31 -0
- package/dist/ValidationEngine.d.ts.map +1 -0
- package/dist/ValidationEngine.js +158 -0
- package/dist/ValidationEngine.js.map +1 -0
- package/dist/helpers/GraphInstrumentationHelper.d.ts +93 -0
- package/dist/helpers/GraphInstrumentationHelper.d.ts.map +1 -0
- package/dist/helpers/GraphInstrumentationHelper.js +248 -0
- package/dist/helpers/GraphInstrumentationHelper.js.map +1 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +34 -0
- package/dist/index.js.map +1 -0
- package/dist/rules/config.d.ts +57 -0
- package/dist/rules/config.d.ts.map +1 -0
- package/dist/rules/config.js +382 -0
- package/dist/rules/config.js.map +1 -0
- package/dist/rules/engine.d.ts +70 -0
- package/dist/rules/engine.d.ts.map +1 -0
- package/dist/rules/engine.js +252 -0
- package/dist/rules/engine.js.map +1 -0
- package/dist/rules/implementations/connection-type-references.d.ts +7 -0
- package/dist/rules/implementations/connection-type-references.d.ts.map +1 -0
- package/dist/rules/implementations/connection-type-references.js +104 -0
- package/dist/rules/implementations/connection-type-references.js.map +1 -0
- package/dist/rules/implementations/dead-end-states.d.ts +17 -0
- package/dist/rules/implementations/dead-end-states.d.ts.map +1 -0
- package/dist/rules/implementations/dead-end-states.js +72 -0
- package/dist/rules/implementations/dead-end-states.js.map +1 -0
- package/dist/rules/implementations/index.d.ts +24 -0
- package/dist/rules/implementations/index.d.ts.map +1 -0
- package/dist/rules/implementations/index.js +62 -0
- package/dist/rules/implementations/index.js.map +1 -0
- package/dist/rules/implementations/library-node-type-match.d.ts +17 -0
- package/dist/rules/implementations/library-node-type-match.d.ts.map +1 -0
- package/dist/rules/implementations/library-node-type-match.js +123 -0
- package/dist/rules/implementations/library-node-type-match.js.map +1 -0
- package/dist/rules/implementations/minimum-node-sources.d.ts +22 -0
- package/dist/rules/implementations/minimum-node-sources.d.ts.map +1 -0
- package/dist/rules/implementations/minimum-node-sources.js +54 -0
- package/dist/rules/implementations/minimum-node-sources.js.map +1 -0
- package/dist/rules/implementations/no-unknown-fields.d.ts +7 -0
- package/dist/rules/implementations/no-unknown-fields.d.ts.map +1 -0
- package/dist/rules/implementations/no-unknown-fields.js +211 -0
- package/dist/rules/implementations/no-unknown-fields.js.map +1 -0
- package/dist/rules/implementations/orphaned-edge-types.d.ts +7 -0
- package/dist/rules/implementations/orphaned-edge-types.d.ts.map +1 -0
- package/dist/rules/implementations/orphaned-edge-types.js +47 -0
- package/dist/rules/implementations/orphaned-edge-types.js.map +1 -0
- package/dist/rules/implementations/orphaned-node-types.d.ts +7 -0
- package/dist/rules/implementations/orphaned-node-types.d.ts.map +1 -0
- package/dist/rules/implementations/orphaned-node-types.js +50 -0
- package/dist/rules/implementations/orphaned-node-types.js.map +1 -0
- package/dist/rules/implementations/required-metadata.d.ts +7 -0
- package/dist/rules/implementations/required-metadata.d.ts.map +1 -0
- package/dist/rules/implementations/required-metadata.js +57 -0
- package/dist/rules/implementations/required-metadata.js.map +1 -0
- package/dist/rules/implementations/state-transition-references.d.ts +7 -0
- package/dist/rules/implementations/state-transition-references.d.ts.map +1 -0
- package/dist/rules/implementations/state-transition-references.js +135 -0
- package/dist/rules/implementations/state-transition-references.js.map +1 -0
- package/dist/rules/implementations/unreachable-states.d.ts +7 -0
- package/dist/rules/implementations/unreachable-states.d.ts.map +1 -0
- package/dist/rules/implementations/unreachable-states.js +80 -0
- package/dist/rules/implementations/unreachable-states.js.map +1 -0
- package/dist/rules/implementations/valid-action-patterns.d.ts +17 -0
- package/dist/rules/implementations/valid-action-patterns.d.ts.map +1 -0
- package/dist/rules/implementations/valid-action-patterns.js +109 -0
- package/dist/rules/implementations/valid-action-patterns.js.map +1 -0
- package/dist/rules/implementations/valid-color-format.d.ts +7 -0
- package/dist/rules/implementations/valid-color-format.d.ts.map +1 -0
- package/dist/rules/implementations/valid-color-format.js +91 -0
- package/dist/rules/implementations/valid-color-format.js.map +1 -0
- package/dist/rules/implementations/valid-edge-types.d.ts +7 -0
- package/dist/rules/implementations/valid-edge-types.d.ts.map +1 -0
- package/dist/rules/implementations/valid-edge-types.js +244 -0
- package/dist/rules/implementations/valid-edge-types.js.map +1 -0
- package/dist/rules/implementations/valid-node-types.d.ts +7 -0
- package/dist/rules/implementations/valid-node-types.d.ts.map +1 -0
- package/dist/rules/implementations/valid-node-types.js +175 -0
- package/dist/rules/implementations/valid-node-types.js.map +1 -0
- package/dist/rules/index.d.ts +28 -0
- package/dist/rules/index.d.ts.map +1 -0
- package/dist/rules/index.js +45 -0
- package/dist/rules/index.js.map +1 -0
- package/dist/rules/types.d.ts +309 -0
- package/dist/rules/types.d.ts.map +1 -0
- package/dist/rules/types.js +35 -0
- package/dist/rules/types.js.map +1 -0
- package/dist/types/canvas.d.ts +409 -0
- package/dist/types/canvas.d.ts.map +1 -0
- package/dist/types/canvas.js +70 -0
- package/dist/types/canvas.js.map +1 -0
- package/dist/types/index.d.ts +311 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +13 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/library.d.ts +185 -0
- package/dist/types/library.d.ts.map +1 -0
- package/dist/types/library.js +15 -0
- package/dist/types/library.js.map +1 -0
- package/dist/types/path-based-config.d.ts +230 -0
- package/dist/types/path-based-config.d.ts.map +1 -0
- package/dist/types/path-based-config.js +9 -0
- package/dist/types/path-based-config.js.map +1 -0
- package/dist/utils/CanvasConverter.d.ts +118 -0
- package/dist/utils/CanvasConverter.d.ts.map +1 -0
- package/dist/utils/CanvasConverter.js +315 -0
- package/dist/utils/CanvasConverter.js.map +1 -0
- package/dist/utils/GraphConverter.d.ts +18 -0
- package/dist/utils/GraphConverter.d.ts.map +1 -0
- package/dist/utils/GraphConverter.js +61 -0
- package/dist/utils/GraphConverter.js.map +1 -0
- package/dist/utils/LibraryConverter.d.ts +113 -0
- package/dist/utils/LibraryConverter.d.ts.map +1 -0
- package/dist/utils/LibraryConverter.js +166 -0
- package/dist/utils/LibraryConverter.js.map +1 -0
- package/dist/utils/PathMatcher.d.ts +55 -0
- package/dist/utils/PathMatcher.d.ts.map +1 -0
- package/dist/utils/PathMatcher.js +172 -0
- package/dist/utils/PathMatcher.js.map +1 -0
- package/dist/utils/YamlParser.d.ts +36 -0
- package/dist/utils/YamlParser.d.ts.map +1 -0
- package/dist/utils/YamlParser.js +63 -0
- package/dist/utils/YamlParser.js.map +1 -0
- package/package.json +47 -0
- package/src/ConfigurationLoader.test.ts +490 -0
- package/src/ConfigurationLoader.ts +185 -0
- package/src/ConfigurationValidator.test.ts +200 -0
- package/src/ConfigurationValidator.ts +283 -0
- package/src/EventProcessor.test.ts +405 -0
- package/src/EventProcessor.ts +250 -0
- package/src/EventRecorderService.test.ts +541 -0
- package/src/EventRecorderService.ts +744 -0
- package/src/LibraryLoader.ts +215 -0
- package/src/PathBasedEventProcessor.test.ts +567 -0
- package/src/PathBasedEventProcessor.ts +332 -0
- package/src/SessionManager.test.ts +424 -0
- package/src/SessionManager.ts +470 -0
- package/src/ValidationEngine.test.ts +371 -0
- package/src/ValidationEngine.ts +196 -0
- package/src/helpers/GraphInstrumentationHelper.test.ts +340 -0
- package/src/helpers/GraphInstrumentationHelper.ts +326 -0
- package/src/index.ts +85 -0
- package/src/rules/config.test.ts +278 -0
- package/src/rules/config.ts +459 -0
- package/src/rules/engine.test.ts +332 -0
- package/src/rules/engine.ts +318 -0
- package/src/rules/implementations/connection-type-references.ts +117 -0
- package/src/rules/implementations/dead-end-states.ts +101 -0
- package/src/rules/implementations/index.ts +73 -0
- package/src/rules/implementations/library-node-type-match.ts +148 -0
- package/src/rules/implementations/minimum-node-sources.ts +82 -0
- package/src/rules/implementations/no-unknown-fields.ts +342 -0
- package/src/rules/implementations/orphaned-edge-types.ts +55 -0
- package/src/rules/implementations/orphaned-node-types.ts +58 -0
- package/src/rules/implementations/required-metadata.ts +64 -0
- package/src/rules/implementations/state-transition-references.ts +151 -0
- package/src/rules/implementations/unreachable-states.ts +94 -0
- package/src/rules/implementations/valid-action-patterns.ts +136 -0
- package/src/rules/implementations/valid-color-format.ts +140 -0
- package/src/rules/implementations/valid-edge-types.ts +258 -0
- package/src/rules/implementations/valid-node-types.ts +189 -0
- package/src/rules/index.ts +95 -0
- package/src/rules/types.ts +426 -0
- package/src/types/canvas.ts +496 -0
- package/src/types/index.ts +382 -0
- package/src/types/library.ts +233 -0
- package/src/types/path-based-config.ts +281 -0
- package/src/utils/CanvasConverter.ts +431 -0
- package/src/utils/GraphConverter.test.ts +195 -0
- package/src/utils/GraphConverter.ts +71 -0
- package/src/utils/LibraryConverter.ts +245 -0
- package/src/utils/PathMatcher.test.ts +148 -0
- package/src/utils/PathMatcher.ts +183 -0
- package/src/utils/YamlParser.ts +75 -0
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* YAML parsing utility for loading configuration files
|
|
3
|
+
*
|
|
4
|
+
* Provides error handling and validation for YAML configuration files.
|
|
5
|
+
* Supports both .yaml and .yml file extensions.
|
|
6
|
+
*/
|
|
7
|
+
import { PathBasedGraphConfiguration } from '../types/path-based-config';
|
|
8
|
+
export interface YamlParseResult {
|
|
9
|
+
success: boolean;
|
|
10
|
+
data?: PathBasedGraphConfiguration;
|
|
11
|
+
error?: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Parse YAML content into a configuration object
|
|
15
|
+
*
|
|
16
|
+
* @param content - Raw YAML string content
|
|
17
|
+
* @param filename - Optional filename for error messages
|
|
18
|
+
* @returns Parse result with configuration or error
|
|
19
|
+
*/
|
|
20
|
+
export declare function parseYaml(content: string, filename?: string): YamlParseResult;
|
|
21
|
+
/**
|
|
22
|
+
* Check if a filename has a valid YAML extension
|
|
23
|
+
*
|
|
24
|
+
* @param filename - Filename to check
|
|
25
|
+
* @returns True if filename ends with .yaml or .yml
|
|
26
|
+
*/
|
|
27
|
+
export declare function isYamlFile(filename: string): boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Extract configuration name from filename
|
|
30
|
+
* Removes the .yaml or .yml extension
|
|
31
|
+
*
|
|
32
|
+
* @param filename - Filename to process
|
|
33
|
+
* @returns Configuration name without extension
|
|
34
|
+
*/
|
|
35
|
+
export declare function getConfigNameFromFilename(filename: string): string;
|
|
36
|
+
//# sourceMappingURL=YamlParser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"YamlParser.d.ts","sourceRoot":"","sources":["../../src/utils/YamlParser.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,2BAA2B,EAAE,MAAM,4BAA4B,CAAC;AAEzE,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,2BAA2B,CAAC;IACnC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,eAAe,CA8B7E;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAEpD;AAED;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAElE"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* YAML parsing utility for loading configuration files
|
|
3
|
+
*
|
|
4
|
+
* Provides error handling and validation for YAML configuration files.
|
|
5
|
+
* Supports both .yaml and .yml file extensions.
|
|
6
|
+
*/
|
|
7
|
+
import * as yaml from 'js-yaml';
|
|
8
|
+
/**
|
|
9
|
+
* Parse YAML content into a configuration object
|
|
10
|
+
*
|
|
11
|
+
* @param content - Raw YAML string content
|
|
12
|
+
* @param filename - Optional filename for error messages
|
|
13
|
+
* @returns Parse result with configuration or error
|
|
14
|
+
*/
|
|
15
|
+
export function parseYaml(content, filename) {
|
|
16
|
+
try {
|
|
17
|
+
const data = yaml.load(content);
|
|
18
|
+
if (!data) {
|
|
19
|
+
return {
|
|
20
|
+
success: false,
|
|
21
|
+
error: `Empty YAML file${filename ? `: ${filename}` : ''}`,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
// Basic validation - ensure it has the required structure
|
|
25
|
+
if (!data.metadata || !data.nodeTypes || !data.edgeTypes) {
|
|
26
|
+
return {
|
|
27
|
+
success: false,
|
|
28
|
+
error: `Invalid configuration structure${filename ? ` in ${filename}` : ''}: missing required fields (metadata, nodeTypes, or edgeTypes)`,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
return {
|
|
32
|
+
success: true,
|
|
33
|
+
data,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
38
|
+
return {
|
|
39
|
+
success: false,
|
|
40
|
+
error: `YAML parse error${filename ? ` in ${filename}` : ''}: ${errorMessage}`,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Check if a filename has a valid YAML extension
|
|
46
|
+
*
|
|
47
|
+
* @param filename - Filename to check
|
|
48
|
+
* @returns True if filename ends with .yaml or .yml
|
|
49
|
+
*/
|
|
50
|
+
export function isYamlFile(filename) {
|
|
51
|
+
return filename.endsWith('.yaml') || filename.endsWith('.yml');
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Extract configuration name from filename
|
|
55
|
+
* Removes the .yaml or .yml extension
|
|
56
|
+
*
|
|
57
|
+
* @param filename - Filename to process
|
|
58
|
+
* @returns Configuration name without extension
|
|
59
|
+
*/
|
|
60
|
+
export function getConfigNameFromFilename(filename) {
|
|
61
|
+
return filename.replace(/\.(yaml|yml)$/, '');
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=YamlParser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"YamlParser.js","sourceRoot":"","sources":["../../src/utils/YamlParser.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,IAAI,MAAM,SAAS,CAAC;AAShC;;;;;;GAMG;AACH,MAAM,UAAU,SAAS,CAAC,OAAe,EAAE,QAAiB;IAC1D,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAgC,CAAC;QAE/D,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,KAAK,EAAE,kBAAkB,QAAQ,CAAC,CAAC,CAAC,KAAK,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE;aAC3D,CAAC;QACJ,CAAC;QAED,0DAA0D;QAC1D,IAAI,CAAC,IAAI,CAAC,QAAQ,IAAI,CAAC,IAAI,CAAC,SAAS,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;YACzD,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,KAAK,EAAE,kCAAkC,QAAQ,CAAC,CAAC,CAAC,OAAO,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,+DAA+D;aAC1I,CAAC;QACJ,CAAC;QAED,OAAO;YACL,OAAO,EAAE,IAAI;YACb,IAAI;SACL,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,YAAY,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAC5E,OAAO;YACL,OAAO,EAAE,KAAK;YACd,KAAK,EAAE,mBAAmB,QAAQ,CAAC,CAAC,CAAC,OAAO,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,YAAY,EAAE;SAC/E,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,UAAU,CAAC,QAAgB;IACzC,OAAO,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;AACjE,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,yBAAyB,CAAC,QAAgB;IACxD,OAAO,QAAQ,CAAC,OAAO,CAAC,eAAe,EAAE,EAAE,CAAC,CAAC;AAC/C,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@principal-ai/principal-view-core",
|
|
3
|
+
"version": "0.5.6",
|
|
4
|
+
"description": "Core logic and types for graph-based principal view framework",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"types": "./dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"default": "./dist/index.js"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"files": ["dist", "src", "README.md"],
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "bun run build:clean && bun run build:ts",
|
|
16
|
+
"build:clean": "rm -rf dist",
|
|
17
|
+
"build:ts": "tsc",
|
|
18
|
+
"dev": "tsc --watch",
|
|
19
|
+
"test": "bun test",
|
|
20
|
+
"test:watch": "bun test --watch",
|
|
21
|
+
"test:coverage": "bun test --coverage"
|
|
22
|
+
},
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"zod": "^3.22.0",
|
|
25
|
+
"date-fns": "^3.0.0",
|
|
26
|
+
"@principal-ai/repository-abstraction": "^0.2.5",
|
|
27
|
+
"js-yaml": "^4.1.0"
|
|
28
|
+
},
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"@types/jest": "^30.0.0",
|
|
31
|
+
"@types/js-yaml": "^4.0.9",
|
|
32
|
+
"jest": "^30.1.3",
|
|
33
|
+
"typescript": "^5.0.4"
|
|
34
|
+
},
|
|
35
|
+
"keywords": [
|
|
36
|
+
"validation",
|
|
37
|
+
"graph",
|
|
38
|
+
"visualization",
|
|
39
|
+
"testing",
|
|
40
|
+
"event-driven"
|
|
41
|
+
],
|
|
42
|
+
"license": "MIT",
|
|
43
|
+
"publishConfig": {
|
|
44
|
+
"access": "public",
|
|
45
|
+
"registry": "https://registry.npmjs.org/"
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -0,0 +1,490 @@
|
|
|
1
|
+
import { describe, expect, test, beforeEach } from 'bun:test';
|
|
2
|
+
import { ConfigurationLoader } from './ConfigurationLoader';
|
|
3
|
+
import type { ConfigurationFile, ConfigurationLoadResult } from './ConfigurationLoader';
|
|
4
|
+
import { InMemoryFileSystemAdapter } from '@principal-ai/repository-abstraction';
|
|
5
|
+
import type { PathBasedGraphConfiguration } from './types/path-based-config';
|
|
6
|
+
|
|
7
|
+
describe('ConfigurationLoader', () => {
|
|
8
|
+
let fsAdapter: InMemoryFileSystemAdapter;
|
|
9
|
+
let loader: ConfigurationLoader;
|
|
10
|
+
|
|
11
|
+
const validConfig: PathBasedGraphConfiguration = {
|
|
12
|
+
metadata: {
|
|
13
|
+
name: 'Test Config',
|
|
14
|
+
version: '1.0.0',
|
|
15
|
+
description: 'A test configuration',
|
|
16
|
+
},
|
|
17
|
+
nodeTypes: {
|
|
18
|
+
service: {
|
|
19
|
+
shape: 'rectangle',
|
|
20
|
+
color: '#4A90E2',
|
|
21
|
+
dataSchema: {
|
|
22
|
+
name: { type: 'string', required: true },
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
edgeTypes: {
|
|
27
|
+
call: {
|
|
28
|
+
style: 'solid',
|
|
29
|
+
color: '#999',
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
allowedConnections: [
|
|
33
|
+
{
|
|
34
|
+
from: 'service',
|
|
35
|
+
to: 'service',
|
|
36
|
+
via: 'call',
|
|
37
|
+
},
|
|
38
|
+
],
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const architectureConfig: PathBasedGraphConfiguration = {
|
|
42
|
+
metadata: {
|
|
43
|
+
name: 'Architecture',
|
|
44
|
+
version: '1.0.0',
|
|
45
|
+
},
|
|
46
|
+
nodeTypes: {
|
|
47
|
+
component: {
|
|
48
|
+
shape: 'hexagon',
|
|
49
|
+
color: '#FF6B6B',
|
|
50
|
+
dataSchema: {
|
|
51
|
+
name: { type: 'string', required: true },
|
|
52
|
+
},
|
|
53
|
+
sources: ['src/**/*.ts'],
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
edgeTypes: {
|
|
57
|
+
dependency: {
|
|
58
|
+
style: 'dashed',
|
|
59
|
+
color: '#888',
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
allowedConnections: [
|
|
63
|
+
{
|
|
64
|
+
from: 'component',
|
|
65
|
+
to: 'component',
|
|
66
|
+
via: 'dependency',
|
|
67
|
+
},
|
|
68
|
+
],
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
beforeEach(() => {
|
|
72
|
+
fsAdapter = new InMemoryFileSystemAdapter();
|
|
73
|
+
loader = new ConfigurationLoader(fsAdapter);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
describe('hasConfigDirectory', () => {
|
|
77
|
+
test('returns true when .vgc directory exists', () => {
|
|
78
|
+
fsAdapter.createDir('/project/.vgc');
|
|
79
|
+
|
|
80
|
+
expect(loader.hasConfigDirectory('/project')).toBe(true);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
test('returns false when .vgc directory does not exist', () => {
|
|
84
|
+
expect(loader.hasConfigDirectory('/project')).toBe(false);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
test('returns false when .vgc exists but is not a directory', () => {
|
|
88
|
+
fsAdapter.writeFile('/project/.vgc', 'not a directory');
|
|
89
|
+
|
|
90
|
+
expect(loader.hasConfigDirectory('/project')).toBe(false);
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
describe('listConfigurations', () => {
|
|
95
|
+
test('returns empty array when .vgc does not exist', () => {
|
|
96
|
+
const configs = loader.listConfigurations('/project');
|
|
97
|
+
|
|
98
|
+
expect(configs).toEqual([]);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
test('returns list of configuration names', () => {
|
|
102
|
+
fsAdapter.createDir('/project/.vgc');
|
|
103
|
+
fsAdapter.writeFile('/project/.vgc/architecture.yaml', JSON.stringify(validConfig));
|
|
104
|
+
fsAdapter.writeFile('/project/.vgc/data-flow.yaml', JSON.stringify(validConfig));
|
|
105
|
+
fsAdapter.writeFile('/project/.vgc/deployment.yml', JSON.stringify(validConfig));
|
|
106
|
+
|
|
107
|
+
const configs = loader.listConfigurations('/project');
|
|
108
|
+
|
|
109
|
+
expect(configs).toEqual(['architecture', 'data-flow', 'deployment']);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
test('filters out non-YAML files', () => {
|
|
113
|
+
fsAdapter.createDir('/project/.vgc');
|
|
114
|
+
fsAdapter.writeFile('/project/.vgc/config1.yaml', JSON.stringify(validConfig));
|
|
115
|
+
fsAdapter.writeFile('/project/.vgc/README.md', '# README');
|
|
116
|
+
fsAdapter.writeFile('/project/.vgc/config.json', '{}');
|
|
117
|
+
|
|
118
|
+
const configs = loader.listConfigurations('/project');
|
|
119
|
+
|
|
120
|
+
expect(configs).toEqual(['config1']);
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
test('returns sorted configuration names', () => {
|
|
124
|
+
fsAdapter.createDir('/project/.vgc');
|
|
125
|
+
fsAdapter.writeFile('/project/.vgc/zebra.yaml', JSON.stringify(validConfig));
|
|
126
|
+
fsAdapter.writeFile('/project/.vgc/alpha.yaml', JSON.stringify(validConfig));
|
|
127
|
+
fsAdapter.writeFile('/project/.vgc/middle.yaml', JSON.stringify(validConfig));
|
|
128
|
+
|
|
129
|
+
const configs = loader.listConfigurations('/project');
|
|
130
|
+
|
|
131
|
+
expect(configs).toEqual(['alpha', 'middle', 'zebra']);
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
describe('loadByName', () => {
|
|
136
|
+
beforeEach(() => {
|
|
137
|
+
fsAdapter.createDir('/project/.vgc');
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
test('loads configuration by name with .yaml extension', () => {
|
|
141
|
+
const yamlContent = `
|
|
142
|
+
metadata:
|
|
143
|
+
name: Test Config
|
|
144
|
+
version: 1.0.0
|
|
145
|
+
nodeTypes:
|
|
146
|
+
service:
|
|
147
|
+
shape: rectangle
|
|
148
|
+
color: '#4A90E2'
|
|
149
|
+
dataSchema:
|
|
150
|
+
name:
|
|
151
|
+
type: string
|
|
152
|
+
required: true
|
|
153
|
+
edgeTypes:
|
|
154
|
+
call:
|
|
155
|
+
style: solid
|
|
156
|
+
color: '#999'
|
|
157
|
+
allowedConnections:
|
|
158
|
+
- from: service
|
|
159
|
+
to: service
|
|
160
|
+
via: call
|
|
161
|
+
`;
|
|
162
|
+
fsAdapter.writeFile('/project/.vgc/simple.yaml', yamlContent);
|
|
163
|
+
|
|
164
|
+
const result = loader.loadByName('simple', '/project');
|
|
165
|
+
|
|
166
|
+
expect(result).not.toBeNull();
|
|
167
|
+
expect(result?.name).toBe('simple');
|
|
168
|
+
expect(result?.config.metadata.name).toBe('Test Config');
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
test('loads configuration by name with .yml extension', () => {
|
|
172
|
+
const yamlContent = `
|
|
173
|
+
metadata:
|
|
174
|
+
name: Alternative Config
|
|
175
|
+
version: 2.0.0
|
|
176
|
+
nodeTypes:
|
|
177
|
+
component:
|
|
178
|
+
shape: hexagon
|
|
179
|
+
color: '#FF6B6B'
|
|
180
|
+
dataSchema:
|
|
181
|
+
id:
|
|
182
|
+
type: string
|
|
183
|
+
required: true
|
|
184
|
+
edgeTypes:
|
|
185
|
+
link:
|
|
186
|
+
style: dashed
|
|
187
|
+
color: '#888'
|
|
188
|
+
allowedConnections:
|
|
189
|
+
- from: component
|
|
190
|
+
to: component
|
|
191
|
+
via: link
|
|
192
|
+
`;
|
|
193
|
+
fsAdapter.writeFile('/project/.vgc/alt.yml', yamlContent);
|
|
194
|
+
|
|
195
|
+
const result = loader.loadByName('alt', '/project');
|
|
196
|
+
|
|
197
|
+
expect(result).not.toBeNull();
|
|
198
|
+
expect(result?.name).toBe('alt');
|
|
199
|
+
expect(result?.config.metadata.name).toBe('Alternative Config');
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
test('returns null when configuration does not exist', () => {
|
|
203
|
+
const result = loader.loadByName('nonexistent', '/project');
|
|
204
|
+
|
|
205
|
+
expect(result).toBeNull();
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
test('returns null when .vgc directory does not exist', () => {
|
|
209
|
+
const result = loader.loadByName('any', '/no-project');
|
|
210
|
+
|
|
211
|
+
expect(result).toBeNull();
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
test('returns null when YAML is invalid', () => {
|
|
215
|
+
fsAdapter.writeFile('/project/.vgc/invalid.yaml', 'invalid: yaml: content:');
|
|
216
|
+
|
|
217
|
+
const result = loader.loadByName('invalid', '/project');
|
|
218
|
+
|
|
219
|
+
expect(result).toBeNull();
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
test('returns null when configuration structure is invalid', () => {
|
|
223
|
+
const yamlContent = `
|
|
224
|
+
metadata:
|
|
225
|
+
name: Incomplete
|
|
226
|
+
nodeTypes: {}
|
|
227
|
+
# Missing edgeTypes and allowedConnections
|
|
228
|
+
`;
|
|
229
|
+
fsAdapter.writeFile('/project/.vgc/incomplete.yaml', yamlContent);
|
|
230
|
+
|
|
231
|
+
const result = loader.loadByName('incomplete', '/project');
|
|
232
|
+
|
|
233
|
+
expect(result).toBeNull();
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
test('prefers .yaml over .yml when both exist', () => {
|
|
237
|
+
const yamlContent = `
|
|
238
|
+
metadata:
|
|
239
|
+
name: YAML Version
|
|
240
|
+
version: 1.0.0
|
|
241
|
+
nodeTypes:
|
|
242
|
+
service:
|
|
243
|
+
shape: rectangle
|
|
244
|
+
dataSchema:
|
|
245
|
+
name:
|
|
246
|
+
type: string
|
|
247
|
+
edgeTypes:
|
|
248
|
+
call:
|
|
249
|
+
style: solid
|
|
250
|
+
allowedConnections:
|
|
251
|
+
- from: service
|
|
252
|
+
to: service
|
|
253
|
+
via: call
|
|
254
|
+
`;
|
|
255
|
+
const ymlContent = `
|
|
256
|
+
metadata:
|
|
257
|
+
name: YML Version
|
|
258
|
+
version: 1.0.0
|
|
259
|
+
nodeTypes:
|
|
260
|
+
service:
|
|
261
|
+
shape: rectangle
|
|
262
|
+
dataSchema:
|
|
263
|
+
name:
|
|
264
|
+
type: string
|
|
265
|
+
edgeTypes:
|
|
266
|
+
call:
|
|
267
|
+
style: solid
|
|
268
|
+
allowedConnections:
|
|
269
|
+
- from: service
|
|
270
|
+
to: service
|
|
271
|
+
via: call
|
|
272
|
+
`;
|
|
273
|
+
fsAdapter.writeFile('/project/.vgc/both.yaml', yamlContent);
|
|
274
|
+
fsAdapter.writeFile('/project/.vgc/both.yml', ymlContent);
|
|
275
|
+
|
|
276
|
+
const result = loader.loadByName('both', '/project');
|
|
277
|
+
|
|
278
|
+
expect(result).not.toBeNull();
|
|
279
|
+
expect(result?.config.metadata.name).toBe('YAML Version');
|
|
280
|
+
});
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
describe('loadAll', () => {
|
|
284
|
+
test('returns error when .vgc directory does not exist', () => {
|
|
285
|
+
const result = loader.loadAll('/project');
|
|
286
|
+
|
|
287
|
+
expect(result.configs).toEqual([]);
|
|
288
|
+
expect(result.errors).toHaveLength(1);
|
|
289
|
+
expect(result.errors[0].file).toBe('.vgc');
|
|
290
|
+
expect(result.errors[0].error).toContain('not found');
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
test('loads all valid configurations', () => {
|
|
294
|
+
fsAdapter.createDir('/project/.vgc');
|
|
295
|
+
|
|
296
|
+
const config1 = `
|
|
297
|
+
metadata:
|
|
298
|
+
name: Config 1
|
|
299
|
+
version: 1.0.0
|
|
300
|
+
nodeTypes:
|
|
301
|
+
service:
|
|
302
|
+
shape: rectangle
|
|
303
|
+
dataSchema:
|
|
304
|
+
name:
|
|
305
|
+
type: string
|
|
306
|
+
edgeTypes:
|
|
307
|
+
call:
|
|
308
|
+
style: solid
|
|
309
|
+
allowedConnections:
|
|
310
|
+
- from: service
|
|
311
|
+
to: service
|
|
312
|
+
via: call
|
|
313
|
+
`;
|
|
314
|
+
const config2 = `
|
|
315
|
+
metadata:
|
|
316
|
+
name: Config 2
|
|
317
|
+
version: 2.0.0
|
|
318
|
+
nodeTypes:
|
|
319
|
+
component:
|
|
320
|
+
shape: hexagon
|
|
321
|
+
dataSchema:
|
|
322
|
+
id:
|
|
323
|
+
type: string
|
|
324
|
+
edgeTypes:
|
|
325
|
+
link:
|
|
326
|
+
style: dashed
|
|
327
|
+
allowedConnections:
|
|
328
|
+
- from: component
|
|
329
|
+
to: component
|
|
330
|
+
via: link
|
|
331
|
+
`;
|
|
332
|
+
|
|
333
|
+
fsAdapter.writeFile('/project/.vgc/first.yaml', config1);
|
|
334
|
+
fsAdapter.writeFile('/project/.vgc/second.yml', config2);
|
|
335
|
+
|
|
336
|
+
const result = loader.loadAll('/project');
|
|
337
|
+
|
|
338
|
+
expect(result.configs).toHaveLength(2);
|
|
339
|
+
expect(result.errors).toEqual([]);
|
|
340
|
+
expect(result.configs[0].name).toBe('first');
|
|
341
|
+
expect(result.configs[1].name).toBe('second');
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
test('skips non-YAML files', () => {
|
|
345
|
+
fsAdapter.createDir('/project/.vgc');
|
|
346
|
+
|
|
347
|
+
const validYaml = `
|
|
348
|
+
metadata:
|
|
349
|
+
name: Valid
|
|
350
|
+
version: 1.0.0
|
|
351
|
+
nodeTypes:
|
|
352
|
+
service:
|
|
353
|
+
shape: rectangle
|
|
354
|
+
dataSchema:
|
|
355
|
+
name:
|
|
356
|
+
type: string
|
|
357
|
+
edgeTypes:
|
|
358
|
+
call:
|
|
359
|
+
style: solid
|
|
360
|
+
allowedConnections:
|
|
361
|
+
- from: service
|
|
362
|
+
to: service
|
|
363
|
+
via: call
|
|
364
|
+
`;
|
|
365
|
+
|
|
366
|
+
fsAdapter.writeFile('/project/.vgc/valid.yaml', validYaml);
|
|
367
|
+
fsAdapter.writeFile('/project/.vgc/README.md', '# README');
|
|
368
|
+
fsAdapter.writeFile('/project/.vgc/config.json', '{}');
|
|
369
|
+
|
|
370
|
+
const result = loader.loadAll('/project');
|
|
371
|
+
|
|
372
|
+
expect(result.configs).toHaveLength(1);
|
|
373
|
+
expect(result.configs[0].name).toBe('valid');
|
|
374
|
+
expect(result.errors).toEqual([]);
|
|
375
|
+
});
|
|
376
|
+
|
|
377
|
+
test('collects errors for invalid files', () => {
|
|
378
|
+
fsAdapter.createDir('/project/.vgc');
|
|
379
|
+
|
|
380
|
+
const validYaml = `
|
|
381
|
+
metadata:
|
|
382
|
+
name: Valid
|
|
383
|
+
version: 1.0.0
|
|
384
|
+
nodeTypes:
|
|
385
|
+
service:
|
|
386
|
+
shape: rectangle
|
|
387
|
+
dataSchema:
|
|
388
|
+
name:
|
|
389
|
+
type: string
|
|
390
|
+
edgeTypes:
|
|
391
|
+
call:
|
|
392
|
+
style: solid
|
|
393
|
+
allowedConnections:
|
|
394
|
+
- from: service
|
|
395
|
+
to: service
|
|
396
|
+
via: call
|
|
397
|
+
`;
|
|
398
|
+
|
|
399
|
+
fsAdapter.writeFile('/project/.vgc/valid.yaml', validYaml);
|
|
400
|
+
fsAdapter.writeFile('/project/.vgc/invalid-yaml.yaml', 'invalid: yaml: content:');
|
|
401
|
+
fsAdapter.writeFile('/project/.vgc/incomplete.yaml', 'metadata:\n name: Incomplete\nnodeTypes: {}');
|
|
402
|
+
|
|
403
|
+
const result = loader.loadAll('/project');
|
|
404
|
+
|
|
405
|
+
expect(result.configs).toHaveLength(1);
|
|
406
|
+
expect(result.configs[0].name).toBe('valid');
|
|
407
|
+
expect(result.errors.length).toBeGreaterThan(0);
|
|
408
|
+
});
|
|
409
|
+
|
|
410
|
+
test('returns configs sorted by name', () => {
|
|
411
|
+
fsAdapter.createDir('/project/.vgc');
|
|
412
|
+
|
|
413
|
+
const configTemplate = (name: string) => `
|
|
414
|
+
metadata:
|
|
415
|
+
name: ${name}
|
|
416
|
+
version: 1.0.0
|
|
417
|
+
nodeTypes:
|
|
418
|
+
service:
|
|
419
|
+
shape: rectangle
|
|
420
|
+
dataSchema:
|
|
421
|
+
name:
|
|
422
|
+
type: string
|
|
423
|
+
edgeTypes:
|
|
424
|
+
call:
|
|
425
|
+
style: solid
|
|
426
|
+
allowedConnections:
|
|
427
|
+
- from: service
|
|
428
|
+
to: service
|
|
429
|
+
via: call
|
|
430
|
+
`;
|
|
431
|
+
|
|
432
|
+
fsAdapter.writeFile('/project/.vgc/zebra.yaml', configTemplate('Zebra'));
|
|
433
|
+
fsAdapter.writeFile('/project/.vgc/alpha.yaml', configTemplate('Alpha'));
|
|
434
|
+
fsAdapter.writeFile('/project/.vgc/middle.yaml', configTemplate('Middle'));
|
|
435
|
+
|
|
436
|
+
const result = loader.loadAll('/project');
|
|
437
|
+
|
|
438
|
+
expect(result.configs).toHaveLength(3);
|
|
439
|
+
expect(result.configs[0].name).toBe('alpha');
|
|
440
|
+
expect(result.configs[1].name).toBe('middle');
|
|
441
|
+
expect(result.configs[2].name).toBe('zebra');
|
|
442
|
+
});
|
|
443
|
+
|
|
444
|
+
test('handles mixed .yaml and .yml extensions', () => {
|
|
445
|
+
fsAdapter.createDir('/project/.vgc');
|
|
446
|
+
|
|
447
|
+
const configTemplate = (name: string) => `
|
|
448
|
+
metadata:
|
|
449
|
+
name: ${name}
|
|
450
|
+
version: 1.0.0
|
|
451
|
+
nodeTypes:
|
|
452
|
+
service:
|
|
453
|
+
shape: rectangle
|
|
454
|
+
dataSchema:
|
|
455
|
+
name:
|
|
456
|
+
type: string
|
|
457
|
+
edgeTypes:
|
|
458
|
+
call:
|
|
459
|
+
style: solid
|
|
460
|
+
allowedConnections:
|
|
461
|
+
- from: service
|
|
462
|
+
to: service
|
|
463
|
+
via: call
|
|
464
|
+
`;
|
|
465
|
+
|
|
466
|
+
fsAdapter.writeFile('/project/.vgc/config1.yaml', configTemplate('Config 1'));
|
|
467
|
+
fsAdapter.writeFile('/project/.vgc/config2.yml', configTemplate('Config 2'));
|
|
468
|
+
|
|
469
|
+
const result = loader.loadAll('/project');
|
|
470
|
+
|
|
471
|
+
expect(result.configs).toHaveLength(2);
|
|
472
|
+
expect(result.errors).toEqual([]);
|
|
473
|
+
});
|
|
474
|
+
});
|
|
475
|
+
|
|
476
|
+
describe('getConfigDirectoryPath', () => {
|
|
477
|
+
test('returns correct .vgc path', () => {
|
|
478
|
+
const path = loader.getConfigDirectoryPath('/my/project');
|
|
479
|
+
|
|
480
|
+
expect(path).toBe('/my/project/.vgc');
|
|
481
|
+
});
|
|
482
|
+
|
|
483
|
+
test('handles trailing slashes', () => {
|
|
484
|
+
const path = loader.getConfigDirectoryPath('/my/project/');
|
|
485
|
+
|
|
486
|
+
// The path should be consistent regardless of trailing slash
|
|
487
|
+
expect(path).toContain('.vgc');
|
|
488
|
+
});
|
|
489
|
+
});
|
|
490
|
+
});
|