@toolproof-npm/schema 0.1.34 → 0.1.36

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.
Files changed (53) hide show
  1. package/dist/_lib/test.js +12 -12
  2. package/dist/_lib/types/Resource_Job.d.ts +55 -0
  3. package/dist/_lib/types/Resource_ResourceFormat.d.ts +40 -0
  4. package/dist/_lib/types/Resource_ResourceFormat.js +1 -0
  5. package/dist/_lib/types/Resource_ResourceType.d.ts +61 -0
  6. package/dist/_lib/types/Resource_ResourceType.js +1 -0
  7. package/dist/_lib/types/Resource_StatelessStrategy.d.ts +79 -0
  8. package/dist/_lib/types/Resource_StatelessStrategy.js +1 -0
  9. package/dist/_lib/types/types.d.ts +495 -355
  10. package/dist/genesis/generated/resources/Genesis.d.ts +2 -0
  11. package/dist/genesis/generated/resources/Genesis.js +2 -0
  12. package/dist/genesis/generated/resources/Genesis.json +2120 -0
  13. package/dist/{schemas → genesis/generated/schemas}/Genesis.json +273 -345
  14. package/dist/{schemas → genesis/generated/schemas}/Job.json +24 -26
  15. package/dist/genesis/generated/schemas/ResourceFormat.d.ts +2 -0
  16. package/dist/genesis/generated/schemas/ResourceFormat.js +2 -0
  17. package/dist/genesis/generated/schemas/ResourceFormat.json +74 -0
  18. package/dist/genesis/generated/schemas/ResourceType.d.ts +2 -0
  19. package/dist/genesis/generated/schemas/ResourceType.js +2 -0
  20. package/dist/genesis/generated/schemas/ResourceType.json +368 -0
  21. package/dist/genesis/generated/schemas/StatefulStrategy.d.ts +2 -0
  22. package/dist/genesis/generated/schemas/StatefulStrategy.js +2 -0
  23. package/dist/genesis/generated/schemas/StatefulStrategy.json +647 -0
  24. package/dist/genesis/generated/schemas/StatelessStrategy.d.ts +2 -0
  25. package/dist/genesis/generated/schemas/StatelessStrategy.js +2 -0
  26. package/dist/genesis/generated/schemas/StatelessStrategy.json +324 -0
  27. package/dist/genesis/resourceTypes/Genesis.d.ts +2 -0
  28. package/dist/genesis/resourceTypes/Genesis.js +2 -0
  29. package/dist/genesis/resourceTypes/Genesis.json +1530 -0
  30. package/dist/index.d.ts +8 -5
  31. package/dist/index.js +4 -3
  32. package/dist/scripts/_lib/config.d.ts +45 -0
  33. package/dist/scripts/_lib/config.js +109 -0
  34. package/dist/scripts/brandFactories.d.ts +5 -5
  35. package/dist/scripts/brandFactories.js +4 -5
  36. package/dist/scripts/extractSchemas.js +33 -8
  37. package/dist/scripts/extractSubschemaWithDefs.js +36 -7
  38. package/dist/scripts/generateResourceEnvelopes.js +77 -0
  39. package/dist/scripts/generateResourceTypeType.d.ts +1 -0
  40. package/dist/scripts/{generateResourceData.js → generateResourceTypeType.js} +21 -19
  41. package/dist/scripts/generateSchemaShims.d.ts +1 -0
  42. package/dist/scripts/generateSchemaShims.js +63 -0
  43. package/dist/scripts/generateTypes.js +125 -83
  44. package/dist/scripts/rewriteAnchors.d.ts +1 -0
  45. package/dist/scripts/rewriteAnchors.js +90 -0
  46. package/package.json +6 -3
  47. package/dist/_lib/types/ResourceData_Job.d.ts +0 -97
  48. /package/dist/_lib/types/{ResourceData_Job.js → Resource_Job.js} +0 -0
  49. /package/dist/{schemas → genesis/generated/schemas}/Genesis.d.ts +0 -0
  50. /package/dist/{schemas → genesis/generated/schemas}/Genesis.js +0 -0
  51. /package/dist/{schemas → genesis/generated/schemas}/Job.d.ts +0 -0
  52. /package/dist/{schemas → genesis/generated/schemas}/Job.js +0 -0
  53. /package/dist/scripts/{generateResourceData.d.ts → generateResourceEnvelopes.d.ts} +0 -0
