@pdtf/schemas 3.6.0-dev.7 → 3.6.0-dev.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/busy-spence-79c6bf/CLAUDE.md +101 -0
- package/busy-spence-79c6bf/LICENSE +21 -0
- package/busy-spence-79c6bf/README.md +435 -0
- package/busy-spence-79c6bf/docs/branch-release-workflow.md +138 -0
- package/busy-spence-79c6bf/docs/sef25-extensions-ui-spec.md +355 -0
- package/busy-spence-79c6bf/index.js +654 -0
- package/busy-spence-79c6bf/package-lock.json +7299 -0
- package/busy-spence-79c6bf/package.json +44 -0
- package/busy-spence-79c6bf/scripts/ta6ed6-titles.js +403 -0
- package/busy-spence-79c6bf/scripts/ta7ed5-titles.js +183 -0
- package/busy-spence-79c6bf/src/examples/v1/exampleAddParticipantVouch.json +32 -0
- package/busy-spence-79c6bf/src/examples/v1/exampleDocumentedVouch.json +40 -0
- package/busy-spence-79c6bf/src/examples/v1/exampleElectronicRecord.json +30 -0
- package/busy-spence-79c6bf/src/examples/v1/exampleTransaction.json +878 -0
- package/busy-spence-79c6bf/src/examples/v1/exampleVouch.json +25 -0
- package/busy-spence-79c6bf/src/examples/v2/exampleTransaction.json +901 -0
- package/busy-spence-79c6bf/src/examples/v3/exampleAddParticipantVouch.json +38 -0
- package/busy-spence-79c6bf/src/examples/v3/exampleCustomOverlay.json +55 -0
- package/busy-spence-79c6bf/src/examples/v3/exampleCustomOverlay2.json +93 -0
- package/busy-spence-79c6bf/src/examples/v3/exampleDocumentedVouch.json +47 -0
- package/busy-spence-79c6bf/src/examples/v3/exampleElectronicRecord.json +36 -0
- package/busy-spence-79c6bf/src/examples/v3/exampleTransaction.json +1038 -0
- package/busy-spence-79c6bf/src/examples/v3/exampleVouch.json +32 -0
- package/busy-spence-79c6bf/src/mappings/SendPropertyDetailsRequestSchema.json +1588 -0
- package/busy-spence-79c6bf/src/mappings/adf.js +198 -0
- package/busy-spence-79c6bf/src/schemas/v1/GeoJSON.json +1279 -0
- package/busy-spence-79c6bf/src/schemas/v1/baspiNotes.html +102 -0
- package/busy-spence-79c6bf/src/schemas/v1/energy-performance-certificate.json +124 -0
- package/busy-spence-79c6bf/src/schemas/v1/freehold-information.json +2051 -0
- package/busy-spence-79c6bf/src/schemas/v1/leasehold-information.json +2064 -0
- package/busy-spence-79c6bf/src/schemas/v1/legal-information.json +1045 -0
- package/busy-spence-79c6bf/src/schemas/v1/material-facts.json +2109 -0
- package/busy-spence-79c6bf/src/schemas/v1/pdtf-transaction-search-results.json +40 -0
- package/busy-spence-79c6bf/src/schemas/v1/pdtf-transaction.json +191 -0
- package/busy-spence-79c6bf/src/schemas/v1/searches/drainage-and-water.json +261 -0
- package/busy-spence-79c6bf/src/schemas/v1/searches/local-land-charges.json +69 -0
- package/busy-spence-79c6bf/src/schemas/v1/searches/local-searches-required.json +857 -0
- package/busy-spence-79c6bf/src/schemas/v1/searches.json +237 -0
- package/busy-spence-79c6bf/src/schemas/v1/title-deed.json +841 -0
- package/busy-spence-79c6bf/src/schemas/v2/baspiNotes.html +102 -0
- package/busy-spence-79c6bf/src/schemas/v2/combined.json +37731 -0
- package/busy-spence-79c6bf/src/schemas/v2/overlays/baspi.json +8132 -0
- package/busy-spence-79c6bf/src/schemas/v2/overlays/con29DW.json +705 -0
- package/busy-spence-79c6bf/src/schemas/v2/overlays/con29R.json +2956 -0
- package/busy-spence-79c6bf/src/schemas/v2/overlays/fme1.json +1259 -0
- package/busy-spence-79c6bf/src/schemas/v2/overlays/llc1.json +25 -0
- package/busy-spence-79c6bf/src/schemas/v2/overlays/lpe1.json +2171 -0
- package/busy-spence-79c6bf/src/schemas/v2/overlays/nts.json +326 -0
- package/busy-spence-79c6bf/src/schemas/v2/overlays/oc1.json +2799 -0
- package/busy-spence-79c6bf/src/schemas/v2/overlays/piq.json +3419 -0
- package/busy-spence-79c6bf/src/schemas/v2/overlays/rds.json +3736 -0
- package/busy-spence-79c6bf/src/schemas/v2/overlays/ta10.json +5306 -0
- package/busy-spence-79c6bf/src/schemas/v2/overlays/ta6.json +4533 -0
- package/busy-spence-79c6bf/src/schemas/v2/overlays/ta7.json +1045 -0
- package/busy-spence-79c6bf/src/schemas/v2/pdtf-transaction.json +34351 -0
- package/busy-spence-79c6bf/src/schemas/v2/skeleton.json +3973 -0
- package/busy-spence-79c6bf/src/schemas/v3/combined.json +48643 -0
- package/busy-spence-79c6bf/src/schemas/v3/compactSkeleton.txt +4519 -0
- package/busy-spence-79c6bf/src/schemas/v3/overlays/README.md +299 -0
- package/busy-spence-79c6bf/src/schemas/v3/overlays/baspi4.json +8030 -0
- package/busy-spence-79c6bf/src/schemas/v3/overlays/baspi5.json +8180 -0
- package/busy-spence-79c6bf/src/schemas/v3/overlays/con29DW.json +716 -0
- package/busy-spence-79c6bf/src/schemas/v3/overlays/con29R.json +2981 -0
- package/busy-spence-79c6bf/src/schemas/v3/overlays/extensions/ac.json +334 -0
- package/busy-spence-79c6bf/src/schemas/v3/overlays/extensions/as.json +74 -0
- package/busy-spence-79c6bf/src/schemas/v3/overlays/extensions/dk.json +33 -0
- package/busy-spence-79c6bf/src/schemas/v3/overlays/extensions/dr.json +73 -0
- package/busy-spence-79c6bf/src/schemas/v3/overlays/extensions/er.json +85 -0
- package/busy-spence-79c6bf/src/schemas/v3/overlays/extensions/fd.json +75 -0
- package/busy-spence-79c6bf/src/schemas/v3/overlays/extensions/hi.json +51 -0
- package/busy-spence-79c6bf/src/schemas/v3/overlays/extensions/hs.json +73 -0
- package/busy-spence-79c6bf/src/schemas/v3/overlays/extensions/ic.json +94 -0
- package/busy-spence-79c6bf/src/schemas/v3/overlays/extensions/jk.json +96 -0
- package/busy-spence-79c6bf/src/schemas/v3/overlays/extensions/la.json +85 -0
- package/busy-spence-79c6bf/src/schemas/v3/overlays/extensions/lc.json +76 -0
- package/busy-spence-79c6bf/src/schemas/v3/overlays/extensions/ma.json +90 -0
- package/busy-spence-79c6bf/src/schemas/v3/overlays/extensions/mc.json +38 -0
- package/busy-spence-79c6bf/src/schemas/v3/overlays/extensions/mi.json +70 -0
- package/busy-spence-79c6bf/src/schemas/v3/overlays/extensions/nd.json +44 -0
- package/busy-spence-79c6bf/src/schemas/v3/overlays/extensions/oa.json +24 -0
- package/busy-spence-79c6bf/src/schemas/v3/overlays/extensions/oc.json +57 -0
- package/busy-spence-79c6bf/src/schemas/v3/overlays/extensions/pc.json +38 -0
- package/busy-spence-79c6bf/src/schemas/v3/overlays/extensions/ph.json +195 -0
- package/busy-spence-79c6bf/src/schemas/v3/overlays/extensions/rw.json +69 -0
- package/busy-spence-79c6bf/src/schemas/v3/overlays/extensions/sb.json +73 -0
- package/busy-spence-79c6bf/src/schemas/v3/overlays/extensions/sc.json +133 -0
- package/busy-spence-79c6bf/src/schemas/v3/overlays/extensions/sd.json +64 -0
- package/busy-spence-79c6bf/src/schemas/v3/overlays/extensions/sf.json +74 -0
- package/busy-spence-79c6bf/src/schemas/v3/overlays/extensions/sl.json +68 -0
- package/busy-spence-79c6bf/src/schemas/v3/overlays/extensions/ta.json +204 -0
- package/busy-spence-79c6bf/src/schemas/v3/overlays/extensions/tf.json +103 -0
- package/busy-spence-79c6bf/src/schemas/v3/overlays/extensions/tr.json +74 -0
- package/busy-spence-79c6bf/src/schemas/v3/overlays/extensions/wg.json +351 -0
- package/busy-spence-79c6bf/src/schemas/v3/overlays/fme1.json +1266 -0
- package/busy-spence-79c6bf/src/schemas/v3/overlays/llc1.json +25 -0
- package/busy-spence-79c6bf/src/schemas/v3/overlays/lpe1.json +2199 -0
- package/busy-spence-79c6bf/src/schemas/v3/overlays/nts.json +2159 -0
- package/busy-spence-79c6bf/src/schemas/v3/overlays/nts2.json +2744 -0
- package/busy-spence-79c6bf/src/schemas/v3/overlays/ntsl.json +1815 -0
- package/busy-spence-79c6bf/src/schemas/v3/overlays/ntsl2.json +2219 -0
- package/busy-spence-79c6bf/src/schemas/v3/overlays/oc1.json +2817 -0
- package/busy-spence-79c6bf/src/schemas/v3/overlays/piq.json +3324 -0
- package/busy-spence-79c6bf/src/schemas/v3/overlays/rds.json +3668 -0
- package/busy-spence-79c6bf/src/schemas/v3/overlays/sef25.json +1653 -0
- package/busy-spence-79c6bf/src/schemas/v3/overlays/sr24.json +38 -0
- package/busy-spence-79c6bf/src/schemas/v3/overlays/ta10.json +4645 -0
- package/busy-spence-79c6bf/src/schemas/v3/overlays/ta6.json +4572 -0
- package/busy-spence-79c6bf/src/schemas/v3/overlays/ta6ed6.json +6665 -0
- package/busy-spence-79c6bf/src/schemas/v3/overlays/ta7.json +1537 -0
- package/busy-spence-79c6bf/src/schemas/v3/overlays/ta7ed5.json +1585 -0
- package/busy-spence-79c6bf/src/schemas/v3/pdtf-transaction.json +41570 -0
- package/busy-spence-79c6bf/src/schemas/v3/skeleton.json +5767 -0
- package/busy-spence-79c6bf/src/schemas/verifiedClaims/README.md +21 -0
- package/busy-spence-79c6bf/src/schemas/verifiedClaims/pdtf-verified-claims.json +447 -0
- package/busy-spence-79c6bf/src/utils/compactSkeleton.js +84 -0
- package/busy-spence-79c6bf/src/utils/countTokens.js +67 -0
- package/busy-spence-79c6bf/src/utils/extractExtensionOverlays.js +633 -0
- package/busy-spence-79c6bf/src/utils/extractOverlay.js +381 -0
- package/busy-spence-79c6bf/src/utils/extractProperties.js +44 -0
- package/busy-spence-79c6bf/src/utils/listPathTitles.js +36 -0
- package/busy-spence-79c6bf/src/utils/minimalSkeleton.js +85 -0
- package/busy-spence-79c6bf/src/utils/pathList.csv +903 -0
- package/busy-spence-79c6bf/src/utils/pathSkeleton.js +181 -0
- package/busy-spence-79c6bf/ta6ed6-titles-plan.md +118 -0
- package/busy-spence-79c6bf/ta7ed5-titles-spec.md +89 -0
- package/package.json +1 -1
- package/src/schemas/v3/combined.json +225 -47
- package/src/schemas/v3/overlays/llc1.json +1 -2
- package/src/schemas/v3/overlays/ta6ed6.json +204 -75
- package/src/schemas/v3/overlays/ta7ed5.json +54 -20
|
@@ -0,0 +1,633 @@
|
|
|
1
|
+
const traverse = require("traverse");
|
|
2
|
+
const jp = require("jsonpointer");
|
|
3
|
+
const fs = require("fs");
|
|
4
|
+
const path = require("path");
|
|
5
|
+
|
|
6
|
+
const combinedSchema = require("../schemas/v3/combined.json");
|
|
7
|
+
|
|
8
|
+
// Derive ref-related field names from a refType
|
|
9
|
+
function getRefConfig(refType) {
|
|
10
|
+
if (refType === "nts2Ref") {
|
|
11
|
+
// Legacy mapping: nts2Ref -> ntsRef in output
|
|
12
|
+
return {
|
|
13
|
+
ref: "nts2Ref",
|
|
14
|
+
outputRef: "ntsRef",
|
|
15
|
+
required: "nts2Required",
|
|
16
|
+
title: "nts2Title",
|
|
17
|
+
description: "nts2Description",
|
|
18
|
+
enumKey: "nts2Enum",
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
if (refType === "sef25Ref") {
|
|
22
|
+
// SEF25 extensions also appear as ntsRef in output
|
|
23
|
+
return {
|
|
24
|
+
ref: "sef25Ref",
|
|
25
|
+
outputRef: "ntsRef",
|
|
26
|
+
required: "sef25Required",
|
|
27
|
+
title: "sef25Title",
|
|
28
|
+
description: "sef25Description",
|
|
29
|
+
enumKey: "sef25Enum",
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
// For other ref types, derive keys by replacing "Ref" suffix
|
|
33
|
+
return {
|
|
34
|
+
ref: refType,
|
|
35
|
+
outputRef: refType,
|
|
36
|
+
required: refType.replace("Ref", "Required"),
|
|
37
|
+
title: refType.replace("Ref", "Title"),
|
|
38
|
+
description: refType.replace("Ref", "Description"),
|
|
39
|
+
enumKey: refType.replace("Ref", "Enum"),
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Define the extension overlay mappings
|
|
44
|
+
const extensionMappings = {
|
|
45
|
+
// Outside areas
|
|
46
|
+
oa: {
|
|
47
|
+
name: "outsideAreas",
|
|
48
|
+
description: "Outside areas extension for NTS",
|
|
49
|
+
paths: [
|
|
50
|
+
"/properties/propertyPack/properties/residentialPropertyFeatures/properties/outsideAreas",
|
|
51
|
+
],
|
|
52
|
+
},
|
|
53
|
+
|
|
54
|
+
// Estate rentcharges for freehold
|
|
55
|
+
er: {
|
|
56
|
+
name: "estateRentcharges",
|
|
57
|
+
description: "Estate rentcharges for freehold properties",
|
|
58
|
+
paths: [
|
|
59
|
+
"/properties/propertyPack/properties/ownership/properties/ownershipsToBeTransferred/items/oneOf/0/properties/estateRentcharges",
|
|
60
|
+
],
|
|
61
|
+
},
|
|
62
|
+
|
|
63
|
+
// Managing agent contact details for leasehold
|
|
64
|
+
ma: {
|
|
65
|
+
name: "managingAgent",
|
|
66
|
+
description: "Managing agent contact details for leasehold",
|
|
67
|
+
paths: [
|
|
68
|
+
"/properties/propertyPack/properties/ownership/properties/ownershipsToBeTransferred/items/oneOf/2/properties/leaseholdInformation/properties/contactDetails",
|
|
69
|
+
],
|
|
70
|
+
},
|
|
71
|
+
|
|
72
|
+
// Transfer fees for leasehold
|
|
73
|
+
tf: {
|
|
74
|
+
name: "transferFees",
|
|
75
|
+
description: "Transfer fees for leasehold",
|
|
76
|
+
paths: [
|
|
77
|
+
"/properties/propertyPack/properties/ownership/properties/ownershipsToBeTransferred/items/oneOf/2/properties/leaseholdInformation/properties/serviceCharge/oneOf/1/properties/transferFees",
|
|
78
|
+
],
|
|
79
|
+
},
|
|
80
|
+
|
|
81
|
+
// Main construction type if standard
|
|
82
|
+
mc: {
|
|
83
|
+
name: "mainConstruction",
|
|
84
|
+
description: "Main construction type if standard form",
|
|
85
|
+
paths: [
|
|
86
|
+
"/properties/propertyPack/properties/typeOfConstruction/properties/isStandardForm/oneOf/0/properties/constructionType",
|
|
87
|
+
],
|
|
88
|
+
},
|
|
89
|
+
|
|
90
|
+
// Loft access and details
|
|
91
|
+
la: {
|
|
92
|
+
name: "loftAccess",
|
|
93
|
+
description: "Loft access and details",
|
|
94
|
+
paths: [
|
|
95
|
+
"/properties/propertyPack/properties/typeOfConstruction/properties/loft",
|
|
96
|
+
],
|
|
97
|
+
},
|
|
98
|
+
|
|
99
|
+
// Spray foam insulation
|
|
100
|
+
sf: {
|
|
101
|
+
name: "sprayFoam",
|
|
102
|
+
description: "Spray foam insulation",
|
|
103
|
+
paths: [
|
|
104
|
+
"/properties/propertyPack/properties/typeOfConstruction/properties/sprayFoamInsulation",
|
|
105
|
+
],
|
|
106
|
+
},
|
|
107
|
+
|
|
108
|
+
// Specialist issues - dry rot
|
|
109
|
+
dr: {
|
|
110
|
+
name: "dryRot",
|
|
111
|
+
description: "Dry rot treatment specialist issue",
|
|
112
|
+
paths: [
|
|
113
|
+
"/properties/propertyPack/properties/specialistIssues/properties/dryRotEtcTreatment",
|
|
114
|
+
],
|
|
115
|
+
},
|
|
116
|
+
|
|
117
|
+
// Specialist issues - asbestos
|
|
118
|
+
as: {
|
|
119
|
+
name: "asbestos",
|
|
120
|
+
description: "Asbestos specialist issue",
|
|
121
|
+
paths: [
|
|
122
|
+
"/properties/propertyPack/properties/specialistIssues/properties/containsAsbestos",
|
|
123
|
+
],
|
|
124
|
+
},
|
|
125
|
+
|
|
126
|
+
// Specialist issues - Japanese knotweed
|
|
127
|
+
jk: {
|
|
128
|
+
name: "japaneseKnotweed",
|
|
129
|
+
description: "Japanese knotweed specialist issue",
|
|
130
|
+
paths: [
|
|
131
|
+
"/properties/propertyPack/properties/specialistIssues/properties/japaneseKnotweed",
|
|
132
|
+
],
|
|
133
|
+
},
|
|
134
|
+
|
|
135
|
+
// Specialist issues - subsidence
|
|
136
|
+
sb: {
|
|
137
|
+
name: "subsidence",
|
|
138
|
+
description: "Subsidence or structural fault specialist issue",
|
|
139
|
+
paths: [
|
|
140
|
+
"/properties/propertyPack/properties/specialistIssues/properties/subsidenceOrStructuralFault",
|
|
141
|
+
],
|
|
142
|
+
},
|
|
143
|
+
|
|
144
|
+
// Specialist issues - health and safety
|
|
145
|
+
hs: {
|
|
146
|
+
name: "healthSafety",
|
|
147
|
+
description: "Health and safety specialist issue",
|
|
148
|
+
paths: [
|
|
149
|
+
"/properties/propertyPack/properties/specialistIssues/properties/ongoingHealthOrSafetyIssue",
|
|
150
|
+
],
|
|
151
|
+
},
|
|
152
|
+
|
|
153
|
+
// Solar panels leased
|
|
154
|
+
sl: {
|
|
155
|
+
name: "solarPanelsLeased",
|
|
156
|
+
description: "Solar panels ownership details",
|
|
157
|
+
paths: [
|
|
158
|
+
"/properties/propertyPack/properties/electricity/properties/solarPanels/oneOf/1/properties/panelsOwnedOutright",
|
|
159
|
+
],
|
|
160
|
+
},
|
|
161
|
+
|
|
162
|
+
// Heating installation date
|
|
163
|
+
hi: {
|
|
164
|
+
name: "heatingInstalled",
|
|
165
|
+
description: "Central heating installation date",
|
|
166
|
+
paths: [
|
|
167
|
+
"/properties/propertyPack/properties/heating/properties/heatingSystem/oneOf/1/properties/centralHeatingDetails/properties/centralHeatingInstalled",
|
|
168
|
+
],
|
|
169
|
+
},
|
|
170
|
+
|
|
171
|
+
// Flood defences
|
|
172
|
+
fd: {
|
|
173
|
+
name: "floodDefences",
|
|
174
|
+
description: "Flood defence information",
|
|
175
|
+
paths: [
|
|
176
|
+
"/properties/propertyPack/properties/environmentalIssues/properties/flooding/properties/floodDefences",
|
|
177
|
+
],
|
|
178
|
+
},
|
|
179
|
+
|
|
180
|
+
// Other property in chain
|
|
181
|
+
oc: {
|
|
182
|
+
name: "otherPropertyChain",
|
|
183
|
+
description: "Other property in chain dependency",
|
|
184
|
+
paths: [
|
|
185
|
+
"/properties/propertyPack/properties/completionAndMoving/properties/otherPropertyInChain",
|
|
186
|
+
],
|
|
187
|
+
},
|
|
188
|
+
|
|
189
|
+
// Private supply costs (water & sewerage)
|
|
190
|
+
sc: {
|
|
191
|
+
name: "supplyCosts",
|
|
192
|
+
description: "Associated costs for private water and sewerage supply",
|
|
193
|
+
refType: "sef25Ref",
|
|
194
|
+
paths: [
|
|
195
|
+
"/properties/propertyPack/properties/waterAndDrainage/properties/water/properties/mainsWater/oneOf/0/properties/associatedCost",
|
|
196
|
+
"/properties/propertyPack/properties/waterAndDrainage/properties/drainage/properties/mainsFoulDrainage/oneOf/2/properties/associatedCost",
|
|
197
|
+
],
|
|
198
|
+
},
|
|
199
|
+
|
|
200
|
+
// Parking permit costs
|
|
201
|
+
pc: {
|
|
202
|
+
name: "parkingPermitCost",
|
|
203
|
+
description: "Parking permit cost and frequency",
|
|
204
|
+
refType: "sef25Ref",
|
|
205
|
+
paths: [
|
|
206
|
+
"/properties/propertyPack/properties/parking/properties/controlledParking/oneOf/1/properties/costOfPermit",
|
|
207
|
+
"/properties/propertyPack/properties/parking/properties/controlledParking/oneOf/1/properties/costOfPermitFrequency",
|
|
208
|
+
],
|
|
209
|
+
},
|
|
210
|
+
|
|
211
|
+
// Property hazards
|
|
212
|
+
ph: {
|
|
213
|
+
name: "propertyHazards",
|
|
214
|
+
description: "Property hazards and known issues",
|
|
215
|
+
refType: "sef25Ref",
|
|
216
|
+
paths: [
|
|
217
|
+
"/properties/propertyPack/properties/specialistIssues",
|
|
218
|
+
],
|
|
219
|
+
},
|
|
220
|
+
|
|
221
|
+
// Dropped kerb access to parking
|
|
222
|
+
dk: {
|
|
223
|
+
name: "droppedKerbAccess",
|
|
224
|
+
description: "Dropped kerb access to parking",
|
|
225
|
+
refType: "sef25Ref",
|
|
226
|
+
paths: [
|
|
227
|
+
"/properties/propertyPack/properties/parking/properties/droppedKerbAccess",
|
|
228
|
+
],
|
|
229
|
+
},
|
|
230
|
+
|
|
231
|
+
// Private right of way
|
|
232
|
+
rw: {
|
|
233
|
+
name: "privateRightOfWay",
|
|
234
|
+
description: "Private right of way",
|
|
235
|
+
refType: "sef25Ref",
|
|
236
|
+
paths: [
|
|
237
|
+
"/properties/propertyPack/properties/rightsAndInformalArrangements/properties/rightsOrArrangements/properties/privateRightOfWay",
|
|
238
|
+
],
|
|
239
|
+
},
|
|
240
|
+
|
|
241
|
+
// Storm, fire or flood damage
|
|
242
|
+
sd: {
|
|
243
|
+
name: "stormFireFloodDamage",
|
|
244
|
+
description: "Storm, fire or flood damage",
|
|
245
|
+
refType: "sef25Ref",
|
|
246
|
+
paths: [
|
|
247
|
+
"/properties/propertyPack/properties/environmentalIssues/properties/stormFireFloodDamage",
|
|
248
|
+
],
|
|
249
|
+
},
|
|
250
|
+
|
|
251
|
+
// Solar panel lease costs
|
|
252
|
+
lc: {
|
|
253
|
+
name: "solarLeaseCosts",
|
|
254
|
+
description: "Solar panel lease costs",
|
|
255
|
+
refType: "sef25Ref",
|
|
256
|
+
paths: [
|
|
257
|
+
"/properties/propertyPack/properties/electricity/properties/solarPanels/oneOf/1/properties/panelsOwnedOutright/oneOf/1/properties/associatedCost",
|
|
258
|
+
],
|
|
259
|
+
},
|
|
260
|
+
|
|
261
|
+
// Warranties and guarantees upfront
|
|
262
|
+
wg: {
|
|
263
|
+
name: "warrantiesGuarantees",
|
|
264
|
+
description: "Warranties and guarantees upfront Y/N for SEF25",
|
|
265
|
+
refType: "sef25Ref",
|
|
266
|
+
paths: [
|
|
267
|
+
"/properties/propertyPack/properties/guaranteesWarrantiesAndIndemnityInsurances",
|
|
268
|
+
],
|
|
269
|
+
},
|
|
270
|
+
|
|
271
|
+
// Insurance claims upfront
|
|
272
|
+
ic: {
|
|
273
|
+
name: "insuranceClaims",
|
|
274
|
+
description: "Insurance claims upfront for SEF25",
|
|
275
|
+
refType: "sef25Ref",
|
|
276
|
+
paths: [
|
|
277
|
+
"/properties/propertyPack/properties/insurance",
|
|
278
|
+
],
|
|
279
|
+
},
|
|
280
|
+
|
|
281
|
+
// Neighbour development upfront
|
|
282
|
+
nd: {
|
|
283
|
+
name: "neighbourDevelopment",
|
|
284
|
+
description: "Neighbour development upfront for SEF25",
|
|
285
|
+
refType: "sef25Ref",
|
|
286
|
+
paths: [
|
|
287
|
+
"/properties/propertyPack/properties/notices/properties/neighbourDevelopment",
|
|
288
|
+
],
|
|
289
|
+
},
|
|
290
|
+
|
|
291
|
+
// Other material issue upfront
|
|
292
|
+
mi: {
|
|
293
|
+
name: "otherMaterialIssue",
|
|
294
|
+
description: "Other material issue upfront for SEF25",
|
|
295
|
+
refType: "sef25Ref",
|
|
296
|
+
paths: [
|
|
297
|
+
"/properties/propertyPack/properties/additionalInformation/properties/otherMaterialIssue",
|
|
298
|
+
],
|
|
299
|
+
},
|
|
300
|
+
|
|
301
|
+
// Title restrictions for freehold
|
|
302
|
+
tr: {
|
|
303
|
+
name: "titleRestrictions",
|
|
304
|
+
description: "Title restrictions for freehold properties",
|
|
305
|
+
refType: "sef25Ref",
|
|
306
|
+
paths: [
|
|
307
|
+
"/properties/propertyPack/properties/ownership/properties/ownershipsToBeTransferred/items/oneOf/0/properties/titleRestrictions",
|
|
308
|
+
],
|
|
309
|
+
},
|
|
310
|
+
|
|
311
|
+
// Alterations and changes
|
|
312
|
+
ac: {
|
|
313
|
+
name: "alterationsAndChanges",
|
|
314
|
+
description: "Selected alterations and changes fields for SEF25",
|
|
315
|
+
refType: "sef25Ref",
|
|
316
|
+
preserveDiscriminators: true,
|
|
317
|
+
paths: [
|
|
318
|
+
"/properties/propertyPack/properties/alterationsAndChanges/properties/extension/properties/yesNo",
|
|
319
|
+
"/properties/propertyPack/properties/alterationsAndChanges/properties/extension/oneOf/1/properties/details",
|
|
320
|
+
"/properties/propertyPack/properties/alterationsAndChanges/properties/extension/oneOf/1/properties/planningPermission/properties/yesNo",
|
|
321
|
+
"/properties/propertyPack/properties/alterationsAndChanges/properties/extension/oneOf/1/properties/buildingRegApproval/properties/yesNo",
|
|
322
|
+
"/properties/propertyPack/properties/alterationsAndChanges/properties/loftConversion/properties/yesNo",
|
|
323
|
+
"/properties/propertyPack/properties/alterationsAndChanges/properties/loftConversion/oneOf/1/properties/details",
|
|
324
|
+
"/properties/propertyPack/properties/alterationsAndChanges/properties/loftConversion/oneOf/1/properties/planningPermission/properties/yesNo",
|
|
325
|
+
"/properties/propertyPack/properties/alterationsAndChanges/properties/loftConversion/oneOf/1/properties/buildingRegApproval/properties/yesNo",
|
|
326
|
+
"/properties/propertyPack/properties/alterationsAndChanges/properties/garageConversion/properties/yesNo",
|
|
327
|
+
"/properties/propertyPack/properties/alterationsAndChanges/properties/garageConversion/oneOf/1/properties/details",
|
|
328
|
+
"/properties/propertyPack/properties/alterationsAndChanges/properties/garageConversion/oneOf/1/properties/planningPermission/properties/yesNo",
|
|
329
|
+
"/properties/propertyPack/properties/alterationsAndChanges/properties/garageConversion/oneOf/1/properties/buildingRegApproval/properties/yesNo",
|
|
330
|
+
"/properties/propertyPack/properties/alterationsAndChanges/properties/removalOfInternalWalls/properties/yesNo",
|
|
331
|
+
"/properties/propertyPack/properties/alterationsAndChanges/properties/removalOfInternalWalls/oneOf/1/properties/details",
|
|
332
|
+
"/properties/propertyPack/properties/alterationsAndChanges/properties/removalOfInternalWalls/oneOf/1/properties/planningPermission/properties/yesNo",
|
|
333
|
+
"/properties/propertyPack/properties/alterationsAndChanges/properties/removalOfInternalWalls/oneOf/1/properties/buildingRegApproval/properties/yesNo",
|
|
334
|
+
"/properties/propertyPack/properties/alterationsAndChanges/properties/changeOfUse/properties/yesNo",
|
|
335
|
+
"/properties/propertyPack/properties/alterationsAndChanges/properties/changeOfUse/oneOf/1/properties/details",
|
|
336
|
+
"/properties/propertyPack/properties/alterationsAndChanges/properties/changeOfUse/oneOf/1/properties/planningPermission/properties/yesNo",
|
|
337
|
+
"/properties/propertyPack/properties/alterationsAndChanges/properties/changeOfUse/oneOf/1/properties/buildingRegApproval/properties/yesNo",
|
|
338
|
+
],
|
|
339
|
+
},
|
|
340
|
+
|
|
341
|
+
// TA6 edition 6 compatibility for shared MI/NTS validation
|
|
342
|
+
ta: {
|
|
343
|
+
name: "ta6Ed6Compatibility",
|
|
344
|
+
description:
|
|
345
|
+
"Compatibility enum ranges for validating shared PDTF state containing TA6 edition 6 answers",
|
|
346
|
+
refType: "ta6ed6CompatRef",
|
|
347
|
+
paths: [
|
|
348
|
+
"/properties/propertyPack/properties/parking",
|
|
349
|
+
"/properties/propertyPack/properties/heating",
|
|
350
|
+
"/properties/propertyPack/properties/rightsAndInformalArrangements",
|
|
351
|
+
"/properties/propertyPack/properties/legalBoundaries",
|
|
352
|
+
],
|
|
353
|
+
},
|
|
354
|
+
};
|
|
355
|
+
|
|
356
|
+
// Function to extract properties at specific paths with given ref type
|
|
357
|
+
function extractPathsWithRef(
|
|
358
|
+
schema,
|
|
359
|
+
paths,
|
|
360
|
+
refConfig,
|
|
361
|
+
preserveDiscriminators = false
|
|
362
|
+
) {
|
|
363
|
+
const result = {};
|
|
364
|
+
|
|
365
|
+
paths.forEach((path) => {
|
|
366
|
+
try {
|
|
367
|
+
const value = jp.get(schema, path);
|
|
368
|
+
if (value && hasRef(value, refConfig)) {
|
|
369
|
+
// Set the value at the same path in result
|
|
370
|
+
jp.set(result, path, extractRefProperties(value, refConfig));
|
|
371
|
+
if (preserveDiscriminators) {
|
|
372
|
+
addAncestorDiscriminators(result, schema, path);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
} catch (err) {
|
|
376
|
+
console.warn(`Path not found: ${path}`);
|
|
377
|
+
}
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
return result;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
function addAncestorDiscriminators(result, schema, path) {
|
|
384
|
+
const parts = path.split("/").filter(Boolean);
|
|
385
|
+
|
|
386
|
+
for (let index = 1; index <= parts.length; index += 1) {
|
|
387
|
+
const ancestorPath = `/${parts.slice(0, index).join("/")}`;
|
|
388
|
+
|
|
389
|
+
try {
|
|
390
|
+
const schemaNode = jp.get(schema, ancestorPath);
|
|
391
|
+
if (!schemaNode?.discriminator) continue;
|
|
392
|
+
|
|
393
|
+
const resultNode = jp.get(result, ancestorPath);
|
|
394
|
+
if (resultNode && typeof resultNode === "object") {
|
|
395
|
+
resultNode.discriminator = schemaNode.discriminator;
|
|
396
|
+
}
|
|
397
|
+
} catch (err) {
|
|
398
|
+
// Ancestor was not materialised by this selected path.
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
// Check if an object or its descendants have the specified ref
|
|
404
|
+
function hasRef(obj, refConfig) {
|
|
405
|
+
let found = false;
|
|
406
|
+
traverse(obj).forEach(function (element) {
|
|
407
|
+
if (element && element[refConfig.ref]) {
|
|
408
|
+
found = true;
|
|
409
|
+
this.stop();
|
|
410
|
+
}
|
|
411
|
+
});
|
|
412
|
+
return found;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
// Extract only ref-specific properties
|
|
416
|
+
function extractRefProperties(obj, refConfig, parentKey) {
|
|
417
|
+
const result = {};
|
|
418
|
+
|
|
419
|
+
// Copy ref-specific metadata at current level
|
|
420
|
+
if (obj[refConfig.ref]) result[refConfig.outputRef] = obj[refConfig.ref];
|
|
421
|
+
if (obj[refConfig.required]) result.required = obj[refConfig.required];
|
|
422
|
+
if (obj[refConfig.title]) result.title = obj[refConfig.title];
|
|
423
|
+
if (obj[refConfig.description]) result.description = obj[refConfig.description];
|
|
424
|
+
if (obj[refConfig.enumKey]) result.enum = obj[refConfig.enumKey];
|
|
425
|
+
|
|
426
|
+
// Handle discriminator
|
|
427
|
+
if (obj.discriminator) {
|
|
428
|
+
result.discriminator = obj.discriminator;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
// Recursively process properties
|
|
432
|
+
if (obj.properties) {
|
|
433
|
+
result.properties = {};
|
|
434
|
+
Object.keys(obj.properties).forEach((key) => {
|
|
435
|
+
const prop = obj.properties[key];
|
|
436
|
+
if (hasRef(prop, refConfig)) {
|
|
437
|
+
result.properties[key] = extractRefProperties(prop, refConfig, key);
|
|
438
|
+
}
|
|
439
|
+
});
|
|
440
|
+
// Only keep properties if we found some with ref
|
|
441
|
+
if (Object.keys(result.properties).length === 0) {
|
|
442
|
+
delete result.properties;
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
// Handle arrays
|
|
447
|
+
if (obj.items) {
|
|
448
|
+
if (hasRef(obj.items, refConfig)) {
|
|
449
|
+
result.items = extractRefProperties(obj.items, refConfig);
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
// Handle oneOf
|
|
454
|
+
if (obj.oneOf) {
|
|
455
|
+
// Always preserve the full array structure and order
|
|
456
|
+
const processedOneOf = obj.oneOf.map((schema, index) => {
|
|
457
|
+
if (hasRef(schema, refConfig)) {
|
|
458
|
+
const extracted = extractRefProperties(schema, refConfig);
|
|
459
|
+
// For oneOf schemas, we need to preserve discriminator enum values
|
|
460
|
+
if (obj.discriminator && schema.properties) {
|
|
461
|
+
const propName = obj.discriminator.propertyName;
|
|
462
|
+
if (schema.properties[propName]) {
|
|
463
|
+
if (!extracted.properties) extracted.properties = {};
|
|
464
|
+
extracted.properties[propName] = {
|
|
465
|
+
enum:
|
|
466
|
+
schema.properties[propName][refConfig.enumKey] ||
|
|
467
|
+
schema.properties[propName].enum,
|
|
468
|
+
};
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
// Also preserve base enum values for all other properties in the extension
|
|
472
|
+
if (schema.properties) {
|
|
473
|
+
if (!extracted.properties) extracted.properties = {};
|
|
474
|
+
Object.keys(schema.properties).forEach((propName) => {
|
|
475
|
+
const prop = schema.properties[propName];
|
|
476
|
+
if (prop.enum) {
|
|
477
|
+
if (!extracted.properties[propName]) {
|
|
478
|
+
extracted.properties[propName] = {
|
|
479
|
+
enum: prop.enum,
|
|
480
|
+
};
|
|
481
|
+
} else if (!extracted.properties[propName].enum) {
|
|
482
|
+
// If the property exists but doesn't have enum, add it
|
|
483
|
+
extracted.properties[propName].enum = prop.enum;
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
});
|
|
487
|
+
}
|
|
488
|
+
return extracted;
|
|
489
|
+
} else {
|
|
490
|
+
// If this branch doesn't have ref, preserve the base discriminator enum
|
|
491
|
+
if (obj.discriminator && schema.properties) {
|
|
492
|
+
const propName = obj.discriminator.propertyName;
|
|
493
|
+
if (schema.properties[propName]) {
|
|
494
|
+
return {
|
|
495
|
+
properties: {
|
|
496
|
+
[propName]: {
|
|
497
|
+
enum: schema.properties[propName].enum,
|
|
498
|
+
},
|
|
499
|
+
},
|
|
500
|
+
};
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
// If no discriminator, return empty object to preserve structure
|
|
504
|
+
return {};
|
|
505
|
+
}
|
|
506
|
+
});
|
|
507
|
+
result.oneOf = processedOneOf;
|
|
508
|
+
|
|
509
|
+
// --- NEW: If this is an extension property inside a oneOf, promote it to the parent overlay ---
|
|
510
|
+
// If parentKey is set, and this object has extension metadata, return a stub for the parent
|
|
511
|
+
if (
|
|
512
|
+
parentKey &&
|
|
513
|
+
(result[refConfig.outputRef] || result.required || result.discriminator)
|
|
514
|
+
) {
|
|
515
|
+
// This is an extension property inside a oneOf branch
|
|
516
|
+
// Return a stub for the parent property with metadata and oneOf structure
|
|
517
|
+
const parentStub = {};
|
|
518
|
+
Object.assign(parentStub, result);
|
|
519
|
+
return parentStub;
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
// Copy other JSON Schema keywords that might be present
|
|
524
|
+
[
|
|
525
|
+
"type",
|
|
526
|
+
"format",
|
|
527
|
+
"minimum",
|
|
528
|
+
"maximum",
|
|
529
|
+
"minLength",
|
|
530
|
+
"maxLength",
|
|
531
|
+
"minItems",
|
|
532
|
+
"maxItems",
|
|
533
|
+
].forEach((keyword) => {
|
|
534
|
+
if (obj[keyword] !== undefined) {
|
|
535
|
+
result[keyword] = obj[keyword];
|
|
536
|
+
}
|
|
537
|
+
});
|
|
538
|
+
|
|
539
|
+
return result;
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
// Add required array at parent levels if needed
|
|
543
|
+
function addRequiredArrays(overlay, schema, refConfig) {
|
|
544
|
+
traverse(overlay).forEach(function (node) {
|
|
545
|
+
if (node && node.properties) {
|
|
546
|
+
const schemaPath = "/" + this.path.join("/");
|
|
547
|
+
try {
|
|
548
|
+
const schemaNode = jp.get(schema, schemaPath);
|
|
549
|
+
if (schemaNode && schemaNode[refConfig.required]) {
|
|
550
|
+
// Filter to only include properties that exist in this overlay
|
|
551
|
+
const overlayProps = Object.keys(node.properties);
|
|
552
|
+
const requiredProps = schemaNode[refConfig.required].filter((prop) =>
|
|
553
|
+
overlayProps.includes(prop)
|
|
554
|
+
);
|
|
555
|
+
if (requiredProps.length > 0) {
|
|
556
|
+
node.required = requiredProps;
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
} catch (err) {
|
|
560
|
+
// Path doesn't exist in schema, skip
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
});
|
|
564
|
+
return overlay;
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
// Annotate intermediate nodes with refs from the source schema
|
|
568
|
+
// This ensures every level of the overlay tree carries an ntsRef
|
|
569
|
+
function addIntermediateRefs(overlay, schema, refConfig) {
|
|
570
|
+
traverse(overlay).forEach(function (node) {
|
|
571
|
+
if (node && typeof node === "object" && !Array.isArray(node) && node.properties) {
|
|
572
|
+
// Skip if this node already has a ref
|
|
573
|
+
if (node[refConfig.outputRef]) return;
|
|
574
|
+
|
|
575
|
+
const schemaPath = "/" + this.path.join("/");
|
|
576
|
+
try {
|
|
577
|
+
const schemaNode = jp.get(schema, schemaPath);
|
|
578
|
+
if (!schemaNode) return;
|
|
579
|
+
// When the output key differs from the source key (e.g. sef25Ref -> ntsRef),
|
|
580
|
+
// prefer the schema's existing outputRef on intermediate parents so we
|
|
581
|
+
// don't clobber legitimate NTS refs when the extension is later merged.
|
|
582
|
+
if (
|
|
583
|
+
refConfig.ref !== refConfig.outputRef &&
|
|
584
|
+
schemaNode[refConfig.outputRef]
|
|
585
|
+
) {
|
|
586
|
+
node[refConfig.outputRef] = schemaNode[refConfig.outputRef];
|
|
587
|
+
} else if (schemaNode[refConfig.ref]) {
|
|
588
|
+
node[refConfig.outputRef] = schemaNode[refConfig.ref];
|
|
589
|
+
}
|
|
590
|
+
} catch (err) {
|
|
591
|
+
// Path doesn't exist in schema, skip
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
});
|
|
595
|
+
return overlay;
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
// Generate extension overlays
|
|
599
|
+
Object.entries(extensionMappings).forEach(([code, config]) => {
|
|
600
|
+
const refType = config.refType || "nts2Ref";
|
|
601
|
+
const refConfig = getRefConfig(refType);
|
|
602
|
+
|
|
603
|
+
console.log(`\nGenerating extension overlay: ${code} (${config.name}) [${refType}]`);
|
|
604
|
+
|
|
605
|
+
// Extract the specific paths
|
|
606
|
+
let overlay = extractPathsWithRef(
|
|
607
|
+
combinedSchema,
|
|
608
|
+
config.paths,
|
|
609
|
+
refConfig,
|
|
610
|
+
config.preserveDiscriminators
|
|
611
|
+
);
|
|
612
|
+
|
|
613
|
+
// Add required arrays where needed
|
|
614
|
+
overlay = addRequiredArrays(overlay, combinedSchema, refConfig);
|
|
615
|
+
|
|
616
|
+
// Add refs to intermediate nodes in the path hierarchy
|
|
617
|
+
overlay = addIntermediateRefs(overlay, combinedSchema, refConfig);
|
|
618
|
+
|
|
619
|
+
// Add schema metadata
|
|
620
|
+
overlay.$schema = "http://json-schema.org/draft-07/schema#";
|
|
621
|
+
overlay.$id = `https://trust.propdata.org.uk/schemas/v3/overlays/extensions/${code}.json`;
|
|
622
|
+
overlay.$comment = config.description;
|
|
623
|
+
|
|
624
|
+
// Write the overlay file
|
|
625
|
+
const fileName = path.join(
|
|
626
|
+
__dirname,
|
|
627
|
+
`../schemas/v3/overlays/extensions/${code}.json`
|
|
628
|
+
);
|
|
629
|
+
fs.writeFileSync(fileName, JSON.stringify(overlay, null, 2));
|
|
630
|
+
console.log(`Extension overlay ${code} written to ${fileName}`);
|
|
631
|
+
});
|
|
632
|
+
|
|
633
|
+
console.log("\nExtension overlay extraction complete!");
|