@pdtf/schemas 2.0.0-2 → 2.0.0-21

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
  });
@@ -110,12 +110,14 @@ test("correctly gets a subschema through a dependency", () => {
110
110
  "/propertyPack/materialFacts/delayFactors/hasDelayFactors/details",
111
111
  schemaId
112
112
  );
113
- expect(subschema.title).toBe("Details");
113
+ expect(subschema.title).toBe(
114
+ "Provide details and likely timescale for delay (if known)"
115
+ );
114
116
  });
115
117
 
116
118
  test("correctly gets another subschema through a dependency", () => {
117
119
  const subschema = getSubschema(
118
- "/propertyPack/materialFacts/ownership/ownershipsToBeTransferred/0/leaseholdInformation/general/leaseTerm/lengthOfLeaseInYears",
120
+ "/propertyPack/materialFacts/ownership/ownershipsToBeTransferred/0/leaseholdInformation/leaseTerm/lengthOfLeaseInYears",
119
121
  schemaId
120
122
  );
121
123
  expect(subschema.title).toBe("Length of lease (years)");
@@ -138,7 +140,7 @@ test("correctly gets yet, yet another subschema through a dependency", () => {
138
140
 
139
141
  test("correctly gets yet, yet, yet another subschema through a dependency", () => {
140
142
  const subschema = getSubschema(
141
- "/propertyPack/materialFacts/environmentalIssues/flooding/typeOfFlooding/groundWater/yesNo"
143
+ "/propertyPack/materialFacts/environmentalIssues/flooding/typeOfFlooding/other/yesNo"
142
144
  );
143
145
  expect(subschema.type).toBe("string");
144
146
  expect(subschema.enum).toStrictEqual(["Yes", "No"]);
@@ -198,7 +200,7 @@ test("correctly gets titles across schemas, arrays and non-existient title prope
198
200
  expect(
199
201
  getTitleAtPath(
200
202
  v2TransactionSchema,
201
- "/propertyPack/materialFacts/ownership/ownershipsToBeTransferred/0/leaseholdInformation/general/leaseTerm/lengthOfLeaseInYears"
203
+ "/propertyPack/materialFacts/ownership/ownershipsToBeTransferred/0/leaseholdInformation/leaseTerm/lengthOfLeaseInYears"
202
204
  )
203
205
  ).toBe("Length of lease (years)");
204
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
+ });
@@ -43,6 +43,32 @@ const combineMerge = (target, source, options) => {
43
43
  return destination;
44
44
  };
45
45
 
46
+ const flattenSkeleton = (schema) => {
47
+ if (!schema) return undefined;
48
+ // console.log(schema.properties);
49
+ let returnStructure = {};
50
+ if (schema.properties) {
51
+ Object.keys(schema.properties).forEach((key) => {
52
+ returnStructure[key] = flattenSkeleton(schema.properties[key]);
53
+ });
54
+ }
55
+ if (schema.oneOf) {
56
+ schema.oneOf.forEach((aOneOf) => {
57
+ // console.log(aOneOf);
58
+ if (aOneOf.properties) {
59
+ Object.entries(aOneOf.properties).forEach(([key, value]) => {
60
+ // console.log(aProperty);
61
+ returnStructure[key] = flattenSkeleton(value);
62
+ });
63
+ }
64
+ });
65
+ }
66
+ if (schema.items) {
67
+ returnStructure = flattenSkeleton(schema.items);
68
+ }
69
+ return returnStructure;
70
+ };
71
+
46
72
  const extractOverlay = (sourceSchema, ref) => {
47
73
  const refName = `${ref}Ref`;
48
74
  const refRequired = `${ref}Required`;
@@ -112,17 +138,29 @@ const coreSchema = deleteProperties(combinedSchema, [
112
138
  ]);
113
139
 
114
140
  fs.writeFileSync(
115
- "../schemas/v2/core.json",
141
+ "../schemas/v2/pdtf-transaction.json",
116
142
  JSON.stringify(coreSchema, null, 2)
117
143
  );
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
- });
144
+ console.log("Core schema written to ../schemas/v2/pdtf-transaction.json");
145
+
146
+ const skeletonSchema = deleteProperties(coreSchema, [
147
+ "$schema",
148
+ "$id",
149
+ "title",
150
+ "description",
151
+ "required",
152
+ "enum",
153
+ "minItems",
154
+ "minLength",
155
+ "format",
156
+ "minimum",
157
+ "maximum",
158
+ ]);
159
+
160
+ const skeletonSchemaFlattened = flattenSkeleton(skeletonSchema);
123
161
 
124
162
  fs.writeFileSync(
125
- "../schemas/v2/merged.json",
126
- JSON.stringify(mergedSchema, null, 2)
163
+ "../schemas/v2/skeleton.json",
164
+ JSON.stringify(skeletonSchemaFlattened, null, 2)
127
165
  );
128
- console.log("Merged schema written to ../schemas/v2/merged.json");
166
+ console.log("Flat Skeleton schema written to ../schemas/v2/skeleton.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
+ );