@pdtf/schemas 3.6.0-dev.14 → 3.6.0-dev.15

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.
@@ -344,7 +344,8 @@
344
344
  "properties": {
345
345
  "isGroundRentPayable": {
346
346
  "enum": [
347
- "No"
347
+ "No",
348
+ "Not applicable"
348
349
  ]
349
350
  }
350
351
  }
@@ -566,7 +566,8 @@
566
566
  "properties": {
567
567
  "isGroundRentPayable": {
568
568
  "enum": [
569
- "No"
569
+ "No",
570
+ "Not applicable"
570
571
  ]
571
572
  }
572
573
  }
@@ -517,6 +517,10 @@
517
517
  "title": "Company number",
518
518
  "type": "string"
519
519
  },
520
+ "directorOrAuthorisedPerson": {
521
+ "title": "Director/authorised person",
522
+ "type": "string"
523
+ },
520
524
  "countryOfIncorporation": {
521
525
  "title": "Country of incorporation",
522
526
  "type": "string"
@@ -5613,7 +5617,8 @@
5613
5617
  "type": "string",
5614
5618
  "enum": [
5615
5619
  "Yes",
5616
- "No"
5620
+ "No",
5621
+ "Not applicable"
5617
5622
  ]
5618
5623
  }
5619
5624
  },
@@ -5622,7 +5627,8 @@
5622
5627
  "properties": {
5623
5628
  "isGroundRentPayable": {
5624
5629
  "enum": [
5625
- "No"
5630
+ "No",
5631
+ "Not applicable"
5626
5632
  ]
5627
5633
  }
5628
5634
  }
