@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 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
- const overlaySchema = overlaysMap[schemaId][overlay] || {};
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 || []).join(".");
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pdtf/schemas",
3
- "version": "3.2.1-8",
3
+ "version": "3.3.0",
4
4
  "description": "Property Data Trust Framework Schemas and Utilities",
5
5
  "main": "index.js",
6
6
  "directories": {
@@ -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
  }