@toolproof-core/schema 1.0.4 → 1.0.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/dist/generated/constants/constants.d.ts +60 -0
- package/dist/generated/constants/constants.js +60 -0
- package/dist/generated/normalized/Genesis.json +0 -261
- package/dist/generated/resources/Genesis.json +0 -299
- package/dist/generated/schemas/Genesis.json +0 -150
- 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 +0 -46
- package/dist/generated/schemas/standalone/ResourceType.json +0 -34
- package/dist/generated/schemas/standalone/RunnableStrategy.json +0 -51
- package/dist/generated/schemas/standalone/StrategyRun.json +0 -65
- package/dist/generated/{typesTS → types}/standalone/Resource_Genesis.d.ts +1 -1
- package/{src/generated/typesTS → dist/generated/types}/standalone/Resource_Job.d.ts +1 -1
- package/{src/generated/typesTS → dist/generated/types}/standalone/Resource_RawStrategy.d.ts +1 -1
- package/{src/generated/typesTS → dist/generated/types}/standalone/Resource_ResourceType.d.ts +1 -1
- package/dist/generated/{typesTS → types}/standalone/Resource_RunnableStrategy.d.ts +1 -1
- package/dist/generated/{typesTS/typesTS.d.ts → types/types.d.ts} +13 -49
- package/dist/index.d.ts +7 -6
- package/dist/index.js +1 -0
- package/dist/scripts/_lib/config.d.ts +15 -12
- package/dist/scripts/_lib/config.js +34 -27
- package/dist/scripts/generateConstants.d.ts +12 -0
- package/dist/scripts/generateConstants.js +179 -0
- package/dist/scripts/generateSchemaShims.js +2 -2
- package/dist/scripts/generateStandaloneSchema.js +1 -1
- package/dist/scripts/{generateStandaloneTypeTS.js → generateStandaloneType.js} +9 -9
- package/dist/scripts/generateTerminals.js +58 -0
- package/dist/scripts/generateTypes.d.ts +1 -0
- package/dist/scripts/{generateTypesTS.js → generateTypes.js} +11 -11
- package/dist/scripts/normalizeAnchorsToPointers.d.ts +1 -1
- package/dist/scripts/normalizeAnchorsToPointers.js +33 -12
- package/package.json +7 -5
- package/src/Genesis.json +0 -174
- package/src/generated/constants/constants.ts +61 -0
- package/src/generated/dependencies/dependencyMap.json +2 -14
- package/src/generated/dependencies/terminals.json +12 -0
- package/src/generated/normalized/Genesis.json +0 -261
- package/src/generated/resources/Genesis.json +0 -299
- package/src/generated/schemas/Genesis.json +0 -150
- 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 +0 -46
- package/src/generated/schemas/standalone/ResourceType.json +0 -34
- package/src/generated/schemas/standalone/RunnableStrategy.json +0 -51
- package/src/generated/schemas/standalone/StrategyRun.json +0 -65
- package/src/generated/{typesTS → types}/standalone/Resource_Genesis.d.ts +1 -1
- package/{dist/generated/typesTS → src/generated/types}/standalone/Resource_Job.d.ts +1 -1
- package/{dist/generated/typesTS → src/generated/types}/standalone/Resource_RawStrategy.d.ts +1 -1
- package/{dist/generated/typesTS → src/generated/types}/standalone/Resource_ResourceType.d.ts +1 -1
- package/src/generated/{typesTS → types}/standalone/Resource_RunnableStrategy.d.ts +1 -1
- package/src/generated/{typesTS/typesTS.d.ts → types/types.d.ts} +13 -49
- package/src/index.ts +9 -7
- package/src/scripts/_lib/config.ts +39 -29
- package/src/scripts/generateConstants.ts +217 -0
- package/src/scripts/generateSchemaShims.ts +2 -2
- package/src/scripts/generateStandaloneSchema.ts +1 -1
- package/src/scripts/{generateStandaloneTypeTS.ts → generateStandaloneType.ts} +9 -9
- package/src/scripts/generateTerminals.ts +73 -0
- package/src/scripts/{generateTypesTS.ts → generateTypes.ts} +11 -11
- package/src/scripts/normalizeAnchorsToPointers.ts +38 -12
- /package/dist/generated/{typesTS → types}/standalone/Resource_Genesis.js +0 -0
- /package/dist/generated/{typesTS → types}/standalone/Resource_Job.js +0 -0
- /package/dist/generated/{typesTS → types}/standalone/Resource_RawStrategy.js +0 -0
- /package/dist/generated/{typesTS → types}/standalone/Resource_ResourceType.js +0 -0
- /package/dist/generated/{typesTS → types}/standalone/Resource_RunnableStrategy.js +0 -0
- /package/dist/generated/{typesTS/typesTS.js → types/types.js} +0 -0
- /package/dist/scripts/{generateStandaloneTypeTS.d.ts → generateStandaloneType.d.ts} +0 -0
- /package/dist/scripts/{generateTypesTS.d.ts → generateTerminals.d.ts} +0 -0
- /package/src/generated/{typesTS → types}/standalone/Resource_Genesis.js +0 -0
- /package/src/generated/{typesTS → types}/standalone/Resource_Job.js +0 -0
- /package/src/generated/{typesTS → types}/standalone/Resource_RawStrategy.js +0 -0
- /package/src/generated/{typesTS → types}/standalone/Resource_ResourceType.js +0 -0
- /package/src/generated/{typesTS → types}/standalone/Resource_RunnableStrategy.js +0 -0
- /package/src/generated/{typesTS/typesTS.js → types/types.js} +0 -0
|
@@ -24,10 +24,11 @@ export class SchemaConfig {
|
|
|
24
24
|
private readonly sourceFile: string;
|
|
25
25
|
private readonly normalizedDir: string;
|
|
26
26
|
private readonly schemasDir: string;
|
|
27
|
+
private readonly constantsDir: string;
|
|
27
28
|
private readonly resourcesDir: string;
|
|
28
29
|
private readonly dependencyMapPath: string;
|
|
29
|
-
private readonly
|
|
30
|
-
private readonly
|
|
30
|
+
private readonly typesSrcDir: string;
|
|
31
|
+
private readonly typesDistDir: string;
|
|
31
32
|
|
|
32
33
|
// Schema metadata
|
|
33
34
|
private readonly baseUrl: string;
|
|
@@ -38,14 +39,13 @@ export class SchemaConfig {
|
|
|
38
39
|
this.root = getEnv('TP_SCHEMA_ROOT', process.cwd());
|
|
39
40
|
this.sourceDir = getEnv('TP_SCHEMA_SOURCE_DIR', 'src/');
|
|
40
41
|
this.sourceFile = getEnv('TP_SCHEMA_SOURCE_FILE', 'Genesis.json');
|
|
41
|
-
// Intermediate, generated artifact produced by normalizeAnchorsToPointers.
|
|
42
|
-
// This should NOT live next to the source-of-truth schemas.
|
|
43
42
|
this.normalizedDir = getEnv('TP_SCHEMA_NORMALIZED_DIR', 'src/generated/normalized');
|
|
44
43
|
this.schemasDir = getEnv('TP_SCHEMA_SCHEMAS_DIR', 'src/generated/schemas');
|
|
44
|
+
this.constantsDir = getEnv('TP_SCHEMA_CONSTANTS_DIR', 'src/generated/constants');
|
|
45
45
|
this.resourcesDir = getEnv('TP_SCHEMA_RESOURCES_DIR', 'src/generated/resources');
|
|
46
46
|
this.dependencyMapPath = getEnv('TP_SCHEMA_DEPENDENCY_MAP_PATH', 'src/generated/dependencies/dependencyMap.json');
|
|
47
|
-
this.
|
|
48
|
-
this.
|
|
47
|
+
this.typesSrcDir = getEnv('TP_SCHEMA_TYPES_SRC_DIR', 'src/generated/types');
|
|
48
|
+
this.typesDistDir = getEnv('TP_SCHEMA_TYPES_DIST_DIR', 'dist/generated/types');
|
|
49
49
|
this.baseUrl = getEnv('TP_SCHEMA_BASE_URL', 'https://schemas.toolproof.com');
|
|
50
50
|
this.version = getEnv('TP_SCHEMA_VERSION', 'v0');
|
|
51
51
|
}
|
|
@@ -96,48 +96,58 @@ export class SchemaConfig {
|
|
|
96
96
|
return path.join(this.getSchemasDir(), filename);
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
-
|
|
99
|
+
getConstantsDir(): string {
|
|
100
|
+
return path.isAbsolute(this.constantsDir)
|
|
101
|
+
? this.constantsDir
|
|
102
|
+
: path.join(this.root, this.constantsDir);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
getConstantsPath(filename: string): string {
|
|
106
|
+
return path.join(this.getConstantsDir(), filename);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
getStandaloneSchemaDir(): string {
|
|
100
110
|
return path.join(this.getSchemasDir(), 'standalone');
|
|
101
111
|
}
|
|
102
112
|
|
|
103
|
-
|
|
104
|
-
return path.join(this.
|
|
113
|
+
getStandaloneSchemaPath(filename: string): string {
|
|
114
|
+
return path.join(this.getStandaloneSchemaDir(), filename);
|
|
105
115
|
}
|
|
106
116
|
|
|
107
|
-
|
|
108
|
-
return path.isAbsolute(this.
|
|
109
|
-
? this.
|
|
110
|
-
: path.join(this.root, this.
|
|
117
|
+
getTypesSrcDir(): string {
|
|
118
|
+
return path.isAbsolute(this.typesSrcDir)
|
|
119
|
+
? this.typesSrcDir
|
|
120
|
+
: path.join(this.root, this.typesSrcDir);
|
|
111
121
|
}
|
|
112
122
|
|
|
113
|
-
|
|
114
|
-
return path.isAbsolute(this.
|
|
115
|
-
? this.
|
|
116
|
-
: path.join(this.root, this.
|
|
123
|
+
getTypesDistDir(): string {
|
|
124
|
+
return path.isAbsolute(this.typesDistDir)
|
|
125
|
+
? this.typesDistDir
|
|
126
|
+
: path.join(this.root, this.typesDistDir);
|
|
117
127
|
}
|
|
118
128
|
|
|
119
|
-
|
|
120
|
-
return path.join(this.
|
|
129
|
+
getTypesSrcPath(filename: string): string {
|
|
130
|
+
return path.join(this.getTypesSrcDir(), filename);
|
|
121
131
|
}
|
|
122
132
|
|
|
123
|
-
|
|
124
|
-
return path.join(this.
|
|
133
|
+
getTypesDistPath(filename: string): string {
|
|
134
|
+
return path.join(this.getTypesDistDir(), filename);
|
|
125
135
|
}
|
|
126
136
|
|
|
127
|
-
|
|
128
|
-
return path.join(this.
|
|
137
|
+
getStandaloneTypeSrcDir(): string {
|
|
138
|
+
return path.join(this.getTypesSrcDir(), 'standalone');
|
|
129
139
|
}
|
|
130
140
|
|
|
131
|
-
|
|
132
|
-
return path.join(this.
|
|
141
|
+
getStandaloneTypeDistDir(): string {
|
|
142
|
+
return path.join(this.getTypesDistDir(), 'standalone');
|
|
133
143
|
}
|
|
134
144
|
|
|
135
|
-
|
|
136
|
-
return path.join(this.
|
|
145
|
+
getStandaloneTypeSrcPath(filename: string): string {
|
|
146
|
+
return path.join(this.getStandaloneTypeSrcDir(), filename);
|
|
137
147
|
}
|
|
138
148
|
|
|
139
|
-
|
|
140
|
-
return path.join(this.
|
|
149
|
+
getStandaloneTypeDistPath(filename: string): string {
|
|
150
|
+
return path.join(this.getStandaloneTypeDistDir(), filename);
|
|
141
151
|
}
|
|
142
152
|
|
|
143
153
|
getResourcesDir(): string {
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { getConfig } from './_lib/config.js';
|
|
4
|
+
|
|
5
|
+
type JSONValue = null | boolean | number | string | JSONValue[] | { [k: string]: JSONValue };
|
|
6
|
+
|
|
7
|
+
export type GeneratedConstants = {
|
|
8
|
+
IDENTIFIABLES: {
|
|
9
|
+
PREFIXES: Record<string, string>;
|
|
10
|
+
NAMES: Record<string, string>;
|
|
11
|
+
};
|
|
12
|
+
ENUMS: Record<string, Record<string, string>>;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
// PURE: Attempt to derive a canonical identity prefix from a canonical identity regex pattern.
|
|
16
|
+
function deriveIdentityPrefixFromPattern(pattern: string): string | undefined {
|
|
17
|
+
// Canonical (currently used across schemas): ^PREFIX-.+$
|
|
18
|
+
const match = /^\^([^$]+)\.\+\$$/.exec(pattern);
|
|
19
|
+
if (!match) return undefined;
|
|
20
|
+
|
|
21
|
+
const prefix = match[1];
|
|
22
|
+
if (!prefix || /[`\n\r]/.test(prefix)) return undefined;
|
|
23
|
+
|
|
24
|
+
return prefix;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// PURE: Extract all identity prefixes from `$defs/*Identity` string-pattern definitions.
|
|
28
|
+
export function extractIdentityPrefixes(schema: unknown): Record<string, string> {
|
|
29
|
+
if (!schema || typeof schema !== 'object') return {};
|
|
30
|
+
|
|
31
|
+
const defs = (schema as any).$defs;
|
|
32
|
+
if (!defs || typeof defs !== 'object') return {};
|
|
33
|
+
|
|
34
|
+
const defEntries = Object.entries(defs as Record<string, unknown>);
|
|
35
|
+
defEntries.sort(([a], [b]) => a.localeCompare(b));
|
|
36
|
+
|
|
37
|
+
const out: Record<string, string> = {};
|
|
38
|
+
|
|
39
|
+
for (const [defName, defVal] of defEntries) {
|
|
40
|
+
if (!/Identity$/.test(defName)) continue;
|
|
41
|
+
if (!defVal || typeof defVal !== 'object' || Array.isArray(defVal)) continue;
|
|
42
|
+
|
|
43
|
+
const v: any = defVal;
|
|
44
|
+
if (v.type !== 'string') continue;
|
|
45
|
+
if (typeof v.pattern !== 'string') continue;
|
|
46
|
+
|
|
47
|
+
const prefix = deriveIdentityPrefixFromPattern(v.pattern);
|
|
48
|
+
if (!prefix) continue;
|
|
49
|
+
|
|
50
|
+
out[defName] = prefix;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return out;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// PURE: Derive identifiables from extracted Identity def names.
|
|
57
|
+
// Example: { BranchStepIdentity: 'BRANCH_STEP-' } => { BranchStep: 'BranchStep' }
|
|
58
|
+
export function deriveIdentifiablesFromIdentityPrefixes(identityPrefixes: Record<string, string>): Record<string, string> {
|
|
59
|
+
const keys = Object.keys(identityPrefixes).sort((a, b) => a.localeCompare(b));
|
|
60
|
+
const out: Record<string, string> = {};
|
|
61
|
+
|
|
62
|
+
for (const key of keys) {
|
|
63
|
+
if (!key.endsWith('Identity')) continue;
|
|
64
|
+
const name = key.slice(0, -'Identity'.length);
|
|
65
|
+
if (!name) continue;
|
|
66
|
+
out[name] = name;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return out;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// PURE: Extract all string enums from `$defs/*Kind|*Status` definitions.
|
|
73
|
+
// Shape: { StepKind: { job: 'job', ... }, ResourceKind: { 'input-potential': 'input-potential', ... } }
|
|
74
|
+
export function extractEnums(schema: unknown): Record<string, Record<string, string>> {
|
|
75
|
+
if (!schema || typeof schema !== 'object') return {};
|
|
76
|
+
|
|
77
|
+
const defs = (schema as any).$defs;
|
|
78
|
+
if (!defs || typeof defs !== 'object') return {};
|
|
79
|
+
|
|
80
|
+
const defEntries = Object.entries(defs as Record<string, unknown>);
|
|
81
|
+
defEntries.sort(([a], [b]) => a.localeCompare(b));
|
|
82
|
+
|
|
83
|
+
const out: Record<string, Record<string, string>> = {};
|
|
84
|
+
|
|
85
|
+
for (const [defName, defVal] of defEntries) {
|
|
86
|
+
if (!/(Kind|Status)$/.test(defName)) continue;
|
|
87
|
+
if (!defVal || typeof defVal !== 'object' || Array.isArray(defVal)) continue;
|
|
88
|
+
|
|
89
|
+
const v: any = defVal;
|
|
90
|
+
if (v.type !== 'string') continue;
|
|
91
|
+
if (!Array.isArray(v.enum) || v.enum.length === 0) continue;
|
|
92
|
+
if (v.enum.some((x: unknown) => typeof x !== 'string')) continue;
|
|
93
|
+
|
|
94
|
+
const members: Record<string, string> = {};
|
|
95
|
+
for (const member of v.enum as readonly string[]) {
|
|
96
|
+
members[member] = member;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
out[defName] = members;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return out;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// PURE: Extract all generated constants from a parsed schema.
|
|
106
|
+
export function extractConstants(schema: unknown): GeneratedConstants {
|
|
107
|
+
const identityPrefixes = extractIdentityPrefixes(schema);
|
|
108
|
+
const identifiables = deriveIdentifiablesFromIdentityPrefixes(identityPrefixes);
|
|
109
|
+
const enums = extractEnums(schema);
|
|
110
|
+
return {
|
|
111
|
+
IDENTIFIABLES: {
|
|
112
|
+
PREFIXES: identityPrefixes,
|
|
113
|
+
NAMES: identifiables,
|
|
114
|
+
},
|
|
115
|
+
ENUMS: enums,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// PURE: Render helpers for TS keys/strings.
|
|
120
|
+
function escapeTsString(value: string): string {
|
|
121
|
+
return value
|
|
122
|
+
.replace(/\\/g, '\\\\')
|
|
123
|
+
.replace(/\r/g, '\\r')
|
|
124
|
+
.replace(/\n/g, '\\n')
|
|
125
|
+
.replace(/\t/g, '\\t')
|
|
126
|
+
.replace(/'/g, "\\'");
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function renderTsStringLiteral(value: string): string {
|
|
130
|
+
return `'${escapeTsString(value)}'`;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function isValidTsIdentifier(key: string): boolean {
|
|
134
|
+
return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(key);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function renderTsKey(key: string): string {
|
|
138
|
+
return isValidTsIdentifier(key) ? key : renderTsStringLiteral(key);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// PURE: Render constants TypeScript source.
|
|
142
|
+
export function renderConstantsTs(constants: GeneratedConstants): string {
|
|
143
|
+
const prefixKeys = Object.keys(constants.IDENTIFIABLES.PREFIXES).sort((a, b) => a.localeCompare(b));
|
|
144
|
+
const nameKeys = Object.keys(constants.IDENTIFIABLES.NAMES).sort((a, b) => a.localeCompare(b));
|
|
145
|
+
const enumKeys = Object.keys(constants.ENUMS).sort((a, b) => a.localeCompare(b));
|
|
146
|
+
|
|
147
|
+
const lines: string[] = [];
|
|
148
|
+
lines.push('const CONSTANTS = {');
|
|
149
|
+
lines.push(' IDENTIFIABLES: {');
|
|
150
|
+
lines.push(' PREFIXES: {');
|
|
151
|
+
|
|
152
|
+
for (const key of prefixKeys) {
|
|
153
|
+
const value = constants.IDENTIFIABLES.PREFIXES[key] ?? '';
|
|
154
|
+
lines.push(` ${renderTsKey(key)}: ${renderTsStringLiteral(value)},`);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
lines.push(' },');
|
|
158
|
+
lines.push(' NAMES: {');
|
|
159
|
+
|
|
160
|
+
for (const key of nameKeys) {
|
|
161
|
+
const value = constants.IDENTIFIABLES.NAMES[key] ?? '';
|
|
162
|
+
lines.push(` ${renderTsKey(key)}: ${renderTsStringLiteral(value)},`);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
lines.push(' },');
|
|
166
|
+
lines.push(' },');
|
|
167
|
+
lines.push(' ENUMS: {');
|
|
168
|
+
|
|
169
|
+
for (const key of enumKeys) {
|
|
170
|
+
const members = constants.ENUMS[key] ?? {};
|
|
171
|
+
lines.push(` ${renderTsKey(key)}: {`);
|
|
172
|
+
|
|
173
|
+
for (const memberKey of Object.keys(members)) {
|
|
174
|
+
const value = members[memberKey] ?? '';
|
|
175
|
+
lines.push(` ${renderTsKey(memberKey)}: ${renderTsStringLiteral(value)},`);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
lines.push(' },');
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
lines.push(' }');
|
|
182
|
+
lines.push('} as const;');
|
|
183
|
+
lines.push('');
|
|
184
|
+
lines.push('export default CONSTANTS;');
|
|
185
|
+
lines.push('');
|
|
186
|
+
|
|
187
|
+
return lines.join('\n');
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// IMPURE: Script entrypoint (config + filesystem I/O + console + process exit code).
|
|
191
|
+
function main() {
|
|
192
|
+
try {
|
|
193
|
+
const config = getConfig();
|
|
194
|
+
|
|
195
|
+
const inPath = config.getSchemaPath('Genesis.json');
|
|
196
|
+
const outPath = config.getConstantsPath('constants.ts');
|
|
197
|
+
|
|
198
|
+
if (!fs.existsSync(inPath)) {
|
|
199
|
+
throw new Error(`Genesis schema not found at ${inPath}. Run extractSchemasFromResourceTypeShells first.`);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const raw = fs.readFileSync(inPath, 'utf8');
|
|
203
|
+
const doc: JSONValue = JSON.parse(raw);
|
|
204
|
+
|
|
205
|
+
const constants = extractConstants(doc);
|
|
206
|
+
const ts = renderConstantsTs(constants);
|
|
207
|
+
|
|
208
|
+
fs.mkdirSync(path.dirname(outPath), { recursive: true });
|
|
209
|
+
fs.writeFileSync(outPath, ts, 'utf8');
|
|
210
|
+
console.log(`Wrote constants to ${outPath}`);
|
|
211
|
+
} catch (error: any) {
|
|
212
|
+
console.error(`Error generating constants: ${error?.message ?? error}`);
|
|
213
|
+
process.exitCode = 1;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
main();
|
|
@@ -11,7 +11,7 @@ import { getConfig } from './_lib/config.js';
|
|
|
11
11
|
*
|
|
12
12
|
* Generates shims for:
|
|
13
13
|
* - schemas dir: config.getSchemasDir() (schema files)
|
|
14
|
-
* - standalone schemas dir: config.
|
|
14
|
+
* - standalone schemas dir: config.getStandaloneSchemaDir() (standalone schema files)
|
|
15
15
|
* - resources dir: config.getResourcesDir() (resource envelope files)
|
|
16
16
|
*
|
|
17
17
|
* Usage: node ./dist/scripts/generateSchemaShims.js
|
|
@@ -38,7 +38,7 @@ function main() {
|
|
|
38
38
|
try {
|
|
39
39
|
const config = getConfig();
|
|
40
40
|
const schemasDir = config.getSchemasDir();
|
|
41
|
-
const standaloneSchemasDir = config.
|
|
41
|
+
const standaloneSchemasDir = config.getStandaloneSchemaDir();
|
|
42
42
|
const resourcesDir = config.getResourcesDir();
|
|
43
43
|
const generatedResourceTypesDir = config.getNormalizedDir();
|
|
44
44
|
|
|
@@ -161,7 +161,7 @@ async function main() {
|
|
|
161
161
|
|
|
162
162
|
const schemasDir = config.getSchemasDir();
|
|
163
163
|
const genesisPath = path.join(schemasDir, config.getSourceFile());
|
|
164
|
-
const outPath = config.
|
|
164
|
+
const outPath = config.getStandaloneSchemaPath(`${name}.json`);
|
|
165
165
|
|
|
166
166
|
if (!fs.existsSync(genesisPath)) {
|
|
167
167
|
throw new Error(`Genesis.json not found at ${genesisPath}. Run extractSchemasFromResourceTypeShells first.`);
|
|
@@ -5,14 +5,14 @@ import { getConfig } from "./_lib/config.js";
|
|
|
5
5
|
* Generate a typed Resource variant where `nucleus` is typed to a specific schema
|
|
6
6
|
* extracted under the configured output directory.
|
|
7
7
|
*
|
|
8
|
-
* Usage: node ./dist/scripts/
|
|
8
|
+
* Usage: node ./dist/scripts/generateStandaloneTypes.js --name Job
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
// PURE: Generate the content of a standalone Resource type definition file for a given schema name.
|
|
12
12
|
function generateStandaloneTypeLogic(name: string): string {
|
|
13
13
|
const header = "// Auto-generated strict composite type. Do not edit.\n";
|
|
14
14
|
const ts =
|
|
15
|
-
`import type { ShellMaterializedBase, ${name} as NucleusSchema } from "../
|
|
15
|
+
`import type { ShellMaterializedBase, ${name} as NucleusSchema } from "../types.js";\n` +
|
|
16
16
|
`export type Resource_${name} = ShellMaterializedBase & { nucleus: NucleusSchema };\n`;
|
|
17
17
|
return header + ts;
|
|
18
18
|
}
|
|
@@ -70,7 +70,7 @@ function main() {
|
|
|
70
70
|
const inPath =
|
|
71
71
|
name === "Genesis"
|
|
72
72
|
? config.getSchemaPath("Genesis.json")
|
|
73
|
-
: config.
|
|
73
|
+
: config.getStandaloneSchemaPath(`${name}.json`);
|
|
74
74
|
|
|
75
75
|
if (!fs.existsSync(inPath)) {
|
|
76
76
|
if (name === "Genesis") {
|
|
@@ -95,13 +95,13 @@ function main() {
|
|
|
95
95
|
// Output setup
|
|
96
96
|
const outName = `Resource_${name}.d.ts`;
|
|
97
97
|
const outJsName = `Resource_${name}.js`;
|
|
98
|
-
const outDir = config.
|
|
99
|
-
const distLibDir = config.
|
|
98
|
+
const outDir = config.getStandaloneTypeSrcDir();
|
|
99
|
+
const distLibDir = config.getStandaloneTypeDistDir();
|
|
100
100
|
|
|
101
101
|
// Process src output
|
|
102
102
|
fs.mkdirSync(outDir, { recursive: true });
|
|
103
|
-
const outPath = config.
|
|
104
|
-
const outJsPath = config.
|
|
103
|
+
const outPath = config.getStandaloneTypeSrcPath(outName);
|
|
104
|
+
const outJsPath = config.getStandaloneTypeSrcPath(outJsName);
|
|
105
105
|
fs.writeFileSync(outPath, tsContent, "utf8");
|
|
106
106
|
console.log(`Wrote ${outPath}`);
|
|
107
107
|
|
|
@@ -112,8 +112,8 @@ function main() {
|
|
|
112
112
|
|
|
113
113
|
// Process dist output
|
|
114
114
|
fs.mkdirSync(distLibDir, { recursive: true });
|
|
115
|
-
const distDtsPath = config.
|
|
116
|
-
const distJsPath = config.
|
|
115
|
+
const distDtsPath = config.getStandaloneTypeDistPath(outName);
|
|
116
|
+
const distJsPath = config.getStandaloneTypeDistPath(outJsName);
|
|
117
117
|
fs.writeFileSync(distDtsPath, tsContent, "utf8");
|
|
118
118
|
fs.writeFileSync(distJsPath, jsContent, "utf8");
|
|
119
119
|
console.log(`Wrote ${distDtsPath}`);
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { getConfig } from "./_lib/config.js";
|
|
4
|
+
|
|
5
|
+
type DependencyMap = Record<string, string[]>;
|
|
6
|
+
|
|
7
|
+
// PURE: Validate + normalize a dependency map loaded from JSON.
|
|
8
|
+
function normalizeDependencyMap(value: unknown): DependencyMap {
|
|
9
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
10
|
+
throw new Error("Invalid dependencyMap.json: expected an object");
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const input = value as Record<string, unknown>;
|
|
14
|
+
const out: DependencyMap = {};
|
|
15
|
+
|
|
16
|
+
// Preserve insertion order from the parsed JSON object.
|
|
17
|
+
for (const [key, rawDeps] of Object.entries(input)) {
|
|
18
|
+
if (rawDeps == null) {
|
|
19
|
+
out[key] = [];
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
if (!Array.isArray(rawDeps)) {
|
|
23
|
+
throw new Error(`Invalid dependencyMap.json: value for ${key} must be an array`);
|
|
24
|
+
}
|
|
25
|
+
out[key] = rawDeps.filter((d): d is string => typeof d === "string");
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return out;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// PURE: Compute terminals (defs that are not depended-upon by any other def).
|
|
32
|
+
function computeTerminalsInKeyOrder(dependencyMap: DependencyMap): string[] {
|
|
33
|
+
const keys = Object.keys(dependencyMap);
|
|
34
|
+
const dependedUpon = new Set<string>();
|
|
35
|
+
|
|
36
|
+
for (const key of keys) {
|
|
37
|
+
for (const dep of dependencyMap[key] ?? []) {
|
|
38
|
+
dependedUpon.add(dep);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Preserve key order from dependencyMap.json.
|
|
43
|
+
return keys.filter((k) => !dependedUpon.has(k));
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// IMPURE: Script entrypoint (config + filesystem I/O + console + process exit code).
|
|
47
|
+
function main() {
|
|
48
|
+
try {
|
|
49
|
+
const config = getConfig();
|
|
50
|
+
|
|
51
|
+
const inPath = config.getDependencyMapPath();
|
|
52
|
+
const outPath = path.join(path.dirname(inPath), "terminals.json");
|
|
53
|
+
|
|
54
|
+
if (!fs.existsSync(inPath)) {
|
|
55
|
+
throw new Error(`Dependency map not found at ${inPath}. Run generateDependencies first.`);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const raw = fs.readFileSync(inPath, "utf8");
|
|
59
|
+
const parsed = JSON.parse(raw) as unknown;
|
|
60
|
+
|
|
61
|
+
const dependencyMap = normalizeDependencyMap(parsed);
|
|
62
|
+
const terminals = computeTerminalsInKeyOrder(dependencyMap);
|
|
63
|
+
|
|
64
|
+
fs.mkdirSync(path.dirname(outPath), { recursive: true });
|
|
65
|
+
fs.writeFileSync(outPath, JSON.stringify(terminals, null, 4), "utf8");
|
|
66
|
+
console.log(`Wrote terminals to ${outPath}`);
|
|
67
|
+
} catch (error: any) {
|
|
68
|
+
console.error(`Error generating terminals: ${error?.message ?? error}`);
|
|
69
|
+
process.exitCode = 1;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
main();
|
|
@@ -407,10 +407,10 @@ function postProcessEmittedTypes(ts: string, parsedSchema: any): string {
|
|
|
407
407
|
}
|
|
408
408
|
|
|
409
409
|
// PURE: Add banner + formatting/guards to build the final .d.ts content.
|
|
410
|
-
function finalizeOutputDts(
|
|
410
|
+
function finalizeOutputDts(emittedType: string): string {
|
|
411
411
|
const banner = '// Auto-generated from JSON schemas. Do not edit.\n';
|
|
412
412
|
|
|
413
|
-
let output = banner + '\n' +
|
|
413
|
+
let output = banner + '\n' + emittedType + '\n';
|
|
414
414
|
|
|
415
415
|
// Final guard: strip any lingering `[k: string]: unknown;` that might have been
|
|
416
416
|
// reintroduced by later transforms.
|
|
@@ -438,8 +438,8 @@ async function main() {
|
|
|
438
438
|
try {
|
|
439
439
|
const config = getConfig();
|
|
440
440
|
const inputDir = config.getSchemasDir();
|
|
441
|
-
const srcLibTypesDir = config.
|
|
442
|
-
const srcLibOutputPath = config.
|
|
441
|
+
const srcLibTypesDir = config.getTypesSrcDir();
|
|
442
|
+
const srcLibOutputPath = config.getTypesSrcPath('types.d.ts');
|
|
443
443
|
|
|
444
444
|
fs.mkdirSync(srcLibTypesDir, { recursive: true });
|
|
445
445
|
|
|
@@ -493,8 +493,8 @@ async function main() {
|
|
|
493
493
|
}
|
|
494
494
|
|
|
495
495
|
// Also write a copy into dist so consumers get the generated declarations
|
|
496
|
-
const distLibTypesDir = config.
|
|
497
|
-
const distLibOutputPath = config.
|
|
496
|
+
const distLibTypesDir = config.getTypesDistDir();
|
|
497
|
+
const distLibOutputPath = config.getTypesDistPath('types.d.ts');
|
|
498
498
|
try {
|
|
499
499
|
fs.mkdirSync(distLibTypesDir, { recursive: true });
|
|
500
500
|
fs.writeFileSync(distLibOutputPath, output, 'utf8');
|
|
@@ -504,24 +504,24 @@ async function main() {
|
|
|
504
504
|
console.warn('Failed to write types to dist:', e);
|
|
505
505
|
}
|
|
506
506
|
|
|
507
|
-
// Ensure there is a runtime-resolvable module next to `
|
|
507
|
+
// Ensure there is a runtime-resolvable module next to `types.d.ts`
|
|
508
508
|
// Some consumers and TS NodeNext resolution expect a concrete .js next to .d.ts
|
|
509
509
|
// The file is intentionally empty as all exports are types-only.
|
|
510
510
|
try {
|
|
511
|
-
const srcLibTypesJsPath = config.
|
|
511
|
+
const srcLibTypesJsPath = config.getTypesSrcPath('types.js');
|
|
512
512
|
if (!fs.existsSync(srcLibTypesJsPath)) {
|
|
513
513
|
fs.writeFileSync(srcLibTypesJsPath, 'export {}\n', 'utf8');
|
|
514
514
|
console.log('Wrote', srcLibTypesJsPath);
|
|
515
515
|
}
|
|
516
516
|
} catch (e) {
|
|
517
|
-
console.warn('Failed to write
|
|
517
|
+
console.warn('Failed to write types.js to src/_lib:', e);
|
|
518
518
|
}
|
|
519
519
|
try {
|
|
520
|
-
const distLibTypesJsPath = config.
|
|
520
|
+
const distLibTypesJsPath = config.getTypesDistPath('types.js');
|
|
521
521
|
fs.writeFileSync(distLibTypesJsPath, 'export {}\n', 'utf8');
|
|
522
522
|
console.log('Wrote', distLibTypesJsPath);
|
|
523
523
|
} catch (e) {
|
|
524
|
-
console.warn('Failed to write
|
|
524
|
+
console.warn('Failed to write types.js to dist/_lib:', e);
|
|
525
525
|
}
|
|
526
526
|
} catch (err) {
|
|
527
527
|
console.error(err);
|
|
@@ -2,18 +2,41 @@ import fs from 'fs';
|
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import { getConfig } from './_lib/config.js';
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
5
|
+
/*
|
|
6
|
+
* Rewrite anchor-style references to JSON Pointer references in Genesis.json.
|
|
7
|
+
* We also strip all $anchor fields from the output since they are no longer needed after rewriting refs.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
// PURE: Remove all `$anchor` keys from a schema tree without rewriting refs.
|
|
11
|
+
export function stripAnchors<T>(schema: T): T {
|
|
12
|
+
const seen = new WeakMap<object, unknown>();
|
|
13
|
+
|
|
14
|
+
function walk(node: unknown): unknown {
|
|
15
|
+
if (!node || typeof node !== 'object') return node;
|
|
16
|
+
|
|
17
|
+
const existing = seen.get(node as object);
|
|
18
|
+
if (existing) return existing;
|
|
19
|
+
|
|
20
|
+
if (Array.isArray(node)) {
|
|
21
|
+
const out: unknown[] = [];
|
|
22
|
+
seen.set(node, out);
|
|
23
|
+
for (const item of node) out.push(walk(item));
|
|
24
|
+
return out;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const out: Record<string, unknown> = {};
|
|
28
|
+
seen.set(node as object, out);
|
|
29
|
+
|
|
30
|
+
for (const [key, value] of Object.entries(node as Record<string, unknown>)) {
|
|
31
|
+
if (key === '$anchor') continue;
|
|
32
|
+
out[key] = walk(value);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return out;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return walk(schema) as T;
|
|
39
|
+
}
|
|
17
40
|
|
|
18
41
|
// PURE: Rewrite anchor-style `$ref` strings (`#Anchor`) into JSON Pointer refs (`#/$defs/DefName`).
|
|
19
42
|
function normalizeAnchorsToPointers(input: any): any {
|
|
@@ -102,6 +125,9 @@ function main() {
|
|
|
102
125
|
// Rewrite anchors in the nucleusSchema (pure function call)
|
|
103
126
|
genesis.nucleusSchema = normalizeAnchorsToPointers(genesis.nucleusSchema);
|
|
104
127
|
|
|
128
|
+
// Strip $anchor fields from the schemas (pure function call)
|
|
129
|
+
genesis.nucleusSchema = stripAnchors(genesis.nucleusSchema);
|
|
130
|
+
|
|
105
131
|
// Write normalized version
|
|
106
132
|
fs.mkdirSync(path.dirname(normalizedPath), { recursive: true });
|
|
107
133
|
fs.writeFileSync(normalizedPath, JSON.stringify(genesis, null, 4), 'utf-8');
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|