@@ -6460,7 +6466,14 @@
6460
6466
  "properties": {
6461
6467
  "year": {
6462
6468
  "title": "Year",
6463
- "type": "integer"
6469
+ "oneOf": [
6470
+ {
6471
+ "type": "integer"
6472
+ },
6473
+ {
6474
+ "const": "Not known"
6475
+ }
6476
+ ]
6464
6477
  },
6465
6478
  "from": {
6466
6479
  "title": "To",
@@ -6480,7 +6493,14 @@
6480
6493
  "properties": {
6481
6494
  "year": {
6482
6495
  "title": "Year",
6483
- "type": "integer"
6496
+ "oneOf": [
6497
+ {
6498
+ "type": "integer"
6499
+ },
6500
+ {
6501
+ "const": "Not known"
6502
+ }
6503
+ ]
6484
6504
  },
6485
6505
  "from": {
6486
6506
  "title": "To",
@@ -8807,7 +8827,8 @@
8807
8827
  "title": "",
8808
8828
  "enum": [
8809
8829
  "Yes",
8810
- "No"
8830
+ "No",
8831
+ "Not known"
8811
8832
  ]
8812
8833
  },
8813
8834
  "detailsAnalysis": {
@@ -8821,7 +8842,8 @@
8821
8842
  "properties": {
8822
8843
  "yesNo": {
8823
8844
  "enum": [
8824
- "No"
8845
+ "No",
8846
+ "Not known"
8825
8847
  ]
8826
8848
  }
8827
8849
  }
@@ -9742,11 +9764,89 @@
9742
9764
  "Yes"
9743
9765
  ]
9744
9766
  },
9767
+ "alterationTypes": {
9768
+ "title": "Which of the following alterations have been made to the property?",
9769
+ "type": "array",
9770
+ "items": {
9771
+ "type": "string",
9772
+ "enum": [
9773
+ "Replacement windows, roof windows, roof lights, glazed doors since 1 April 2002",
9774
+ "Extension",
9775
+ "Conservatory",
9776
+ "Loft conversion",
9777
+ "Garage conversion",
9778
+ "Removal of internal walls",
9779
+ "Removal of chimney breast",
9780
+ "Insulation",
9781
+ "Other building works or changes to the property"
9782
+ ]
9783
+ }
9784
+ },
9745
9785
  "details": {
9746
9786
  "title": "Please give details including dates of all work undertaken",
9747
9787
  "type": "string",
9748
9788
  "minLength": 1
9749
9789
  },
9790
+ "workCompleted": {
9791
+ "title": "Has all this work been completed?",
9792
+ "type": "object",
9793
+ "properties": {
9794
+ "yesNo": {
9795
+ "type": "string",
9796
+ "title": "",
9797
+ "enum": [
9798
+ "Yes",
9799
+ "No"
9800
+ ]
9801
+ }
9802
+ },
9803
+ "oneOf": [
9804
+ {
9805
+ "properties": {
9806
+ "yesNo": {
9807
+ "enum": [
9808
+ "Yes"
9809
+ ]
9810
+ }
9811
+ }
9812
+ },
9813
+ {
9814
+ "properties": {
9815
+ "yesNo": {
9816
+ "enum": [
9817
+ "No"
9818
+ ]
9819
+ },
9820
+ "details": {
9821
+ "title": "Give details of what remains to be completed",
9822
+ "type": "string",
9823
+ "minLength": 1
9824
+ }
9825
+ }
9826
+ }
9827
+ ]
9828
+ },
9829
+ "documents": {
9830
+ "title": "Supply copies of the planning permissions, building regulations approvals, completion certificates or competent person certificates for the work if you have them",
9831
+ "type": "string",
9832
+ "enum": [
9833
+ "Attached",
9834
+ "To follow",
9835
+ "Not available"
9836
+ ]
9837
+ },
9838
+ "approvalsObtained": {
9839
+ "title": "If any of the work was undertaken during your ownership, did you get planning permissions, building regulations approvals, completion certificates or competent person certificates when necessary?",
9840
+ "type": "string",
9841
+ "enum": [
9842
+ "Yes",
9843
+ "No"
9844
+ ]
9845
+ },
9846
+ "approvalsNotRequiredReason": {
9847
+ "title": "If planning permissions, building regulations approvals, completion certificates or competent person certificates were not required, explain why",
9848
+ "type": "string"
9849
+ },
9750
9850
  "buildingRegApproval": {
9751
9851
  "title": "Was Building Regulation approval and a completion certificate obtained or an equivalent Competent Person Scheme Certificate?",
9752
9852
  "type": "object",
@@ -20419,6 +20519,110 @@
20419
20519
  }
20420
20520
  ]
20421
20521
  },
