@pdtf/schemas 2.0.0-1 → 2.0.0-10

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.
@@ -10,6 +10,14 @@ const {
10
10
  } = require("../../../index.js");
11
11
  const exampleTransaction = require("../../examples/v1/exampleTransaction.json");
12
12
 
13
+ const getV1Subschema = (path) => {
14
+ return getSubschema(
15
+ path,
16
+ "https://trust.propdata.org.uk/schemas/v1/pdtf-transaction.json",
17
+ null
18
+ );
19
+ };
20
+
13
21
  test("exports a property pack schema", () => {
14
22
  expect(transactionSchema).not.toBeNull();
15
23
  });
@@ -65,45 +73,45 @@ test("correctly identifies an array invalid path", () => {
65
73
  });
66
74
 
67
75
  test("correctly gets a subschema", () => {
68
- const subschema = getSubschema("/propertyPack/materialFacts/notices");
76
+ const subschema = getV1Subschema("/propertyPack/materialFacts/notices");
69
77
  expect(subschema.title).toBe("Notices which Affect the Property");
70
78
  });
71
79
 
72
80
  test("correctly gets a subschema through an arrays element", () => {
73
- const subschema = getSubschema(
81
+ const subschema = getV1Subschema(
74
82
  "/propertyPack/titlesToBeSold/0/registerExtract"
75
83
  );
76
84
  expect(subschema.title).toBe("HMLR Official Copy Register Extract");
77
85
  });
78
86
 
79
87
  test("correctly gets another subschema through an arrays element", () => {
80
- const subschema = getSubschema("/participants/0/name/firstName");
88
+ const subschema = getV1Subschema("/participants/0/name/firstName");
81
89
  expect(subschema.title).toBe("First name");
82
90
  });
83
91
 
84
92
  test("correctly gets a subschema through a dependency", () => {
85
- const subschema = getSubschema(
93
+ const subschema = getV1Subschema(
86
94
  "/propertyPack/materialFacts/delayFactors/hasDelayFactors/details"
87
95
  );
88
96
  expect(subschema.title).toBe("Details");
89
97
  });
90
98
 
91
99
  test("correctly gets another subschema through a dependency", () => {
92
- const subschema = getSubschema(
100
+ const subschema = getV1Subschema(
93
101
  "/propertyPack/materialFacts/ownership/ownershipsToBeTransferred/0/lengthOfLeaseInYears"
94
102
  );
95
103
  expect(subschema.title).toBe("Length of lease (years)");
96
104
  });
97
105
 
98
106
  test("correctly gets yet another subschema through a dependency", () => {
99
- const subschema = getSubschema(
107
+ const subschema = getV1Subschema(
100
108
  "/propertyPack/materialFacts/ownership/ownershipsToBeTransferred/0/rentIncrease/details"
101
109
  );
102
110
  expect(subschema.title).toBe("Details");
103
111
  });
104
112
 
105
113
  test("correctly gets yet, yet another subschema through a dependency", () => {
106
- const subschema = getSubschema(
114
+ const subschema = getV1Subschema(
107
115
  "/propertyPack/materialFacts/listingAndConservation/isConservationArea/yesNo"
108
116
  );
109
117
  expect(subschema.type).toBe("string");
@@ -111,7 +119,7 @@ test("correctly gets yet, yet another subschema through a dependency", () => {
111
119
  });
112
120
 
113
121
  test("correctly gets yet, yet, yet another subschema through a dependency", () => {
114
- const subschema = getSubschema(
122
+ const subschema = getV1Subschema(
115
123
  "/propertyPack/materialFacts/otherIssues/flooding/typeOfFlooding/groundWater/yesNo"
116
124
  );
117
125
  expect(subschema.type).toBe("string");
@@ -119,21 +127,21 @@ test("correctly gets yet, yet, yet another subschema through a dependency", () =
119
127
  });
120
128
 
121
129
  test("correctly gets yet, yet, yet another subschema through a second item dependency", () => {
122
- const subschema = getSubschema(
130
+ const subschema = getV1Subschema(
123
131
  "/propertyPack/materialFacts/otherIssues/flooding/typeOfFlooding"
124
132
  );
125
133
  expect(subschema.type).toBe("object");
126
134
  });
127
135
 
128
136
  test("correctly gets yes another subschema but through a non-baspi oneOf structure", () => {
129
- const subschema = getSubschema(
137
+ const subschema = getV1Subschema(
130
138
  "/propertyPack/titlesToBeSold/0/registerExtract/OCSummaryData/RestrictionDetails/RestrictionEntry/ChargeRestriction/EntryDetails/EntryText"
131
139
  );
132
140
  expect(subschema).toEqual({ type: "string" });
133
141
  });
134
142
 
135
143
  test("correctly gets yes another subschema but through a non-baspi oneOf structure with array option", () => {
136
- const subschema = getSubschema(
144
+ const subschema = getV1Subschema(
137
145
  "/propertyPack/titlesToBeSold/0/registerExtract/OCSummaryData/RestrictionDetails/RestrictionEntry/0/ChargeRestriction/EntryDetails/EntryText"
138
146
  );
139
147
  expect(subschema).toEqual({ type: "string" });
@@ -141,11 +149,11 @@ test("correctly gets yes another subschema but through a non-baspi oneOf structu
141
149
 
142
150
  test("correctly gets a subschema validator which is already cached", () => {
143
151
  const validator = getSubschemaValidator(
144
- "/propertyPack/energyPerformanceCertificate"
152
+ "/propertyPack/materialFacts/energyEfficiency/certificate"
145
153
  );
146
154
  expect(validator).not.toBeNull();
147
155
  const anotherValidator = getSubschemaValidator(
148
- "/propertyPack/energyPerformanceCertificate"
156
+ "/propertyPack/materialFacts/energyEfficiency/certificate"
149
157
  );
150
158
  expect(anotherValidator).not.toBeNull();
151
159
  });
@@ -59,46 +59,37 @@ test("sample with missing dependent required fields is invalid", () => {
59
59
  });
60
60
 
61
61
  test("correctly gets a top level subschema", () => {
62
- const subschema = getSubschema("/propertyPack", v2TransactionSchema);
62
+ const subschema = getSubschema("/propertyPack");
63
63
  expect(subschema.title).toBe("Property Pack");
64
64
  });
65
65
 
66
66
  test("correctly identifies a valid path", () => {
67
- const isValid = isPathValid(
68
- "/propertyPack/materialFacts",
69
- v2TransactionSchema
70
- );
67
+ const isValid = isPathValid("/propertyPack/materialFacts");
71
68
  expect(isValid).toBe(true);
72
69
  });
73
70
 
74
71
  test("correctly identifies an undefined invalid path", () => {
75
- const isValid = isPathValid(
76
- "/propertyPack/materialItems",
77
- v2TransactionSchema
78
- );
72
+ const isValid = isPathValid("/propertyPack/materialItems");
79
73
  expect(isValid).toBe(false);
80
74
  });
81
75
 
82
76
  test("correctly identifies an error generating invalid path", () => {
83
77
  const isValid = isPathValid(
84
78
  "/propertyPack/materialItems/someProperty/item",
85
- v2TransactionSchema
79
+ schemaId
86
80
  );
87
81
  expect(isValid).toBe(false);
88
82
  });
89
83
 
90
84
  test("correctly identifies an array invalid path", () => {
91
- const isValid = isPathValid(
92
- "/propertyPack/materialFacts/1/item",
93
- v2TransactionSchema
94
- );
85
+ const isValid = isPathValid("/propertyPack/materialFacts/1/item");
95
86
  expect(isValid).toBe(false);
96
87
  });
97
88
 
98
89
  test("correctly gets a subschema", () => {
99
90
  const subschema = getSubschema(
100
91
  "/propertyPack/materialFacts/notices",
101
- v2TransactionSchema
92
+ schemaId
102
93
  );
103
94
  expect(subschema.title).toBe("Notices which Affect the Property");
104
95
  });
@@ -106,7 +97,7 @@ test("correctly gets a subschema", () => {
106
97
  test("correctly gets a subschema through an arrays element", () => {
107
98
  const subschema = getSubschema(
108
99
  "/propertyPack/titlesToBeSold/0/registerExtract",
109
- v2TransactionSchema
100
+ schemaId
110
101
  );
111
102
  expect(Object.keys(subschema.properties)).toEqual([
112
103
  "OCSummaryData",
@@ -117,24 +108,26 @@ test("correctly gets a subschema through an arrays element", () => {
117
108
  test("correctly gets a subschema through a dependency", () => {
118
109
  const subschema = getSubschema(
119
110
  "/propertyPack/materialFacts/delayFactors/hasDelayFactors/details",
120
- v2TransactionSchema
111
+ schemaId
112
+ );
113
+ expect(subschema.title).toBe(
114
+ "Provide details and likely timescale for delay (if known)"
121
115
  );
122
- expect(subschema.title).toBe("Details");
123
116
  });
124
117
 
125
118
  test("correctly gets another subschema through a dependency", () => {
126
119
  const subschema = getSubschema(
127
- "/propertyPack/materialFacts/ownership/ownershipsToBeTransferred/0/leaseholdInformation/general/leaseTerm/lengthOfLeaseInYears",
128
- v2TransactionSchema
120
+ "/propertyPack/materialFacts/ownership/ownershipsToBeTransferred/0/leaseholdInformation/leaseTerm/lengthOfLeaseInYears",
121
+ schemaId
129
122
  );
130
123
  expect(subschema.title).toBe("Length of lease (years)");
131
124
  });
132
125
 
133
126
  test("correctly gets yet another subschema through a dependency", () => {
134
127
  const subschema = getSubschema(
135
- "/propertyPack/materialFacts/ownership/ownershipsToBeTransferred/0/rentIncrease/details"
128
+ "/propertyPack/materialFacts/ownership/ownershipsToBeTransferred/0/leaseholdInformation/groundRent/rentSubjectToIncrease/rentIncreaseCalculated"
136
129
  );
137
- expect(subschema.title).toBe("Details");
130
+ expect(subschema.title).toBe("How is the increase calculated?");
138
131
  });
139
132
 
140
133
  test("correctly gets yet, yet another subschema through a dependency", () => {
@@ -147,7 +140,7 @@ test("correctly gets yet, yet another subschema through a dependency", () => {
147
140
 
148
141
  test("correctly gets yet, yet, yet another subschema through a dependency", () => {
149
142
  const subschema = getSubschema(
150
- "/propertyPack/materialFacts/otherIssues/flooding/typeOfFlooding/groundWater/yesNo"
143
+ "/propertyPack/materialFacts/environmentalIssues/flooding/typeOfFlooding/groundWater/yesNo"
151
144
  );
152
145
  expect(subschema.type).toBe("string");
153
146
  expect(subschema.enum).toStrictEqual(["Yes", "No"]);
@@ -155,7 +148,7 @@ test("correctly gets yet, yet, yet another subschema through a dependency", () =
155
148
 
156
149
  test("correctly gets yet, yet, yet another subschema through a second item dependency", () => {
157
150
  const subschema = getSubschema(
158
- "/propertyPack/materialFacts/otherIssues/flooding/typeOfFlooding"
151
+ "/propertyPack/materialFacts/environmentalIssues/flooding/typeOfFlooding"
159
152
  );
160
153
  expect(subschema.type).toBe("object");
161
154
  });
@@ -176,11 +169,11 @@ test("correctly gets yes another subschema but through a non-baspi oneOf structu
176
169
 
177
170
  test("correctly gets a subschema validator which is already cached", () => {
178
171
  const validator = getSubschemaValidator(
179
- "/propertyPack/energyPerformanceCertificate"
172
+ "/propertyPack/materialFacts/energyEfficiency/certificate"
180
173
  );
181
174
  expect(validator).not.toBeNull();
182
175
  const anotherValidator = getSubschemaValidator(
183
- "/propertyPack/energyPerformanceCertificate"
176
+ "/propertyPack/materialFacts/energyEfficiency/certificate"
184
177
  );
185
178
  expect(anotherValidator).not.toBeNull();
186
179
  });
@@ -207,7 +200,7 @@ test("correctly gets titles across schemas, arrays and non-existient title prope
207
200
  expect(
208
201
  getTitleAtPath(
209
202
  v2TransactionSchema,
210
- "/propertyPack/materialFacts/ownership/ownershipsToBeTransferred/0/leaseholdInformation/general/leaseTerm/lengthOfLeaseInYears"
203
+ "/propertyPack/materialFacts/ownership/ownershipsToBeTransferred/0/leaseholdInformation/leaseTerm/lengthOfLeaseInYears"
211
204
  )
212
205
  ).toBe("Length of lease (years)");
213
206
  expect(
@@ -0,0 +1,128 @@
1
+ const { validateVerifiedClaims } = require("../../../index.js");
2
+
3
+ const exampleVouch = require("../../examples/v1/exampleVouch.json");
4
+ const exampleDocumentedVouch = require("../../examples/v1/exampleDocumentedVouch.json");
5
+ const v2SchemaId =
6
+ "https://trust.propdata.org.uk/schemas/v2/pdtf-transaction.json";
7
+
8
+ test("returns an empty array for a valid claim", () => {
9
+ expect(validateVerifiedClaims([exampleVouch])).toEqual([]);
10
+ });
11
+
12
+ test("returns an empty array for a valid array of claims", () => {
13
+ const claimsArray = [exampleVouch, exampleDocumentedVouch];
14
+ expect(validateVerifiedClaims(claimsArray)).toEqual([]);
15
+ });
16
+
17
+ test("returns an array with an error stating if path is incorrect", () => {
18
+ const clonedVouch = JSON.parse(JSON.stringify(exampleVouch));
19
+ const originalPath = Object.keys(clonedVouch.claims)[0];
20
+ const data = clonedVouch.claims[originalPath];
21
+ clonedVouch.claims = {
22
+ "/propertyPack/INVALID/materialFacts/councilTax": data,
23
+ };
24
+ // v2 schema, no overlay
25
+ expect(validateVerifiedClaims([clonedVouch], v2SchemaId, null)).toEqual([
26
+ "Path /propertyPack/INVALID/materialFacts/councilTax is not a valid PDTF schema path",
27
+ ]);
28
+ });
29
+
30
+ test("returns errors if BASPI requirements are not met and BASPI overlay is specified (default)", () => {
31
+ const clonedVouch = JSON.parse(JSON.stringify(exampleVouch));
32
+ clonedVouch.claims = {
33
+ "/propertyPack/materialFacts/delayFactors": {
34
+ hasDelayFactors: { yesNo: "Yes" },
35
+ },
36
+ };
37
+ const errors = validateVerifiedClaims([clonedVouch], v2SchemaId);
38
+ expect(errors).toEqual([
39
+ {
40
+ instancePath: "/hasDelayFactors",
41
+ schemaPath: "#/properties/hasDelayFactors/oneOf/1/required",
42
+ keyword: "required",
43
+ params: { missingProperty: "details" },
44
+ message: "must have required property 'details'",
45
+ },
46
+ {
47
+ instancePath: "/hasDelayFactors",
48
+ schemaPath: "#/properties/hasDelayFactors/oneOf/1/required",
49
+ keyword: "required",
50
+ params: { missingProperty: "attachments" },
51
+ message: "must have required property 'attachments'",
52
+ },
53
+ ]);
54
+ });
55
+
56
+ test("returns no errors if BASPI requirements are not met and null overlay is specified", () => {
57
+ const clonedVouch = JSON.parse(JSON.stringify(exampleVouch));
58
+ clonedVouch.claims = {
59
+ "/propertyPack/materialFacts/delayFactors": {
60
+ hasDelayFactors: { yesNo: "Yes" },
61
+ },
62
+ };
63
+ const errors = validateVerifiedClaims([clonedVouch], v2SchemaId, null);
64
+ expect(errors).toEqual([]);
65
+ });
66
+
67
+ test("returns errors for invalid fields even if null overlay is specified", () => {
68
+ const clonedVouch = JSON.parse(JSON.stringify(exampleVouch));
69
+ clonedVouch.claims = {
70
+ "/propertyPack/materialFacts/delayFactors": {
71
+ hasDelayFactors: { yesNo: "Maybe" },
72
+ },
73
+ };
74
+ const errors = validateVerifiedClaims([clonedVouch], v2SchemaId, null);
75
+ expect(errors).toHaveLength(4);
76
+ });
77
+
78
+ test("returns an array of errors for verified claim with multiple paths", () => {
79
+ const clonedVouch = JSON.parse(JSON.stringify(exampleVouch));
80
+ clonedVouch.claims = {
81
+ "/propertyPack/materialFacts/cousncilTaxBad": {
82
+ councilTaxBand: "D",
83
+ councilTaxAffectingAlterations: {
84
+ yesNo: "Yes",
85
+ details:
86
+ "Extension added in 2005 to add bedroom with ensuite shower room. Certificate of Compliance issued 17th Feb 2006 and council tax updated",
87
+ },
88
+ },
89
+ "/propertyPack/materialFacts/councilTaxBadTwo": {
90
+ councilTaxBand: "D",
91
+ councilTaxAffectingAlterations: {
92
+ yesNo: "Yes",
93
+ details:
94
+ "Extension added in 2005 to add bedroom with ensuite shower room. Certificate of Compliance issued 17th Feb 2006 and council tax updated",
95
+ },
96
+ },
97
+ };
98
+ expect(validateVerifiedClaims([clonedVouch], v2SchemaId, null)).toEqual([
99
+ "Path /propertyPack/materialFacts/cousncilTaxBad is not a valid PDTF schema path",
100
+ "Path /propertyPack/materialFacts/councilTaxBadTwo is not a valid PDTF schema path",
101
+ ]);
102
+ });
103
+
104
+ test("returns an empty array of errors for verified claim with multiple valid paths", () => {
105
+ const clonedVouch = JSON.parse(
106
+ JSON.stringify(exampleVouch),
107
+ v2SchemaId,
108
+ null
109
+ );
110
+ clonedVouch.claims = {
111
+ "/propertyPack/materialFacts/councilTax": {
112
+ councilTaxBand: "D",
113
+ councilTaxAffectingAlterations: {
114
+ yesNo: "Yes",
115
+ details:
116
+ "Extension added in 2005 to add bedroom with ensuite shower room. Certificate of Compliance issued 17th Feb 2006 and council tax updated",
117
+ },
118
+ },
119
+ "/propertyPack/materialFacts/address": {
120
+ line1: "property.line1",
121
+ line2: "property.line2",
122
+ town: "property.city",
123
+ county: "property.province",
124
+ postcode: "property.postcode",
125
+ },
126
+ };
127
+ expect(validateVerifiedClaims([clonedVouch], v2SchemaId, null)).toEqual([]);
128
+ });
@@ -112,17 +112,7 @@ const coreSchema = deleteProperties(combinedSchema, [
112
112
  ]);
113
113
 
114
114
  fs.writeFileSync(
115
- "../schemas/v2/core.json",
115
+ "../schemas/v2/pdtf-transaction.json",
116
116
  JSON.stringify(coreSchema, null, 2)
117
117
  );
118
- console.log("Core schema written to ../schemas/v2/core.json");
119
- console.log(overlays.baspi);
120
- const mergedSchema = merge(overlays.baspi, coreSchema, {
121
- arrayMerge: combineMerge,
122
- });
123
-
124
- fs.writeFileSync(
125
- "../schemas/v2/merged.json",
126
- JSON.stringify(mergedSchema, null, 2)
127
- );
128
- console.log("Merged schema written to ../schemas/v2/merged.json");
118
+ console.log("Core schema written to ../schemas/v2/pdtf-transaction.json");
@@ -0,0 +1,44 @@
1
+ const { dereference } = require("@jdw/jst");
2
+ const traverse = require("traverse");
3
+ const jp = require("jsonpointer");
4
+ const fs = require("fs");
5
+ const merge = require("deepmerge");
6
+
7
+ const combinedSchema = require("../schemas/v2/combined.json");
8
+
9
+ const overlay = "baspiUI";
10
+ const keys = [
11
+ "isDependent",
12
+ "component",
13
+ "htmlClass",
14
+ "addButtonLabelFirst",
15
+ "addButtonLabelSubsequent",
16
+ ];
17
+
18
+ const returnSchema = {
19
+ $schema: "http://json-schema.org/draft-07/schema#",
20
+ $id: `https://trust.propdata.org.uk/schemas/v2/overlays/${overlay}.json`,
21
+ };
22
+
23
+ traverse(combinedSchema).forEach(function (element) {
24
+ let path = "/" + this.path.join("/");
25
+ if (path === "/") path = "";
26
+ if (keys.includes(this.key)) {
27
+ jp.set(returnSchema, path, element);
28
+ }
29
+ });
30
+
31
+ const fileName = `../schemas/v2/overlays/${overlay}.json`;
32
+ fs.writeFileSync(fileName, JSON.stringify(returnSchema, null, 2));
33
+ console.log(`Overlay ${overlay} written to ${overlay}`);
34
+
35
+ traverse(combinedSchema).forEach(function (element) {
36
+ if (keys.includes(this.key)) {
37
+ this.delete(true); // true = stop here
38
+ }
39
+ });
40
+
41
+ fs.writeFileSync(
42
+ "../schemas/v2/combined.json",
43
+ JSON.stringify(combinedSchema, null, 2)
44
+ );