@toolproof-core/genesis 1.0.47
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/src/utils/constantsAndMappings.d.ts +20 -0
- package/dist/src/utils/constantsAndMappings.js +155 -0
- package/dist/src/utils/coreProjection.d.ts +16 -0
- package/dist/src/utils/coreProjection.js +29 -0
- package/dist/src/utils/resourceTypes.d.ts +12 -0
- package/dist/src/utils/resourceTypes.js +17 -0
- package/dist/src/utils/resources.d.ts +5 -0
- package/dist/src/utils/resources.js +17 -0
- package/dist/src/utils/schemaDependencies.d.ts +13 -0
- package/dist/src/utils/schemaDependencies.js +94 -0
- package/dist/src/utils/schemaObjectNormalization.d.ts +1 -0
- package/dist/src/utils/schemaObjectNormalization.js +66 -0
- package/dist/src/utils/schemaRefNormalization.d.ts +2 -0
- package/dist/src/utils/schemaRefNormalization.js +76 -0
- package/dist/src/utils/schemaShims.d.ts +2 -0
- package/dist/src/utils/schemaShims.js +13 -0
- package/dist/src/utils/standaloneSchemas.d.ts +16 -0
- package/dist/src/utils/standaloneSchemas.js +101 -0
- package/dist/src/utils/standaloneTypes.d.ts +8 -0
- package/dist/src/utils/standaloneTypes.js +22 -0
- package/dist/src/utils/standaloneZodSchemas.d.ts +8 -0
- package/dist/src/utils/standaloneZodSchemas.js +53 -0
- package/dist/src/utils/typeGeneration.d.ts +1 -0
- package/dist/src/utils/typeGeneration.js +25 -0
- package/dist/src/utils/typeGenerationPostProcess.d.ts +2 -0
- package/dist/src/utils/typeGenerationPostProcess.js +166 -0
- package/dist/src/utils/typeGenerationPreflight.d.ts +2 -0
- package/dist/src/utils/typeGenerationPreflight.js +93 -0
- package/dist/src/utils/zodCodegen.d.ts +10 -0
- package/dist/src/utils/zodCodegen.js +521 -0
- package/generated-src/derived/constants.ts +130 -0
- package/generated-src/derived/mappings.ts +12 -0
- package/generated-src/metadata/Core.json +1919 -0
- package/generated-src/metadata/dependencyMap.json +283 -0
- package/generated-src/metadata/terminals.json +17 -0
- package/generated-src/resourceTypes/resourceTypes.json +375 -0
- package/generated-src/resourceTypes/resourceTypes.ts +2 -0
- package/generated-src/resources/resourceTypes.json +456 -0
- package/generated-src/resources/resourceTypes.ts +2 -0
- package/generated-src/schemas/schemas.json +1670 -0
- package/generated-src/schemas/schemas.ts +2 -0
- package/generated-src/schemas/standalone/Boolean.json +5 -0
- package/generated-src/schemas/standalone/Boolean.ts +2 -0
- package/generated-src/schemas/standalone/Error.json +78 -0
- package/generated-src/schemas/standalone/Error.ts +2 -0
- package/generated-src/schemas/standalone/Goal.json +53 -0
- package/generated-src/schemas/standalone/Goal.ts +2 -0
- package/generated-src/schemas/standalone/Natural.json +6 -0
- package/generated-src/schemas/standalone/Natural.ts +2 -0
- package/generated-src/schemas/standalone/Resource.json +170 -0
- package/generated-src/schemas/standalone/Resource.ts +2 -0
- package/generated-src/schemas/standalone/ResourceType.json +131 -0
- package/generated-src/schemas/standalone/ResourceType.ts +2 -0
- package/generated-src/schemas/standalone/Strategy.json +641 -0
- package/generated-src/schemas/standalone/Strategy.ts +2 -0
- package/generated-src/schemas/standalone/StrategyTrace.json +820 -0
- package/generated-src/schemas/standalone/StrategyTrace.ts +2 -0
- package/generated-src/schemas/standalone/Tool.json +508 -0
- package/generated-src/schemas/standalone/Tool.ts +2 -0
- package/generated-src/schemas/zod/Boolean.ts +6 -0
- package/generated-src/schemas/zod/Error.ts +11 -0
- package/generated-src/schemas/zod/Goal.ts +8 -0
- package/generated-src/schemas/zod/Natural.ts +6 -0
- package/generated-src/schemas/zod/Resource.ts +21 -0
- package/generated-src/schemas/zod/ResourceType.ts +14 -0
- package/generated-src/schemas/zod/Strategy.ts +68 -0
- package/generated-src/schemas/zod/StrategyTrace.ts +75 -0
- package/generated-src/schemas/zod/Tool.ts +29 -0
- package/generated-src/schemas/zod/index.ts +10 -0
- package/generated-src/types/standalone/BooleanResource.d.ts +3 -0
- package/generated-src/types/standalone/BooleanResource.js +1 -0
- package/generated-src/types/standalone/ErrorResource.d.ts +3 -0
- package/generated-src/types/standalone/ErrorResource.js +1 -0
- package/generated-src/types/standalone/GoalResource.d.ts +3 -0
- package/generated-src/types/standalone/GoalResource.js +1 -0
- package/generated-src/types/standalone/NaturalResource.d.ts +3 -0
- package/generated-src/types/standalone/NaturalResource.js +1 -0
- package/generated-src/types/standalone/ResourceResource.d.ts +3 -0
- package/generated-src/types/standalone/ResourceResource.js +1 -0
- package/generated-src/types/standalone/ResourceTypeResource.d.ts +3 -0
- package/generated-src/types/standalone/ResourceTypeResource.js +1 -0
- package/generated-src/types/standalone/StrategyResource.d.ts +3 -0
- package/generated-src/types/standalone/StrategyResource.js +1 -0
- package/generated-src/types/standalone/StrategyTraceResource.d.ts +3 -0
- package/generated-src/types/standalone/StrategyTraceResource.js +1 -0
- package/generated-src/types/standalone/ToolResource.d.ts +3 -0
- package/generated-src/types/standalone/ToolResource.js +1 -0
- package/generated-src/types/types.d.ts +701 -0
- package/generated-src/types/types.js +1 -0
- package/package.json +52 -0
- package/src/genesis/resourceTypeShells.json +47 -0
- package/src/genesis/resources/booleans.json +24 -0
- package/src/genesis/resources/implementations/foo.ts +182 -0
- package/src/genesis/resources/naturals.json +112 -0
- package/src/genesis/resources/tools.json +840 -0
- package/src/genesis/schemas.json +1670 -0
- package/src/index.ts +27 -0
- package/src/utils/constantsAndMappings.ts +195 -0
- package/src/utils/coreProjection.ts +53 -0
- package/src/utils/resourceTypes.ts +39 -0
- package/src/utils/resources.ts +26 -0
- package/src/utils/schemaDependencies.ts +115 -0
- package/src/utils/schemaObjectNormalization.ts +71 -0
- package/src/utils/schemaRefNormalization.ts +83 -0
- package/src/utils/schemaShims.ts +17 -0
- package/src/utils/standaloneSchemas.ts +114 -0
- package/src/utils/standaloneTypes.ts +28 -0
- package/src/utils/standaloneZodSchemas.ts +72 -0
- package/src/utils/typeGeneration.ts +31 -0
- package/src/utils/typeGenerationPostProcess.ts +246 -0
- package/src/utils/typeGenerationPreflight.ts +119 -0
- package/src/utils/zodCodegen.ts +549 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
type JSONValue = null | boolean | number | string | JSONValue[] | {
|
|
2
|
+
[k: string]: JSONValue;
|
|
3
|
+
};
|
|
4
|
+
export type GeneratedConstants = {
|
|
5
|
+
Names: Record<string, string>;
|
|
6
|
+
Enums: Record<string, Record<string, string>>;
|
|
7
|
+
};
|
|
8
|
+
export type GeneratedMappings = {
|
|
9
|
+
HandleNameToPrefix: Record<string, string>;
|
|
10
|
+
};
|
|
11
|
+
export declare function extractHandlePrefixes(schema: unknown): Record<string, string>;
|
|
12
|
+
export declare function extractSubschemaNames(schema: unknown): Record<string, string>;
|
|
13
|
+
export declare function extractEnums(schema: unknown): Record<string, Record<string, string>>;
|
|
14
|
+
export declare function extractGeneratedConstantsAndMappings(schema: JSONValue): {
|
|
15
|
+
CONSTANTS: GeneratedConstants;
|
|
16
|
+
MAPPINGS: GeneratedMappings;
|
|
17
|
+
};
|
|
18
|
+
export declare function renderConstantsTs(constants: GeneratedConstants): string;
|
|
19
|
+
export declare function renderMappingsTs(mappings: GeneratedMappings): string;
|
|
20
|
+
export {};
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
function deriveIdPrefixFromPattern(pattern) {
|
|
2
|
+
const match = /^\^([^$]+)\.\+\$$/.exec(pattern);
|
|
3
|
+
if (!match)
|
|
4
|
+
return undefined;
|
|
5
|
+
const prefix = match[1];
|
|
6
|
+
if (!prefix || /[`\n\r]/.test(prefix))
|
|
7
|
+
return undefined;
|
|
8
|
+
return prefix;
|
|
9
|
+
}
|
|
10
|
+
export function extractHandlePrefixes(schema) {
|
|
11
|
+
if (!schema || typeof schema !== 'object')
|
|
12
|
+
return {};
|
|
13
|
+
const defs = schema.$defs;
|
|
14
|
+
if (!defs || typeof defs !== 'object')
|
|
15
|
+
return {};
|
|
16
|
+
const defEntries = Object.entries(defs);
|
|
17
|
+
defEntries.sort(([a], [b]) => a.localeCompare(b));
|
|
18
|
+
const out = {};
|
|
19
|
+
for (const [defName, defVal] of defEntries) {
|
|
20
|
+
if (!/(Id|Handle)$/.test(defName))
|
|
21
|
+
continue;
|
|
22
|
+
if (!defVal || typeof defVal !== 'object' || Array.isArray(defVal))
|
|
23
|
+
continue;
|
|
24
|
+
const value = defVal;
|
|
25
|
+
if (value.type !== 'string')
|
|
26
|
+
continue;
|
|
27
|
+
if (typeof value.pattern !== 'string')
|
|
28
|
+
continue;
|
|
29
|
+
const prefix = deriveIdPrefixFromPattern(value.pattern);
|
|
30
|
+
if (!prefix)
|
|
31
|
+
continue;
|
|
32
|
+
out[defName] = prefix;
|
|
33
|
+
}
|
|
34
|
+
return out;
|
|
35
|
+
}
|
|
36
|
+
export function extractSubschemaNames(schema) {
|
|
37
|
+
if (!schema || typeof schema !== 'object')
|
|
38
|
+
return {};
|
|
39
|
+
const defs = schema.$defs;
|
|
40
|
+
if (!defs || typeof defs !== 'object')
|
|
41
|
+
return {};
|
|
42
|
+
const defEntries = Object.entries(defs);
|
|
43
|
+
defEntries.sort(([a], [b]) => a.localeCompare(b));
|
|
44
|
+
const out = {};
|
|
45
|
+
for (const [defName] of defEntries) {
|
|
46
|
+
if (!defName || /[\n\r`]/.test(defName))
|
|
47
|
+
continue;
|
|
48
|
+
out[defName] = defName;
|
|
49
|
+
}
|
|
50
|
+
return out;
|
|
51
|
+
}
|
|
52
|
+
export function extractEnums(schema) {
|
|
53
|
+
if (!schema || typeof schema !== 'object')
|
|
54
|
+
return {};
|
|
55
|
+
const defs = schema.$defs;
|
|
56
|
+
if (!defs || typeof defs !== 'object')
|
|
57
|
+
return {};
|
|
58
|
+
const defEntries = Object.entries(defs);
|
|
59
|
+
defEntries.sort(([a], [b]) => a.localeCompare(b));
|
|
60
|
+
const out = {};
|
|
61
|
+
for (const [defName, defVal] of defEntries) {
|
|
62
|
+
if (!/(Kind|Status)$/.test(defName))
|
|
63
|
+
continue;
|
|
64
|
+
if (!defVal || typeof defVal !== 'object' || Array.isArray(defVal))
|
|
65
|
+
continue;
|
|
66
|
+
const value = defVal;
|
|
67
|
+
if (value.type !== 'string')
|
|
68
|
+
continue;
|
|
69
|
+
if (!Array.isArray(value.enum) || value.enum.length === 0)
|
|
70
|
+
continue;
|
|
71
|
+
if (value.enum.some((item) => typeof item !== 'string'))
|
|
72
|
+
continue;
|
|
73
|
+
const members = {};
|
|
74
|
+
for (const member of value.enum) {
|
|
75
|
+
members[member] = member;
|
|
76
|
+
}
|
|
77
|
+
out[defName] = members;
|
|
78
|
+
}
|
|
79
|
+
return out;
|
|
80
|
+
}
|
|
81
|
+
export function extractGeneratedConstantsAndMappings(schema) {
|
|
82
|
+
const names = extractSubschemaNames(schema);
|
|
83
|
+
const enums = extractEnums(schema);
|
|
84
|
+
const handlePrefixes = extractHandlePrefixes(schema);
|
|
85
|
+
return {
|
|
86
|
+
CONSTANTS: {
|
|
87
|
+
Names: names,
|
|
88
|
+
Enums: enums,
|
|
89
|
+
},
|
|
90
|
+
MAPPINGS: {
|
|
91
|
+
HandleNameToPrefix: handlePrefixes,
|
|
92
|
+
},
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
function escapeTsString(value) {
|
|
96
|
+
return value
|
|
97
|
+
.replace(/\\/g, '\\\\')
|
|
98
|
+
.replace(/\r/g, '\\r')
|
|
99
|
+
.replace(/\n/g, '\\n')
|
|
100
|
+
.replace(/\t/g, '\\t')
|
|
101
|
+
.replace(/'/g, "\\'");
|
|
102
|
+
}
|
|
103
|
+
function renderTsStringLiteral(value) {
|
|
104
|
+
return `'${escapeTsString(value)}'`;
|
|
105
|
+
}
|
|
106
|
+
function isValidTsIdentifier(key) {
|
|
107
|
+
return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(key);
|
|
108
|
+
}
|
|
109
|
+
function renderTsKey(key) {
|
|
110
|
+
return isValidTsIdentifier(key) ? key : renderTsStringLiteral(key);
|
|
111
|
+
}
|
|
112
|
+
export function renderConstantsTs(constants) {
|
|
113
|
+
const nameKeys = Object.keys(constants.Names).sort((a, b) => a.localeCompare(b));
|
|
114
|
+
const enumKeys = Object.keys(constants.Enums).sort((a, b) => a.localeCompare(b));
|
|
115
|
+
const lines = [];
|
|
116
|
+
lines.push('const CONSTANTS = {');
|
|
117
|
+
lines.push(' Names: {');
|
|
118
|
+
for (const key of nameKeys) {
|
|
119
|
+
const value = constants.Names[key] ?? '';
|
|
120
|
+
lines.push(` ${renderTsKey(key)}: ${renderTsStringLiteral(value)},`);
|
|
121
|
+
}
|
|
122
|
+
lines.push(' },');
|
|
123
|
+
lines.push(' Enums: {');
|
|
124
|
+
for (const key of enumKeys) {
|
|
125
|
+
const members = constants.Enums[key] ?? {};
|
|
126
|
+
lines.push(` ${renderTsKey(key)}: {`);
|
|
127
|
+
for (const memberKey of Object.keys(members)) {
|
|
128
|
+
const value = members[memberKey] ?? '';
|
|
129
|
+
lines.push(` ${renderTsKey(memberKey)}: ${renderTsStringLiteral(value)},`);
|
|
130
|
+
}
|
|
131
|
+
lines.push(' },');
|
|
132
|
+
}
|
|
133
|
+
lines.push(' }');
|
|
134
|
+
lines.push('} as const;');
|
|
135
|
+
lines.push('');
|
|
136
|
+
lines.push('export default CONSTANTS;');
|
|
137
|
+
lines.push('');
|
|
138
|
+
return lines.join('\n');
|
|
139
|
+
}
|
|
140
|
+
export function renderMappingsTs(mappings) {
|
|
141
|
+
const handleKeys = Object.keys(mappings.HandleNameToPrefix).sort((a, b) => a.localeCompare(b));
|
|
142
|
+
const lines = [];
|
|
143
|
+
lines.push('const MAPPINGS = {');
|
|
144
|
+
lines.push(' HandleNameToPrefix: {');
|
|
145
|
+
for (const key of handleKeys) {
|
|
146
|
+
const value = mappings.HandleNameToPrefix[key] ?? '';
|
|
147
|
+
lines.push(` ${renderTsKey(key)}: ${renderTsStringLiteral(value)},`);
|
|
148
|
+
}
|
|
149
|
+
lines.push(' },');
|
|
150
|
+
lines.push('} as const;');
|
|
151
|
+
lines.push('');
|
|
152
|
+
lines.push('export default MAPPINGS;');
|
|
153
|
+
lines.push('');
|
|
154
|
+
return lines.join('\n');
|
|
155
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export type CoreProjectionNode = CoreProjectionDirectoryNode | CoreProjectionFileNode;
|
|
2
|
+
export interface CoreProjectionBaseNode {
|
|
3
|
+
kind: 'directory' | 'file';
|
|
4
|
+
name: string;
|
|
5
|
+
path: string;
|
|
6
|
+
}
|
|
7
|
+
export interface CoreProjectionDirectoryNode extends CoreProjectionBaseNode {
|
|
8
|
+
kind: 'directory';
|
|
9
|
+
children: CoreProjectionNode[];
|
|
10
|
+
}
|
|
11
|
+
export interface CoreProjectionFileNode extends CoreProjectionBaseNode {
|
|
12
|
+
kind: 'file';
|
|
13
|
+
}
|
|
14
|
+
export declare function toPosixPath(value: string): string;
|
|
15
|
+
export declare function shouldExclude(relativePath: string, isDirectory: boolean, excludedRelativePathPrefixes: string[]): boolean;
|
|
16
|
+
export declare function compareNodes(a: CoreProjectionNode, b: CoreProjectionNode): number;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import * as path from 'node:path';
|
|
2
|
+
const EXCLUDED_DIRECTORY_NAMES = new Set([
|
|
3
|
+
'.git',
|
|
4
|
+
'.next',
|
|
5
|
+
'dist',
|
|
6
|
+
'node_modules',
|
|
7
|
+
]);
|
|
8
|
+
export function toPosixPath(value) {
|
|
9
|
+
return value.split(path.sep).join('/');
|
|
10
|
+
}
|
|
11
|
+
export function shouldExclude(relativePath, isDirectory, excludedRelativePathPrefixes) {
|
|
12
|
+
if (!relativePath || relativePath === '.') {
|
|
13
|
+
return false;
|
|
14
|
+
}
|
|
15
|
+
const normalizedPath = toPosixPath(relativePath);
|
|
16
|
+
const baseName = path.posix.basename(normalizedPath);
|
|
17
|
+
if (isDirectory && EXCLUDED_DIRECTORY_NAMES.has(baseName)) {
|
|
18
|
+
return true;
|
|
19
|
+
}
|
|
20
|
+
return excludedRelativePathPrefixes.some((prefix) => {
|
|
21
|
+
return normalizedPath === prefix || normalizedPath.startsWith(`${prefix}/`);
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
export function compareNodes(a, b) {
|
|
25
|
+
if (a.kind !== b.kind) {
|
|
26
|
+
return a.kind === 'directory' ? -1 : 1;
|
|
27
|
+
}
|
|
28
|
+
return a.name.localeCompare(b.name);
|
|
29
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
type JsonObject = Record<string, unknown>;
|
|
2
|
+
type SchemasDocument = {
|
|
3
|
+
$defs?: Record<string, JsonObject>;
|
|
4
|
+
};
|
|
5
|
+
type ResourceTypeShell = JsonObject & {
|
|
6
|
+
handle?: unknown;
|
|
7
|
+
name?: unknown;
|
|
8
|
+
description?: unknown;
|
|
9
|
+
};
|
|
10
|
+
type ResourceTypeShellByName = Record<string, ResourceTypeShell>;
|
|
11
|
+
export declare function generateResourceTypes(schemasDocument: SchemasDocument, resourceTypeShells: ResourceTypeShellByName): ResourceTypeShellByName;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export function generateResourceTypes(schemasDocument, resourceTypeShells) {
|
|
2
|
+
if (!schemasDocument.$defs || typeof schemasDocument.$defs !== 'object') {
|
|
3
|
+
throw new Error('Schema document must have root $defs');
|
|
4
|
+
}
|
|
5
|
+
const resourceTypes = {};
|
|
6
|
+
for (const [resourceTypeName, resourceTypeShell] of Object.entries(resourceTypeShells)) {
|
|
7
|
+
const valueSchema = schemasDocument.$defs[resourceTypeName];
|
|
8
|
+
if (!valueSchema || typeof valueSchema !== 'object' || Array.isArray(valueSchema)) {
|
|
9
|
+
throw new Error(`Missing matching schema for resource type record ${resourceTypeName}`);
|
|
10
|
+
}
|
|
11
|
+
resourceTypes[resourceTypeName] = {
|
|
12
|
+
...resourceTypeShell,
|
|
13
|
+
valueSchema,
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
return resourceTypes;
|
|
17
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
const GENESIS_TIMESTAMP = '2025-11-30T00:00:00.000Z';
|
|
2
|
+
export function generateResources(resourceTypes) {
|
|
3
|
+
const resources = {};
|
|
4
|
+
for (const [name, resourceType] of Object.entries(resourceTypes)) {
|
|
5
|
+
resources[name] = {
|
|
6
|
+
id: `RESOURCE-${name}`,
|
|
7
|
+
resourceTypeHandle: 'TYPE-ResourceType',
|
|
8
|
+
provenance: {
|
|
9
|
+
resourceProvenanceKind: 'genesis',
|
|
10
|
+
},
|
|
11
|
+
version: 1,
|
|
12
|
+
timestamp: GENESIS_TIMESTAMP,
|
|
13
|
+
value: resourceType,
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
return resources;
|
|
17
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
type JSONValue = null | boolean | number | string | JSONValue[] | {
|
|
2
|
+
[k: string]: JSONValue;
|
|
3
|
+
};
|
|
4
|
+
export type DependencyMap = Record<string, string[]>;
|
|
5
|
+
export declare function decodeJsonPointerSegment(segment: string): string;
|
|
6
|
+
export declare function collectRefs(node: unknown, out: Set<string>): void;
|
|
7
|
+
export declare function resolveInternalRefToDefKey(ref: string, defKeys: Set<string>, anchorToDef: Record<string, string>): string | null;
|
|
8
|
+
export declare function generateDependencyMap(doc: {
|
|
9
|
+
$defs?: Record<string, JSONValue>;
|
|
10
|
+
} | null | undefined): DependencyMap;
|
|
11
|
+
export declare function normalizeDependencyMap(value: unknown): DependencyMap;
|
|
12
|
+
export declare function computeTerminalsInKeyOrder(dependencyMap: DependencyMap): string[];
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
export function decodeJsonPointerSegment(segment) {
|
|
2
|
+
return segment.replace(/~1/g, '/').replace(/~0/g, '~');
|
|
3
|
+
}
|
|
4
|
+
export function collectRefs(node, out) {
|
|
5
|
+
if (Array.isArray(node)) {
|
|
6
|
+
for (const item of node)
|
|
7
|
+
collectRefs(item, out);
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
10
|
+
if (!node || typeof node !== 'object')
|
|
11
|
+
return;
|
|
12
|
+
const obj = node;
|
|
13
|
+
const ref = obj.$ref;
|
|
14
|
+
if (typeof ref === 'string')
|
|
15
|
+
out.add(ref);
|
|
16
|
+
for (const value of Object.values(obj)) {
|
|
17
|
+
collectRefs(value, out);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
export function resolveInternalRefToDefKey(ref, defKeys, anchorToDef) {
|
|
21
|
+
if (!ref.startsWith('#'))
|
|
22
|
+
return null;
|
|
23
|
+
const defsPrefix = '#/$defs/';
|
|
24
|
+
if (ref.startsWith(defsPrefix)) {
|
|
25
|
+
const rest = ref.slice(defsPrefix.length);
|
|
26
|
+
const firstSegment = rest.split('/')[0] ?? '';
|
|
27
|
+
const defKey = decodeJsonPointerSegment(firstSegment);
|
|
28
|
+
return defKeys.has(defKey) ? defKey : null;
|
|
29
|
+
}
|
|
30
|
+
if (!ref.startsWith('#/')) {
|
|
31
|
+
const anchor = ref.slice(1);
|
|
32
|
+
const mapped = anchorToDef[anchor];
|
|
33
|
+
if (mapped && defKeys.has(mapped))
|
|
34
|
+
return mapped;
|
|
35
|
+
if (defKeys.has(anchor))
|
|
36
|
+
return anchor;
|
|
37
|
+
}
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
export function generateDependencyMap(doc) {
|
|
41
|
+
const defs = doc?.$defs && typeof doc.$defs === 'object' ? doc.$defs : {};
|
|
42
|
+
const defKeys = new Set(Object.keys(defs));
|
|
43
|
+
const anchorToDef = {};
|
|
44
|
+
for (const [defKey, defSchema] of Object.entries(defs)) {
|
|
45
|
+
if (!defSchema || typeof defSchema !== 'object' || Array.isArray(defSchema))
|
|
46
|
+
continue;
|
|
47
|
+
const anchor = defSchema.$anchor;
|
|
48
|
+
if (typeof anchor === 'string' && !(anchor in anchorToDef)) {
|
|
49
|
+
anchorToDef[anchor] = defKey;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
const dependencyMap = {};
|
|
53
|
+
for (const [defKey, defSchema] of Object.entries(defs)) {
|
|
54
|
+
const refs = new Set();
|
|
55
|
+
collectRefs(defSchema, refs);
|
|
56
|
+
const deps = new Set();
|
|
57
|
+
for (const ref of refs) {
|
|
58
|
+
const depKey = resolveInternalRefToDefKey(ref, defKeys, anchorToDef);
|
|
59
|
+
if (!depKey || depKey === defKey)
|
|
60
|
+
continue;
|
|
61
|
+
deps.add(depKey);
|
|
62
|
+
}
|
|
63
|
+
dependencyMap[defKey] = Array.from(deps);
|
|
64
|
+
}
|
|
65
|
+
return dependencyMap;
|
|
66
|
+
}
|
|
67
|
+
export function normalizeDependencyMap(value) {
|
|
68
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
69
|
+
throw new Error('Invalid dependencyMap.json: expected an object');
|
|
70
|
+
}
|
|
71
|
+
const input = value;
|
|
72
|
+
const out = {};
|
|
73
|
+
for (const [key, rawDeps] of Object.entries(input)) {
|
|
74
|
+
if (rawDeps == null) {
|
|
75
|
+
out[key] = [];
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
if (!Array.isArray(rawDeps)) {
|
|
79
|
+
throw new Error(`Invalid dependencyMap.json: value for ${key} must be an array`);
|
|
80
|
+
}
|
|
81
|
+
out[key] = rawDeps.filter((dep) => typeof dep === 'string');
|
|
82
|
+
}
|
|
83
|
+
return out;
|
|
84
|
+
}
|
|
85
|
+
export function computeTerminalsInKeyOrder(dependencyMap) {
|
|
86
|
+
const keys = Object.keys(dependencyMap);
|
|
87
|
+
const dependedUpon = new Set();
|
|
88
|
+
for (const key of keys) {
|
|
89
|
+
for (const dep of dependencyMap[key] ?? []) {
|
|
90
|
+
dependedUpon.add(dep);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return keys.filter((key) => !dependedUpon.has(key));
|
|
94
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function normalizeAllOfSiblingObjectKeywords(node: any): any;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
export function normalizeAllOfSiblingObjectKeywords(node) {
|
|
2
|
+
if (Array.isArray(node)) {
|
|
3
|
+
let changed = false;
|
|
4
|
+
const out = node.map((item) => {
|
|
5
|
+
const next = normalizeAllOfSiblingObjectKeywords(item);
|
|
6
|
+
if (next !== item)
|
|
7
|
+
changed = true;
|
|
8
|
+
return next;
|
|
9
|
+
});
|
|
10
|
+
return changed ? out : node;
|
|
11
|
+
}
|
|
12
|
+
if (!node || typeof node !== 'object')
|
|
13
|
+
return node;
|
|
14
|
+
const hasAllOf = Array.isArray(node.allOf) && node.allOf.length > 0;
|
|
15
|
+
const looksLikeObjectSchema = node.type === 'object' ||
|
|
16
|
+
node.properties !== undefined ||
|
|
17
|
+
node.required !== undefined ||
|
|
18
|
+
node.unevaluatedProperties !== undefined ||
|
|
19
|
+
node.additionalProperties !== undefined ||
|
|
20
|
+
node.propertyNames !== undefined;
|
|
21
|
+
const siblingKeys = [
|
|
22
|
+
'type',
|
|
23
|
+
'properties',
|
|
24
|
+
'required',
|
|
25
|
+
'additionalProperties',
|
|
26
|
+
'unevaluatedProperties',
|
|
27
|
+
'propertyNames',
|
|
28
|
+
'patternProperties',
|
|
29
|
+
'dependentRequired',
|
|
30
|
+
'dependentSchemas',
|
|
31
|
+
'minProperties',
|
|
32
|
+
'maxProperties',
|
|
33
|
+
];
|
|
34
|
+
let localNode = node;
|
|
35
|
+
if (hasAllOf && looksLikeObjectSchema) {
|
|
36
|
+
const hasSiblingObjectKeywords = siblingKeys.some((key) => key in localNode);
|
|
37
|
+
if (hasSiblingObjectKeywords) {
|
|
38
|
+
const overlay = {};
|
|
39
|
+
const nextNode = { ...localNode };
|
|
40
|
+
for (const key of siblingKeys) {
|
|
41
|
+
if (key in nextNode) {
|
|
42
|
+
overlay[key] = nextNode[key];
|
|
43
|
+
delete nextNode[key];
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
nextNode.allOf = [overlay, ...nextNode.allOf];
|
|
47
|
+
localNode = nextNode;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
let changed = localNode !== node;
|
|
51
|
+
const out = localNode === node ? {} : { ...localNode };
|
|
52
|
+
for (const [key, value] of Object.entries(localNode)) {
|
|
53
|
+
const next = normalizeAllOfSiblingObjectKeywords(value);
|
|
54
|
+
if (next !== value) {
|
|
55
|
+
if (!changed) {
|
|
56
|
+
changed = true;
|
|
57
|
+
Object.assign(out, localNode);
|
|
58
|
+
}
|
|
59
|
+
out[key] = next;
|
|
60
|
+
}
|
|
61
|
+
else if (changed) {
|
|
62
|
+
out[key] = value;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return changed ? out : node;
|
|
66
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
export function stripAnchors(schema) {
|
|
2
|
+
const seen = new WeakMap();
|
|
3
|
+
function walk(node) {
|
|
4
|
+
if (!node || typeof node !== 'object')
|
|
5
|
+
return node;
|
|
6
|
+
const existing = seen.get(node);
|
|
7
|
+
if (existing)
|
|
8
|
+
return existing;
|
|
9
|
+
if (Array.isArray(node)) {
|
|
10
|
+
const out = [];
|
|
11
|
+
seen.set(node, out);
|
|
12
|
+
for (const item of node)
|
|
13
|
+
out.push(walk(item));
|
|
14
|
+
return out;
|
|
15
|
+
}
|
|
16
|
+
const out = {};
|
|
17
|
+
seen.set(node, out);
|
|
18
|
+
for (const [key, value] of Object.entries(node)) {
|
|
19
|
+
if (key === '$anchor')
|
|
20
|
+
continue;
|
|
21
|
+
out[key] = walk(value);
|
|
22
|
+
}
|
|
23
|
+
return out;
|
|
24
|
+
}
|
|
25
|
+
return walk(schema);
|
|
26
|
+
}
|
|
27
|
+
export function normalizeAnchorsToPointers(input) {
|
|
28
|
+
if (!input || typeof input !== 'object')
|
|
29
|
+
return input;
|
|
30
|
+
const root = JSON.parse(JSON.stringify(input));
|
|
31
|
+
const defs = root.$defs && typeof root.$defs === 'object' ? root.$defs : {};
|
|
32
|
+
const anchorToDef = {};
|
|
33
|
+
for (const [defName, defValue] of Object.entries(defs)) {
|
|
34
|
+
if (!anchorToDef[defName]) {
|
|
35
|
+
anchorToDef[defName] = defName;
|
|
36
|
+
}
|
|
37
|
+
if (!defValue || typeof defValue !== 'object')
|
|
38
|
+
continue;
|
|
39
|
+
const envelope = defValue;
|
|
40
|
+
const valueSchema = envelope.valueSchema;
|
|
41
|
+
if (valueSchema && typeof valueSchema === 'object') {
|
|
42
|
+
const anchor = valueSchema.$anchor;
|
|
43
|
+
if (typeof anchor === 'string' && !anchorToDef[anchor]) {
|
|
44
|
+
anchorToDef[anchor] = defName;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
const anchor = envelope.$anchor;
|
|
49
|
+
if (typeof anchor === 'string' && !anchorToDef[anchor]) {
|
|
50
|
+
anchorToDef[anchor] = defName;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
function walk(node) {
|
|
55
|
+
if (Array.isArray(node)) {
|
|
56
|
+
for (const item of node)
|
|
57
|
+
walk(item);
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
if (!node || typeof node !== 'object')
|
|
61
|
+
return;
|
|
62
|
+
const obj = node;
|
|
63
|
+
if (typeof obj.$ref === 'string' && obj.$ref.startsWith('#') && !obj.$ref.startsWith('#/')) {
|
|
64
|
+
const anchor = obj.$ref.slice(1);
|
|
65
|
+
const defName = anchorToDef[anchor];
|
|
66
|
+
if (defName) {
|
|
67
|
+
obj.$ref = `#/$defs/${defName}`;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
for (const value of Object.values(obj)) {
|
|
71
|
+
walk(value);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
walk(root);
|
|
75
|
+
return root;
|
|
76
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import * as path from 'node:path';
|
|
2
|
+
export function generateShimContent(jsonFile, variableName) {
|
|
3
|
+
return `import ${variableName} from './${jsonFile}' with { type: 'json' };\nexport default ${variableName};\n`;
|
|
4
|
+
}
|
|
5
|
+
export function getShimsForFiles(jsonFiles, variableName) {
|
|
6
|
+
const shims = {};
|
|
7
|
+
for (const jsonFile of jsonFiles) {
|
|
8
|
+
const baseName = path.basename(jsonFile, '.json');
|
|
9
|
+
const tsFile = `${baseName}.ts`;
|
|
10
|
+
shims[tsFile] = generateShimContent(jsonFile, variableName);
|
|
11
|
+
}
|
|
12
|
+
return shims;
|
|
13
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export declare function isObject(value: unknown): value is Record<string, unknown>;
|
|
2
|
+
export declare function deepClone<T>(value: T): T;
|
|
3
|
+
export declare function extractPointerDefName(ref: string): string | null;
|
|
4
|
+
export declare function collectLocalDefClosure(node: unknown, rootDefs: Record<string, unknown>): Set<string>;
|
|
5
|
+
export declare function extractStandaloneSchema(schemasDocument: {
|
|
6
|
+
$defs?: Record<string, unknown>;
|
|
7
|
+
}, name: string): {
|
|
8
|
+
schema: unknown;
|
|
9
|
+
warnings: string[];
|
|
10
|
+
};
|
|
11
|
+
export declare function generateStandaloneSchemas(schemasDocument: {
|
|
12
|
+
$defs?: Record<string, unknown>;
|
|
13
|
+
}, names: string[]): {
|
|
14
|
+
standaloneSchemas: Record<string, unknown>;
|
|
15
|
+
warnings: string[];
|
|
16
|
+
};
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
export function isObject(value) {
|
|
2
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
3
|
+
}
|
|
4
|
+
export function deepClone(value) {
|
|
5
|
+
if (Array.isArray(value))
|
|
6
|
+
return value.map((item) => deepClone(item));
|
|
7
|
+
if (isObject(value)) {
|
|
8
|
+
const out = {};
|
|
9
|
+
for (const key of Object.keys(value))
|
|
10
|
+
out[key] = deepClone(value[key]);
|
|
11
|
+
return out;
|
|
12
|
+
}
|
|
13
|
+
return value;
|
|
14
|
+
}
|
|
15
|
+
export function extractPointerDefName(ref) {
|
|
16
|
+
if (!ref || !ref.startsWith('#/'))
|
|
17
|
+
return null;
|
|
18
|
+
const parts = ref.slice(2).split('/');
|
|
19
|
+
if (parts.length !== 2)
|
|
20
|
+
return null;
|
|
21
|
+
if (parts[0] !== '$defs')
|
|
22
|
+
return null;
|
|
23
|
+
const defName = parts[1];
|
|
24
|
+
if (defName === undefined)
|
|
25
|
+
return null;
|
|
26
|
+
return defName.replace(/~1/g, '/').replace(/~0/g, '~');
|
|
27
|
+
}
|
|
28
|
+
export function collectLocalDefClosure(node, rootDefs) {
|
|
29
|
+
const needed = new Set();
|
|
30
|
+
const queue = [];
|
|
31
|
+
function visit(value) {
|
|
32
|
+
if (Array.isArray(value)) {
|
|
33
|
+
for (const item of value)
|
|
34
|
+
visit(item);
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
if (!isObject(value))
|
|
38
|
+
return;
|
|
39
|
+
if (typeof value.$ref === 'string') {
|
|
40
|
+
const name = extractPointerDefName(value.$ref);
|
|
41
|
+
if (name && !needed.has(name)) {
|
|
42
|
+
needed.add(name);
|
|
43
|
+
queue.push(name);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
for (const nested of Object.values(value))
|
|
47
|
+
visit(nested);
|
|
48
|
+
}
|
|
49
|
+
visit(node);
|
|
50
|
+
while (queue.length > 0) {
|
|
51
|
+
const name = queue.shift();
|
|
52
|
+
if (!name)
|
|
53
|
+
continue;
|
|
54
|
+
const def = rootDefs[name];
|
|
55
|
+
if (def === undefined)
|
|
56
|
+
continue;
|
|
57
|
+
visit(def);
|
|
58
|
+
}
|
|
59
|
+
return needed;
|
|
60
|
+
}
|
|
61
|
+
export function extractStandaloneSchema(schemasDocument, name) {
|
|
62
|
+
const rootDefs = schemasDocument.$defs;
|
|
63
|
+
if (!rootDefs || typeof rootDefs !== 'object') {
|
|
64
|
+
throw new Error('No $defs object found in schema document');
|
|
65
|
+
}
|
|
66
|
+
const target = rootDefs[name];
|
|
67
|
+
if (target === undefined) {
|
|
68
|
+
throw new Error(`Subschema named '${name}' not found under $defs in schema document`);
|
|
69
|
+
}
|
|
70
|
+
const needed = collectLocalDefClosure(target, rootDefs);
|
|
71
|
+
const targetClone = deepClone(target);
|
|
72
|
+
const defsOut = {};
|
|
73
|
+
const warnings = [];
|
|
74
|
+
for (const defName of needed) {
|
|
75
|
+
if (defName === name)
|
|
76
|
+
continue;
|
|
77
|
+
const defSchema = rootDefs[defName];
|
|
78
|
+
if (defSchema === undefined) {
|
|
79
|
+
warnings.push(`Warning: referenced def '${defName}' missing in root $defs (skipped).`);
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
defsOut[defName] = deepClone(defSchema);
|
|
83
|
+
}
|
|
84
|
+
const existingInner = isObject(targetClone) && isObject(targetClone.$defs)
|
|
85
|
+
? targetClone.$defs
|
|
86
|
+
: {};
|
|
87
|
+
if (isObject(targetClone)) {
|
|
88
|
+
targetClone.$defs = { ...existingInner, ...defsOut };
|
|
89
|
+
}
|
|
90
|
+
return { schema: targetClone, warnings };
|
|
91
|
+
}
|
|
92
|
+
export function generateStandaloneSchemas(schemasDocument, names) {
|
|
93
|
+
const standaloneSchemas = {};
|
|
94
|
+
const warnings = [];
|
|
95
|
+
for (const name of names) {
|
|
96
|
+
const result = extractStandaloneSchema(schemasDocument, name);
|
|
97
|
+
standaloneSchemas[name] = result.schema;
|
|
98
|
+
warnings.push(...result.warnings);
|
|
99
|
+
}
|
|
100
|
+
return { standaloneSchemas, warnings };
|
|
101
|
+
}
|