20522
+ "mainHeatingTypes": {
20523
+ "title": "How is the property heated?",
20524
+ "type": "array",
20525
+ "items": {
20526
+ "type": "string",
20527
+ "enum": [
20528
+ "Mains gas",
20529
+ "Oil",
20530
+ "Heat pumps",
20531
+ "Liquid gas",
20532
+ "Electricity",
20533
+ "Underfloor",
20534
+ "Woodburning / multi-fuel stove",
20535
+ "Other"
20536
+ ]
20537
+ }
20538
+ },
20539
+ "mainHeatingTypesOtherDetails": {
20540
+ "title": "If you selected 'Other', give details",
20541
+ "type": "string"
20542
+ },
20543
+ "heatingInstalledDate": {
20544
+ "title": "When was the heating system installed?",
20545
+ "type": "string",
20546
+ "oneOf": [
20547
+ {
20548
+ "format": "date"
20549
+ },
20550
+ {
20551
+ "enum": [
20552
+ "Not known"
20553
+ ]
20554
+ }
20555
+ ]
20556
+ },
20557
+ "boilerInstalledDate": {
20558
+ "title": "If there is a boiler (of any kind) when was it installed?",
20559
+ "type": "string",
20560
+ "oneOf": [
20561
+ {
20562
+ "format": "date"
20563
+ },
20564
+ {
20565
+ "enum": [
20566
+ "Not known"
20567
+ ]
20568
+ }
20569
+ ]
20570
+ },
20571
+ "heatingSystemReplaced": {
20572
+ "title": "Has there been any replacement to the heating system (other than replacement of a boiler)?",
20573
+ "type": "string",
20574
+ "enum": [
20575
+ "Yes",
20576
+ "No",
20577
+ "Not known"
20578
+ ]
20579
+ },
20580
+ "complianceCertificates": {
20581
+ "title": "Supply compliance certificates or documentation for the installation or alteration of each heating system",
20582
+ "type": "string",
20583
+ "enum": [
20584
+ "Attached",
20585
+ "To follow",
20586
+ "None"
20587
+ ]
20588
+ },
20589
+ "inspectionReport": {
20590
+ "title": "Supply a copy of the latest inspection report",
20591
+ "type": "string",
20592
+ "enum": [
20593
+ "Attached",
20594
+ "To follow",
20595
+ "None"
20596
+ ]
20597
+ },
20598
+ "inGoodWorkingOrder": {
20599
+ "title": "Is the boiler and heating system working?",
20600
+ "type": "string",
20601
+ "enum": [
20602
+ "Yes",
20603
+ "No",
20604
+ "Not known"
20605
+ ]
20606
+ },
20607
+ "lastServicedYear": {
20608
+ "title": "In what year was the boiler and heating system last serviced or maintained?",
20609
+ "oneOf": [
20610
+ {
20611
+ "type": "integer"
20612
+ },
20613
+ {
20614
+ "const": "Not known"
20615
+ }
20616
+ ]
20617
+ },
20618
+ "lastServicedReport": {
20619
+ "title": "Supply a copy of the service report",
20620
+ "type": "string",
20621
+ "enum": [
20622
+ "Attached",
20623
+ "To follow"
20624
+ ]
20625
+ },
20422
20626
  "otherHeatingFeatures": {
20423
20627
  "title": "What other heating features does the property have?",
20424
20628
  "type": "array",
@@ -22005,7 +22209,8 @@
22005
22209
  "type": "string",
22006
22210
  "enum": [
22007
22211
  "Yes",
22008
- "No"
22212
+ "No",
22213
+ "Not known"
22009
22214
  ]
22010
22215
  }
22011
22216
  },
@@ -22014,7 +22219,8 @@
22014
22219
  "properties": {
22015
22220
  "hasFloodDefences": {
22016
22221
  "enum": [
22017
- "No"
22222
+ "No",
22223
+ "Not known"
22018
22224
  ]
22019
22225
  }
22020
22226
  }
@@ -82,6 +82,7 @@
82
82
  "attachments": "string",
83
83
  "companyName": "string",
84
84
  "companyNumber": "string",
85
+ "directorOrAuthorisedPerson": "string",
85
86
  "countryOfIncorporation": "string"
86
87
  },
87
88
  "dateBecameOwnerOrAuthority": "string"
@@ -1004,12 +1005,12 @@
1004
1005
  },
