@pdtf/schemas 3.6.0-9 → 3.6.0-dev.3
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.md +101 -0
- package/README.md +57 -33
- package/docs/branch-release-workflow.md +138 -0
- package/docs/sef25-extensions-ui-spec.md +355 -0
- package/index.js +131 -75
- package/package.json +6 -2
- package/pensive-tesla-d0d355/CLAUDE.md +101 -0
- package/pensive-tesla-d0d355/LICENSE +21 -0
- package/pensive-tesla-d0d355/README.md +435 -0
- package/pensive-tesla-d0d355/docs/branch-release-workflow.md +138 -0
- package/pensive-tesla-d0d355/docs/sef25-extensions-ui-spec.md +355 -0
- package/pensive-tesla-d0d355/index.js +654 -0
- package/pensive-tesla-d0d355/package-lock.json +7297 -0
- package/pensive-tesla-d0d355/package.json +44 -0
- package/pensive-tesla-d0d355/src/examples/v1/exampleAddParticipantVouch.json +32 -0
- package/pensive-tesla-d0d355/src/examples/v1/exampleDocumentedVouch.json +40 -0
- package/pensive-tesla-d0d355/src/examples/v1/exampleElectronicRecord.json +30 -0
- package/pensive-tesla-d0d355/src/examples/v1/exampleTransaction.json +878 -0
- package/pensive-tesla-d0d355/src/examples/v1/exampleVouch.json +25 -0
- package/pensive-tesla-d0d355/src/examples/v2/exampleTransaction.json +901 -0
- package/pensive-tesla-d0d355/src/examples/v3/exampleAddParticipantVouch.json +38 -0
- package/pensive-tesla-d0d355/src/examples/v3/exampleCustomOverlay.json +55 -0
- package/pensive-tesla-d0d355/src/examples/v3/exampleCustomOverlay2.json +93 -0
- package/pensive-tesla-d0d355/src/examples/v3/exampleDocumentedVouch.json +47 -0
- package/pensive-tesla-d0d355/src/examples/v3/exampleElectronicRecord.json +36 -0
- package/pensive-tesla-d0d355/src/examples/v3/exampleTransaction.json +1038 -0
- package/pensive-tesla-d0d355/src/examples/v3/exampleVouch.json +32 -0
- package/pensive-tesla-d0d355/src/mappings/SendPropertyDetailsRequestSchema.json +1588 -0
- package/pensive-tesla-d0d355/src/mappings/adf.js +198 -0
- package/pensive-tesla-d0d355/src/schemas/v1/GeoJSON.json +1279 -0
- package/pensive-tesla-d0d355/src/schemas/v1/baspiNotes.html +102 -0
- package/pensive-tesla-d0d355/src/schemas/v1/energy-performance-certificate.json +124 -0
- package/pensive-tesla-d0d355/src/schemas/v1/freehold-information.json +2051 -0
- package/pensive-tesla-d0d355/src/schemas/v1/leasehold-information.json +2064 -0
- package/pensive-tesla-d0d355/src/schemas/v1/legal-information.json +1045 -0
- package/pensive-tesla-d0d355/src/schemas/v1/material-facts.json +2109 -0
- package/pensive-tesla-d0d355/src/schemas/v1/pdtf-transaction-search-results.json +40 -0
- package/pensive-tesla-d0d355/src/schemas/v1/pdtf-transaction.json +191 -0
- package/pensive-tesla-d0d355/src/schemas/v1/searches/drainage-and-water.json +261 -0
- package/pensive-tesla-d0d355/src/schemas/v1/searches/local-land-charges.json +69 -0
- package/pensive-tesla-d0d355/src/schemas/v1/searches/local-searches-required.json +857 -0
- package/pensive-tesla-d0d355/src/schemas/v1/searches.json +237 -0
- package/pensive-tesla-d0d355/src/schemas/v1/title-deed.json +841 -0
- package/pensive-tesla-d0d355/src/schemas/v2/baspiNotes.html +102 -0
- package/pensive-tesla-d0d355/src/schemas/v2/combined.json +37731 -0
- package/pensive-tesla-d0d355/src/schemas/v2/overlays/baspi.json +8132 -0
- package/pensive-tesla-d0d355/src/schemas/v2/overlays/con29DW.json +705 -0
- package/pensive-tesla-d0d355/src/schemas/v2/overlays/con29R.json +2956 -0
- package/pensive-tesla-d0d355/src/schemas/v2/overlays/fme1.json +1259 -0
- package/pensive-tesla-d0d355/src/schemas/v2/overlays/llc1.json +25 -0
- package/pensive-tesla-d0d355/src/schemas/v2/overlays/lpe1.json +2171 -0
- package/pensive-tesla-d0d355/src/schemas/v2/overlays/nts.json +326 -0
- package/pensive-tesla-d0d355/src/schemas/v2/overlays/oc1.json +2799 -0
- package/pensive-tesla-d0d355/src/schemas/v2/overlays/piq.json +3419 -0
- package/pensive-tesla-d0d355/src/schemas/v2/overlays/rds.json +3736 -0
- package/pensive-tesla-d0d355/src/schemas/v2/overlays/ta10.json +5306 -0
- package/pensive-tesla-d0d355/src/schemas/v2/overlays/ta6.json +4533 -0
- package/pensive-tesla-d0d355/src/schemas/v2/overlays/ta7.json +1045 -0
- package/pensive-tesla-d0d355/src/schemas/v2/pdtf-transaction.json +34351 -0
- package/pensive-tesla-d0d355/src/schemas/v2/skeleton.json +3973 -0
- package/pensive-tesla-d0d355/src/schemas/v3/combined.json +48469 -0
- package/pensive-tesla-d0d355/src/schemas/v3/compactSkeleton.txt +4519 -0
- package/pensive-tesla-d0d355/src/schemas/v3/overlays/README.md +299 -0
- package/pensive-tesla-d0d355/src/schemas/v3/overlays/baspi4.json +8025 -0
- package/pensive-tesla-d0d355/src/schemas/v3/overlays/baspi5.json +8175 -0
- package/pensive-tesla-d0d355/src/schemas/v3/overlays/con29DW.json +716 -0
- package/pensive-tesla-d0d355/src/schemas/v3/overlays/con29R.json +2981 -0
- package/pensive-tesla-d0d355/src/schemas/v3/overlays/extensions/ac.json +333 -0
- package/pensive-tesla-d0d355/src/schemas/v3/overlays/extensions/as.json +74 -0
- package/pensive-tesla-d0d355/src/schemas/v3/overlays/extensions/dk.json +32 -0
- package/pensive-tesla-d0d355/src/schemas/v3/overlays/extensions/dr.json +73 -0
- package/pensive-tesla-d0d355/src/schemas/v3/overlays/extensions/er.json +85 -0
- package/pensive-tesla-d0d355/src/schemas/v3/overlays/extensions/fd.json +75 -0
- package/pensive-tesla-d0d355/src/schemas/v3/overlays/extensions/hi.json +51 -0
- package/pensive-tesla-d0d355/src/schemas/v3/overlays/extensions/hs.json +73 -0
- package/pensive-tesla-d0d355/src/schemas/v3/overlays/extensions/ic.json +59 -0
- package/pensive-tesla-d0d355/src/schemas/v3/overlays/extensions/jk.json +96 -0
- package/pensive-tesla-d0d355/src/schemas/v3/overlays/extensions/la.json +85 -0
- package/pensive-tesla-d0d355/src/schemas/v3/overlays/extensions/lc.json +75 -0
- package/pensive-tesla-d0d355/src/schemas/v3/overlays/extensions/ma.json +90 -0
- package/pensive-tesla-d0d355/src/schemas/v3/overlays/extensions/mc.json +38 -0
- package/pensive-tesla-d0d355/src/schemas/v3/overlays/extensions/mi.json +69 -0
- package/pensive-tesla-d0d355/src/schemas/v3/overlays/extensions/nd.json +43 -0
- package/pensive-tesla-d0d355/src/schemas/v3/overlays/extensions/oa.json +24 -0
- package/pensive-tesla-d0d355/src/schemas/v3/overlays/extensions/oc.json +57 -0
- package/pensive-tesla-d0d355/src/schemas/v3/overlays/extensions/pc.json +37 -0
- package/pensive-tesla-d0d355/src/schemas/v3/overlays/extensions/ph.json +194 -0
- package/pensive-tesla-d0d355/src/schemas/v3/overlays/extensions/rw.json +68 -0
- package/pensive-tesla-d0d355/src/schemas/v3/overlays/extensions/sb.json +73 -0
- package/pensive-tesla-d0d355/src/schemas/v3/overlays/extensions/sc.json +129 -0
- package/pensive-tesla-d0d355/src/schemas/v3/overlays/extensions/sd.json +63 -0
- package/pensive-tesla-d0d355/src/schemas/v3/overlays/extensions/sf.json +74 -0
- package/pensive-tesla-d0d355/src/schemas/v3/overlays/extensions/sl.json +68 -0
- package/pensive-tesla-d0d355/src/schemas/v3/overlays/extensions/ta.json +252 -0
- package/pensive-tesla-d0d355/src/schemas/v3/overlays/extensions/tf.json +103 -0
- package/pensive-tesla-d0d355/src/schemas/v3/overlays/extensions/tr.json +73 -0
- package/pensive-tesla-d0d355/src/schemas/v3/overlays/extensions/wg.json +350 -0
- package/pensive-tesla-d0d355/src/schemas/v3/overlays/fme1.json +1266 -0
- package/pensive-tesla-d0d355/src/schemas/v3/overlays/llc1.json +25 -0
- package/pensive-tesla-d0d355/src/schemas/v3/overlays/lpe1.json +2199 -0
- package/pensive-tesla-d0d355/src/schemas/v3/overlays/nts.json +2157 -0
- package/pensive-tesla-d0d355/src/schemas/v3/overlays/nts2.json +2742 -0
- package/pensive-tesla-d0d355/src/schemas/v3/overlays/ntsl.json +1813 -0
- package/pensive-tesla-d0d355/src/schemas/v3/overlays/ntsl2.json +2217 -0
- package/pensive-tesla-d0d355/src/schemas/v3/overlays/oc1.json +2817 -0
- package/pensive-tesla-d0d355/src/schemas/v3/overlays/piq.json +3322 -0
- package/pensive-tesla-d0d355/src/schemas/v3/overlays/rds.json +3665 -0
- package/pensive-tesla-d0d355/src/schemas/v3/overlays/sef25.json +1639 -0
- package/pensive-tesla-d0d355/src/schemas/v3/overlays/sr24.json +38 -0
- package/pensive-tesla-d0d355/src/schemas/v3/overlays/ta10.json +4654 -0
- package/pensive-tesla-d0d355/src/schemas/v3/overlays/ta6.json +4568 -0
- package/pensive-tesla-d0d355/src/schemas/v3/overlays/ta6ed6.json +6534 -0
- package/pensive-tesla-d0d355/src/schemas/v3/overlays/ta7.json +1537 -0
- package/pensive-tesla-d0d355/src/schemas/v3/overlays/ta7ed5.json +1551 -0
- package/pensive-tesla-d0d355/src/schemas/v3/pdtf-transaction.json +41573 -0
- package/pensive-tesla-d0d355/src/schemas/v3/skeleton.json +5767 -0
- package/pensive-tesla-d0d355/src/schemas/verifiedClaims/README.md +21 -0
- package/pensive-tesla-d0d355/src/schemas/verifiedClaims/pdtf-verified-claims.json +447 -0
- package/pensive-tesla-d0d355/src/utils/compactSkeleton.js +84 -0
- package/pensive-tesla-d0d355/src/utils/countTokens.js +67 -0
- package/pensive-tesla-d0d355/src/utils/extractExtensionOverlays.js +624 -0
- package/pensive-tesla-d0d355/src/utils/extractOverlay.js +381 -0
- package/pensive-tesla-d0d355/src/utils/extractProperties.js +44 -0
- package/pensive-tesla-d0d355/src/utils/listPathTitles.js +36 -0
- package/pensive-tesla-d0d355/src/utils/minimalSkeleton.js +85 -0
- package/pensive-tesla-d0d355/src/utils/pathList.csv +903 -0
- package/pensive-tesla-d0d355/src/utils/pathSkeleton.js +181 -0
- package/src/examples/v3/exampleTransaction.json +3 -3
- package/src/schemas/v3/combined.json +8047 -1982
- package/src/schemas/v3/compactSkeleton.txt +379 -5
- package/src/schemas/v3/overlays/baspi4.json +164 -21
- package/src/schemas/v3/overlays/baspi5.json +169 -23
- package/src/schemas/v3/overlays/extensions/ac.json +333 -0
- package/src/schemas/v3/overlays/extensions/as.json +4 -2
- package/src/schemas/v3/overlays/extensions/dk.json +32 -0
- package/src/schemas/v3/overlays/extensions/dr.json +9 -9
- package/src/schemas/v3/overlays/extensions/er.json +4 -2
- package/src/schemas/v3/overlays/extensions/fd.json +6 -3
- package/src/schemas/v3/overlays/extensions/hi.json +6 -3
- package/src/schemas/v3/overlays/extensions/hs.json +4 -2
- package/src/schemas/v3/overlays/extensions/ic.json +59 -0
- package/src/schemas/v3/overlays/extensions/jk.json +28 -8
- package/src/schemas/v3/overlays/extensions/la.json +4 -2
- package/src/schemas/v3/overlays/extensions/lc.json +75 -0
- package/src/schemas/v3/overlays/extensions/ma.json +6 -3
- package/src/schemas/v3/overlays/extensions/mc.json +4 -2
- package/src/schemas/v3/overlays/extensions/mi.json +69 -0
- package/src/schemas/v3/overlays/extensions/nd.json +43 -0
- package/src/schemas/v3/overlays/extensions/oa.json +4 -2
- package/src/schemas/v3/overlays/extensions/oc.json +4 -2
- package/src/schemas/v3/overlays/extensions/pc.json +37 -0
- package/src/schemas/v3/overlays/extensions/ph.json +194 -0
- package/src/schemas/v3/overlays/extensions/rw.json +68 -0
- package/src/schemas/v3/overlays/extensions/sb.json +4 -2
- package/src/schemas/v3/overlays/extensions/sc.json +129 -0
- package/src/schemas/v3/overlays/extensions/sd.json +63 -0
- package/src/schemas/v3/overlays/extensions/sf.json +4 -2
- package/src/schemas/v3/overlays/extensions/sl.json +4 -2
- package/src/schemas/v3/overlays/extensions/ta.json +204 -0
- package/src/schemas/v3/overlays/extensions/tf.json +6 -3
- package/src/schemas/v3/overlays/extensions/tr.json +73 -0
- package/src/schemas/v3/overlays/extensions/wg.json +350 -0
- package/src/schemas/v3/overlays/fme1.json +16 -14
- package/src/schemas/v3/overlays/lpe1.json +60 -30
- package/src/schemas/v3/overlays/nts.json +68 -1
- package/src/schemas/v3/overlays/nts2.json +68 -4
- package/src/schemas/v3/overlays/ntsl.json +68 -1
- package/src/schemas/v3/overlays/ntsl2.json +68 -4
- package/src/schemas/v3/overlays/piq.json +39 -4
- package/src/schemas/v3/overlays/rds.json +117 -8
- package/src/schemas/v3/overlays/sef25.json +1639 -0
- package/src/schemas/v3/overlays/ta6.json +46 -16
- package/src/schemas/v3/overlays/ta6ed6.json +6534 -0
- package/src/schemas/v3/overlays/ta7.json +70 -6
- package/src/schemas/v3/overlays/ta7ed5.json +1551 -0
- package/src/schemas/v3/pdtf-transaction.json +4565 -1021
- package/src/schemas/v3/skeleton.json +510 -38
- package/src/utils/extractExtensionOverlays.js +293 -31
- package/src/utils/extractOverlay.js +94 -27
- package/src/utils/pathSkeleton.js +1 -1
- package/.claude/settings.local.json +0 -42
- package/.github/workflows/pages.yml +0 -50
- package/CNAME +0 -1
- package/_config.yml +0 -1
- package/src/tests/v3/caching.test.js +0 -591
- package/src/tests/v3/enquiries.test.js +0 -1096
- package/src/tests/v3/extensionOverlays.test.js +0 -525
- package/src/tests/v3/offers.test.js +0 -823
- package/src/tests/v3/patternProperties.test.js +0 -688
- package/src/tests/v3/transactionSchema.test.js +0 -615
- package/src/tests/v3/verifiedClaimsValidator.test.js +0 -195
package/index.js
CHANGED
|
@@ -18,7 +18,7 @@ const cacheStats = {
|
|
|
18
18
|
hits: 0,
|
|
19
19
|
misses: 0,
|
|
20
20
|
totalQueries: 0,
|
|
21
|
-
cacheStartTime: Date.now()
|
|
21
|
+
cacheStartTime: Date.now(),
|
|
22
22
|
};
|
|
23
23
|
|
|
24
24
|
const verifiedClaimsSchema = require("./src/schemas/verifiedClaims/pdtf-verified-claims.json");
|
|
@@ -52,6 +52,24 @@ const extensionOverlays = {
|
|
|
52
52
|
|
|
53
53
|
// Transaction Extensions
|
|
54
54
|
oc: require("./src/schemas/v3/overlays/extensions/oc.json"),
|
|
55
|
+
|
|
56
|
+
// SEF25 Extensions
|
|
57
|
+
sc: require("./src/schemas/v3/overlays/extensions/sc.json"),
|
|
58
|
+
pc: require("./src/schemas/v3/overlays/extensions/pc.json"),
|
|
59
|
+
ph: require("./src/schemas/v3/overlays/extensions/ph.json"),
|
|
60
|
+
dk: require("./src/schemas/v3/overlays/extensions/dk.json"),
|
|
61
|
+
rw: require("./src/schemas/v3/overlays/extensions/rw.json"),
|
|
62
|
+
sd: require("./src/schemas/v3/overlays/extensions/sd.json"),
|
|
63
|
+
lc: require("./src/schemas/v3/overlays/extensions/lc.json"),
|
|
64
|
+
wg: require("./src/schemas/v3/overlays/extensions/wg.json"),
|
|
65
|
+
ic: require("./src/schemas/v3/overlays/extensions/ic.json"),
|
|
66
|
+
nd: require("./src/schemas/v3/overlays/extensions/nd.json"),
|
|
67
|
+
mi: require("./src/schemas/v3/overlays/extensions/mi.json"),
|
|
68
|
+
tr: require("./src/schemas/v3/overlays/extensions/tr.json"),
|
|
69
|
+
ac: require("./src/schemas/v3/overlays/extensions/ac.json"),
|
|
70
|
+
|
|
71
|
+
// Compatibility Extensions
|
|
72
|
+
ta: require("./src/schemas/v3/overlays/extensions/ta.json"),
|
|
55
73
|
};
|
|
56
74
|
|
|
57
75
|
const overlaysMap = {
|
|
@@ -75,7 +93,9 @@ const overlaysMap = {
|
|
|
75
93
|
baspiV4: require("./src/schemas/v3/overlays/baspi4.json"),
|
|
76
94
|
baspiV5: require("./src/schemas/v3/overlays/baspi5.json"),
|
|
77
95
|
ta6ed4: require("./src/schemas/v3/overlays/ta6.json"),
|
|
96
|
+
ta6ed6: require("./src/schemas/v3/overlays/ta6ed6.json"),
|
|
78
97
|
ta7ed3: require("./src/schemas/v3/overlays/ta7.json"),
|
|
98
|
+
ta7ed5: require("./src/schemas/v3/overlays/ta7ed5.json"),
|
|
79
99
|
ta10ed3: require("./src/schemas/v3/overlays/ta10.json"),
|
|
80
100
|
lpe1ed4: require("./src/schemas/v3/overlays/lpe1.json"),
|
|
81
101
|
fme1ed2: require("./src/schemas/v3/overlays/fme1.json"),
|
|
@@ -117,21 +137,27 @@ const arrayMerge = (target, source, options) => {
|
|
|
117
137
|
// Detect if this is a required array by checking the parent key
|
|
118
138
|
// Required arrays are property names (camelCase, no spaces)
|
|
119
139
|
// Enum arrays are values (can contain spaces, capitals, etc.)
|
|
120
|
-
const isRequiredArray =
|
|
121
|
-
(
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
(item
|
|
134
|
-
|
|
140
|
+
const isRequiredArray =
|
|
141
|
+
target.every(
|
|
142
|
+
(item) =>
|
|
143
|
+
typeof item === "string" &&
|
|
144
|
+
item.length > 0 &&
|
|
145
|
+
// Required field names are typically camelCase without spaces
|
|
146
|
+
!item.includes(" ") &&
|
|
147
|
+
// First character is usually lowercase for field names
|
|
148
|
+
(item[0] === item[0].toLowerCase() ||
|
|
149
|
+
item.startsWith("is") ||
|
|
150
|
+
item.startsWith("has")),
|
|
151
|
+
) &&
|
|
152
|
+
source.every(
|
|
153
|
+
(item) =>
|
|
154
|
+
typeof item === "string" &&
|
|
155
|
+
item.length > 0 &&
|
|
156
|
+
!item.includes(" ") &&
|
|
157
|
+
(item[0] === item[0].toLowerCase() ||
|
|
158
|
+
item.startsWith("is") ||
|
|
159
|
+
item.startsWith("has")),
|
|
160
|
+
);
|
|
135
161
|
|
|
136
162
|
if (isRequiredArray) {
|
|
137
163
|
// Combine required arrays
|
|
@@ -176,7 +202,7 @@ const arrayMerge = (target, source, options) => {
|
|
|
176
202
|
|
|
177
203
|
const getTransactionSchema = (
|
|
178
204
|
schemaId = "https://trust.propdata.org.uk/schemas/v3/pdtf-transaction.json",
|
|
179
|
-
overlays
|
|
205
|
+
overlays,
|
|
180
206
|
) => {
|
|
181
207
|
const sourceSchema = transactionSchemas[schemaId];
|
|
182
208
|
if (!overlays || overlays.length < 1) return sourceSchema;
|
|
@@ -184,7 +210,7 @@ const getTransactionSchema = (
|
|
|
184
210
|
let mergedSchema = JSON.parse(JSON.stringify(sourceSchema)); // Deep copy
|
|
185
211
|
overlays.forEach((overlay) => {
|
|
186
212
|
const overlaySchema = JSON.parse(
|
|
187
|
-
JSON.stringify(overlaysMap[schemaId][overlay] || {})
|
|
213
|
+
JSON.stringify(overlaysMap[schemaId][overlay] || {}),
|
|
188
214
|
); // Deep copy
|
|
189
215
|
mergedSchema = merge(mergedSchema, overlaySchema, { arrayMerge });
|
|
190
216
|
});
|
|
@@ -211,7 +237,7 @@ const getCachedSchemaData = (path, schemaId, overlays) => {
|
|
|
211
237
|
const sourceSchema = getTransactionSchema(schemaId, overlays);
|
|
212
238
|
const pathArray = path.split("/").slice(1);
|
|
213
239
|
let subSchema = sourceSchema;
|
|
214
|
-
|
|
240
|
+
|
|
215
241
|
if (pathArray.length >= 1) {
|
|
216
242
|
subSchema = pathArray.reduce((schema, pathElement) => {
|
|
217
243
|
if (!schema) return undefined;
|
|
@@ -233,33 +259,52 @@ const getCachedSchemaData = (path, schemaId, overlays) => {
|
|
|
233
259
|
}
|
|
234
260
|
} catch (e) {
|
|
235
261
|
// Invalid regex pattern in schema - skip it
|
|
236
|
-
console.warn(
|
|
262
|
+
console.warn(
|
|
263
|
+
`Invalid regex pattern in patternProperties: ${pattern}`,
|
|
264
|
+
e,
|
|
265
|
+
);
|
|
237
266
|
}
|
|
238
267
|
}
|
|
239
268
|
}
|
|
240
269
|
|
|
241
|
-
// Check oneOf discriminators
|
|
270
|
+
// Check oneOf discriminators (recursively for nested oneOf)
|
|
242
271
|
if (oneOf) {
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
272
|
+
const findInOneOf = (branches) => {
|
|
273
|
+
let arrayFallback;
|
|
274
|
+
for (const branch of branches) {
|
|
275
|
+
if (!branch) continue;
|
|
276
|
+
// Track array matches as fallback (prefer property matches)
|
|
277
|
+
if (
|
|
278
|
+
branch.type === "array" &&
|
|
279
|
+
!Number.isNaN(pathElement) &&
|
|
280
|
+
!arrayFallback
|
|
281
|
+
) {
|
|
282
|
+
arrayFallback = branch.items;
|
|
283
|
+
}
|
|
284
|
+
if (branch.properties?.[pathElement]) {
|
|
285
|
+
return branch.properties[pathElement];
|
|
286
|
+
}
|
|
287
|
+
if (branch.patternProperties) {
|
|
288
|
+
for (const pattern in branch.patternProperties) {
|
|
289
|
+
try {
|
|
290
|
+
const regex = new RegExp(pattern);
|
|
291
|
+
if (regex.test(pathElement)) {
|
|
292
|
+
return branch.patternProperties[pattern];
|
|
293
|
+
}
|
|
294
|
+
} catch (e) {
|
|
295
|
+
// Invalid regex pattern - skip
|
|
256
296
|
}
|
|
257
|
-
} catch (e) {
|
|
258
|
-
// Invalid regex pattern - skip
|
|
259
297
|
}
|
|
260
298
|
}
|
|
299
|
+
// Recurse into nested oneOf branches
|
|
300
|
+
if (branch.oneOf) {
|
|
301
|
+
const nested = findInOneOf(branch.oneOf);
|
|
302
|
+
if (nested) return nested;
|
|
303
|
+
}
|
|
261
304
|
}
|
|
262
|
-
|
|
305
|
+
return arrayFallback;
|
|
306
|
+
};
|
|
307
|
+
const matchingProperty = findInOneOf(oneOf);
|
|
263
308
|
if (matchingProperty) return matchingProperty;
|
|
264
309
|
}
|
|
265
310
|
|
|
@@ -270,7 +315,7 @@ const getCachedSchemaData = (path, schemaId, overlays) => {
|
|
|
270
315
|
// Add schema to AJV and get validator
|
|
271
316
|
// Only add valid schemas to AJV
|
|
272
317
|
let validator;
|
|
273
|
-
if (subSchema && typeof subSchema ===
|
|
318
|
+
if (subSchema && typeof subSchema === "object") {
|
|
274
319
|
// Check if schema already exists in AJV to avoid duplicates
|
|
275
320
|
validator = ajv.getSchema(cacheKey);
|
|
276
321
|
if (!validator) {
|
|
@@ -287,7 +332,7 @@ const getCachedSchemaData = (path, schemaId, overlays) => {
|
|
|
287
332
|
subSchema,
|
|
288
333
|
validator,
|
|
289
334
|
cacheKey,
|
|
290
|
-
createdAt: Date.now()
|
|
335
|
+
createdAt: Date.now(),
|
|
291
336
|
};
|
|
292
337
|
schemaCache.set(cacheKey, cached);
|
|
293
338
|
} else {
|
|
@@ -353,13 +398,13 @@ const getTitleAtPath = (schema, path, rootPath = path) => {
|
|
|
353
398
|
if (oneOfs) {
|
|
354
399
|
// only single dependency discriminator, oneOf keyword is supported
|
|
355
400
|
const matchingOneOf = oneOfs.find(
|
|
356
|
-
(oneOf) => oneOf["properties"][propertyName]
|
|
401
|
+
(oneOf) => oneOf["properties"][propertyName],
|
|
357
402
|
);
|
|
358
403
|
if (matchingOneOf)
|
|
359
404
|
return getTitleAtPath(
|
|
360
405
|
matchingOneOf["properties"][propertyName],
|
|
361
406
|
subPath,
|
|
362
|
-
rootPath
|
|
407
|
+
rootPath,
|
|
363
408
|
);
|
|
364
409
|
}
|
|
365
410
|
};
|
|
@@ -392,7 +437,7 @@ const validateVerifiedClaims = (verifiedClaims, schemaId, overlays) => {
|
|
|
392
437
|
}
|
|
393
438
|
} else {
|
|
394
439
|
validationErrorsArr.push(
|
|
395
|
-
`Path ${path} is not a valid PDTF schema path
|
|
440
|
+
`Path ${path} is not a valid PDTF schema path`,
|
|
396
441
|
);
|
|
397
442
|
}
|
|
398
443
|
}
|
|
@@ -404,8 +449,11 @@ const validateVerifiedClaims = (verifiedClaims, schemaId, overlays) => {
|
|
|
404
449
|
// Cache management functions
|
|
405
450
|
const getCacheStats = () => {
|
|
406
451
|
const runtime = Date.now() - cacheStats.cacheStartTime;
|
|
407
|
-
const hitRate =
|
|
408
|
-
|
|
452
|
+
const hitRate =
|
|
453
|
+
cacheStats.totalQueries > 0
|
|
454
|
+
? (cacheStats.hits / cacheStats.totalQueries) * 100
|
|
455
|
+
: 0;
|
|
456
|
+
|
|
409
457
|
return {
|
|
410
458
|
totalEntries: schemaCache.size,
|
|
411
459
|
hits: cacheStats.hits,
|
|
@@ -417,8 +465,8 @@ const getCacheStats = () => {
|
|
|
417
465
|
memoryUsage: {
|
|
418
466
|
entriesCount: schemaCache.size,
|
|
419
467
|
// Rough estimate of memory usage per entry
|
|
420
|
-
estimatedSizeKB: Math.round((schemaCache.size * 2) / 1024 * 100) / 100 // Rough estimate
|
|
421
|
-
}
|
|
468
|
+
estimatedSizeKB: Math.round(((schemaCache.size * 2) / 1024) * 100) / 100, // Rough estimate
|
|
469
|
+
},
|
|
422
470
|
};
|
|
423
471
|
};
|
|
424
472
|
|
|
@@ -428,15 +476,17 @@ const getDetailedCacheStats = () => {
|
|
|
428
476
|
key,
|
|
429
477
|
createdAt: value.createdAt,
|
|
430
478
|
age: Date.now() - value.createdAt,
|
|
431
|
-
hasValidator: typeof value.validator ===
|
|
432
|
-
hasSubSchema: value.subSchema !== undefined
|
|
479
|
+
hasValidator: typeof value.validator === "function",
|
|
480
|
+
hasSubSchema: value.subSchema !== undefined,
|
|
433
481
|
}));
|
|
434
482
|
|
|
435
483
|
return {
|
|
436
484
|
...baseStats,
|
|
437
485
|
entries: entries.sort((a, b) => b.createdAt - a.createdAt), // Most recent first
|
|
438
|
-
oldestEntry:
|
|
439
|
-
|
|
486
|
+
oldestEntry:
|
|
487
|
+
entries.length > 0 ? Math.max(...entries.map((e) => e.age)) : 0,
|
|
488
|
+
newestEntry:
|
|
489
|
+
entries.length > 0 ? Math.min(...entries.map((e) => e.age)) : 0,
|
|
440
490
|
};
|
|
441
491
|
};
|
|
442
492
|
|
|
@@ -449,17 +499,17 @@ const clearSchemaCache = (pattern) => {
|
|
|
449
499
|
keysToDelete.push(key);
|
|
450
500
|
}
|
|
451
501
|
});
|
|
452
|
-
keysToDelete.forEach(key => schemaCache.delete(key));
|
|
453
|
-
|
|
502
|
+
keysToDelete.forEach((key) => schemaCache.delete(key));
|
|
503
|
+
|
|
454
504
|
// Also remove matching schemas from AJV
|
|
455
|
-
keysToDelete.forEach(key => {
|
|
505
|
+
keysToDelete.forEach((key) => {
|
|
456
506
|
try {
|
|
457
507
|
ajv.removeSchema(key);
|
|
458
508
|
} catch (e) {
|
|
459
509
|
// Schema might not exist in AJV, ignore
|
|
460
510
|
}
|
|
461
511
|
});
|
|
462
|
-
|
|
512
|
+
|
|
463
513
|
return keysToDelete.length;
|
|
464
514
|
} else {
|
|
465
515
|
// Clear all cache
|
|
@@ -470,20 +520,24 @@ const clearSchemaCache = (pattern) => {
|
|
|
470
520
|
cacheStats.misses = 0;
|
|
471
521
|
cacheStats.totalQueries = 0;
|
|
472
522
|
cacheStats.cacheStartTime = Date.now();
|
|
473
|
-
|
|
523
|
+
|
|
474
524
|
// Also clear AJV's internal cache to prevent duplicates
|
|
475
525
|
ajv.removeSchema();
|
|
476
|
-
|
|
526
|
+
|
|
477
527
|
return entriesCleared;
|
|
478
528
|
}
|
|
479
529
|
};
|
|
480
530
|
|
|
481
|
-
const warmupCache = (
|
|
531
|
+
const warmupCache = (
|
|
532
|
+
paths,
|
|
533
|
+
schemaId = "https://trust.propdata.org.uk/schemas/v3/pdtf-transaction.json",
|
|
534
|
+
overlaysList = [],
|
|
535
|
+
) => {
|
|
482
536
|
const warmupStats = {
|
|
483
537
|
totalAttempted: 0,
|
|
484
538
|
successful: 0,
|
|
485
539
|
failed: 0,
|
|
486
|
-
errors: []
|
|
540
|
+
errors: [],
|
|
487
541
|
};
|
|
488
542
|
|
|
489
543
|
// Default common paths if none provided
|
|
@@ -495,7 +549,7 @@ const warmupCache = (paths, schemaId = "https://trust.propdata.org.uk/schemas/v3
|
|
|
495
549
|
"/propertyPack/valuations",
|
|
496
550
|
"/propertyPack/waterAndDrainage",
|
|
497
551
|
"/propertyPack/ownership",
|
|
498
|
-
"/propertyPack/notices"
|
|
552
|
+
"/propertyPack/notices",
|
|
499
553
|
];
|
|
500
554
|
|
|
501
555
|
// Default common overlays if none provided
|
|
@@ -504,14 +558,15 @@ const warmupCache = (paths, schemaId = "https://trust.propdata.org.uk/schemas/v3
|
|
|
504
558
|
["baspiV5"],
|
|
505
559
|
["ta6ed4"],
|
|
506
560
|
["nts2023"],
|
|
507
|
-
["baspiV5", "ta6ed4"]
|
|
561
|
+
["baspiV5", "ta6ed4"],
|
|
508
562
|
];
|
|
509
563
|
|
|
510
564
|
const pathsToWarm = paths || defaultPaths;
|
|
511
|
-
const overlaysToWarm =
|
|
565
|
+
const overlaysToWarm =
|
|
566
|
+
overlaysList.length > 0 ? overlaysList : defaultOverlays;
|
|
512
567
|
|
|
513
|
-
pathsToWarm.forEach(path => {
|
|
514
|
-
overlaysToWarm.forEach(overlays => {
|
|
568
|
+
pathsToWarm.forEach((path) => {
|
|
569
|
+
overlaysToWarm.forEach((overlays) => {
|
|
515
570
|
warmupStats.totalAttempted++;
|
|
516
571
|
try {
|
|
517
572
|
// This will populate the cache
|
|
@@ -523,7 +578,7 @@ const warmupCache = (paths, schemaId = "https://trust.propdata.org.uk/schemas/v3
|
|
|
523
578
|
warmupStats.errors.push({
|
|
524
579
|
path,
|
|
525
580
|
overlays,
|
|
526
|
-
error: error.message
|
|
581
|
+
error: error.message,
|
|
527
582
|
});
|
|
528
583
|
}
|
|
529
584
|
});
|
|
@@ -535,14 +590,14 @@ const warmupCache = (paths, schemaId = "https://trust.propdata.org.uk/schemas/v3
|
|
|
535
590
|
const pruneCacheByAge = (maxAgeMs) => {
|
|
536
591
|
const now = Date.now();
|
|
537
592
|
const keysToDelete = [];
|
|
538
|
-
|
|
593
|
+
|
|
539
594
|
schemaCache.forEach((value, key) => {
|
|
540
595
|
if (now - value.createdAt > maxAgeMs) {
|
|
541
596
|
keysToDelete.push(key);
|
|
542
597
|
}
|
|
543
598
|
});
|
|
544
|
-
|
|
545
|
-
keysToDelete.forEach(key => {
|
|
599
|
+
|
|
600
|
+
keysToDelete.forEach((key) => {
|
|
546
601
|
schemaCache.delete(key);
|
|
547
602
|
try {
|
|
548
603
|
ajv.removeSchema(key);
|
|
@@ -550,21 +605,22 @@ const pruneCacheByAge = (maxAgeMs) => {
|
|
|
550
605
|
// Schema might not exist in AJV, ignore
|
|
551
606
|
}
|
|
552
607
|
});
|
|
553
|
-
|
|
608
|
+
|
|
554
609
|
return keysToDelete.length;
|
|
555
610
|
};
|
|
556
611
|
|
|
557
612
|
const setCacheMaxSize = (maxSize) => {
|
|
558
613
|
if (schemaCache.size <= maxSize) return 0;
|
|
559
|
-
|
|
614
|
+
|
|
560
615
|
// Get entries sorted by creation time (oldest first)
|
|
561
|
-
const entries = Array.from(schemaCache.entries())
|
|
562
|
-
|
|
563
|
-
|
|
616
|
+
const entries = Array.from(schemaCache.entries()).sort(
|
|
617
|
+
(a, b) => a[1].createdAt - b[1].createdAt,
|
|
618
|
+
);
|
|
619
|
+
|
|
564
620
|
const toRemove = schemaCache.size - maxSize;
|
|
565
621
|
const keysToDelete = entries.slice(0, toRemove).map(([key]) => key);
|
|
566
|
-
|
|
567
|
-
keysToDelete.forEach(key => {
|
|
622
|
+
|
|
623
|
+
keysToDelete.forEach((key) => {
|
|
568
624
|
schemaCache.delete(key);
|
|
569
625
|
try {
|
|
570
626
|
ajv.removeSchema(key);
|
|
@@ -572,7 +628,7 @@ const setCacheMaxSize = (maxSize) => {
|
|
|
572
628
|
// Schema might not exist in AJV, ignore
|
|
573
629
|
}
|
|
574
630
|
});
|
|
575
|
-
|
|
631
|
+
|
|
576
632
|
return keysToDelete.length;
|
|
577
633
|
};
|
|
578
634
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pdtf/schemas",
|
|
3
|
-
"version": "3.6.0-
|
|
3
|
+
"version": "3.6.0-dev.3",
|
|
4
4
|
"description": "Property Data Trust Framework Schemas and Utilities",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"directories": {
|
|
@@ -9,7 +9,11 @@
|
|
|
9
9
|
"scripts": {
|
|
10
10
|
"test": "jest",
|
|
11
11
|
"test:watch": "jest --watch",
|
|
12
|
-
"extract-overlays": "cd src/utils && node extractOverlay.js"
|
|
12
|
+
"extract-overlays": "cd src/utils && node extractOverlay.js",
|
|
13
|
+
"extract-extension-overlays": "cd src/utils && node extractExtensionOverlays.js",
|
|
14
|
+
"publish:dev": "npm publish --tag dev",
|
|
15
|
+
"publish:next": "npm publish --tag next",
|
|
16
|
+
"publish:latest": "npm publish --tag latest"
|
|
13
17
|
},
|
|
14
18
|
"repository": {
|
|
15
19
|
"type": "git",
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance for AI coding agents when working with code in this repository.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
This repository contains the Property Data Trust Framework (PDTF) schemas - JSON Schema-based definitions for digital residential property data exchange in England and Wales. The framework enables frictionless exchange of property data between software products and services.
|
|
8
|
+
|
|
9
|
+
## Commands
|
|
10
|
+
|
|
11
|
+
### Testing
|
|
12
|
+
```bash
|
|
13
|
+
npm test # Run all tests
|
|
14
|
+
npm run test:watch # Run tests in watch mode
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
### Development
|
|
18
|
+
```bash
|
|
19
|
+
npm install # Install dependencies
|
|
20
|
+
npm run extract-overlays # Regenerate v3 schemas and overlays from combined.json
|
|
21
|
+
npm run extract-extension-overlays # Regenerate v3 extension overlays from combined.json
|
|
22
|
+
npm run publish:dev # Publish the dev branch package to npm tag dev
|
|
23
|
+
npm run publish:next # Publish the next branch package to npm tag next
|
|
24
|
+
npm run publish:latest # Publish the main branch package to npm tag latest
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
**Important**: `src/schemas/v3/combined.json` is the source of truth for v3 schema changes. Never edit generated schema artifacts directly; there are no exceptions. Utility/source files may be edited normally. After changing `combined.json`, always run both overlay extraction commands so derived files stay in sync.
|
|
28
|
+
|
|
29
|
+
## Architecture
|
|
30
|
+
|
|
31
|
+
### Schema System
|
|
32
|
+
The PDTF uses a flexible overlay system where a base transaction schema can be extended with form-specific overlays:
|
|
33
|
+
|
|
34
|
+
- **Base Schema**: Core transaction schema at `/src/schemas/v3/pdtf-transaction.json`
|
|
35
|
+
- **Overlays**: Form-specific extensions in `/src/schemas/v3/overlays/` (e.g., baspi5.json, ta6.json)
|
|
36
|
+
- **Merging**: Overlays are merged with the base schema using deepmerge with custom merge strategies
|
|
37
|
+
- **Generated Files**: `pdtf-transaction.json`, `skeleton.json`, `compactSkeleton.txt`, `src/schemas/v3/overlays/*.json`, and `src/schemas/v3/overlays/extensions/*.json` are generated from `combined.json`
|
|
38
|
+
|
|
39
|
+
### Key Components
|
|
40
|
+
|
|
41
|
+
1. **index.js**: Main module exposing schema utilities
|
|
42
|
+
- `getTransactionSchema(schemaId, overlays)`: Merges base schema with overlays
|
|
43
|
+
- `getValidator(schemaId, overlays)`: Returns AJV validator for schema
|
|
44
|
+
- `validateVerifiedClaims()`: Validates verified claims structure
|
|
45
|
+
|
|
46
|
+
2. **Schema Versions**: Currently on v3, with v2 still supported
|
|
47
|
+
- Use `https://trust.propdata.org.uk/schemas/v3/pdtf-transaction.json` for v3
|
|
48
|
+
|
|
49
|
+
3. **Overlay System**: Supports multiple UK property forms
|
|
50
|
+
- BASPI (v4 and v5)
|
|
51
|
+
- Law Society TA forms (TA6, TA7, TA10)
|
|
52
|
+
- NTS forms (2023 and 2025 versions)
|
|
53
|
+
- CON29R, PIQ, RDS, and others
|
|
54
|
+
|
|
55
|
+
### Testing Approach
|
|
56
|
+
Tests in `/src/tests/` validate:
|
|
57
|
+
- Schema structure with different overlay combinations
|
|
58
|
+
- Path validation for nested properties
|
|
59
|
+
- Custom overlay merging
|
|
60
|
+
- Verified claims validation
|
|
61
|
+
|
|
62
|
+
Use existing test patterns when adding new tests.
|
|
63
|
+
|
|
64
|
+
## Branch And Release Workflow
|
|
65
|
+
|
|
66
|
+
This repository publishes `@pdtf/schemas` through three branches and npm
|
|
67
|
+
dist-tags:
|
|
68
|
+
|
|
69
|
+
- `main` -> npm `latest`: stable PDTF releases for broad industry use.
|
|
70
|
+
- `next` -> npm `next`: tested capabilities proposed for the next managed PDTF
|
|
71
|
+
point release.
|
|
72
|
+
- `dev` -> npm `dev`: the unstable coal face for faster-moving integration work
|
|
73
|
+
and early adopters.
|
|
74
|
+
|
|
75
|
+
PRs may be merged into `dev` to prove out work before it is ready for the managed
|
|
76
|
+
release path. Once a `dev` PR has been tested and is suitable for standards
|
|
77
|
+
review, promote the same change into `next` via a focused PR. Do not treat `dev`
|
|
78
|
+
as the standard, and do not publish `dev` or `next` builds to npm `latest`.
|
|
79
|
+
|
|
80
|
+
Promotion is automatic by default: after a PR is merged into `dev`,
|
|
81
|
+
`.github/workflows/promote-dev-to-next.yml` creates a matching PR into `next` by
|
|
82
|
+
cherry-picking the merged dev PR. Add the `no-promote-next` label before merging
|
|
83
|
+
a dev PR only when it should stay out of the `next` review queue. Reviewers
|
|
84
|
+
should still inspect the promotion PR, resolve conflicts, and adjust
|
|
85
|
+
release/version metadata if needed before merging to `next`.
|
|
86
|
+
|
|
87
|
+
Each npm publish needs a unique semver version. Use `-dev.N` versions on `dev`,
|
|
88
|
+
prerelease versions on `next`, and normal release versions on `main`.
|
|
89
|
+
|
|
90
|
+
Consumer-specific compatibility profiles belong in the consuming application or
|
|
91
|
+
service unless the capability becomes generic PDTF package functionality.
|
|
92
|
+
Consumers should pin/hash supplied schemas and use their own target-profile
|
|
93
|
+
configuration for API calls and webhooks.
|
|
94
|
+
|
|
95
|
+
See `docs/branch-release-workflow.md` for the full workflow.
|
|
96
|
+
|
|
97
|
+
## Important Notes
|
|
98
|
+
|
|
99
|
+
- All schemas use JSON Schema Draft 07
|
|
100
|
+
- The repository publishes to npm as `@pdtf/schemas`
|
|
101
|
+
- Overlays may contain fields from licensed forms (BASPI, PIQ, Law Society) - ensure compliance when rendering data
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Property Data Trust Framework
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|