@toolproof-core/schema 1.0.3 → 1.0.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/dist/generated/normalized/Genesis.json +16 -265
- package/dist/generated/resources/Genesis.json +18 -305
- package/dist/generated/schemas/Genesis.json +14 -152
- package/dist/generated/schemas/standalone/Goal.json +0 -33
- package/dist/generated/schemas/standalone/Job.json +0 -42
- package/dist/generated/schemas/standalone/RawStrategy.json +14 -52
- package/dist/generated/schemas/standalone/ResourceType.json +0 -34
- package/dist/generated/schemas/standalone/RunnableStrategy.json +14 -57
- package/dist/generated/schemas/standalone/StrategyRun.json +14 -71
- package/dist/generated/types/standalone/Resource_Genesis.d.ts +1 -1
- package/dist/generated/types/standalone/Resource_Job.d.ts +1 -1
- package/dist/generated/types/standalone/Resource_RawStrategy.d.ts +1 -1
- package/dist/generated/types/standalone/Resource_ResourceType.d.ts +1 -1
- package/dist/generated/types/standalone/Resource_RunnableStrategy.d.ts +1 -1
- package/dist/generated/types/types.d.ts +119 -1126
- package/dist/index.d.ts +1 -4
- package/dist/index.js +0 -2
- package/dist/scripts/_lib/config.d.ts +6 -6
- package/dist/scripts/_lib/config.js +10 -12
- package/dist/scripts/extractSchemasFromResourceTypeShells.js +109 -103
- package/dist/scripts/generateDependencies.js +15 -14
- package/dist/scripts/generateSchemaShims.js +77 -85
- package/dist/scripts/generateStandaloneSchema.js +47 -37
- package/dist/scripts/generateStandaloneType.js +85 -79
- package/dist/scripts/generateTypes.js +350 -470
- package/dist/scripts/normalizeAnchorsToPointers.d.ts +1 -1
- package/dist/scripts/normalizeAnchorsToPointers.js +61 -33
- package/dist/scripts/wrapResourceTypesWithResourceShells.js +14 -16
- package/package.json +7 -8
- package/src/Genesis.json +1837 -1999
- package/src/generated/{dependencyMap.json → dependencies/dependencyMap.json} +9 -19
- package/src/generated/normalized/Genesis.json +16 -265
- package/src/generated/resources/Genesis.json +18 -305
- package/src/generated/schemas/Genesis.json +14 -152
- package/src/generated/schemas/standalone/Goal.json +0 -33
- package/src/generated/schemas/standalone/Job.json +0 -42
- package/src/generated/schemas/standalone/RawStrategy.json +14 -52
- package/src/generated/schemas/standalone/ResourceType.json +0 -34
- package/src/generated/schemas/standalone/RunnableStrategy.json +14 -57
- package/src/generated/schemas/standalone/StrategyRun.json +14 -71
- package/src/generated/types/standalone/Resource_Genesis.d.ts +1 -1
- package/src/generated/types/standalone/Resource_Job.d.ts +1 -1
- package/src/generated/types/standalone/Resource_RawStrategy.d.ts +1 -1
- package/src/generated/types/standalone/Resource_ResourceType.d.ts +1 -1
- package/src/generated/types/standalone/Resource_RunnableStrategy.d.ts +1 -1
- package/src/generated/types/types.d.ts +119 -1126
- package/src/index.ts +66 -93
- package/src/scripts/_lib/config.ts +203 -205
- package/src/scripts/extractSchemasFromResourceTypeShells.ts +261 -218
- package/src/scripts/generateDependencies.ts +121 -120
- package/src/scripts/generateSchemaShims.ts +127 -135
- package/src/scripts/generateStandaloneSchema.ts +185 -175
- package/src/scripts/generateStandaloneType.ts +127 -119
- package/src/scripts/generateTypes.ts +532 -615
- package/src/scripts/normalizeAnchorsToPointers.ts +141 -123
- package/src/scripts/wrapResourceTypesWithResourceShells.ts +82 -84
- package/dist/generated/dependencyMap.json +0 -292
package/dist/index.d.ts
CHANGED
|
@@ -1,13 +1,10 @@
|
|
|
1
|
-
import { JobStepIdentity, BranchStepIdentity, WhileStepIdentity, ForStepIdentity } from './generated/types/types.js';
|
|
2
1
|
export { default as SchemaGenesis } from './generated/schemas/Genesis.js';
|
|
3
2
|
export { default as SchemaJob } from './generated/schemas/standalone/Job.js';
|
|
4
3
|
export { default as SchemaStrategyRun } from './generated/schemas/standalone/StrategyRun.js';
|
|
5
4
|
export { default as ResourceTypeGenesis } from './generated/resources/Genesis.js';
|
|
6
|
-
export { default as dependencies } from './generated/dependencyMap.json';
|
|
7
5
|
export type { Resource_Genesis as Resource_GenesisJson } from './generated/types/standalone/Resource_Genesis.js';
|
|
8
6
|
export type { Resource_ResourceType as Resource_ResourceTypeJson } from './generated/types/standalone/Resource_ResourceType.js';
|
|
9
7
|
export type { Resource_Job as Resource_JobJson } from './generated/types/standalone/Resource_Job.js';
|
|
10
8
|
export type { Resource_RawStrategy as Resource_RawStrategyJson } from './generated/types/standalone/Resource_RawStrategy.js';
|
|
11
9
|
export type { Resource_RunnableStrategy as Resource_RunnableStrategyJson } from './generated/types/standalone/Resource_RunnableStrategy.js';
|
|
12
|
-
export type
|
|
13
|
-
export type { DocumentationFacet as DocumentationFacetJson, NucleusFacet as NucleusFacetJson, ResourceTypeIdentity as ResourceTypeIdentityJson, ResourceType as ResourceTypeJson, ResourceRoleIdentity as ResourceRoleIdentityJson, ResourceRoleValue as ResourceRoleValueJson, Conditional as ConditionalJson, RoleMap as RoleMapJson, Roles as RolesJson, RoleBindings as RoleBindingsJson, ResourceIdentity as ResourceIdentityJson, JobStepIdentity as JobStepIdentityJson, BranchStepIdentity as BranchStepIdentityJson, WhileStepIdentity as WhileStepIdentityJson, ForStepIdentity as ForStepIdentityJson, JobStep as JobStepJson, BranchStep as BranchStepJson, WhileStep as WhileStepJson, ForStep as ForStepJson, StepKind as StepKindJson, Step as StepJson, CreationContext as CreationContextJson, ResourceMissing as ResourceMissingJson, Resource as ResourceJson, StrategyState as StrategyStateJson, StepsFacet as StepsFacetJson, RawStrategy as RawStrategyJson, RunnableStrategyIdentity as RunnableStrategyIdentityJson, RunnableStrategyStatus as RunnableStrategyStatusJson, RunnableStrategy as RunnableStrategyJson, RunnableStrategyUpdate as RunnableStrategyUpdateJson, Domain as DomainJson, JobIdentity as JobIdentityJson, Job as JobJson, JsonData as JsonDataJson, StrategyThreadIdentity as StrategyThreadIdentityJson, StrategyThreadMap as StrategyThreadMapJson, Timestamp as TimestampJson, Goal as GoalJson, } from './generated/types/types.js';
|
|
10
|
+
export type { DocumentationFacet as DocumentationFacetJson, NucleusFacet as NucleusFacetJson, ResourceTypeIdentity as ResourceTypeIdentityJson, ResourceType as ResourceTypeJson, ResourceRoleIdentity as ResourceRoleIdentityJson, ResourceRoleValue as ResourceRoleValueJson, Conditional as ConditionalJson, RoleMap as RoleMapJson, Roles as RolesJson, RoleBindings as RoleBindingsJson, ResourceIdentity as ResourceIdentityJson, JobStepIdentity as JobStepIdentityJson, BranchStepIdentity as BranchStepIdentityJson, WhileStepIdentity as WhileStepIdentityJson, ForStepIdentity as ForStepIdentityJson, JobStep as JobStepJson, BranchStep as BranchStepJson, WhileStep as WhileStepJson, ForStep as ForStepJson, StepKind as StepKindJson, StepIdentity as StepIdentityJson, Step as StepJson, CreationContext as CreationContextJson, ResourceMissing as ResourceMissingJson, Resource as ResourceJson, StrategyState as StrategyStateJson, StepsFacet as StepsFacetJson, RawStrategy as RawStrategyJson, RunnableStrategyIdentity as RunnableStrategyIdentityJson, RunnableStrategyStatus as RunnableStrategyStatusJson, RunnableStrategy as RunnableStrategyJson, RunnableStrategyUpdate as RunnableStrategyUpdateJson, JobIdentity as JobIdentityJson, Job as JobJson, JsonData as JsonDataJson, StrategyThreadIdentity as StrategyThreadIdentityJson, StrategyThreadMap as StrategyThreadMapJson, JobStepSocket as JobStepSocketJson, Timestamp as TimestampJson, Goal as GoalJson, } from './generated/types/types.js';
|
package/dist/index.js
CHANGED
|
@@ -3,5 +3,3 @@ export { default as SchemaGenesis } from './generated/schemas/Genesis.js';
|
|
|
3
3
|
export { default as SchemaJob } from './generated/schemas/standalone/Job.js';
|
|
4
4
|
export { default as SchemaStrategyRun } from './generated/schemas/standalone/StrategyRun.js';
|
|
5
5
|
export { default as ResourceTypeGenesis } from './generated/resources/Genesis.js';
|
|
6
|
-
export { default as dependencies } from './generated/dependencyMap.json';
|
|
7
|
-
// export { isResourceRoleIdentityJson, isStrategyThreadIdentityJson } from './identityGuards.js';
|
|
@@ -28,16 +28,16 @@ export declare class SchemaConfig {
|
|
|
28
28
|
getNormalizedSourcePath(): string;
|
|
29
29
|
getSchemasDir(): string;
|
|
30
30
|
getSchemaPath(filename: string): string;
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
getStandaloneSchemaDir(): string;
|
|
32
|
+
getStandaloneSchemaPath(filename: string): string;
|
|
33
33
|
getTypesSrcDir(): string;
|
|
34
34
|
getTypesDistDir(): string;
|
|
35
35
|
getTypesSrcPath(filename: string): string;
|
|
36
36
|
getTypesDistPath(filename: string): string;
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
37
|
+
getStandaloneTypeSrcDir(): string;
|
|
38
|
+
getStandaloneTypeDistDir(): string;
|
|
39
|
+
getStandaloneTypeSrcPath(filename: string): string;
|
|
40
|
+
getStandaloneTypeDistPath(filename: string): string;
|
|
41
41
|
getResourcesDir(): string;
|
|
42
42
|
getDependencyMapPath(): string;
|
|
43
43
|
getBaseUrl(): string;
|
|
@@ -20,12 +20,10 @@ export class SchemaConfig {
|
|
|
20
20
|
this.root = getEnv('TP_SCHEMA_ROOT', process.cwd());
|
|
21
21
|
this.sourceDir = getEnv('TP_SCHEMA_SOURCE_DIR', 'src/');
|
|
22
22
|
this.sourceFile = getEnv('TP_SCHEMA_SOURCE_FILE', 'Genesis.json');
|
|
23
|
-
// Intermediate, generated artifact produced by normalizeAnchorsToPointers.
|
|
24
|
-
// This should NOT live next to the source-of-truth schemas.
|
|
25
23
|
this.normalizedDir = getEnv('TP_SCHEMA_NORMALIZED_DIR', 'src/generated/normalized');
|
|
26
24
|
this.schemasDir = getEnv('TP_SCHEMA_SCHEMAS_DIR', 'src/generated/schemas');
|
|
27
25
|
this.resourcesDir = getEnv('TP_SCHEMA_RESOURCES_DIR', 'src/generated/resources');
|
|
28
|
-
this.dependencyMapPath = getEnv('TP_SCHEMA_DEPENDENCY_MAP_PATH', 'src/generated/dependencyMap.json');
|
|
26
|
+
this.dependencyMapPath = getEnv('TP_SCHEMA_DEPENDENCY_MAP_PATH', 'src/generated/dependencies/dependencyMap.json');
|
|
29
27
|
this.typesSrcDir = getEnv('TP_SCHEMA_TYPES_SRC_DIR', 'src/generated/types');
|
|
30
28
|
this.typesDistDir = getEnv('TP_SCHEMA_TYPES_DIST_DIR', 'dist/generated/types');
|
|
31
29
|
this.baseUrl = getEnv('TP_SCHEMA_BASE_URL', 'https://schemas.toolproof.com');
|
|
@@ -68,11 +66,11 @@ export class SchemaConfig {
|
|
|
68
66
|
getSchemaPath(filename) {
|
|
69
67
|
return path.join(this.getSchemasDir(), filename);
|
|
70
68
|
}
|
|
71
|
-
|
|
69
|
+
getStandaloneSchemaDir() {
|
|
72
70
|
return path.join(this.getSchemasDir(), 'standalone');
|
|
73
71
|
}
|
|
74
|
-
|
|
75
|
-
return path.join(this.
|
|
72
|
+
getStandaloneSchemaPath(filename) {
|
|
73
|
+
return path.join(this.getStandaloneSchemaDir(), filename);
|
|
76
74
|
}
|
|
77
75
|
getTypesSrcDir() {
|
|
78
76
|
return path.isAbsolute(this.typesSrcDir)
|
|
@@ -90,17 +88,17 @@ export class SchemaConfig {
|
|
|
90
88
|
getTypesDistPath(filename) {
|
|
91
89
|
return path.join(this.getTypesDistDir(), filename);
|
|
92
90
|
}
|
|
93
|
-
|
|
91
|
+
getStandaloneTypeSrcDir() {
|
|
94
92
|
return path.join(this.getTypesSrcDir(), 'standalone');
|
|
95
93
|
}
|
|
96
|
-
|
|
94
|
+
getStandaloneTypeDistDir() {
|
|
97
95
|
return path.join(this.getTypesDistDir(), 'standalone');
|
|
98
96
|
}
|
|
99
|
-
|
|
100
|
-
return path.join(this.
|
|
97
|
+
getStandaloneTypeSrcPath(filename) {
|
|
98
|
+
return path.join(this.getStandaloneTypeSrcDir(), filename);
|
|
101
99
|
}
|
|
102
|
-
|
|
103
|
-
return path.join(this.
|
|
100
|
+
getStandaloneTypeDistPath(filename) {
|
|
101
|
+
return path.join(this.getStandaloneTypeDistDir(), filename);
|
|
104
102
|
}
|
|
105
103
|
getResourcesDir() {
|
|
106
104
|
return path.isAbsolute(this.resourcesDir)
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
import fs from "fs";
|
|
2
2
|
import path from "path";
|
|
3
|
-
import { fileURLToPath } from "url";
|
|
4
3
|
import { getConfig } from "./_lib/config.js";
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
let
|
|
9
|
-
let outPath = "";
|
|
4
|
+
// PURE: Parse CLI args (no defaults, no filesystem probing).
|
|
5
|
+
function parseArgs(argv) {
|
|
6
|
+
let inPath;
|
|
7
|
+
let outPath;
|
|
10
8
|
let topLevelId;
|
|
11
9
|
for (let i = 0; i < argv.length; i++) {
|
|
12
10
|
const a = argv[i];
|
|
@@ -23,45 +21,23 @@ function parseArgs() {
|
|
|
23
21
|
topLevelId = v;
|
|
24
22
|
}
|
|
25
23
|
}
|
|
26
|
-
// Use config defaults if not provided via CLI
|
|
27
|
-
if (!inPath) {
|
|
28
|
-
// Use generated/normalized version with anchor refs rewritten to pointers
|
|
29
|
-
inPath = config.getNormalizedSourcePath();
|
|
30
|
-
}
|
|
31
|
-
if (!outPath) {
|
|
32
|
-
outPath = config.getSchemaPath(config.getSourceFile());
|
|
33
|
-
}
|
|
34
|
-
if (!topLevelId) {
|
|
35
|
-
topLevelId = config.getSchemaId('Genesis');
|
|
36
|
-
}
|
|
37
|
-
// Resolve to absolute paths from project root
|
|
38
|
-
const cwd = config.getRoot();
|
|
39
|
-
const wasInRelative = !path.isAbsolute(inPath);
|
|
40
|
-
const wasOutRelative = !path.isAbsolute(outPath);
|
|
41
|
-
if (wasInRelative)
|
|
42
|
-
inPath = path.join(cwd, inPath);
|
|
43
|
-
if (wasOutRelative)
|
|
44
|
-
outPath = path.join(cwd, outPath);
|
|
45
|
-
// Fallback: resolve relative to script directory if not found
|
|
46
|
-
const scriptDir = path.dirname(fileURLToPath(import.meta.url));
|
|
47
|
-
if (!fs.existsSync(inPath) && wasInRelative)
|
|
48
|
-
inPath = path.resolve(scriptDir, inPath);
|
|
49
|
-
const outDir = path.dirname(outPath);
|
|
50
|
-
if (!fs.existsSync(outDir) && wasOutRelative) {
|
|
51
|
-
// Try making directory relative to script dir
|
|
52
|
-
const altOut = path.resolve(scriptDir, outPath);
|
|
53
|
-
const altOutDir = path.dirname(altOut);
|
|
54
|
-
if (!fs.existsSync(path.dirname(outPath))) {
|
|
55
|
-
// Prefer creating outDir at cwd location if possible; otherwise fallback below when writing
|
|
56
|
-
}
|
|
57
|
-
else {
|
|
58
|
-
outPath = altOut;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
24
|
return { inPath, outPath, topLevelId };
|
|
62
25
|
}
|
|
63
|
-
//
|
|
64
|
-
|
|
26
|
+
// PURE: Apply defaults for any missing values.
|
|
27
|
+
function applyDefaults(args, defaults) {
|
|
28
|
+
return {
|
|
29
|
+
inPath: args.inPath?.trim() ? args.inPath : defaults.inPath,
|
|
30
|
+
outPath: args.outPath?.trim() ? args.outPath : defaults.outPath,
|
|
31
|
+
topLevelId: args.topLevelId?.trim() ? args.topLevelId : defaults.topLevelId
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
// PURE: Resolve relative paths against a root directory (no heuristics).
|
|
35
|
+
function resolvePaths(options, rootDir) {
|
|
36
|
+
const inPath = path.isAbsolute(options.inPath) ? options.inPath : path.join(rootDir, options.inPath);
|
|
37
|
+
const outPath = path.isAbsolute(options.outPath) ? options.outPath : path.join(rootDir, options.outPath);
|
|
38
|
+
return { ...options, inPath, outPath };
|
|
39
|
+
}
|
|
40
|
+
// PURE: Determine whether a node is a Type shell.
|
|
65
41
|
function isTypeShell(node) {
|
|
66
42
|
return (node && typeof node === "object" && !Array.isArray(node) &&
|
|
67
43
|
// Treat any object that has an 'nucleusSchema' AND 'identity' as a Type shell
|
|
@@ -69,84 +45,99 @@ function isTypeShell(node) {
|
|
|
69
45
|
node.nucleusSchema && typeof node.nucleusSchema === "object" &&
|
|
70
46
|
node.identity && typeof node.identity === "string");
|
|
71
47
|
}
|
|
72
|
-
//
|
|
73
|
-
function
|
|
48
|
+
// PURE: Sanitize labels for use in deterministic collision keys.
|
|
49
|
+
function sanitizeLabel(label) {
|
|
50
|
+
return (label || "defs").replace(/[^A-Za-z0-9_]+/g, "_");
|
|
51
|
+
}
|
|
52
|
+
// PURE: Extract a `$defs` object from a schema node, if present.
|
|
53
|
+
function getDefsObject(source) {
|
|
74
54
|
if (!source || typeof source !== "object")
|
|
75
|
-
return;
|
|
55
|
+
return undefined;
|
|
76
56
|
const src = source["$defs"];
|
|
77
|
-
if (!src || typeof src !== "object")
|
|
78
|
-
return;
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
target[altKey] = v;
|
|
91
|
-
}
|
|
57
|
+
if (!src || typeof src !== "object" || Array.isArray(src))
|
|
58
|
+
return undefined;
|
|
59
|
+
return src;
|
|
60
|
+
}
|
|
61
|
+
// PURE: Merge defs without mutating inputs; collisions are namespaced deterministically.
|
|
62
|
+
function mergeDefs(existing, incoming, label) {
|
|
63
|
+
if (!incoming)
|
|
64
|
+
return { ...existing };
|
|
65
|
+
const merged = { ...existing };
|
|
66
|
+
for (const [k, v] of Object.entries(incoming)) {
|
|
67
|
+
if (!(k in merged)) {
|
|
68
|
+
merged[k] = v;
|
|
69
|
+
continue;
|
|
92
70
|
}
|
|
93
|
-
|
|
71
|
+
const current = merged[k];
|
|
72
|
+
const same = JSON.stringify(current) === JSON.stringify(v);
|
|
73
|
+
if (same)
|
|
74
|
+
continue;
|
|
75
|
+
const altKey = `${k}__from_${sanitizeLabel(label)}`;
|
|
76
|
+
if (!(altKey in merged))
|
|
77
|
+
merged[altKey] = v;
|
|
78
|
+
}
|
|
79
|
+
return merged;
|
|
94
80
|
}
|
|
95
|
-
//
|
|
96
|
-
|
|
97
|
-
function unwrapTypes(node, topDefs, labelPath = [], visited = new Set()) {
|
|
98
|
-
if (node && typeof node === "object") {
|
|
99
|
-
if (visited.has(node))
|
|
100
|
-
return node; // avoid cycles
|
|
101
|
-
visited.add(node);
|
|
102
|
-
}
|
|
81
|
+
// PURE: Unwrap Type shells and collect any encountered inner `$defs` hoist events.
|
|
82
|
+
function traverseTypes(node, labelPath = []) {
|
|
103
83
|
if (isTypeShell(node)) {
|
|
104
84
|
const env = node;
|
|
105
85
|
const inner = env.nucleusSchema;
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
const
|
|
110
|
-
|
|
86
|
+
const label = labelPath.join("_");
|
|
87
|
+
const innerDefs = getDefsObject(inner);
|
|
88
|
+
const innerResult = traverseTypes(inner, labelPath.concat([String(env.identity || "env")]));
|
|
89
|
+
const events = [];
|
|
90
|
+
if (innerDefs)
|
|
91
|
+
events.push({ defs: innerDefs, label });
|
|
92
|
+
events.push(...innerResult.hoistEvents);
|
|
93
|
+
return { value: innerResult.value, hoistEvents: events };
|
|
111
94
|
}
|
|
112
95
|
if (Array.isArray(node)) {
|
|
113
|
-
|
|
96
|
+
const events = [];
|
|
97
|
+
const mapped = node.map((v, i) => {
|
|
98
|
+
const r = traverseTypes(v, labelPath.concat([String(i)]));
|
|
99
|
+
events.push(...r.hoistEvents);
|
|
100
|
+
return r.value;
|
|
101
|
+
});
|
|
102
|
+
return { value: mapped, hoistEvents: events };
|
|
114
103
|
}
|
|
115
104
|
if (node && typeof node === "object") {
|
|
105
|
+
const events = [];
|
|
116
106
|
const out = {};
|
|
117
107
|
for (const [k, v] of Object.entries(node)) {
|
|
118
108
|
if (k === "$defs" && v && typeof v === "object" && !Array.isArray(v)) {
|
|
119
|
-
// Process nested $defs: unwrap each entry value if it's a Type shell
|
|
120
109
|
const defsOut = {};
|
|
121
110
|
for (const [dk, dv] of Object.entries(v)) {
|
|
122
|
-
const
|
|
123
|
-
|
|
111
|
+
const r = traverseTypes(dv, labelPath.concat(["$defs", dk]));
|
|
112
|
+
events.push(...r.hoistEvents);
|
|
113
|
+
defsOut[dk] = r.value;
|
|
124
114
|
}
|
|
125
115
|
out[k] = defsOut;
|
|
116
|
+
continue;
|
|
126
117
|
}
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
118
|
+
const r = traverseTypes(v, labelPath.concat([k]));
|
|
119
|
+
events.push(...r.hoistEvents);
|
|
120
|
+
out[k] = r.value;
|
|
130
121
|
}
|
|
131
|
-
return out;
|
|
122
|
+
return { value: out, hoistEvents: events };
|
|
132
123
|
}
|
|
133
|
-
return node;
|
|
124
|
+
return { value: node, hoistEvents: [] };
|
|
134
125
|
}
|
|
135
|
-
|
|
136
|
-
* Pure function that takes a schema document and options, and returns the flattened schema.
|
|
137
|
-
* Performs no I/O operations.
|
|
138
|
-
*/
|
|
126
|
+
// PURE: Flatten a Type shell JSON into a single JSON Schema document.
|
|
139
127
|
function extractSchemaLogic(doc, topLevelId) {
|
|
140
128
|
if (!doc || typeof doc !== "object" || !doc.nucleusSchema) {
|
|
141
129
|
throw new Error("Input must be a Type JSON with an nucleusSchema at the top level");
|
|
142
130
|
}
|
|
143
131
|
const topSchema = doc.nucleusSchema;
|
|
144
132
|
// Collect $defs so that any '#/$defs/...' pointers can be resolved from the root.
|
|
145
|
-
const
|
|
146
|
-
// Seed with top-level $defs (if any) before unwrapping
|
|
147
|
-
mergeDefs(outDefs, topSchema, "top");
|
|
133
|
+
const seededDefs = mergeDefs({}, getDefsObject(topSchema), "top");
|
|
148
134
|
// Unwrap the entire top schema tree so that any nested Type shells become raw schemas
|
|
149
|
-
const
|
|
135
|
+
const traversal = traverseTypes(topSchema, ["nucleusSchema"]);
|
|
136
|
+
const flattened = traversal.value;
|
|
137
|
+
let outDefs = seededDefs;
|
|
138
|
+
for (const ev of traversal.hoistEvents) {
|
|
139
|
+
outDefs = mergeDefs(outDefs, ev.defs, ev.label);
|
|
140
|
+
}
|
|
150
141
|
// Assemble output: force $schema, optionally set $id, hoist collected $defs
|
|
151
142
|
let base;
|
|
152
143
|
if (flattened && typeof flattened === "object" && !Array.isArray(flattened)) {
|
|
@@ -180,18 +171,33 @@ function extractSchemaLogic(doc, topLevelId) {
|
|
|
180
171
|
// Preserve natural key ordering (do not reorder for readability)
|
|
181
172
|
return output;
|
|
182
173
|
}
|
|
174
|
+
// IMPURE: Script entrypoint (config + filesystem I/O + console + process exit code).
|
|
183
175
|
function main() {
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
176
|
+
try {
|
|
177
|
+
const config = getConfig();
|
|
178
|
+
const defaults = {
|
|
179
|
+
// Use generated/normalized version with anchor refs rewritten to pointers
|
|
180
|
+
inPath: config.getNormalizedSourcePath(),
|
|
181
|
+
outPath: config.getSchemaPath(config.getSourceFile()),
|
|
182
|
+
topLevelId: config.getSchemaId("Genesis")
|
|
183
|
+
};
|
|
184
|
+
const cli = parseArgs(process.argv.slice(2));
|
|
185
|
+
const opts = resolvePaths(applyDefaults(cli, defaults), config.getRoot());
|
|
186
|
+
const { inPath, outPath, topLevelId } = opts;
|
|
187
|
+
if (!fs.existsSync(inPath)) {
|
|
188
|
+
throw new Error(`Input file not found at ${inPath}`);
|
|
189
|
+
}
|
|
190
|
+
const raw = fs.readFileSync(inPath, "utf8");
|
|
191
|
+
const doc = JSON.parse(raw);
|
|
192
|
+
// Core logic is now in a pure function
|
|
193
|
+
const extracted = extractSchemaLogic(doc, topLevelId);
|
|
194
|
+
fs.mkdirSync(path.dirname(outPath), { recursive: true });
|
|
195
|
+
fs.writeFileSync(outPath, JSON.stringify(extracted, null, 4), "utf8");
|
|
196
|
+
console.log(`Wrote flattened schema to ${outPath}`);
|
|
197
|
+
}
|
|
198
|
+
catch (e) {
|
|
199
|
+
console.error(e);
|
|
200
|
+
process.exitCode = 1;
|
|
188
201
|
}
|
|
189
|
-
const raw = fs.readFileSync(inPath, "utf8");
|
|
190
|
-
const doc = JSON.parse(raw);
|
|
191
|
-
// Core logic is now in a pure function
|
|
192
|
-
const ordered = extractSchemaLogic(doc, topLevelId);
|
|
193
|
-
fs.mkdirSync(path.dirname(outPath), { recursive: true });
|
|
194
|
-
fs.writeFileSync(outPath, JSON.stringify(ordered, null, 4), "utf8");
|
|
195
|
-
console.log(`Wrote flattened schema to ${outPath}`);
|
|
196
202
|
}
|
|
197
203
|
main();
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import fs from "fs";
|
|
2
2
|
import path from "path";
|
|
3
3
|
import { getConfig } from "./_lib/config.js";
|
|
4
|
+
// PURE: Decode a single JSON Pointer segment.
|
|
4
5
|
function decodeJsonPointerSegment(segment) {
|
|
5
6
|
// JSON Pointer decoding: ~1 => / and ~0 => ~
|
|
6
7
|
return segment.replace(/~1/g, "/").replace(/~0/g, "~");
|
|
7
8
|
}
|
|
9
|
+
// PURE: Collect all `$ref` strings from a JSON-ish tree.
|
|
8
10
|
function collectRefs(node, out) {
|
|
9
11
|
if (Array.isArray(node)) {
|
|
10
12
|
for (const item of node)
|
|
@@ -21,6 +23,7 @@ function collectRefs(node, out) {
|
|
|
21
23
|
collectRefs(value, out);
|
|
22
24
|
}
|
|
23
25
|
}
|
|
26
|
+
// PURE: Resolve an internal ref (pointer or anchor) to a root $defs key, if possible.
|
|
24
27
|
function resolveInternalRefToDefKey(ref, defKeys, anchorToDef) {
|
|
25
28
|
if (!ref.startsWith("#"))
|
|
26
29
|
return null;
|
|
@@ -49,6 +52,7 @@ function resolveInternalRefToDefKey(ref, defKeys, anchorToDef) {
|
|
|
49
52
|
* @param doc The source JSON Schema document
|
|
50
53
|
* @returns A record mapping definition names to their dependency lists
|
|
51
54
|
*/
|
|
55
|
+
// PURE: Generate a $defs dependency map from a JSON Schema document (no I/O).
|
|
52
56
|
function generateDependencyMapLogic(doc) {
|
|
53
57
|
const defs = doc?.$defs && typeof doc.$defs === "object" ? doc.$defs : {};
|
|
54
58
|
const defKeys = new Set(Object.keys(defs));
|
|
@@ -79,15 +83,15 @@ function generateDependencyMapLogic(doc) {
|
|
|
79
83
|
}
|
|
80
84
|
return dependencyMap;
|
|
81
85
|
}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
const inPath = config.getSchemaPath("Genesis.json");
|
|
85
|
-
const outPath = config.getDependencyMapPath();
|
|
86
|
-
if (!fs.existsSync(inPath)) {
|
|
87
|
-
console.error(`Genesis schema not found at ${inPath}. Run extractSchemasFromResourceTypeShells first.`);
|
|
88
|
-
process.exit(1);
|
|
89
|
-
}
|
|
86
|
+
// IMPURE: Script entrypoint (config + filesystem I/O + console + process exit code).
|
|
87
|
+
function main() {
|
|
90
88
|
try {
|
|
89
|
+
const config = getConfig();
|
|
90
|
+
const inPath = config.getSchemaPath("Genesis.json");
|
|
91
|
+
const outPath = config.getDependencyMapPath();
|
|
92
|
+
if (!fs.existsSync(inPath)) {
|
|
93
|
+
throw new Error(`Genesis schema not found at ${inPath}. Run extractSchemasFromResourceTypeShells first.`);
|
|
94
|
+
}
|
|
91
95
|
const raw = fs.readFileSync(inPath, "utf8");
|
|
92
96
|
const doc = JSON.parse(raw);
|
|
93
97
|
const dependencyMap = generateDependencyMapLogic(doc);
|
|
@@ -96,11 +100,8 @@ async function main() {
|
|
|
96
100
|
console.log(`Wrote dependency map to ${outPath}`);
|
|
97
101
|
}
|
|
98
102
|
catch (error) {
|
|
99
|
-
console.error(`Error generating dependency map: ${error
|
|
100
|
-
process.
|
|
103
|
+
console.error(`Error generating dependency map: ${error?.message ?? error}`);
|
|
104
|
+
process.exitCode = 1;
|
|
101
105
|
}
|
|
102
106
|
}
|
|
103
|
-
main()
|
|
104
|
-
console.error(e);
|
|
105
|
-
process.exit(1);
|
|
106
|
-
});
|
|
107
|
+
main();
|
|
@@ -10,28 +10,16 @@ import { getConfig } from './_lib/config.js';
|
|
|
10
10
|
*
|
|
11
11
|
* Generates shims for:
|
|
12
12
|
* - schemas dir: config.getSchemasDir() (schema files)
|
|
13
|
-
* - standalone schemas dir: config.
|
|
13
|
+
* - standalone schemas dir: config.getStandaloneSchemaDir() (standalone schema files)
|
|
14
14
|
* - resources dir: config.getResourcesDir() (resource envelope files)
|
|
15
15
|
*
|
|
16
16
|
* Usage: node ./dist/scripts/generateSchemaShims.js
|
|
17
17
|
*/
|
|
18
|
-
|
|
19
|
-
* Pure function to generate the content of a TypeScript shim file.
|
|
20
|
-
*
|
|
21
|
-
* @param jsonFile The name of the JSON file to import
|
|
22
|
-
* @param variableName The name of the variable to use for the import
|
|
23
|
-
* @returns The TypeScript file content
|
|
24
|
-
*/
|
|
18
|
+
// PURE: Generate the .ts shim module content for a given .json filename.
|
|
25
19
|
function generateShimContent(jsonFile, variableName) {
|
|
26
20
|
return `import ${variableName} from './${jsonFile}' with { type: 'json' };\nexport default ${variableName};\n`;
|
|
27
21
|
}
|
|
28
|
-
|
|
29
|
-
* Pure function to map a list of JSON files to their corresponding TypeScript shim files and contents.
|
|
30
|
-
*
|
|
31
|
-
* @param jsonFiles List of JSON filenames
|
|
32
|
-
* @param variableName The variable name to use in the shim
|
|
33
|
-
* @returns A record mapping TS filenames to their contents
|
|
34
|
-
*/
|
|
22
|
+
// PURE: Map JSON filenames to deterministic shim file contents.
|
|
35
23
|
function getShimsForFiles(jsonFiles, variableName) {
|
|
36
24
|
const shims = {};
|
|
37
25
|
for (const jsonFile of jsonFiles) {
|
|
@@ -41,83 +29,87 @@ function getShimsForFiles(jsonFiles, variableName) {
|
|
|
41
29
|
}
|
|
42
30
|
return shims;
|
|
43
31
|
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
32
|
+
// IMPURE: Script entrypoint (config + filesystem I/O + console + process exit code).
|
|
33
|
+
function main() {
|
|
34
|
+
try {
|
|
35
|
+
const config = getConfig();
|
|
36
|
+
const schemasDir = config.getSchemasDir();
|
|
37
|
+
const standaloneSchemasDir = config.getStandaloneSchemaDir();
|
|
38
|
+
const resourcesDir = config.getResourcesDir();
|
|
39
|
+
const generatedResourceTypesDir = config.getNormalizedDir();
|
|
40
|
+
let totalCount = 0;
|
|
41
|
+
// Process schemas directory
|
|
42
|
+
if (fs.existsSync(schemasDir)) {
|
|
43
|
+
const files = fs.readdirSync(schemasDir);
|
|
44
|
+
const jsonFiles = files.filter((f) => f.endsWith('.json') && !f.startsWith('.'));
|
|
45
|
+
const shims = getShimsForFiles(jsonFiles, 'schema');
|
|
46
|
+
for (const [tsFile, content] of Object.entries(shims)) {
|
|
47
|
+
const tsPath = path.join(schemasDir, tsFile);
|
|
48
|
+
fs.writeFileSync(tsPath, content, 'utf-8');
|
|
49
|
+
console.log('Generated ' + tsFile + ' in ' + schemasDir);
|
|
50
|
+
totalCount++;
|
|
51
|
+
}
|
|
52
|
+
console.log('Generated ' + jsonFiles.length + ' TypeScript schema shims in ' + schemasDir);
|
|
61
53
|
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
else {
|
|
65
|
-
console.warn(`Schemas directory not found at ${schemasDir}`);
|
|
66
|
-
}
|
|
67
|
-
// Process standalone schemas directory
|
|
68
|
-
if (fs.existsSync(standaloneSchemasDir)) {
|
|
69
|
-
const files = fs.readdirSync(standaloneSchemasDir);
|
|
70
|
-
const jsonFiles = files.filter(f => f.endsWith('.json') && !f.startsWith('.'));
|
|
71
|
-
const shims = getShimsForFiles(jsonFiles, 'schema');
|
|
72
|
-
for (const [tsFile, content] of Object.entries(shims)) {
|
|
73
|
-
const tsPath = path.join(standaloneSchemasDir, tsFile);
|
|
74
|
-
fs.writeFileSync(tsPath, content, 'utf-8');
|
|
75
|
-
console.log(`Generated ${tsFile} in ${standaloneSchemasDir}`);
|
|
76
|
-
totalCount++;
|
|
54
|
+
else {
|
|
55
|
+
console.warn('Schemas directory not found at ' + schemasDir);
|
|
77
56
|
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
fs.writeFileSync(tsPath, content, 'utf-8');
|
|
91
|
-
console.log(`Generated ${tsFile} in ${resourcesDir}`);
|
|
92
|
-
totalCount++;
|
|
57
|
+
// Process standalone schemas directory
|
|
58
|
+
if (fs.existsSync(standaloneSchemasDir)) {
|
|
59
|
+
const files = fs.readdirSync(standaloneSchemasDir);
|
|
60
|
+
const jsonFiles = files.filter((f) => f.endsWith('.json') && !f.startsWith('.'));
|
|
61
|
+
const shims = getShimsForFiles(jsonFiles, 'schema');
|
|
62
|
+
for (const [tsFile, content] of Object.entries(shims)) {
|
|
63
|
+
const tsPath = path.join(standaloneSchemasDir, tsFile);
|
|
64
|
+
fs.writeFileSync(tsPath, content, 'utf-8');
|
|
65
|
+
console.log('Generated ' + tsFile + ' in ' + standaloneSchemasDir);
|
|
66
|
+
totalCount++;
|
|
67
|
+
}
|
|
68
|
+
console.log('Generated ' + jsonFiles.length + ' TypeScript standalone schema shims in ' + standaloneSchemasDir);
|
|
93
69
|
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
console.log(
|
|
109
|
-
totalCount++;
|
|
70
|
+
else {
|
|
71
|
+
// Standalone schemas are optional
|
|
72
|
+
}
|
|
73
|
+
// Process resources directory
|
|
74
|
+
if (fs.existsSync(resourcesDir)) {
|
|
75
|
+
const files = fs.readdirSync(resourcesDir);
|
|
76
|
+
const jsonFiles = files.filter((f) => f.endsWith('.json') && !f.startsWith('.'));
|
|
77
|
+
const shims = getShimsForFiles(jsonFiles, 'resources');
|
|
78
|
+
for (const [tsFile, content] of Object.entries(shims)) {
|
|
79
|
+
const tsPath = path.join(resourcesDir, tsFile);
|
|
80
|
+
fs.writeFileSync(tsPath, content, 'utf-8');
|
|
81
|
+
console.log('Generated ' + tsFile + ' in ' + resourcesDir);
|
|
82
|
+
totalCount++;
|
|
83
|
+
}
|
|
84
|
+
console.log('Generated ' + jsonFiles.length + ' TypeScript resource shims in ' + resourcesDir);
|
|
110
85
|
}
|
|
111
86
|
else {
|
|
112
|
-
console.warn(
|
|
87
|
+
console.warn('Resources directory not found at ' + resourcesDir);
|
|
88
|
+
}
|
|
89
|
+
// Genesis (normalized) shim
|
|
90
|
+
try {
|
|
91
|
+
const genesisJsonPath = config.getNormalizedSourcePath();
|
|
92
|
+
if (fs.existsSync(genesisJsonPath)) {
|
|
93
|
+
fs.mkdirSync(generatedResourceTypesDir, { recursive: true });
|
|
94
|
+
const tsFile = 'Genesis.ts';
|
|
95
|
+
const content = generateShimContent('Genesis.json', 'schema');
|
|
96
|
+
const tsPath = path.join(generatedResourceTypesDir, tsFile);
|
|
97
|
+
fs.writeFileSync(tsPath, content, 'utf-8');
|
|
98
|
+
console.log('Generated ' + tsFile + ' in ' + generatedResourceTypesDir);
|
|
99
|
+
totalCount++;
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
console.warn('Genesis source JSON not found at ' + genesisJsonPath + '; skipping Genesis.ts shim');
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
catch (e) {
|
|
106
|
+
console.warn('Failed to generate Genesis.ts shim:', e);
|
|
113
107
|
}
|
|
108
|
+
console.log('Generated ' + totalCount + ' total TypeScript shims');
|
|
114
109
|
}
|
|
115
110
|
catch (e) {
|
|
116
|
-
console.
|
|
111
|
+
console.error(e);
|
|
112
|
+
process.exitCode = 1;
|
|
117
113
|
}
|
|
118
|
-
console.log(`Generated ${totalCount} total TypeScript shims`);
|
|
119
114
|
}
|
|
120
|
-
main()
|
|
121
|
-
console.error(e);
|
|
122
|
-
process.exit(1);
|
|
123
|
-
});
|
|
115
|
+
main();
|