1005
1006
  "lastDecoratedPeriod": {
1006
1007
  "externally": {
1007
- "year": "integer",
1008
+ "year": {},
1008
1009
  "from": "string",
1009
1010
  "to": "string"
1010
1011
  },
1011
1012
  "internally": {
1012
- "year": "integer",
1013
+ "year": {},
1013
1014
  "from": "string",
1014
1015
  "to": "string"
1015
1016
  }
@@ -1460,7 +1461,17 @@
1460
1461
  "hasStructuralAlterations": {
1461
1462
  "yesNo": "variant",
1462
1463
  "detailsAnalysis": {},
1464
+ "alterationTypes": [
1465
+ "string"
1466
+ ],
1463
1467
  "details": "string",
1468
+ "workCompleted": {
1469
+ "yesNo": "variant",
1470
+ "details": "string"
1471
+ },
1472
+ "documents": "string",
1473
+ "approvalsObtained": "string",
1474
+ "approvalsNotRequiredReason": "string",
1464
1475
  "buildingRegApproval": {
1465
1476
  "yesNo": "variant",
1466
1477
  "detailsAnalysis": {},
@@ -2658,6 +2669,18 @@
2658
2669
  },
2659
2670
  "details": "string"
2660
2671
  },
2672
+ "mainHeatingTypes": [
2673
+ "string"
2674
+ ],
2675
+ "mainHeatingTypesOtherDetails": "string",
2676
+ "heatingInstalledDate": {},
2677
+ "boilerInstalledDate": {},
2678
+ "heatingSystemReplaced": "string",
2679
+ "complianceCertificates": "string",
2680
+ "inspectionReport": "string",
2681
+ "inGoodWorkingOrder": "string",
2682
+ "lastServicedYear": {},
2683
+ "lastServicedReport": "string",
2661
2684
  "otherHeatingFeatures": [
2662
2685
  "string"
2663
2686
  ],
@@ -30,6 +30,7 @@ const extractFields = [
30
30
  "ntsl2",
31
31
  "ta6",
32
32
  "ta6ed6",
33
+ "ta6ed6v2",
33
34
  "ta7",
34
35
  "ta7ed5",
35
36
  "ta10",
@@ -0,0 +1,92 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Sync ta6ed6v2 markers from ta6ed6 across combined.json.
4
+ *
5
+ * ta6ed6v2 is a "full marker set" twin of ta6ed6: every shared field carries its
6
+ * own `ta6ed6v2*` markers so that inclusion is presence and suppression is the
7
+ * ABSENCE of a v2 ref (see src/tests/v3/ta6ed6v2.test.js — the drift-lint).
8
+ *
9
+ * Two subtrees intentionally diverge (their v2 shape is hand-authored) and are
10
+ * excluded from sync: propertyPack.heating and propertyPack.alterationsAndChanges.
11
+ *
12
+ * For every OTHER node, this tool guarantees each `ta6ed6<Suffix>` marker has a
13
+ * matching `ta6ed6v2<Suffix>` marker of equal value — adding missing twins and
14
+ * repairing drifted values. Edits are minimal text splices that preserve the
15
+ * file's existing formatting.
16
+ *
17
+ * node src/utils/syncTa6ed6v2Markers.js # apply (write)
18
+ * node src/utils/syncTa6ed6v2Markers.js --check # exit 1 if out of sync (CI)
19
+ *
20
+ * After running, regenerate overlays: node src/utils/extractOverlay.js
21
+ */
22
+ const fs = require("fs");
23
+ const path = require("path");
24
+
25
+ const FILE = process.env.COMBINED_PATH || path.resolve(__dirname, "../schemas/v3/combined.json");
26
+ const CHECK = process.argv.includes("--check");
27
+
28
+ const MARKER_RE = /^ta6ed6(Ref|Required|Title|Description|Enum|EnumNames)$/;
29
+ const v2Of = (k) => k.replace(/^ta6ed6/, "ta6ed6v2");
30
+ // NOTE: array indices are numbers in the tokenizer path (strict-equal), so use 2 not "2".
31
+ const COMPANY = ["properties", "participants", "items", "oneOf", 2, "properties", "sellersCapacity", "oneOf", 2, "properties"];
32
+ const EXCLUDED_PREFIXES = [
33
+ ["properties", "propertyPack", "properties", "heating"],
34
+ ["properties", "propertyPack", "properties", "alterationsAndChanges"],
35
+ // §1.6 company seller fields: v2 realigns refs to the form (companyNumber→1.6.1,
36
+ // directorOrAuthorisedPerson→1.6.2) while ed6 keeps its existing refs — hand-authored.
37
+ [...COMPANY, "companyName"],
38
+ [...COMPANY, "companyNumber"],
39
+ [...COMPANY, "directorOrAuthorisedPerson"],
40
+ ];
41
+ const isExcluded = (p) => EXCLUDED_PREFIXES.some((pre) => pre.every((seg, i) => p[i] === seg));
42
+
43
+ // minimal position-tracking JSON tokenizer
44
+ function tokenize(text) {
45
+ let i = 0; const n = text.length; const members = [];
46
+ const ws = () => { while (i < n && /\s/.test(text[i])) i++; };
47
+ const str = () => { i++; while (i < n) { const c = text[i]; if (c === "\\") { i += 2; continue; } if (c === '"') { i++; break; } i++; } };
48
+ const val = (p) => { ws(); const c = text[i]; if (c === "{") obj(p); else if (c === "[") arr(p); else if (c === '"') str(); else { while (i < n && !/[,}\]\s]/.test(text[i])) i++; } };
49
+ function obj(p) { i++; ws(); if (text[i] === "}") { i++; return; } while (i < n) { ws(); const ks = i; str(); const key = JSON.parse(text.slice(ks, i)); ws(); i++; ws(); const vs = i; val(p.concat(key)); members.push({ path: p.concat(key), key, keyStart: ks, valueStart: vs, valueEnd: i }); ws(); if (text[i] === ",") { i++; continue; } if (text[i] === "}") { i++; break; } break; } }
50
+ function arr(p) { i++; ws(); if (text[i] === "]") { i++; return; } let k = 0; while (i < n) { ws(); val(p.concat(k)); k++; ws(); if (text[i] === ",") { i++; continue; } if (text[i] === "]") { i++; break; } break; } }
51
+ ws(); val([]); return members;
52
+ }
53
+
54
+ let text = fs.readFileSync(FILE, "utf8");
55
+ const members = tokenize(text);
56
+ const owner = (m) => m.path.slice(0, -1).join("/");
57
+ const keysByOwner = new Map();
58
+ for (const m of members) { const o = owner(m); if (!keysByOwner.has(o)) keysByOwner.set(o, new Map()); keysByOwner.get(o).set(m.key, m); }
59
+ const indentAt = (off) => text.slice(text.lastIndexOf("\n", off - 1) + 1, off);
60
+
61
+ const edits = []; // {at, end, text} (end omitted => pure insert)
62
+ const adds = [], fixes = [];
63
+ for (const m of members) {
64
+ if (!MARKER_RE.test(m.key)) continue;
65
+ if (isExcluded(m.path)) continue;
66
+ const v2 = v2Of(m.key);
67
+ const siblings = keysByOwner.get(owner(m));
68
+ const ed6Val = text.slice(m.valueStart, m.valueEnd);
69
+ if (!siblings.has(v2)) {
70
+ const indent = indentAt(m.keyStart);
71
+ edits.push({ at: m.valueEnd, text: `,\n${indent}"${v2}": ${ed6Val}` });
72
+ adds.push("/" + m.path.join("/"));
73
+ } else {
74
+ const tw = siblings.get(v2);
75
+ const v2Val = text.slice(tw.valueStart, tw.valueEnd);
76
+ if (JSON.stringify(JSON.parse(v2Val)) !== JSON.stringify(JSON.parse(ed6Val))) {
77
+ edits.push({ at: tw.valueStart, end: tw.valueEnd, text: ed6Val });
78
+ fixes.push("/" + tw.path.join("/"));
79
+ }
80
+ }
81
+ }
82
+
83
+ if (!edits.length) { console.log("ta6ed6v2 markers in sync — nothing to do."); process.exit(0); }
84
+ console.log(`Out of sync: ${adds.length} missing twin(s), ${fixes.length} drifted value(s).`);
85
+ [...adds, ...fixes].slice(0, 20).forEach((p) => console.log(" " + p));
86
+ if (CHECK) process.exit(1);
87
+
88
+ edits.sort((a, b) => b.at - a.at);
89
+ for (const e of edits) text = text.slice(0, e.at) + e.text + text.slice(e.end ?? e.at);
90
+ JSON.parse(text); // guard
91
+ fs.writeFileSync(FILE, text);
92
+ console.log(`Applied ${edits.length} edit(s) to ${FILE}. Now run: node src/utils/extractOverlay.js`);