@pdtf/schemas 3.2.1-8 → 3.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +61 -4
- package/package.json +1 -1
- package/src/examples/v3/exampleCustomOverlay.json +55 -0
- package/src/examples/v3/exampleCustomOverlay2.json +93 -0
- package/src/examples/v3/exampleTransaction.json +55 -1
- package/src/schemas/v3/combined.json +212 -20
- package/src/schemas/v3/overlays/baspi4.json +1 -0
- package/src/schemas/v3/overlays/baspi5.json +1 -0
- package/src/schemas/v3/overlays/con29R.json +25 -0
- package/src/schemas/v3/overlays/nts-sef.json +7 -2
- package/src/schemas/v3/overlays/nts.json +15 -4
- package/src/schemas/v3/overlays/ntsl.json +1 -2
- package/src/schemas/v3/overlays/piq.json +1 -0
- package/src/schemas/v3/overlays/rds.json +1 -0
- package/src/schemas/v3/pdtf-transaction.json +202 -17
- package/src/schemas/v3/skeleton.json +25 -1
- package/src/tests/v3/transactionSchema.test.js +244 -0
package/index.js
CHANGED
|
@@ -61,14 +61,49 @@ const transactionSchemas = {
|
|
|
61
61
|
};
|
|
62
62
|
|
|
63
63
|
const combineMerge = (target, source, options) => {
|
|
64
|
+
// Special handling for 'required' arrays - combine them uniquely
|
|
65
|
+
if (target.some((item) => typeof item === "string")) {
|
|
66
|
+
return [...new Set([...target, ...source])];
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// For other arrays, concatenate while preserving uniqueness for primitive values
|
|
70
|
+
if (!options.isMergeableObject(target[0])) {
|
|
71
|
+
return [...new Set([...target, ...source])];
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Special handling for oneOf arrays - merge matching schemas based on discriminator
|
|
75
|
+
if (target[0]?.properties && source[0]?.properties) {
|
|
76
|
+
// Find a common discriminator property (a property with an enum)
|
|
77
|
+
const findDiscriminator = (schema) => {
|
|
78
|
+
const props = schema.properties;
|
|
79
|
+
return Object.keys(props).find((key) => Array.isArray(props[key]?.enum));
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
const discriminator = findDiscriminator(target[0]);
|
|
83
|
+
if (discriminator) {
|
|
84
|
+
return target.map((targetSchema) => {
|
|
85
|
+
const targetEnum = targetSchema.properties?.[discriminator]?.enum || [];
|
|
86
|
+
const matchingSourceSchema = source.find((sourceSchema) => {
|
|
87
|
+
const sourceEnum =
|
|
88
|
+
sourceSchema.properties?.[discriminator]?.enum || [];
|
|
89
|
+
// Check if there's any overlap between the enum values
|
|
90
|
+
return sourceEnum.some((value) => targetEnum.includes(value));
|
|
91
|
+
});
|
|
92
|
+
if (matchingSourceSchema) {
|
|
93
|
+
return merge(targetSchema, matchingSourceSchema, options);
|
|
94
|
+
}
|
|
95
|
+
return targetSchema;
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// For arrays of objects, merge by index and append remaining items
|
|
64
101
|
const destination = target.slice();
|
|
65
102
|
source.forEach((item, index) => {
|
|
66
103
|
if (typeof destination[index] === "undefined") {
|
|
67
104
|
destination[index] = options.cloneUnlessOtherwiseSpecified(item, options);
|
|
68
105
|
} else if (options.isMergeableObject(item)) {
|
|
69
106
|
destination[index] = merge(target[index], item, options);
|
|
70
|
-
} else if (target.indexOf(item) === -1) {
|
|
71
|
-
destination.push(item);
|
|
72
107
|
}
|
|
73
108
|
});
|
|
74
109
|
return destination;
|
|
@@ -84,7 +119,12 @@ const getTransactionSchema = (
|
|
|
84
119
|
if (!overlays || overlays.length < 1) return sourceSchema;
|
|
85
120
|
let mergedSchema = sourceSchema;
|
|
86
121
|
overlays.forEach((overlay) => {
|
|
87
|
-
|
|
122
|
+
// Handle both string keys and direct overlay objects
|
|
123
|
+
const overlaySchema =
|
|
124
|
+
typeof overlay === "string"
|
|
125
|
+
? overlaysMap[schemaId][overlay] || {}
|
|
126
|
+
: overlay;
|
|
127
|
+
|
|
88
128
|
mergedSchema = merge(mergedSchema, overlaySchema, {
|
|
89
129
|
customMerge: (key) => {
|
|
90
130
|
if (key === "enum") {
|
|
@@ -97,6 +137,23 @@ const getTransactionSchema = (
|
|
|
97
137
|
return mergedSchema;
|
|
98
138
|
};
|
|
99
139
|
|
|
140
|
+
// Add helper function to generate cache key
|
|
141
|
+
const generateOverlayKey = (overlays) => {
|
|
142
|
+
if (!overlays) return "";
|
|
143
|
+
return overlays
|
|
144
|
+
.map((overlay) => {
|
|
145
|
+
if (typeof overlay === "string") return overlay;
|
|
146
|
+
// Generate a simple hash of the object for caching
|
|
147
|
+
return JSON.stringify(overlay)
|
|
148
|
+
.split("")
|
|
149
|
+
.reduce((hash, char) => {
|
|
150
|
+
return ((hash << 5) - hash + char.charCodeAt(0)) | 0;
|
|
151
|
+
}, 0)
|
|
152
|
+
.toString(36);
|
|
153
|
+
})
|
|
154
|
+
.join(".");
|
|
155
|
+
};
|
|
156
|
+
|
|
100
157
|
const getValidator = (schemaId, overlays) => {
|
|
101
158
|
return getSubschemaValidator("", schemaId, overlays);
|
|
102
159
|
};
|
|
@@ -135,7 +192,7 @@ const isPathValid = (path, schemaId, overlays) => {
|
|
|
135
192
|
|
|
136
193
|
const getSubschemaValidator = (path, schemaId, overlays) => {
|
|
137
194
|
const subSchema = getSubschema(path, schemaId, overlays);
|
|
138
|
-
const overlayKey = (overlays
|
|
195
|
+
const overlayKey = generateOverlayKey(overlays);
|
|
139
196
|
// see if we can retrieve the schema by path, schemaId and overlays
|
|
140
197
|
const cacheKey = `${path}-${schemaId}-${overlayKey}`;
|
|
141
198
|
let validator = ajv.getSchema(cacheKey);
|
package/package.json
CHANGED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "https://trust.propdata.org.uk/schemas/v3/overlays/custom.json",
|
|
4
|
+
"properties": {
|
|
5
|
+
"propertyPack": {
|
|
6
|
+
"customRef": "JKW",
|
|
7
|
+
"type": "object",
|
|
8
|
+
"required": ["specialistIssues"],
|
|
9
|
+
"properties": {
|
|
10
|
+
"specialistIssues": {
|
|
11
|
+
"customRef": "JKW.7",
|
|
12
|
+
"required": ["japaneseKnotweed"],
|
|
13
|
+
"properties": {
|
|
14
|
+
"japaneseKnotweed": {
|
|
15
|
+
"customRef": "JKW.7.8",
|
|
16
|
+
"discriminator": {
|
|
17
|
+
"propertyName": "yesNo"
|
|
18
|
+
},
|
|
19
|
+
"oneOf": [
|
|
20
|
+
{
|
|
21
|
+
"properties": {
|
|
22
|
+
"yesNo": {
|
|
23
|
+
"enum": ["No", "Not known"]
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"properties": {
|
|
29
|
+
"yesNo": {
|
|
30
|
+
"enum": ["Yes"]
|
|
31
|
+
},
|
|
32
|
+
"managementPlanInPlace": {
|
|
33
|
+
"customRef": "JKW.7.8.2"
|
|
34
|
+
},
|
|
35
|
+
"attachments": {
|
|
36
|
+
"customRef": "JKW.7.8.3"
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
"required": ["managementPlanInPlace", "attachments"]
|
|
40
|
+
}
|
|
41
|
+
],
|
|
42
|
+
"required": ["yesNo"],
|
|
43
|
+
"title": "Is the property affected by Japanese knotweed?",
|
|
44
|
+
"properties": {
|
|
45
|
+
"yesNo": {
|
|
46
|
+
"customRef": "JKW.7.8.1"
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "https://trust.propdata.org.uk/schemas/v3/overlays/ta7.json",
|
|
4
|
+
"properties": {
|
|
5
|
+
"propertyPack": {
|
|
6
|
+
"macRef": "MAC",
|
|
7
|
+
"required": ["ownership"],
|
|
8
|
+
"properties": {
|
|
9
|
+
"ownership": {
|
|
10
|
+
"macRef": "MAC.1",
|
|
11
|
+
"required": ["ownershipsToBeTransferred"],
|
|
12
|
+
"properties": {
|
|
13
|
+
"ownershipsToBeTransferred": {
|
|
14
|
+
"macRef": "MAC.1",
|
|
15
|
+
"items": {
|
|
16
|
+
"discriminator": {
|
|
17
|
+
"propertyName": "ownershipType"
|
|
18
|
+
},
|
|
19
|
+
"oneOf": [
|
|
20
|
+
{
|
|
21
|
+
"properties": {
|
|
22
|
+
"ownershipType": {
|
|
23
|
+
"enum": ["Leasehold"]
|
|
24
|
+
},
|
|
25
|
+
"leaseholdInformation": {
|
|
26
|
+
"required": ["contactDetails"],
|
|
27
|
+
"properties": {
|
|
28
|
+
"contactDetails": {
|
|
29
|
+
"macRef": "MAC.4.1",
|
|
30
|
+
"required": ["contacts"],
|
|
31
|
+
"properties": {
|
|
32
|
+
"contacts": {
|
|
33
|
+
"macRef": "MAC.4.1",
|
|
34
|
+
"required": ["managingAgent"],
|
|
35
|
+
"properties": {
|
|
36
|
+
"managingAgent": {
|
|
37
|
+
"macRef": "MAC.4.1c",
|
|
38
|
+
"required": ["contact"],
|
|
39
|
+
"properties": {
|
|
40
|
+
"contact": {
|
|
41
|
+
"macRef": "MAC.4.1c",
|
|
42
|
+
"required": ["nameOrOrganisation"],
|
|
43
|
+
"properties": {
|
|
44
|
+
"nameOrOrganisation": {
|
|
45
|
+
"macRef": "MAC.4.1c.1"
|
|
46
|
+
},
|
|
47
|
+
"address": {
|
|
48
|
+
"macRef": "MAC.4.1c.0",
|
|
49
|
+
"properties": {
|
|
50
|
+
"line1": {
|
|
51
|
+
"macRef": "MAC.4.1c.2"
|
|
52
|
+
},
|
|
53
|
+
"line2": {
|
|
54
|
+
"macRef": "MAC.4.1c.3"
|
|
55
|
+
},
|
|
56
|
+
"line3": {
|
|
57
|
+
"macRef": "MAC.4.1c.4"
|
|
58
|
+
},
|
|
59
|
+
"town": {
|
|
60
|
+
"macRef": "MAC.4.1c.5"
|
|
61
|
+
},
|
|
62
|
+
"postcode": {
|
|
63
|
+
"macRef": "MAC.4.1c.6"
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
"telephone": {
|
|
68
|
+
"macRef": "MAC.4.1c.7"
|
|
69
|
+
},
|
|
70
|
+
"emailAddress": {
|
|
71
|
+
"macRef": "MAC.4.1c.8"
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
]
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
@@ -976,5 +976,59 @@
|
|
|
976
976
|
"contentTypes": ["Environmental Risks"]
|
|
977
977
|
}
|
|
978
978
|
]
|
|
979
|
-
}
|
|
979
|
+
},
|
|
980
|
+
"contracts": [
|
|
981
|
+
{
|
|
982
|
+
"contract": {
|
|
983
|
+
"template": {
|
|
984
|
+
"name": "Example Agency Agreement",
|
|
985
|
+
"url": "https://example.com/example-agency-agreement",
|
|
986
|
+
"externalIds": {
|
|
987
|
+
"Moverly": "file123"
|
|
988
|
+
},
|
|
989
|
+
"requiredSignatories": [
|
|
990
|
+
{
|
|
991
|
+
"role": "Seller",
|
|
992
|
+
"requiresAll": true
|
|
993
|
+
}
|
|
994
|
+
]
|
|
995
|
+
},
|
|
996
|
+
"terms": {
|
|
997
|
+
"propertyAddress": "123 Maple Street, London, SW1A 1AA",
|
|
998
|
+
"sellersNames": "Peter and Clarissa Hetherington-Smythe",
|
|
999
|
+
"sellersContactAddress": "47 Park Road, Harpenden, AL3 5AF",
|
|
1000
|
+
"sellersTelephoneNumber": "07700 900123",
|
|
1001
|
+
"sellersEmail": "peter.hetherington-smyth@email.com",
|
|
1002
|
+
"typeOfAgency": "Sole Agency",
|
|
1003
|
+
"feeAsPercent": "1.5%",
|
|
1004
|
+
"fixedFeeExVat": "£2,500",
|
|
1005
|
+
"estimatedFeeIncludingVat": "£3,000",
|
|
1006
|
+
"includeAdditionalChargeEpc": true,
|
|
1007
|
+
"additionalChargeForEpcExVat": "75",
|
|
1008
|
+
"includeAdditionalChargeForEpcAndFloorplan": true,
|
|
1009
|
+
"additionalChargeForEpcAndFloorplanExVat": "150",
|
|
1010
|
+
"includeAdditionalChargeForEpcFloorplanAndPhotos": true,
|
|
1011
|
+
"additionalChargeForEpcFloorplanAndPhotosExVat": "150",
|
|
1012
|
+
"includeAdditionalChargeForPremiumPhotos ": true,
|
|
1013
|
+
"additionalChargeForPremiumPhotosExVat": "150",
|
|
1014
|
+
"includeAdditionalChargeForBrochure": true,
|
|
1015
|
+
"additionalChargeForBrochureExVat": "150",
|
|
1016
|
+
"includeAdditionalChargeForBespokeAdvertising": true,
|
|
1017
|
+
"additionalChargeForBespokeAdvertisingExVat": "150",
|
|
1018
|
+
"initialMarketingPrice": "£450,000"
|
|
1019
|
+
}
|
|
1020
|
+
},
|
|
1021
|
+
"signatures": [
|
|
1022
|
+
{
|
|
1023
|
+
"name": "Peter Ronald Hetherington-Smythe",
|
|
1024
|
+
"signedOn": "2024-11-29T16:15:02.735Z",
|
|
1025
|
+
"externalIds": {
|
|
1026
|
+
"Moverly": "123434"
|
|
1027
|
+
},
|
|
1028
|
+
"role": "Seller",
|
|
1029
|
+
"contractHash": "IYnBjUI8TauXFop6WCvnPA=="
|
|
1030
|
+
}
|
|
1031
|
+
]
|
|
1032
|
+
}
|
|
1033
|
+
]
|
|
980
1034
|
}
|