@pdtf/schemas 3.4.1-6 → 3.4.1-8
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 +6 -1
- package/index.js +190 -12
- package/package.json +2 -1
- package/src/schemas/v3/combined.json +11 -0
- package/src/schemas/v3/compactSkeleton.txt +3340 -0
- package/src/schemas/v3/overlays/ntsl2.json +11 -0
- package/src/schemas/v3/skeleton.json +3208 -3036
- package/src/tests/v3/caching.test.js +274 -0
- package/src/tests/v3/transactionSchema.test.js +60 -14
- 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
|
@@ -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
|
+
}
|