@pdtf/schemas 3.4.1-7 → 3.5.0
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/.claude/settings.local.json +12 -1
- package/index.js +263 -33
- package/package.json +2 -1
- package/src/examples/v3/exampleDocumentedVouch.json +1 -0
- package/src/examples/v3/exampleVouch.json +1 -0
- package/src/schemas/v3/combined.json +1662 -165
- package/src/schemas/v3/compactSkeleton.txt +3325 -0
- package/src/schemas/v3/overlays/nts.json +4 -1
- package/src/schemas/v3/overlays/nts2.json +4 -1
- package/src/schemas/v3/overlays/ntsl.json +4 -1
- package/src/schemas/v3/overlays/ntsl2.json +4 -1
- package/src/schemas/v3/pdtf-transaction.json +2609 -4
- package/src/schemas/v3/skeleton.json +3187 -3037
- package/src/schemas/verifiedClaims/pdtf-verified-claims.json +5 -0
- package/src/tests/v3/caching.test.js +591 -0
- package/src/tests/v3/transactionSchema.test.js +78 -0
- package/src/utils/compactSkeleton.js +84 -0
- package/src/utils/countTokens.js +67 -0
- package/src/utils/extractOverlay.js +96 -5
- package/src/utils/minimalSkeleton.js +85 -0
- package/src/utils/pathSkeleton.js +181 -0
- package/src/schemas/v3/property-transaction-milestones.json +0 -91
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
const fs = require("fs");
|
|
2
|
+
|
|
3
|
+
// Read the current skeleton
|
|
4
|
+
const skeleton = require("../schemas/v3/skeleton.json");
|
|
5
|
+
|
|
6
|
+
// Convert to ultra-compact format
|
|
7
|
+
const toCompact = (obj, indent = "") => {
|
|
8
|
+
if (typeof obj === "string") {
|
|
9
|
+
// Type indicators
|
|
10
|
+
if (["string", "number", "integer", "boolean", "variant"].includes(obj)) {
|
|
11
|
+
return obj[0]; // Just first letter: s, n, i, b, v
|
|
12
|
+
}
|
|
13
|
+
return obj;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
if (Array.isArray(obj)) {
|
|
17
|
+
if (obj.length === 0) return "[]";
|
|
18
|
+
// Array with content
|
|
19
|
+
const inner = toCompact(obj[0], indent + " ");
|
|
20
|
+
if (typeof inner === "string" && inner.length === 1) {
|
|
21
|
+
return `[${inner}]`; // Simple array like [s]
|
|
22
|
+
}
|
|
23
|
+
return `[\n${indent} ${inner}\n${indent}]`;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (obj && typeof obj === "object") {
|
|
27
|
+
const keys = Object.keys(obj);
|
|
28
|
+
if (keys.length === 0) return "{}";
|
|
29
|
+
|
|
30
|
+
// Check if it's a simple object with only type indicators
|
|
31
|
+
const allSimple = keys.every(k =>
|
|
32
|
+
typeof obj[k] === "string" &&
|
|
33
|
+
["s", "n", "i", "b", "v"].includes(toCompact(obj[k]))
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
if (allSimple && keys.length < 5) {
|
|
37
|
+
// Inline format: {a:s b:n c:s}
|
|
38
|
+
return `{${keys.map(k => `${k}:${toCompact(obj[k])}`).join(" ")}}`;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Multi-line format
|
|
42
|
+
const lines = keys.map(k => {
|
|
43
|
+
const val = toCompact(obj[k], indent + " ");
|
|
44
|
+
if (typeof val === "string" && val.length === 1) {
|
|
45
|
+
return `${indent} ${k}:${val}`;
|
|
46
|
+
} else if (typeof val === "string" && (val === "{}" || val === "[]")) {
|
|
47
|
+
return `${indent} ${k}${val}`;
|
|
48
|
+
} else if (typeof val === "string" && val.startsWith("{") && val.endsWith("}")) {
|
|
49
|
+
return `${indent} ${k}${val}`;
|
|
50
|
+
} else if (typeof val === "string" && val.startsWith("[") && !val.includes("\n")) {
|
|
51
|
+
return `${indent} ${k}${val}`;
|
|
52
|
+
} else {
|
|
53
|
+
return `${indent} ${k}:\n${indent} ${val}`;
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
return `{\n${lines.join("\n")}\n${indent}}`;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return String(obj);
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
// Generate ultra-compact version
|
|
64
|
+
const compact = toCompact(skeleton);
|
|
65
|
+
|
|
66
|
+
// Write compact version
|
|
67
|
+
fs.writeFileSync("../schemas/v3/compactSkeleton.txt", compact);
|
|
68
|
+
|
|
69
|
+
console.log("Compact skeleton written to ../schemas/v3/compactSkeleton.txt");
|
|
70
|
+
console.log(`Size: ${compact.length} bytes`);
|
|
71
|
+
|
|
72
|
+
// Count tokens
|
|
73
|
+
try {
|
|
74
|
+
const GPT3Encoder = require('gpt-3-encoder');
|
|
75
|
+
const encoded = GPT3Encoder.encode(compact);
|
|
76
|
+
console.log(`Tokens (GPT-3): ${encoded.length}`);
|
|
77
|
+
console.log(`Reduction: ${((1 - encoded.length / 78734) * 100).toFixed(1)}% fewer tokens than JSON skeleton`);
|
|
78
|
+
|
|
79
|
+
// Show sample
|
|
80
|
+
console.log("\nFirst 500 chars:");
|
|
81
|
+
console.log(compact.substring(0, 500));
|
|
82
|
+
} catch (e) {
|
|
83
|
+
console.log(`Estimated tokens: ~${Math.ceil(compact.length / 4)}`);
|
|
84
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
|
|
3
|
+
// Try to use tiktoken or a similar library
|
|
4
|
+
// For Claude/Anthropic models, we can estimate using the cl100k_base encoding
|
|
5
|
+
// which is similar to what Claude uses
|
|
6
|
+
|
|
7
|
+
// First, let's check what's available
|
|
8
|
+
try {
|
|
9
|
+
// Option 1: Use gpt-tokenizer (common npm package)
|
|
10
|
+
const { encode } = require('gpt-tokenizer');
|
|
11
|
+
|
|
12
|
+
const content = fs.readFileSync('../schemas/v3/skeleton.json', 'utf8');
|
|
13
|
+
const tokens = encode(content);
|
|
14
|
+
|
|
15
|
+
console.log(`Using gpt-tokenizer:`);
|
|
16
|
+
console.log(`Total tokens: ${tokens.length}`);
|
|
17
|
+
console.log(`File size: ${content.length} characters`);
|
|
18
|
+
console.log(`Ratio: ${(content.length / tokens.length).toFixed(2)} characters per token`);
|
|
19
|
+
|
|
20
|
+
} catch (e1) {
|
|
21
|
+
console.log("gpt-tokenizer not found, trying gpt-3-encoder...");
|
|
22
|
+
|
|
23
|
+
try {
|
|
24
|
+
// Option 2: Use gpt-3-encoder
|
|
25
|
+
const GPT3Encoder = require('gpt-3-encoder');
|
|
26
|
+
|
|
27
|
+
const content = fs.readFileSync('../schemas/v3/skeleton.json', 'utf8');
|
|
28
|
+
const encoded = GPT3Encoder.encode(content);
|
|
29
|
+
|
|
30
|
+
console.log(`Using gpt-3-encoder:`);
|
|
31
|
+
console.log(`Total tokens: ${encoded.length}`);
|
|
32
|
+
console.log(`File size: ${content.length} characters`);
|
|
33
|
+
console.log(`Ratio: ${(content.length / encoded.length).toFixed(2)} characters per token`);
|
|
34
|
+
|
|
35
|
+
} catch (e2) {
|
|
36
|
+
console.log("No tokenizer library found. Falling back to estimation...");
|
|
37
|
+
|
|
38
|
+
// Option 3: Manual estimation
|
|
39
|
+
const content = fs.readFileSync('../schemas/v3/skeleton.json', 'utf8');
|
|
40
|
+
|
|
41
|
+
// Count different types of content for better estimation
|
|
42
|
+
const lines = content.split('\n');
|
|
43
|
+
const words = content.split(/\s+/);
|
|
44
|
+
const punctuation = content.match(/[{}:,\[\]"]/g) || [];
|
|
45
|
+
|
|
46
|
+
// Rough estimation:
|
|
47
|
+
// - JSON structure tokens (brackets, colons, quotes): ~1 token each
|
|
48
|
+
// - Words: ~1 token each
|
|
49
|
+
// - Whitespace: usually absorbed into adjacent tokens
|
|
50
|
+
|
|
51
|
+
const structureTokens = punctuation.length;
|
|
52
|
+
const wordTokens = words.length;
|
|
53
|
+
const estimatedTokens = Math.ceil((structureTokens + wordTokens) * 0.75); // 0.75 factor for overlap
|
|
54
|
+
|
|
55
|
+
console.log("Manual estimation:");
|
|
56
|
+
console.log(`File size: ${content.length} characters`);
|
|
57
|
+
console.log(`Lines: ${lines.length}`);
|
|
58
|
+
console.log(`Words: ${words.length}`);
|
|
59
|
+
console.log(`JSON punctuation: ${punctuation.length}`);
|
|
60
|
+
console.log(`Estimated tokens: ~${estimatedTokens}`);
|
|
61
|
+
console.log(`Ratio: ${(content.length / estimatedTokens).toFixed(2)} characters per token`);
|
|
62
|
+
|
|
63
|
+
// Also do a simple character-based estimation
|
|
64
|
+
const simpleEstimate = Math.ceil(content.length / 4);
|
|
65
|
+
console.log(`\nSimple estimation (chars/4): ~${simpleEstimate} tokens`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
@@ -29,25 +29,58 @@ const extractFields = [
|
|
|
29
29
|
|
|
30
30
|
const flattenSkeleton = (schema) => {
|
|
31
31
|
if (!schema) return undefined;
|
|
32
|
+
|
|
33
|
+
// Handle arrays - mark with special notation
|
|
34
|
+
if (schema.type === "array" && schema.items) {
|
|
35
|
+
const itemSchema = flattenSkeleton(schema.items);
|
|
36
|
+
// Use array notation to indicate this is an array
|
|
37
|
+
return [itemSchema];
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Handle primitives - return type indicator
|
|
41
|
+
if (schema.type && !schema.properties && !schema.oneOf && !schema.items) {
|
|
42
|
+
// Return a type indicator for primitive types
|
|
43
|
+
if (schema.type === "string") return "string";
|
|
44
|
+
if (schema.type === "number") return "number";
|
|
45
|
+
if (schema.type === "integer") return "integer";
|
|
46
|
+
if (schema.type === "boolean") return "boolean";
|
|
47
|
+
if (schema.type === "null") return "null";
|
|
48
|
+
}
|
|
49
|
+
|
|
32
50
|
let returnStructure = {};
|
|
51
|
+
|
|
52
|
+
// Handle object properties
|
|
33
53
|
if (schema.properties) {
|
|
34
54
|
Object.keys(schema.properties).forEach((key) => {
|
|
35
55
|
returnStructure[key] = flattenSkeleton(schema.properties[key]);
|
|
36
56
|
});
|
|
37
57
|
}
|
|
58
|
+
|
|
59
|
+
// Handle oneOf - merge all possible properties
|
|
38
60
|
if (schema.oneOf) {
|
|
39
61
|
schema.oneOf.forEach((aOneOf) => {
|
|
40
62
|
if (aOneOf.properties) {
|
|
41
63
|
Object.entries(aOneOf.properties).forEach(([key, value]) => {
|
|
42
|
-
|
|
64
|
+
// If property already exists and differs, mark as variant
|
|
65
|
+
const newValue = flattenSkeleton(value);
|
|
66
|
+
if (returnStructure[key] && JSON.stringify(returnStructure[key]) !== JSON.stringify(newValue)) {
|
|
67
|
+
// For primitive types, just mark as variant type
|
|
68
|
+
if (typeof returnStructure[key] === "string" || typeof newValue === "string") {
|
|
69
|
+
returnStructure[key] = "variant";
|
|
70
|
+
} else {
|
|
71
|
+
// For complex types, merge properties
|
|
72
|
+
returnStructure[key] = { ...returnStructure[key], ...newValue, _variants: true };
|
|
73
|
+
}
|
|
74
|
+
} else {
|
|
75
|
+
returnStructure[key] = newValue;
|
|
76
|
+
}
|
|
43
77
|
});
|
|
44
78
|
}
|
|
45
79
|
});
|
|
46
80
|
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
}
|
|
50
|
-
return returnStructure;
|
|
81
|
+
|
|
82
|
+
// Return empty object for objects without properties
|
|
83
|
+
return Object.keys(returnStructure).length > 0 ? returnStructure : {};
|
|
51
84
|
};
|
|
52
85
|
|
|
53
86
|
const extractOverlay = (sourceSchema, ref) => {
|
|
@@ -197,3 +230,61 @@ fs.writeFileSync(
|
|
|
197
230
|
JSON.stringify(skeletonSchemaFlattened, null, 2)
|
|
198
231
|
);
|
|
199
232
|
console.log("Flat Skeleton schema written to ../schemas/v3/skeleton.json");
|
|
233
|
+
|
|
234
|
+
// Generate compact skeleton format for better token efficiency
|
|
235
|
+
const toCompact = (obj, indent = "") => {
|
|
236
|
+
if (typeof obj === "string") {
|
|
237
|
+
// Skip type indicators entirely
|
|
238
|
+
return "";
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
if (Array.isArray(obj)) {
|
|
242
|
+
if (obj.length === 0) return "[]";
|
|
243
|
+
// Array with content
|
|
244
|
+
const inner = toCompact(obj[0], indent);
|
|
245
|
+
if (inner === "") {
|
|
246
|
+
return "[]"; // Array of primitives
|
|
247
|
+
}
|
|
248
|
+
return `[\n${inner}\n${indent}]`;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
if (obj && typeof obj === "object") {
|
|
252
|
+
const keys = Object.keys(obj);
|
|
253
|
+
if (keys.length === 0) return "";
|
|
254
|
+
|
|
255
|
+
// Process each key
|
|
256
|
+
const lines = [];
|
|
257
|
+
keys.forEach(k => {
|
|
258
|
+
const val = toCompact(obj[k], indent + " ");
|
|
259
|
+
|
|
260
|
+
if (val === "") {
|
|
261
|
+
// Leaf node - just show the property name
|
|
262
|
+
lines.push(`${indent} ${k}`);
|
|
263
|
+
} else if (val === "[]") {
|
|
264
|
+
// Array property
|
|
265
|
+
lines.push(`${indent} ${k}[]`);
|
|
266
|
+
} else if (val.startsWith("[")) {
|
|
267
|
+
// Array with nested content - simple concatenation
|
|
268
|
+
lines.push(`${indent} ${k}${val}`);
|
|
269
|
+
} else {
|
|
270
|
+
// Object property - show name on its own line, content below
|
|
271
|
+
lines.push(`${indent} ${k}`);
|
|
272
|
+
lines.push(val);
|
|
273
|
+
}
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
return lines.length > 0 ? lines.join("\n") : "";
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
return "";
|
|
280
|
+
};
|
|
281
|
+
|
|
282
|
+
// Since toCompact returns lines without wrapping braces, add them for the root
|
|
283
|
+
const innerContent = toCompact(skeletonSchemaFlattened, "");
|
|
284
|
+
const compactSkeleton = innerContent ? innerContent : "";
|
|
285
|
+
|
|
286
|
+
fs.writeFileSync(
|
|
287
|
+
"../schemas/v3/compactSkeleton.txt",
|
|
288
|
+
compactSkeleton
|
|
289
|
+
);
|
|
290
|
+
console.log("Compact Skeleton written to ../schemas/v3/compactSkeleton.txt");
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
const fs = require("fs");
|
|
2
|
+
|
|
3
|
+
// Read the current skeleton
|
|
4
|
+
const skeleton = require("../schemas/v3/skeleton.json");
|
|
5
|
+
|
|
6
|
+
// Ultra-minimal format: use indentation only, no brackets
|
|
7
|
+
const toMinimal = (obj, prefix = "", isArrayItem = false) => {
|
|
8
|
+
const lines = [];
|
|
9
|
+
|
|
10
|
+
if (typeof obj === "string") {
|
|
11
|
+
// Type indicators - single letter
|
|
12
|
+
const typeMap = {
|
|
13
|
+
"string": "s",
|
|
14
|
+
"number": "n",
|
|
15
|
+
"integer": "i",
|
|
16
|
+
"boolean": "b",
|
|
17
|
+
"variant": "v"
|
|
18
|
+
};
|
|
19
|
+
return typeMap[obj] || obj;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (Array.isArray(obj)) {
|
|
23
|
+
lines.push(prefix + "[]");
|
|
24
|
+
if (obj.length > 0) {
|
|
25
|
+
const itemLines = toMinimal(obj[0], prefix + " ", true);
|
|
26
|
+
lines.push(...(Array.isArray(itemLines) ? itemLines : [itemLines]));
|
|
27
|
+
}
|
|
28
|
+
return lines;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (obj && typeof obj === "object") {
|
|
32
|
+
const keys = Object.keys(obj);
|
|
33
|
+
if (keys.length === 0) {
|
|
34
|
+
return prefix + "{}";
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
keys.forEach((key, index) => {
|
|
38
|
+
const val = obj[key];
|
|
39
|
+
const keyPrefix = prefix + key;
|
|
40
|
+
|
|
41
|
+
if (typeof val === "string") {
|
|
42
|
+
const type = toMinimal(val);
|
|
43
|
+
lines.push(keyPrefix + ":" + type);
|
|
44
|
+
} else if (Array.isArray(val)) {
|
|
45
|
+
const arrLines = toMinimal(val, keyPrefix);
|
|
46
|
+
lines.push(...arrLines);
|
|
47
|
+
} else if (val && typeof val === "object" && Object.keys(val).length > 0) {
|
|
48
|
+
lines.push(keyPrefix);
|
|
49
|
+
const subLines = toMinimal(val, prefix + " ");
|
|
50
|
+
lines.push(...(Array.isArray(subLines) ? subLines : [subLines]));
|
|
51
|
+
} else {
|
|
52
|
+
lines.push(keyPrefix);
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
return lines;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return prefix + String(obj);
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
// Generate minimal version
|
|
63
|
+
const minimalLines = toMinimal(skeleton);
|
|
64
|
+
const minimal = minimalLines.join("\n");
|
|
65
|
+
|
|
66
|
+
// Write minimal version
|
|
67
|
+
fs.writeFileSync("../schemas/v3/minimalSkeleton.txt", minimal);
|
|
68
|
+
|
|
69
|
+
console.log("Minimal skeleton written to ../schemas/v3/minimalSkeleton.txt");
|
|
70
|
+
console.log(`Size: ${minimal.length} bytes`);
|
|
71
|
+
console.log(`Lines: ${minimalLines.length}`);
|
|
72
|
+
|
|
73
|
+
// Count tokens
|
|
74
|
+
try {
|
|
75
|
+
const GPT3Encoder = require('gpt-3-encoder');
|
|
76
|
+
const encoded = GPT3Encoder.encode(minimal);
|
|
77
|
+
console.log(`Tokens (GPT-3): ${encoded.length}`);
|
|
78
|
+
console.log(`Reduction: ${((1 - encoded.length / 78734) * 100).toFixed(1)}% fewer tokens than JSON skeleton`);
|
|
79
|
+
|
|
80
|
+
// Show sample
|
|
81
|
+
console.log("\nFirst 20 lines:");
|
|
82
|
+
console.log(minimalLines.slice(0, 20).join("\n"));
|
|
83
|
+
} catch (e) {
|
|
84
|
+
console.log(`Estimated tokens: ~${Math.ceil(minimal.length / 4)}`);
|
|
85
|
+
}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
const fs = require("fs");
|
|
2
|
+
const traverse = require("traverse");
|
|
3
|
+
|
|
4
|
+
const combinedSchema = require("../schemas/v3/combined.json");
|
|
5
|
+
|
|
6
|
+
// Extract fields that have overlay-specific properties
|
|
7
|
+
const extractFields = [
|
|
8
|
+
"baspi4", "baspi5", "nts", "nts2", "ntsl", "ntsl2",
|
|
9
|
+
"ta6", "ta7", "ta10", "lpe1", "fme1", "piq",
|
|
10
|
+
"con29R", "con29DW", "llc1", "rds", "oc1", "sr24",
|
|
11
|
+
];
|
|
12
|
+
|
|
13
|
+
// Delete properties we don't want in the skeleton
|
|
14
|
+
const deleteProperties = (sourceSchema, propertyNames) => {
|
|
15
|
+
traverse(sourceSchema).forEach(function (element) {
|
|
16
|
+
if (propertyNames.includes(this.key)) {
|
|
17
|
+
this.delete(true);
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
return sourceSchema;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
// Collect all paths in path notation
|
|
24
|
+
const collectPaths = (schema, currentPath = "") => {
|
|
25
|
+
const paths = [];
|
|
26
|
+
|
|
27
|
+
if (!schema || typeof schema !== 'object') {
|
|
28
|
+
return paths;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Handle arrays
|
|
32
|
+
if (schema.type === "array" && schema.items) {
|
|
33
|
+
const arrayPath = currentPath + "[]";
|
|
34
|
+
paths.push(arrayPath);
|
|
35
|
+
// Continue with items
|
|
36
|
+
const itemPaths = collectPaths(schema.items, arrayPath);
|
|
37
|
+
paths.push(...itemPaths);
|
|
38
|
+
return paths;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Handle primitives - add type suffix
|
|
42
|
+
if (schema.type && !schema.properties && !schema.oneOf && !schema.items) {
|
|
43
|
+
let typeChar = "";
|
|
44
|
+
switch(schema.type) {
|
|
45
|
+
case "string": typeChar = ":s"; break;
|
|
46
|
+
case "number": typeChar = ":n"; break;
|
|
47
|
+
case "integer": typeChar = ":i"; break;
|
|
48
|
+
case "boolean": typeChar = ":b"; break;
|
|
49
|
+
default: typeChar = "";
|
|
50
|
+
}
|
|
51
|
+
if (currentPath) {
|
|
52
|
+
paths.push(currentPath + typeChar);
|
|
53
|
+
}
|
|
54
|
+
return paths;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Handle objects with properties
|
|
58
|
+
if (schema.properties) {
|
|
59
|
+
// If this is an object without a path yet, don't add it
|
|
60
|
+
if (currentPath && !schema.type?.includes("array")) {
|
|
61
|
+
paths.push(currentPath);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
Object.keys(schema.properties).forEach((propName) => {
|
|
65
|
+
const newPath = currentPath ? `${currentPath}.${propName}` : propName;
|
|
66
|
+
const propPaths = collectPaths(schema.properties[propName], newPath);
|
|
67
|
+
paths.push(...propPaths);
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Handle oneOf - collect all possible properties
|
|
72
|
+
if (schema.oneOf) {
|
|
73
|
+
const variantProps = new Set();
|
|
74
|
+
schema.oneOf.forEach((oneOfSchema) => {
|
|
75
|
+
if (oneOfSchema.properties) {
|
|
76
|
+
Object.keys(oneOfSchema.properties).forEach((propName) => {
|
|
77
|
+
variantProps.add(propName);
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
// Process each unique property
|
|
83
|
+
variantProps.forEach((propName) => {
|
|
84
|
+
const newPath = currentPath ? `${currentPath}.${propName}` : propName;
|
|
85
|
+
// Check if all variants have the same type
|
|
86
|
+
let commonType = null;
|
|
87
|
+
let isVariant = false;
|
|
88
|
+
|
|
89
|
+
schema.oneOf.forEach((oneOfSchema) => {
|
|
90
|
+
if (oneOfSchema.properties && oneOfSchema.properties[propName]) {
|
|
91
|
+
const propType = oneOfSchema.properties[propName].type;
|
|
92
|
+
if (commonType === null) {
|
|
93
|
+
commonType = propType;
|
|
94
|
+
} else if (commonType !== propType) {
|
|
95
|
+
isVariant = true;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
if (isVariant || !commonType) {
|
|
101
|
+
paths.push(newPath + ":v"); // variant
|
|
102
|
+
} else {
|
|
103
|
+
// Process the first variant's version of this property
|
|
104
|
+
for (const oneOfSchema of schema.oneOf) {
|
|
105
|
+
if (oneOfSchema.properties && oneOfSchema.properties[propName]) {
|
|
106
|
+
const propPaths = collectPaths(oneOfSchema.properties[propName], newPath);
|
|
107
|
+
paths.push(...propPaths);
|
|
108
|
+
break;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Empty objects
|
|
116
|
+
if (currentPath && !schema.properties && !schema.oneOf && !schema.items && !schema.type) {
|
|
117
|
+
paths.push(currentPath);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return paths;
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
// Remove duplicates
|
|
124
|
+
const deduplicatePaths = (paths) => {
|
|
125
|
+
return [...new Set(paths)];
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
// Sort paths for readability
|
|
129
|
+
const sortPaths = (paths) => {
|
|
130
|
+
return paths.sort((a, b) => {
|
|
131
|
+
// Sort by depth first (fewer dots = higher up)
|
|
132
|
+
const depthA = (a.match(/\./g) || []).length;
|
|
133
|
+
const depthB = (b.match(/\./g) || []).length;
|
|
134
|
+
if (depthA !== depthB) return depthA - depthB;
|
|
135
|
+
|
|
136
|
+
// Then alphabetically
|
|
137
|
+
return a.localeCompare(b);
|
|
138
|
+
});
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
// Create clean schema
|
|
142
|
+
const coreSchema = deleteProperties(JSON.parse(JSON.stringify(combinedSchema)), [
|
|
143
|
+
"discriminator",
|
|
144
|
+
...extractFields.map((item) => `${item}Ref`),
|
|
145
|
+
...extractFields.map((item) => `${item}Required`),
|
|
146
|
+
...extractFields.map((item) => `${item}Title`),
|
|
147
|
+
...extractFields.map((item) => `${item}Description`),
|
|
148
|
+
...extractFields.map((item) => `${item}Enum`),
|
|
149
|
+
]);
|
|
150
|
+
|
|
151
|
+
// Remove metadata
|
|
152
|
+
const skeletonSchema = deleteProperties(coreSchema, [
|
|
153
|
+
"$schema", "$id", "title", "description", "required",
|
|
154
|
+
"enum", "minItems", "minLength", "format", "minimum", "maximum",
|
|
155
|
+
]);
|
|
156
|
+
|
|
157
|
+
// Collect paths
|
|
158
|
+
const allPaths = collectPaths(skeletonSchema);
|
|
159
|
+
const uniquePaths = deduplicatePaths(allPaths);
|
|
160
|
+
const sortedPaths = sortPaths(uniquePaths);
|
|
161
|
+
|
|
162
|
+
// Write as text file
|
|
163
|
+
const pathContent = sortedPaths.join('\n');
|
|
164
|
+
fs.writeFileSync("../schemas/v3/pathSkeleton.txt", pathContent);
|
|
165
|
+
|
|
166
|
+
// Also create a JSON version for comparison
|
|
167
|
+
fs.writeFileSync("../schemas/v3/pathSkeleton.json", JSON.stringify(sortedPaths, null, 2));
|
|
168
|
+
|
|
169
|
+
console.log(`Path skeleton written to ../schemas/v3/pathSkeleton.txt`);
|
|
170
|
+
console.log(`Total paths: ${sortedPaths.length}`);
|
|
171
|
+
console.log(`Text size: ${pathContent.length} bytes`);
|
|
172
|
+
|
|
173
|
+
// Count tokens
|
|
174
|
+
try {
|
|
175
|
+
const GPT3Encoder = require('gpt-3-encoder');
|
|
176
|
+
const encoded = GPT3Encoder.encode(pathContent);
|
|
177
|
+
console.log(`Tokens (GPT-3): ${encoded.length}`);
|
|
178
|
+
console.log(`Reduction: ${((1 - encoded.length / 78734) * 100).toFixed(1)}% fewer tokens than JSON skeleton`);
|
|
179
|
+
} catch (e) {
|
|
180
|
+
console.log(`Estimated tokens: ~${Math.ceil(pathContent.length / 4)}`);
|
|
181
|
+
}
|
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
-
"title": "Transaction Milestones",
|
|
4
|
-
"description": "Schema for tracking transaction milestones throughout the conveyancing process",
|
|
5
|
-
"type": "object",
|
|
6
|
-
"properties": {
|
|
7
|
-
"listed": {
|
|
8
|
-
"type": "object",
|
|
9
|
-
"properties": {
|
|
10
|
-
"completed": {
|
|
11
|
-
"type": "string",
|
|
12
|
-
"format": "date-time"
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
},
|
|
16
|
-
"legalForms": {
|
|
17
|
-
"type": "object",
|
|
18
|
-
"properties": {
|
|
19
|
-
"completed": {
|
|
20
|
-
"type": "string",
|
|
21
|
-
"format": "date-time"
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
},
|
|
25
|
-
"soldSubjectToContract": {
|
|
26
|
-
"type": "object",
|
|
27
|
-
"properties": {
|
|
28
|
-
"completed": {
|
|
29
|
-
"type": "string",
|
|
30
|
-
"format": "date-time"
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
},
|
|
34
|
-
"searches": {
|
|
35
|
-
"type": "object",
|
|
36
|
-
"properties": {
|
|
37
|
-
"ordered": {
|
|
38
|
-
"type": "string",
|
|
39
|
-
"format": "date-time"
|
|
40
|
-
},
|
|
41
|
-
"expected": {
|
|
42
|
-
"type": "string",
|
|
43
|
-
"format": "date-time"
|
|
44
|
-
},
|
|
45
|
-
"completed": {
|
|
46
|
-
"type": "string",
|
|
47
|
-
"format": "date-time"
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
},
|
|
51
|
-
"enquiries": {
|
|
52
|
-
"type": "object",
|
|
53
|
-
"properties": {
|
|
54
|
-
"completed": {
|
|
55
|
-
"type": "string",
|
|
56
|
-
"format": "date-time"
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
},
|
|
60
|
-
"exchangeOfContracts": {
|
|
61
|
-
"type": "object",
|
|
62
|
-
"properties": {
|
|
63
|
-
"expected": {
|
|
64
|
-
"type": "string",
|
|
65
|
-
"format": "date-time"
|
|
66
|
-
},
|
|
67
|
-
"completed": {
|
|
68
|
-
"type": "string",
|
|
69
|
-
"format": "date-time"
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
},
|
|
73
|
-
"completion": {
|
|
74
|
-
"type": "object",
|
|
75
|
-
"properties": {
|
|
76
|
-
"started": {
|
|
77
|
-
"type": "string",
|
|
78
|
-
"format": "date-time"
|
|
79
|
-
},
|
|
80
|
-
"expected": {
|
|
81
|
-
"type": "string",
|
|
82
|
-
"format": "date-time"
|
|
83
|
-
},
|
|
84
|
-
"completed": {
|
|
85
|
-
"type": "string",
|
|
86
|
-
"format": "date-time"
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
}
|