@7365admin1/core 3.41.0 → 3.42.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/CHANGELOG.md +33 -0
- package/dist/index.d.ts +22 -1
- package/dist/index.js +333 -28
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +579 -272
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/test/site-name.util.test.mjs +146 -0
package/package.json
CHANGED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import test from "node:test";
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
distinguishingTokens,
|
|
6
|
+
findSiteNameClash,
|
|
7
|
+
matchSiteName,
|
|
8
|
+
normalizeSiteName,
|
|
9
|
+
siteNameClashMessage,
|
|
10
|
+
} from "./.build/utils/site-name.util.mjs";
|
|
11
|
+
|
|
12
|
+
// ---------------------------------------------------------------------------
|
|
13
|
+
// The report: two real, different properties in one organisation.
|
|
14
|
+
// ---------------------------------------------------------------------------
|
|
15
|
+
|
|
16
|
+
test("Winsland House II can be created alongside Winsland House I", () => {
|
|
17
|
+
assert.equal(matchSiteName("Winsland House II", "Winsland House I"), null);
|
|
18
|
+
assert.equal(matchSiteName("Winsland House I", "Winsland House II"), null);
|
|
19
|
+
assert.equal(matchSiteName("Winsland House III", "Winsland House II"), null);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
test("the old rule would have blocked it — one character apart", () => {
|
|
23
|
+
// Guards the reason this fix exists: the names ARE within the old threshold
|
|
24
|
+
// of 2, so nothing but the significant-token rule is letting them through.
|
|
25
|
+
const a = normalizeSiteName("Winsland House I");
|
|
26
|
+
const b = normalizeSiteName("Winsland House II");
|
|
27
|
+
|
|
28
|
+
assert.equal(b.length - a.length, 1);
|
|
29
|
+
assert.notDeepEqual(distinguishingTokens(a), distinguishingTokens(b));
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
// ---------------------------------------------------------------------------
|
|
33
|
+
// Significant tokens: numerals, digits, letters.
|
|
34
|
+
// ---------------------------------------------------------------------------
|
|
35
|
+
|
|
36
|
+
test("Roman numerals I to X are all distinct from each other", () => {
|
|
37
|
+
const numerals = ["I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", "X"];
|
|
38
|
+
|
|
39
|
+
for (const a of numerals) {
|
|
40
|
+
for (const b of numerals) {
|
|
41
|
+
if (a === b) continue;
|
|
42
|
+
assert.equal(
|
|
43
|
+
matchSiteName(`Parc Vista ${a}`, `Parc Vista ${b}`),
|
|
44
|
+
null,
|
|
45
|
+
`${a} should not collide with ${b}`,
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
test("towers, phases, blocks and wings are told apart", () => {
|
|
52
|
+
assert.equal(matchSiteName("Tower A", "Tower B"), null);
|
|
53
|
+
assert.equal(matchSiteName("Marina Bay Tower A", "Marina Bay Tower B"), null);
|
|
54
|
+
assert.equal(matchSiteName("Phase 1", "Phase 2"), null);
|
|
55
|
+
assert.equal(matchSiteName("Kent Ridge Phase 1", "Kent Ridge Phase 2"), null);
|
|
56
|
+
assert.equal(matchSiteName("Block 5", "Block 15"), null);
|
|
57
|
+
assert.equal(matchSiteName("Bedok Block 105", "Bedok Block 106"), null);
|
|
58
|
+
assert.equal(matchSiteName("Riverside Wing C", "Riverside Wing D"), null);
|
|
59
|
+
assert.equal(matchSiteName("The Sail Stack 2", "The Sail Stack 3"), null);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
test("a numeral and its digit are the same building", () => {
|
|
63
|
+
assert.equal(matchSiteName("Winsland House 1", "Winsland House I"), "near-duplicate");
|
|
64
|
+
assert.equal(matchSiteName("Parc Vista 4", "Parc Vista IV"), "near-duplicate");
|
|
65
|
+
assert.deepEqual(distinguishingTokens("winsland house ix"), ["9"]);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
test("adding a numeral to a bare name is a different site", () => {
|
|
69
|
+
assert.equal(matchSiteName("Winsland House II", "Winsland House"), null);
|
|
70
|
+
assert.equal(matchSiteName("Winsland House", "Winsland House II"), null);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
// ---------------------------------------------------------------------------
|
|
74
|
+
// Real duplicates that must STILL be caught.
|
|
75
|
+
// ---------------------------------------------------------------------------
|
|
76
|
+
|
|
77
|
+
test("an exact repeat is a duplicate", () => {
|
|
78
|
+
assert.equal(matchSiteName("Winsland House II", "Winsland House II"), "duplicate");
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
test("case differences are a duplicate", () => {
|
|
82
|
+
assert.equal(matchSiteName("winsland house ii", "Winsland House II"), "duplicate");
|
|
83
|
+
assert.equal(matchSiteName("WINSLAND HOUSE II", "Winsland House II"), "duplicate");
|
|
84
|
+
assert.equal(matchSiteName("WiNsLaNd HoUsE ii", "Winsland House II"), "duplicate");
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
test("leading, trailing and doubled whitespace is a duplicate", () => {
|
|
88
|
+
assert.equal(matchSiteName(" Winsland House II", "Winsland House II"), "duplicate");
|
|
89
|
+
assert.equal(matchSiteName("Winsland House II ", "Winsland House II"), "duplicate");
|
|
90
|
+
assert.equal(matchSiteName("Winsland House II", "Winsland House II"), "duplicate");
|
|
91
|
+
assert.equal(matchSiteName("\tWinsland House II\n", "Winsland House II"), "duplicate");
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
test("punctuation differences are a duplicate", () => {
|
|
95
|
+
assert.equal(matchSiteName("St. John's Court", "St Johns Court"), "duplicate");
|
|
96
|
+
assert.equal(matchSiteName("Marina-Bay Residences", "Marina Bay Residences"), "duplicate");
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
test("a typo in the same building is a near-duplicate", () => {
|
|
100
|
+
assert.equal(matchSiteName("Winsland Hosue II", "Winsland House II"), "near-duplicate");
|
|
101
|
+
assert.equal(matchSiteName("Winsland Huse II", "Winsland House II"), "near-duplicate");
|
|
102
|
+
assert.equal(matchSiteName("Marina Bay Residence", "Marina Bay Residences"), "near-duplicate");
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
test("genuinely unrelated names never collide", () => {
|
|
106
|
+
assert.equal(matchSiteName("Winsland House II", "Orchard Central"), null);
|
|
107
|
+
assert.equal(matchSiteName("Parc Vista", "Park Vista Residences"), null);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
test("a blank or missing name is not treated as a clash", () => {
|
|
111
|
+
assert.equal(matchSiteName("", "Winsland House II"), null);
|
|
112
|
+
assert.equal(matchSiteName(" ", "Winsland House II"), null);
|
|
113
|
+
assert.equal(matchSiteName("Winsland House II", undefined), null);
|
|
114
|
+
assert.equal(matchSiteName(null, "Winsland House II"), null);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
// ---------------------------------------------------------------------------
|
|
118
|
+
// What the service actually calls.
|
|
119
|
+
// ---------------------------------------------------------------------------
|
|
120
|
+
|
|
121
|
+
test("findSiteNameClash reports which existing site matched", () => {
|
|
122
|
+
const existing = ["Orchard Central", "Winsland House I", "Winsland House II"];
|
|
123
|
+
|
|
124
|
+
assert.equal(findSiteNameClash("Winsland House III", existing), null);
|
|
125
|
+
assert.deepEqual(findSiteNameClash("winsland house ii", existing), {
|
|
126
|
+
name: "Winsland House II",
|
|
127
|
+
match: "duplicate",
|
|
128
|
+
});
|
|
129
|
+
assert.deepEqual(findSiteNameClash("Winsland Hosue I", existing), {
|
|
130
|
+
name: "Winsland House I",
|
|
131
|
+
match: "near-duplicate",
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
test("the message names the site and says what to do, without telling anyone to call support", () => {
|
|
136
|
+
const duplicate = siteNameClashMessage("Winsland House II", "duplicate");
|
|
137
|
+
const near = siteNameClashMessage("Winsland House II", "near-duplicate");
|
|
138
|
+
|
|
139
|
+
for (const message of [duplicate, near]) {
|
|
140
|
+
assert.match(message, /Winsland House II/);
|
|
141
|
+
assert.doesNotMatch(message, /support/i);
|
|
142
|
+
assert.doesNotMatch(message, /Failed to add site/i);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
assert.match(near, /block, tower, phase, or number/);
|
|
146
|
+
});
|