@pdtf/schemas 3.6.0-17 → 3.6.0-19
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 +2 -1
- package/docs/sef25-extensions-ui-spec.md +146 -0
- package/index.js +5 -0
- package/package.json +1 -1
- package/src/schemas/v3/combined.json +230 -19
- package/src/schemas/v3/compactSkeleton.txt +19 -0
- package/src/schemas/v3/overlays/extensions/jk.json +24 -6
- package/src/schemas/v3/overlays/extensions/pc.json +28 -0
- package/src/schemas/v3/overlays/extensions/ph.json +191 -0
- package/src/schemas/v3/overlays/extensions/sc.json +77 -0
- package/src/schemas/v3/overlays/lpe1.json +14 -2
- package/src/schemas/v3/overlays/ta7ed5.json +11 -7
- package/src/schemas/v3/pdtf-transaction.json +262 -3
- package/src/schemas/v3/skeleton.json +26 -1
- package/src/tests/v3/extensionOverlays.test.js +433 -0
- package/src/tests/v3/ta7ed5.test.js +10 -10
- package/src/utils/extractExtensionOverlays.js +92 -31
|
@@ -5,6 +5,30 @@ const path = require("path");
|
|
|
5
5
|
|
|
6
6
|
const combinedSchema = require("../schemas/v3/combined.json");
|
|
7
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
|
+
// For other ref types, derive keys by replacing "Ref" suffix
|
|
22
|
+
return {
|
|
23
|
+
ref: refType,
|
|
24
|
+
outputRef: refType,
|
|
25
|
+
required: refType.replace("Ref", "Required"),
|
|
26
|
+
title: refType.replace("Ref", "Title"),
|
|
27
|
+
description: refType.replace("Ref", "Description"),
|
|
28
|
+
enumKey: refType.replace("Ref", "Enum"),
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
8
32
|
// Define the extension overlay mappings
|
|
9
33
|
const extensionMappings = {
|
|
10
34
|
// Outside areas
|
|
@@ -150,18 +174,52 @@ const extensionMappings = {
|
|
|
150
174
|
"/properties/propertyPack/properties/completionAndMoving/properties/otherPropertyInChain",
|
|
151
175
|
],
|
|
152
176
|
},
|
|
177
|
+
|
|
178
|
+
// Private supply costs (water & sewerage)
|
|
179
|
+
sc: {
|
|
180
|
+
name: "supplyCosts",
|
|
181
|
+
description: "Associated costs for private water and sewerage supply",
|
|
182
|
+
refType: "sef25Ref",
|
|
183
|
+
paths: [
|
|
184
|
+
"/properties/propertyPack/properties/waterAndDrainage/properties/water/properties/mainsWater/oneOf/0/properties/associatedCost",
|
|
185
|
+
"/properties/propertyPack/properties/waterAndDrainage/properties/drainage/properties/mainsFoulDrainage/oneOf/2/properties/associatedCost",
|
|
186
|
+
],
|
|
187
|
+
},
|
|
188
|
+
|
|
189
|
+
// Parking permit costs
|
|
190
|
+
pc: {
|
|
191
|
+
name: "parkingPermitCost",
|
|
192
|
+
description: "Parking permit cost and frequency",
|
|
193
|
+
refType: "sef25Ref",
|
|
194
|
+
paths: [
|
|
195
|
+
"/properties/propertyPack/properties/parking/properties/controlledParking/oneOf/1/properties/costOfPermitFrequency",
|
|
196
|
+
],
|
|
197
|
+
},
|
|
198
|
+
|
|
199
|
+
// Property hazards
|
|
200
|
+
ph: {
|
|
201
|
+
name: "propertyHazards",
|
|
202
|
+
description: "Property hazards and known issues",
|
|
203
|
+
refType: "sef25Ref",
|
|
204
|
+
paths: [
|
|
205
|
+
"/properties/propertyPack/properties/specialistIssues/properties/wellsDitchesShaft",
|
|
206
|
+
"/properties/propertyPack/properties/specialistIssues/properties/damagedOrExposedElectrics",
|
|
207
|
+
"/properties/propertyPack/properties/specialistIssues/properties/damageToFlooringOrStaircases",
|
|
208
|
+
"/properties/propertyPack/properties/specialistIssues/properties/knownAreasInPoorCondition",
|
|
209
|
+
],
|
|
210
|
+
},
|
|
153
211
|
};
|
|
154
212
|
|
|
155
|
-
// Function to extract properties at specific paths with
|
|
156
|
-
function
|
|
213
|
+
// Function to extract properties at specific paths with given ref type
|
|
214
|
+
function extractPathsWithRef(schema, paths, refConfig) {
|
|
157
215
|
const result = {};
|
|
158
216
|
|
|
159
217
|
paths.forEach((path) => {
|
|
160
218
|
try {
|
|
161
219
|
const value = jp.get(schema, path);
|
|
162
|
-
if (value &&
|
|
220
|
+
if (value && hasRef(value, refConfig)) {
|
|
163
221
|
// Set the value at the same path in result
|
|
164
|
-
jp.set(result, path,
|
|
222
|
+
jp.set(result, path, extractRefProperties(value, refConfig));
|
|
165
223
|
}
|
|
166
224
|
} catch (err) {
|
|
167
225
|
console.warn(`Path not found: ${path}`);
|
|
@@ -171,11 +229,11 @@ function extractPathsWithNts2Ref(schema, paths) {
|
|
|
171
229
|
return result;
|
|
172
230
|
}
|
|
173
231
|
|
|
174
|
-
// Check if an object or its descendants have
|
|
175
|
-
function
|
|
232
|
+
// Check if an object or its descendants have the specified ref
|
|
233
|
+
function hasRef(obj, refConfig) {
|
|
176
234
|
let found = false;
|
|
177
235
|
traverse(obj).forEach(function (element) {
|
|
178
|
-
if (element && element.
|
|
236
|
+
if (element && element[refConfig.ref]) {
|
|
179
237
|
found = true;
|
|
180
238
|
this.stop();
|
|
181
239
|
}
|
|
@@ -183,16 +241,16 @@ function hasNts2Ref(obj) {
|
|
|
183
241
|
return found;
|
|
184
242
|
}
|
|
185
243
|
|
|
186
|
-
// Extract only
|
|
187
|
-
function
|
|
244
|
+
// Extract only ref-specific properties
|
|
245
|
+
function extractRefProperties(obj, refConfig, parentKey) {
|
|
188
246
|
const result = {};
|
|
189
247
|
|
|
190
|
-
// Copy
|
|
191
|
-
if (obj.
|
|
192
|
-
if (obj.
|
|
193
|
-
if (obj.
|
|
194
|
-
if (obj.
|
|
195
|
-
if (obj.
|
|
248
|
+
// Copy ref-specific metadata at current level
|
|
249
|
+
if (obj[refConfig.ref]) result[refConfig.outputRef] = obj[refConfig.ref];
|
|
250
|
+
if (obj[refConfig.required]) result.required = obj[refConfig.required];
|
|
251
|
+
if (obj[refConfig.title]) result.title = obj[refConfig.title];
|
|
252
|
+
if (obj[refConfig.description]) result.description = obj[refConfig.description];
|
|
253
|
+
if (obj[refConfig.enumKey]) result.enum = obj[refConfig.enumKey];
|
|
196
254
|
|
|
197
255
|
// Handle discriminator
|
|
198
256
|
if (obj.discriminator) {
|
|
@@ -204,11 +262,11 @@ function extractNts2Properties(obj, parentKey) {
|
|
|
204
262
|
result.properties = {};
|
|
205
263
|
Object.keys(obj.properties).forEach((key) => {
|
|
206
264
|
const prop = obj.properties[key];
|
|
207
|
-
if (
|
|
208
|
-
result.properties[key] =
|
|
265
|
+
if (hasRef(prop, refConfig)) {
|
|
266
|
+
result.properties[key] = extractRefProperties(prop, refConfig, key);
|
|
209
267
|
}
|
|
210
268
|
});
|
|
211
|
-
// Only keep properties if we found some with
|
|
269
|
+
// Only keep properties if we found some with ref
|
|
212
270
|
if (Object.keys(result.properties).length === 0) {
|
|
213
271
|
delete result.properties;
|
|
214
272
|
}
|
|
@@ -216,8 +274,8 @@ function extractNts2Properties(obj, parentKey) {
|
|
|
216
274
|
|
|
217
275
|
// Handle arrays
|
|
218
276
|
if (obj.items) {
|
|
219
|
-
if (
|
|
220
|
-
result.items =
|
|
277
|
+
if (hasRef(obj.items, refConfig)) {
|
|
278
|
+
result.items = extractRefProperties(obj.items, refConfig);
|
|
221
279
|
}
|
|
222
280
|
}
|
|
223
281
|
|
|
@@ -225,8 +283,8 @@ function extractNts2Properties(obj, parentKey) {
|
|
|
225
283
|
if (obj.oneOf) {
|
|
226
284
|
// Always preserve the full array structure and order
|
|
227
285
|
const processedOneOf = obj.oneOf.map((schema, index) => {
|
|
228
|
-
if (
|
|
229
|
-
const extracted =
|
|
286
|
+
if (hasRef(schema, refConfig)) {
|
|
287
|
+
const extracted = extractRefProperties(schema, refConfig);
|
|
230
288
|
// For oneOf schemas, we need to preserve discriminator enum values
|
|
231
289
|
if (obj.discriminator && schema.properties) {
|
|
232
290
|
const propName = obj.discriminator.propertyName;
|
|
@@ -234,7 +292,7 @@ function extractNts2Properties(obj, parentKey) {
|
|
|
234
292
|
if (!extracted.properties) extracted.properties = {};
|
|
235
293
|
extracted.properties[propName] = {
|
|
236
294
|
enum:
|
|
237
|
-
schema.properties[propName].
|
|
295
|
+
schema.properties[propName][refConfig.enumKey] ||
|
|
238
296
|
schema.properties[propName].enum,
|
|
239
297
|
};
|
|
240
298
|
}
|
|
@@ -258,7 +316,7 @@ function extractNts2Properties(obj, parentKey) {
|
|
|
258
316
|
}
|
|
259
317
|
return extracted;
|
|
260
318
|
} else {
|
|
261
|
-
// If this branch doesn't have
|
|
319
|
+
// If this branch doesn't have ref, preserve the base discriminator enum
|
|
262
320
|
if (obj.discriminator && schema.properties) {
|
|
263
321
|
const propName = obj.discriminator.propertyName;
|
|
264
322
|
if (schema.properties[propName]) {
|
|
@@ -281,7 +339,7 @@ function extractNts2Properties(obj, parentKey) {
|
|
|
281
339
|
// If parentKey is set, and this object has extension metadata, return a stub for the parent
|
|
282
340
|
if (
|
|
283
341
|
parentKey &&
|
|
284
|
-
(result.
|
|
342
|
+
(result[refConfig.outputRef] || result.required || result.discriminator)
|
|
285
343
|
) {
|
|
286
344
|
// This is an extension property inside a oneOf branch
|
|
287
345
|
// Return a stub for the parent property with metadata and oneOf structure
|
|
@@ -311,16 +369,16 @@ function extractNts2Properties(obj, parentKey) {
|
|
|
311
369
|
}
|
|
312
370
|
|
|
313
371
|
// Add required array at parent levels if needed
|
|
314
|
-
function addRequiredArrays(overlay, schema) {
|
|
372
|
+
function addRequiredArrays(overlay, schema, refConfig) {
|
|
315
373
|
traverse(overlay).forEach(function (node) {
|
|
316
374
|
if (node && node.properties) {
|
|
317
375
|
const schemaPath = "/" + this.path.join("/");
|
|
318
376
|
try {
|
|
319
377
|
const schemaNode = jp.get(schema, schemaPath);
|
|
320
|
-
if (schemaNode && schemaNode.
|
|
378
|
+
if (schemaNode && schemaNode[refConfig.required]) {
|
|
321
379
|
// Filter to only include properties that exist in this overlay
|
|
322
380
|
const overlayProps = Object.keys(node.properties);
|
|
323
|
-
const requiredProps = schemaNode.
|
|
381
|
+
const requiredProps = schemaNode[refConfig.required].filter((prop) =>
|
|
324
382
|
overlayProps.includes(prop)
|
|
325
383
|
);
|
|
326
384
|
if (requiredProps.length > 0) {
|
|
@@ -337,13 +395,16 @@ function addRequiredArrays(overlay, schema) {
|
|
|
337
395
|
|
|
338
396
|
// Generate extension overlays
|
|
339
397
|
Object.entries(extensionMappings).forEach(([code, config]) => {
|
|
340
|
-
|
|
398
|
+
const refType = config.refType || "nts2Ref";
|
|
399
|
+
const refConfig = getRefConfig(refType);
|
|
400
|
+
|
|
401
|
+
console.log(`\nGenerating extension overlay: ${code} (${config.name}) [${refType}]`);
|
|
341
402
|
|
|
342
403
|
// Extract the specific paths
|
|
343
|
-
let overlay =
|
|
404
|
+
let overlay = extractPathsWithRef(combinedSchema, config.paths, refConfig);
|
|
344
405
|
|
|
345
406
|
// Add required arrays where needed
|
|
346
|
-
overlay = addRequiredArrays(overlay, combinedSchema);
|
|
407
|
+
overlay = addRequiredArrays(overlay, combinedSchema, refConfig);
|
|
347
408
|
|
|
348
409
|
// Add schema metadata
|
|
349
410
|
overlay.$schema = "http://json-schema.org/draft-07/schema#";
|