@@ -1,11 +1,13 @@
1
1
  import fs from 'fs';
2
2
  import path from 'path';
3
3
  import { compileFromFile } from 'json-schema-to-typescript';
4
- const projectRoot = process.cwd();
5
- const inputDir = path.join(projectRoot, 'src', 'schemas');
4
+ import { getConfig } from './_lib/config.js';
5
+ const config = getConfig();
6
+ const projectRoot = config.getRoot();
7
+ const inputDir = config.getOutputDir();
6
8
  // We emit under src/_lib/types and dist/_lib/types
7
- const srcLibTypesDir = path.join(projectRoot, 'src', '_lib', 'types');
8
- const srcLibOutputPath = path.join(srcLibTypesDir, 'types.d.ts');
9
+ const srcLibTypesDir = config.getTypesSrcDir();
10
+ const srcLibOutputPath = config.getTypesSrcPath('types.d.ts');
9
11
  // Build an index of all schema files by their basename
10
12
  // This supports location-independent $id values where folder segments were removed
11
13
  function buildSchemaIndex(root) {
@@ -59,7 +61,7 @@ function listAllSchemaFiles(root) {
59
61
  else if (entry.isFile() && entry.name.endsWith('.json')) {
60
62
  if (entry.name === '.combined-schema.json')
61
63
  continue; // ignore temp
62
- // buildersuce path relative to root with posix separators
64
+ // produce path relative to root with posix separators
63
65
  const rel = path.relative(root, full).split(path.sep).join('/');
64
66
  files.push(rel);
65
67
  }
@@ -77,28 +79,28 @@ async function main() {
77
79
  const schemaIndex = buildSchemaIndex(inputDir);
78
80
  const idToCanonical = {};
79
81
  // Custom resolver to map our absolute schema IDs to local files, preventing HTTP fetches.
80
- // Supports two patterns:
81
- // 1. Legacy full-path IDs: https://schemas.toolproof.com/v0/genesis/Foo.json
82
- // 2. Location-independent IDs: https://schemas.toolproof.com/v0/Foo.json
83
82
  const toolproofResolver = {
84
83
  order: 1,
85
84
  canRead: (file) => {
86
- const url = (typeof file.url === 'string' ? file.url : file.url?.href) || '';
87
- return (/^https?:\/\/schemas\.toolproof\.(documentation|com)\//i.test(url) ||
88
- /^https?:\/\/toolproof\.com\/schemas\//i.test(url));
85
+ let url = (typeof file.url === 'string' ? file.url : file.url?.href) || '';
86
+ // Strip accidental wrapping quotes
87
+ if ((url.startsWith("'") && url.endsWith("'")) || (url.startsWith('"') && url.endsWith('"'))) {
88
+ url = url.slice(1, -1);
89
+ }
90
+ return config.isSchemaUrl(url);
89
91
  },
90
92
  read: (file) => {
91
- const url = (typeof file.url === 'string' ? file.url : file.url?.href) || '';
93
+ let url = (typeof file.url === 'string' ? file.url : file.url?.href) || '';
94
+ // Strip accidental wrapping quotes
95
+ if ((url.startsWith("'") && url.endsWith("'")) || (url.startsWith('"') && url.endsWith('"'))) {
96
+ url = url.slice(1, -1);
97
+ }
92
98
  // Strip hash part (anchors) for path resolution
93
99
  const noHash = url.split('#')[0];
94
- // Remove base domains
95
- let rel = noHash
96
- .replace(/^https?:\/\/schemas\.toolproof\.(documentation|com)\//i, '')
97
- .replace(/^https?:\/\/toolproof\.com\/schemas\//i, '');
98
- // Drop leading version segment (v0/, v1/, etc.) if present
99
- rel = rel.replace(/^v\d+\//i, '');
100
+ // Extract schema name using config
101
+ const schemaName = config.extractSchemaName(noHash);
102
+ const fileName = schemaName.endsWith('.json') ? schemaName : `${schemaName}.json`;
100
103
  // Resolve by basename only (location-independent IDs)
101
- const fileName = path.basename(rel);
102
104
  const indexed = schemaIndex.get(fileName);
103
105
  if (indexed) {
104
106
  return fs.readFileSync(indexed, 'utf8');
@@ -109,7 +111,7 @@ async function main() {
109
111
  };
110
112
  // Files to include in the combined schema (auto-discovered, excludes documentation)
111
113
  const toCompile = listAllSchemaFiles(inputDir);
112
- // Build definitions for a combined schema that references each file.
114
+ // Collect schema refs and defs; we'll compile files individually to avoid combined-schema traversal issues.
113
115
  const definitions = {};
114
116
  const includedNames = [];
115
117
  for (const fileName of toCompile) {
@@ -127,7 +129,13 @@ async function main() {
127
129
  const raw = fs.readFileSync(p, 'utf8');
128
130
  const parsed = JSON.parse(raw);
129
131
  if (parsed && typeof parsed.$id === 'string' && parsed.$id.trim()) {
130
- refValue = parsed.$id.trim();
132
+ // Sanitize IDs that may have been emitted with surrounding quotes
133
+ // e.g. quotes around schema URL
134
+ let cleaned = parsed.$id.trim();
135
+ if ((cleaned.startsWith("'") && cleaned.endsWith("'")) || (cleaned.startsWith('"') && cleaned.endsWith('"'))) {
136
+ cleaned = cleaned.slice(1, -1);
137
+ }
138
+ refValue = cleaned;
131
139
  idToCanonical[refValue] = base + 'Json';
132
140
  }
133
141
  // Promote this file's $defs to top-level combined $defs so each gets its own exported type
@@ -156,40 +164,87 @@ async function main() {
156
164
  console.warn('No schema files found to compile. Nothing to do.');
157
165
  return;
158
166
  }
159
- const combinedSchema = {
160
- $id: 'combined-entry',
161
- $schema: 'https://json-schema.org/draft/2020-12/schema',
162
- $defs: definitions,
163
- anyOf: includedNames.map((n) => ({ $ref: `#/$defs/${n}` }))
164
- };
165
- console.log('combinedSchema:', JSON.stringify(combinedSchema, null, 2));
166
- // Write combined schema to a temp file inside inputDir so relative $ref resolves.
167
- const combinedPath = path.join(inputDir, '.combined-schema.json');
167
+ // Instead of building a combined schema (which can trip json-schema-to-typescript traversals),
168
+ // compile each discovered schema file individually and concatenate the outputs.
168
169
  try {
169
- fs.writeFileSync(combinedPath, JSON.stringify(combinedSchema, null, 2), 'utf8');
170
- // Compile the single combined schema; referenced schemas will be emitted once.
171
- let ts = await compileFromFile(combinedPath, {
172
- bannerComment: '',
173
- //
174
- declareExternallyReferenced: true,
175
- unreachableDefinitions: true,
176
- // Forward ref parser options so absolute $id/$ref URLs resolve from local files
177
- $refOptions: {
178
- // Don’t go to the network; we provide a local resolver for our domain
179
- resolve: {
180
- file: { order: 2 },
181
- http: false,
182
- https: false,
183
- toolproof: toolproofResolver
170
+ let ts = '';
171
+ for (const fileName of toCompile) {
172
+ const schemaPath = path.join(inputDir, fileName);
173
+ if (!fs.existsSync(schemaPath))
174
+ continue;
175
+ // Load and defensively normalize array-expected keywords to avoid generator crashes
176
+ let toCompilePath = schemaPath;
177
+ try {
178
+ const rawSchema = fs.readFileSync(schemaPath, 'utf8');
179
+ const parsedSchema = JSON.parse(rawSchema);
180
+ function normalizeArrays(node) {
181
+ if (Array.isArray(node)) {
182
+ for (let i = 0; i < node.length; i++)
183
+ normalizeArrays(node[i]);
184
+ return;
185
+ }
186
+ if (!node || typeof node !== 'object')
187
+ return;
188
+ const arrayKeys = ['anyOf', 'allOf', 'oneOf', 'required', 'enum'];
189
+ for (const k of arrayKeys) {
190
+ if (k in node) {
191
+ const v = node[k];
192
+ if (!Array.isArray(v))
193
+ node[k] = [v];
194
+ }
195
+ }
196
+ for (const val of Object.values(node))
197
+ normalizeArrays(val);
184
198
  }
199
+ // Normalize expected arrays to prevent traversal crashes
200
+ normalizeArrays(parsedSchema);
201
+ const tmpPath = path.join(inputDir, `.normalized.${path.basename(fileName)}`);
202
+ fs.writeFileSync(tmpPath, JSON.stringify(parsedSchema, null, 2), 'utf8');
203
+ toCompilePath = tmpPath;
185
204
  }
186
- });
205
+ catch (e) {
206
+ // If normalization fails, fall back to original path
207
+ }
208
+ const part = await compileFromFile(toCompilePath, {
209
+ bannerComment: '',
210
+ //
211
+ declareExternallyReferenced: true,
212
+ unreachableDefinitions: true,
213
+ // Forward ref parser options so absolute $id/$ref URLs resolve from local files
214
+ $refOptions: {
215
+ // Don’t go to the network; we provide a local resolver for our domain
216
+ resolve: {
217
+ file: { order: 2 },
218
+ http: false,
219
+ https: false,
220
+ toolproof: toolproofResolver
221
+ }
222
+ }
223
+ });
224
+ ts += '\n' + part + '\n';
225
+ // Cleanup temp normalized file
226
+ if (toCompilePath !== schemaPath) {
227
+ try {
228
+ fs.unlinkSync(toCompilePath);
229
+ }
230
+ catch { }
231
+ }
232
+ }
187
233
  // Remove permissive index signatures that make interfaces open-ended.
188
234
  // Keep meaningful map-like signatures (e.g., `[k: string]: ResourceRoleValue`) intact.
189
235
  // Robust single-pass: delete the entire line (with optional trailing newline) where the signature appears.
190
236
  // This avoids introducing extra blank lines while handling CRLF/LF and varying indentation.
191
237
  ts = ts.replace(/^\s*\[k:\s*string\]:\s*unknown;\s*(?:\r?\n)?/gm, '');
192
- // Prune verbose type/interface names buildersuced from absolute $id URLs.
238
+ // Fix meta-schema types where json-schema-to-typescript incorrectly interprets
239
+ // schema definitions as literal values. ExtractionSchemaValue describes what
240
+ // an extraction schema looks like, not what the schema meta-properties should be.
241
+ ts = ts.replace(/^(export type ExtractionSchemaValue =[\s\S]*?)(\$defs\?:\s*\{[\s\S]*?};)/gm, '$1$defs?: {\n [k: string]: unknown;\n };');
242
+ ts = ts.replace(/^(export type ExtractionSchemaValue =[\s\S]*?)(properties\?:\s*\{[\s\S]*?};)/gm, '$1properties?: {\n [k: string]: unknown;\n };');
243
+ ts = ts.replace(/^(export type ExtractionSchemaValue =[\s\S]*?)(allOf\?:\s*\[\{type:\s*"array";\s*items:\s*\{type:\s*"object"\}\}\];)/gm, '$1allOf?: Array<{[k: string]: unknown}>;');
244
+ ts = ts.replace(/^(export type ExtractionSchemaValue =[\s\S]*?)(required\?:\s*\[\{type:\s*"array";\s*items:\s*\{type:\s*"string"\};\s*uniqueItems:\s*true\}\];)/gm, '$1required?: string[];');
245
+ // Similarly fix IdentityProp which has the same issue
246
+ ts = ts.replace(/^(export interface IdentityProp[\s\S]*?)(required:\s*\[\{type:\s*"array";\s*contains:\s*\{const:\s*"identity"\};\s*items:\s*\{type:\s*"string"\};\s*uniqueItems:\s*true\}\];)/gm, '$1required?: string[];');
247
+ // Prune verbose type/interface names produced from absolute $id URLs.
193
248
  // Deterministic pruning based on original $id -> baseName map
194
249
  // This avoids heuristic truncation that dropped prefixes like Resource / Workflow.
195
250
  function idToGeneratedIdentifier(id) {
@@ -217,8 +272,8 @@ async function main() {
217
272
  // Final cleanup: aggressively strip the domain prefix `HttpsSchemasToolproofCom` from ALL identifiers.
218
273
  // This is safe because those long names are only artifacts of json-schema-to-typescript; base names don't start with that sequence.
219
274
  ts = ts.replace(/\bHttpsSchemasToolproofCom(?=[A-Z])/g, '');
220
- // Remove accidental duplicate union entries in CombinedEntry after shortening.
221
- ts = ts.replace(/export type CombinedEntry =([\s\S]*?);/, (m, body) => {
275
+ // Remove accidental duplicate union entries in any exported union types after shortening.
276
+ ts = ts.replace(/export type ([A-Za-z0-9_]+) =([\s\S]*?);/g, (m, typeName, body) => {
222
277
  const lines = body.split(/\n/);
223
278
  const seen2 = new Set();
224
279
  const kept = [];
@@ -236,31 +291,25 @@ async function main() {
236
291
  kept.push(line);
237
292
  }
238
293
  }
239
- return 'export type CombinedEntry =\n' + kept.join('\n') + ';';
294
+ return `export type ${typeName} =\n` + kept.join('\n') + ';';
240
295
  });
241
- // If the compiler returned nothing (can happen if everything is externalized),
242
- // try a direct compile of the primary catalog (Genesis.json) as a fallback.
296
+ // If nothing was emitted, compile Genesis.json as a final fallback.
243
297
  if (!ts || !ts.trim()) {
244
298
  const primary = path.join(inputDir, 'Genesis.json');
245
299
  if (fs.existsSync(primary)) {
246
- try {
247
- ts = await compileFromFile(primary, {
248
- bannerComment: '',
249
- declareExternallyReferenced: true,
250
- unreachableDefinitions: true,
251
- $refOptions: {
252
- resolve: {
253
- file: { order: 2 },
254
- http: false,
255
- https: false,
256
- toolproof: toolproofResolver
257
- }
300
+ ts = await compileFromFile(primary, {
301
+ bannerComment: '',
302
+ declareExternallyReferenced: true,
303
+ unreachableDefinitions: true,
304
+ $refOptions: {
305
+ resolve: {
306
+ file: { order: 2 },
307
+ http: false,
308
+ https: false,
309
+ toolproof: toolproofResolver
258
310
  }
259
- });
260
- }
261
- catch (e) {
262
- // ignore and fall through to stub
263
- }
311
+ }
312
+ });
264
313
  }
265
314
  }
266
315
  // Still nothing? ensure we emit a module so downstream imports don't fail.
@@ -294,7 +343,7 @@ async function main() {
294
343
  function loadIdTemplates() {
295
344
  const map = {};
296
345
  try {
297
- const genesisPath = path.join(inputDir, 'Genesis.json');
346
+ const genesisPath = path.join(inputDir, config.getSourceFile());
298
347
  if (fs.existsSync(genesisPath)) {
299
348
  const raw = fs.readFileSync(genesisPath, 'utf8');
300
349
  const parsed = JSON.parse(raw);
@@ -333,7 +382,7 @@ async function main() {
333
382
  // Replace index-signature interfaces with Record<IdType, ValueType> so object literal keys are checked.
334
383
  ts = ts.replace(/export interface RoleMap\s*{[^}]*}/g, 'export type RoleMap = Record<ResourceRoleId, ResourceRoleValue>;');
335
384
  ts = ts.replace(/export interface RoleBindingMap\s*{[^}]*}/g, 'export type RoleBindingMap = Record<ResourceRoleId, ResourceId>;');
336
- ts = ts.replace(/export interface ResourceMap\s*\{[^}]*\{[^}]*\}[^}]*\}/gs, 'export type ResourceMap = Record<ExecutionId, Record<ResourceRoleId, ResourcePotentialInput | ResourcePotentialOutput | ResourceData>>;');
385
+ ts = ts.replace(/export interface StrategyState\s*\{[^}]*\{[^}]*\}[^}]*\}/gs, 'export type StrategyState = Record<ExecutionId, Record<ResourceRoleId, ResourcePotentialInput | ResourcePotentialOutput | Resource>>;');
337
386
  parts.push(ts);
338
387
  let output = parts.join('\n');
339
388
  // Final guard: strip any lingering `[k: string]: unknown;` that might have been
@@ -361,8 +410,8 @@ async function main() {
361
410
  }
362
411
  // Also write a copy into dist so consumers get the generated declarations
363
412
  // Write only to dist/_lib/types to keep the same path structure under dist
364
- const distLibTypesDir = path.join(projectRoot, 'dist', '_lib', 'types');
365
- const distLibOutputPath = path.join(distLibTypesDir, 'types.d.ts');
413
+ const distLibTypesDir = config.getTypesDistDir();
414
+ const distLibOutputPath = config.getTypesDistPath('types.d.ts');
366
415
  try {
367
416
  fs.mkdirSync(distLibTypesDir, { recursive: true });
368
417
  fs.writeFileSync(distLibOutputPath, output, 'utf8');
@@ -376,7 +425,7 @@ async function main() {
376
425
  // Some consumers and TS NodeNext resolution expect a concrete .js next to .d.ts
377
426
  // The file is intentionally empty as all exports are types-only.
378
427
  try {
379
- const srcLibTypesJsPath = path.join(srcLibTypesDir, 'types.js');
428
+ const srcLibTypesJsPath = config.getTypesSrcPath('types.js');
380
429
  if (!fs.existsSync(srcLibTypesJsPath)) {
381
430
  fs.writeFileSync(srcLibTypesJsPath, 'export {}\n', 'utf8');
382
431
  console.log('Wrote', srcLibTypesJsPath);
@@ -386,7 +435,7 @@ async function main() {
386
435
  console.warn('Failed to write types.js to src/_lib:', e);
387
436
  }
388
437
  try {
389
- const distLibTypesJsPath = path.join(distLibTypesDir, 'types.js');
438
+ const distLibTypesJsPath = config.getTypesDistPath('types.js');
390
439
  fs.writeFileSync(distLibTypesJsPath, 'export {}\n', 'utf8');
391
440
  console.log('Wrote', distLibTypesJsPath);
392
441
  }
@@ -395,14 +444,7 @@ async function main() {
395
444
  }
396
445
  }
397
446
  finally {
398
- // Best-effort cleanup of the temporary combined schema
399
- try {
400
- if (fs.existsSync(combinedPath))
401
- fs.unlinkSync(combinedPath);
402
- }
403
- catch (e) {
404
- // ignore cleanup errors
405
- }
447
+ // No temp combined schema used.
406
448
  }
407
449
  }
408
450
  main().catch((err) => {
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,90 @@
1
+ import fs from 'fs';
2
+ import { getConfig } from './_lib/config.js';
3
+ /**
4
+ * Rewrite anchor-style references to JSON Pointer references
5
+ * Converts #AnchorName to #/$defs/AnchorName for compatibility with strict JSON Schema validators
6
+ *
7
+ * This function works on a schema object that has $defs at its top level.
8
+ * For Genesis, each $defs entry is a Type envelope with an extractionSchema that may have $anchor.
9
+ */
10
+ function rewriteAnchorsToPointers(root) {
11
+ if (!root || typeof root !== "object")
12
+ return;
13
+ // Build a map of anchors to their definition names
14
+ const defs = root.$defs && typeof root.$defs === "object" ? root.$defs : {};
15
+ const anchorToDef = {};
16
+ // For Genesis structure: each def is a Type envelope with extractionSchema.$anchor
17
+ for (const [defName, defValue] of Object.entries(defs)) {
18
+ if (!defValue || typeof defValue !== "object")
19
+ continue;
20
+ // Check if this is a Type envelope (has extractionSchema property)
21
+ const extractionSchema = defValue.extractionSchema;
22
+ if (extractionSchema && typeof extractionSchema === "object") {
23
+ // Look for $anchor inside the extractionSchema
24
+ const anchor = extractionSchema.$anchor;
25
+ if (typeof anchor === "string" && !anchorToDef[anchor]) {
26
+ anchorToDef[anchor] = defName;
27
+ }
28
+ }
29
+ else {
30
+ // Fallback: check for $anchor at the def level (non-envelope case)
31
+ const anchor = defValue.$anchor;
32
+ if (typeof anchor === "string" && !anchorToDef[anchor]) {
33
+ anchorToDef[anchor] = defName;
34
+ }
35
+ }
36
+ }
37
+ // Walk the entire tree and rewrite anchor refs to pointer refs
38
+ function walk(node) {
39
+ if (Array.isArray(node)) {
40
+ for (const item of node)
41
+ walk(item);
42
+ return;
43
+ }
44
+ if (!node || typeof node !== "object")
45
+ return;
46
+ // Rewrite $ref if it's an anchor-style reference
47
+ if (typeof node.$ref === "string") {
48
+ const ref = node.$ref;
49
+ // Match anchor refs: starts with # but not #/ (JSON Pointer syntax)
50
+ if (ref.startsWith("#") && !ref.startsWith("#/")) {
51
+ const anchor = ref.slice(1);
52
+ const defName = anchorToDef[anchor];
53
+ if (defName) {
54
+ node.$ref = `#/$defs/${defName}`;
55
+ }
56
+ }
57
+ }
58
+ // Recursively walk all properties
59
+ for (const val of Object.values(node)) {
60
+ walk(val);
61
+ }
62
+ }
63
+ walk(root);
64
+ }
65
+ async function main() {
66
+ const config = getConfig();
67
+ const genesisSourcePath = config.getSourcePath();
68
+ // Create a temporary normalized version
69
+ const normalizedPath = genesisSourcePath.replace('.json', '.normalized.json');
70
+ if (!fs.existsSync(genesisSourcePath)) {
71
+ console.error(`Genesis source file not found at ${genesisSourcePath}`);
72
+ process.exit(1);
73
+ }
74
+ const raw = fs.readFileSync(genesisSourcePath, 'utf-8');
75
+ const genesis = JSON.parse(raw);
76
+ // Validate structure
77
+ if (!genesis.extractionSchema || !genesis.extractionSchema.$defs) {
78
+ console.error('Genesis.json must have extractionSchema.$defs');
79
+ process.exit(1);
80
+ }
81
+ // Rewrite anchors in the extractionSchema (where $defs is at the top level)
82
+ rewriteAnchorsToPointers(genesis.extractionSchema);
83
+ // Write normalized version
84
+ fs.writeFileSync(normalizedPath, JSON.stringify(genesis, null, 4), 'utf-8');
85
+ console.log(`Wrote normalized Genesis with pointer refs to ${normalizedPath}`);
86
+ }
87
+ main().catch((e) => {
88
+ console.error(e);
89
+ process.exit(1);
90
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@toolproof-npm/schema",
3
- "version": "0.1.34",
3
+ "version": "0.1.36",
4
4
  "description": "JSON schemas and TypeScript types for ToolProof",
5
5
  "keywords": [
6
6
  "toolproof",
@@ -44,10 +44,13 @@
44
44
  "scripts": {
45
45
  "build": "tsc -b",
46
46
  "build:scripts": "tsc -p tsconfig.scripts.json",
47
+ "rewriteAnchors": "node ./dist/scripts/rewriteAnchors.js",
47
48
  "extractSchemas": "node ./dist/scripts/extractSchemas.js",
48
49
  "extractSubschema": "node ./dist/scripts/extractSubschemaWithDefs.js",
49
50
  "generateTypes": "node ./dist/scripts/generateTypes.js",
50
- "generateResourceData": "node ./dist/scripts/generateResourceData.js",
51
- "update": "rimraf /s /q dist && pnpm run build:scripts && pnpm run extractSchemas -- --in src/genesis/Genesis.json --out src/schemas/Genesis.json --id 'https://schemas.toolproof.com/v0/Genesis.json' && pnpm run extractSubschema -- --name Job && pnpm run generateTypes && pnpm run generateResourceData -- --name Job && pnpm run build"
51
+ "generateResourceTypeType": "node ./dist/scripts/generateResourceTypeType.js",
52
+ "generateResourceEnvelopes": "node ./dist/scripts/generateResourceEnvelopes.js",
53
+ "generateSchemaShims": "node ./dist/scripts/generateSchemaShims.js",
54
+ "update": "rimraf /s /q dist && pnpm run build:scripts && pnpm run rewriteAnchors && pnpm run generateResourceEnvelopes && pnpm run extractSchemas && pnpm run extractSubschema -- --name Job && pnpm run extractSubschema -- --name ResourceFormat && pnpm run extractSubschema -- --name ResourceType && pnpm run extractSubschema -- --name StatelessStrategy && pnpm run extractSubschema -- --name StatefulStrategy && pnpm run generateSchemaShims && pnpm run generateTypes && pnpm run generateResourceTypeType -- --name Job && pnpm run generateResourceTypeType -- --name ResourceFormat && pnpm run generateResourceTypeType -- --name ResourceType && pnpm run generateResourceTypeType -- --name StatelessStrategy && pnpm run build"
52
55
  }
53
56
  }
@@ -1,97 +0,0 @@
1
- // Auto-generated strict composite type. Do not edit.
2
- export type ResourceData_Job = ResourceMetaBase & {
3
- extractedData: Job;
4
- };
5
- export type ResourceMetaBase = ResourceBase &
6
- ResourceKind & {
7
- kind: "materialized";
8
- } & Path &
9
- Timestamp;
10
- export type ResourceBase = Identifiable & {
11
- id: string;
12
- } & {
13
- resourceTypeId: string;
14
- } & CreationContext;
15
- export type Job = Documented &
16
- RolesOuter &
17
- Uri & {
18
- identity: string;
19
- };
20
- /**
21
- * This interface was referenced by `undefined`'s JSON-Schema
22
- * via the `definition` "Documented".
23
- */
24
- export type Documented = Name & Description;
25
- /**
26
- * This interface was referenced by `undefined`'s JSON-Schema
27
- * via the `definition` "ResourceRoleValue".
28
- */
29
- export type ResourceRoleValue = {
30
- /**
31
- * This interface was referenced by `undefined`'s JSON-Schema
32
- * via the `definition` "ResourceTypeId".
33
- */
34
- resourceTypeId: string;
35
- } & Documented;
36
-
37
- export interface Identifiable {
38
- }
39
- export interface CreationContext {
40
- creationContext: ResourceSocket;
41
- }
42
- export interface ResourceSocket {
43
- executionId: string;
44
- resourceRoleId: string;
45
- }
46
- export interface ResourceKind {
47
- kind: "potential-input" | "potential-output" | "materialized";
48
- }
49
- export interface Path {
50
- path: string;
51
- }
52
- export interface Timestamp {
53
- timestamp: string;
54
- }
55
- /**
56
- * This interface was referenced by `undefined`'s JSON-Schema
57
- * via the `definition` "Name".
58
- */
59
- export interface Name {
60
- name: string;
61
- }
62
- /**
63
- * This interface was referenced by `undefined`'s JSON-Schema
64
- * via the `definition` "Description".
65
- */
66
- export interface Description {
67
- description: string;
68
- }
69
- /**
70
- * This interface was referenced by `undefined`'s JSON-Schema
71
- * via the `definition` "RolesOuter".
72
- */
73
- export interface RolesOuter {
74
- roles: RolesInner;
75
- }
76
- /**
77
- * This interface was referenced by `undefined`'s JSON-Schema
78
- * via the `definition` "RolesInner".
79
- */
80
- export interface RolesInner {
81
- inputMap: RoleMap;
82
- outputMap: RoleMap;
83
- }
84
- /**
85
- * This interface was referenced by `undefined`'s JSON-Schema
86
- * via the `definition` "RoleMap".
87
- */
88
- export interface RoleMap {
89
- [k: string]: ResourceRoleValue;
90
- }
91
- /**
92
- * This interface was referenced by `undefined`'s JSON-Schema
93
- * via the `definition` "Uri".
94
- */
95
- export interface Uri {
96
- uri: string;
97
- }