@cavoq/mcc-mnc-list 1.2.2 → 2.0.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 +20 -0
- package/fetch.js +239 -170
- package/index.js +14 -14
- package/mcc-mnc-list.json +494 -242
- package/package.json +25 -8
- package/status-codes.json +1 -1
- package/types.d.ts +17 -26
- package/.github/workflows/release.yml +0 -43
- package/Dockerfile +0 -19
- package/eslint.config.js +0 -17
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 2.0.0
|
|
4
|
+
|
|
5
|
+
### Migration
|
|
6
|
+
|
|
7
|
+
- Install `@cavoq/mcc-mnc-list` and update imports from `mcc-mnc-list` to `@cavoq/mcc-mnc-list`.
|
|
8
|
+
- Use Node `^22.22.2 || ^24.15.0 || >=26.0.0`, as required by jsdom 30. The previous package did not declare its transitive runtime requirements.
|
|
9
|
+
- TypeScript callers must handle nullable operator metadata and `undefined` from `find()`. Numeric filters and null filter objects now match the documented runtime API.
|
|
10
|
+
- Zero and empty-string filters are applied instead of being ignored. Arrays are rejected as filter objects, and combining MCC+MNC with a separate MCC or MNC always fails, including zero values.
|
|
11
|
+
|
|
12
|
+
### Maintenance
|
|
13
|
+
|
|
14
|
+
- Refresh all seven Wikipedia source pages on 2026-09-12: 3,467 records (previously 3,446) and 14 status codes.
|
|
15
|
+
- Parse nested Wikipedia sections and both wrapped and direct headings. Preserve the country heading for international territories, rowspans, and rows without a final notes cell.
|
|
16
|
+
- Remove citations without truncating the preceding text; preserve meaningful bracketed text and separate line breaks.
|
|
17
|
+
- Propagate download, parse, and write errors with a failing exit code. Validate all sources and reject suspicious shrinkage before replacing data.
|
|
18
|
+
- Update jsdom 28.1.0 → 30.0.1, AVA 6.4.1 → 8.0.1, ESLint 10.0.1 → 10.10.0, and globals 17.3.0 → 17.12.0. `@eslint/js` 10.0.1 is already current. Pin pnpm 10.34.5 and refresh the lockfile.
|
|
19
|
+
- Add CI across Node 22, 24, and 26, plus npm publishing on matching version tags with prerelease handling and OIDC/token authentication.
|
|
20
|
+
- Limit package contents to the library, types, updater, data, and standard npm documentation. Use locked production dependencies and a writable work directory in Docker.
|
package/fetch.js
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
const fs = require("fs");
|
|
4
|
-
const path = require("path");
|
|
5
|
-
const
|
|
6
|
-
const { JSDOM } = jsdom;
|
|
3
|
+
const fs = require("node:fs/promises");
|
|
4
|
+
const path = require("node:path");
|
|
5
|
+
const { JSDOM } = require("jsdom");
|
|
7
6
|
|
|
8
7
|
const WIKI_URL = "https://en.wikipedia.org/wiki/Mobile_country_code";
|
|
9
8
|
const WIKI_URL_REGIONS = [
|
|
@@ -18,148 +17,198 @@ const WIKI_URL_REGIONS = [
|
|
|
18
17
|
const MCC_MNC_OUTPUT_FILE = path.join(__dirname, "mcc-mnc-list.json");
|
|
19
18
|
const STATUS_CODES_OUTPUT_FILE = path.join(__dirname, "status-codes.json");
|
|
20
19
|
|
|
21
|
-
function fetch() {
|
|
22
|
-
|
|
23
|
-
|
|
20
|
+
async function fetch() {
|
|
21
|
+
const records = [];
|
|
22
|
+
const statusCodes = [];
|
|
24
23
|
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
for (let i = 0; i < WIKI_URL_REGIONS.length; i++) {
|
|
30
|
-
const region = WIKI_URL_REGIONS[i];
|
|
31
|
-
await process(region, records, statusCodes);
|
|
32
|
-
console.log(region, records.length, statusCodes.length);
|
|
33
|
-
}
|
|
24
|
+
for (const region of WIKI_URL_REGIONS) {
|
|
25
|
+
await collect(region, records, statusCodes);
|
|
26
|
+
console.log(region, records.length, statusCodes.length);
|
|
27
|
+
}
|
|
34
28
|
|
|
35
|
-
|
|
36
|
-
|
|
29
|
+
await collect(WIKI_URL, records, statusCodes, true);
|
|
30
|
+
console.log(WIKI_URL, records.length, statusCodes.length);
|
|
37
31
|
|
|
38
|
-
|
|
39
|
-
})();
|
|
32
|
+
await writeData(records, statusCodes);
|
|
40
33
|
}
|
|
41
34
|
|
|
42
|
-
function collect(
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
35
|
+
async function collect(from, records, statusCodes, globals = false) {
|
|
36
|
+
const response = await globalThis.fetch(from, {
|
|
37
|
+
headers: {
|
|
38
|
+
"User-Agent": "mcc-mnc-list/2.0 (https://github.com/cavoq/mcc-mnc-list)",
|
|
39
|
+
},
|
|
40
|
+
signal: AbortSignal.timeout(60_000),
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
if (!response.ok) {
|
|
44
|
+
throw new Error(`HTTP ${response.status} fetching ${from}`);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const dom = new JSDOM(await response.text());
|
|
48
|
+
|
|
49
|
+
try {
|
|
50
|
+
const content = dom.window.document.querySelector(
|
|
51
|
+
"#mw-content-text > .mw-parser-output, body > .mw-parser-output"
|
|
47
52
|
);
|
|
48
53
|
|
|
49
|
-
if (!content
|
|
50
|
-
|
|
51
|
-
return;
|
|
54
|
+
if (!content) {
|
|
55
|
+
throw new Error(`Wikipedia article content was not found: ${from}`);
|
|
52
56
|
}
|
|
53
57
|
|
|
54
|
-
|
|
58
|
+
removeCiteReferences(content);
|
|
55
59
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
60
|
+
// Headings and tables can be nested inside Wikipedia section elements.
|
|
61
|
+
const children = content.querySelectorAll("h2, h3, h4, table");
|
|
62
|
+
const previousCount = records.length;
|
|
63
|
+
let recordType = null;
|
|
64
|
+
let countryInfo = { name: null, code: null };
|
|
59
65
|
|
|
60
|
-
for (
|
|
61
|
-
|
|
66
|
+
for (const node of children) {
|
|
67
|
+
// Ignore hidden headings used as link targets inside table cells.
|
|
68
|
+
if (node.parentElement.closest("table")) {
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
62
71
|
|
|
63
|
-
if (
|
|
72
|
+
if (node.nodeName === "H2") {
|
|
73
|
+
recordType = getRecordType(node);
|
|
74
|
+
countryInfo = { name: null, code: null };
|
|
64
75
|
continue;
|
|
65
76
|
}
|
|
66
77
|
|
|
67
|
-
if (node.nodeName === "
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
78
|
+
if (node.nodeName === "H3" || node.nodeName === "H4") {
|
|
79
|
+
countryInfo = getCountryInfo(node);
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (!recordType || (globals && recordType === "National")) {
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const rows = getTableRows(node);
|
|
88
|
+
const headings = rows[0];
|
|
89
|
+
|
|
90
|
+
if (
|
|
91
|
+
!headings ||
|
|
92
|
+
headings.length < 2 ||
|
|
93
|
+
getCellText(headings[0]) !== "MCC" ||
|
|
94
|
+
getCellText(headings[1]) !== "MNC"
|
|
95
|
+
) {
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (recordType === "National" && !countryInfo.code) {
|
|
100
|
+
throw new Error(`Operator table has no country heading: ${from}`);
|
|
76
101
|
}
|
|
77
102
|
|
|
78
|
-
|
|
79
|
-
if (
|
|
103
|
+
for (const cols of rows.slice(1)) {
|
|
104
|
+
if (cols.every((cell) => cell.nodeName === "TH")) {
|
|
80
105
|
continue;
|
|
81
106
|
}
|
|
82
107
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
let cols = rows[j].querySelectorAll("td");
|
|
87
|
-
|
|
88
|
-
if (cols.length < 7) {
|
|
89
|
-
// console.log('WARN invalid table row:', rows[j], node.textContent);
|
|
90
|
-
continue;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
/*
|
|
94
|
-
Remove hidden child node of first cell:
|
|
95
|
-
|
|
96
|
-
<td><div style="overflow:hidden;width:0;height:0;margin:-1ex;float:right">
|
|
97
|
-
<h3><span class="mw-headline" id="United_States_of_America_-_US_-_313">United States of America - US - 313</span></h3>
|
|
98
|
-
</div>313
|
|
99
|
-
</td>
|
|
100
|
-
*/
|
|
101
|
-
const mccChild = cols[0].querySelector("div");
|
|
102
|
-
if (mccChild !== null) {
|
|
103
|
-
cols[0].removeChild(mccChild);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
let status = cleanup(cols[4].textContent);
|
|
107
|
-
if (status === "Not Operational" || status === "Not opearational") {
|
|
108
|
-
status = "Not operational";
|
|
109
|
-
}
|
|
110
|
-
if (status === "operational") {
|
|
111
|
-
status = "Operational";
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
if (status && statusCodes.indexOf(status) === -1) {
|
|
115
|
-
statusCodes.push(status);
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
records.push({
|
|
119
|
-
type: recordType,
|
|
120
|
-
countryName: countryInfo.name,
|
|
121
|
-
countryCode: countryInfo.code,
|
|
122
|
-
mcc: cleanup(cols[0].textContent),
|
|
123
|
-
mnc: cleanup(cols[1].textContent),
|
|
124
|
-
brand: cleanup(cols[2].textContent),
|
|
125
|
-
operator: cleanup(cols[3].textContent),
|
|
126
|
-
status: status,
|
|
127
|
-
bands: cleanup(cols[5].textContent),
|
|
128
|
-
notes: cleanup(cols[6].textContent),
|
|
129
|
-
});
|
|
108
|
+
// Wikipedia occasionally omits the final, empty notes cell.
|
|
109
|
+
if (cols.length < 6 || cols.length > 7) {
|
|
110
|
+
throw new Error(`Unexpected operator row in ${from}`);
|
|
130
111
|
}
|
|
112
|
+
|
|
113
|
+
const mcc = getCellText(cols[0], true);
|
|
114
|
+
const mnc = getCellText(cols[1]);
|
|
115
|
+
|
|
116
|
+
if (!/^\d{3}$/.test(mcc) || !mnc) {
|
|
117
|
+
throw new Error(`Invalid MCC/MNC row: ${mcc}/${mnc}`);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
let status = getCellText(cols[4]);
|
|
121
|
+
|
|
122
|
+
if (/^not (operational|opearational)$/i.test(status)) {
|
|
123
|
+
status = "Not operational";
|
|
124
|
+
}
|
|
125
|
+
if (/^operational$/i.test(status)) {
|
|
126
|
+
status = "Operational";
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (status && statusCodes.indexOf(status) === -1) {
|
|
130
|
+
statusCodes.push(status);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
records.push({
|
|
134
|
+
type: recordType,
|
|
135
|
+
countryName: countryInfo.name,
|
|
136
|
+
countryCode: countryInfo.code,
|
|
137
|
+
mcc: mcc,
|
|
138
|
+
mnc: mnc,
|
|
139
|
+
brand: getCellText(cols[2]),
|
|
140
|
+
operator: getCellText(cols[3]),
|
|
141
|
+
status: status,
|
|
142
|
+
bands: getCellText(cols[5]),
|
|
143
|
+
notes: cols[6] ? getCellText(cols[6]) : null,
|
|
144
|
+
});
|
|
131
145
|
}
|
|
132
146
|
}
|
|
133
147
|
|
|
134
|
-
|
|
135
|
-
});
|
|
136
|
-
}
|
|
148
|
+
const pageRecords = records.slice(previousCount);
|
|
137
149
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
(
|
|
143
|
-
|
|
144
|
-
|
|
150
|
+
if (!pageRecords.length) {
|
|
151
|
+
throw new Error(`No operator records found: ${from}`);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (globals) {
|
|
155
|
+
for (const type of ["Test", "International"]) {
|
|
156
|
+
if (!pageRecords.some((record) => record.type === type)) {
|
|
157
|
+
throw new Error(`Missing ${type} operator table: ${from}`);
|
|
158
|
+
}
|
|
145
159
|
}
|
|
146
|
-
console.log("MCC-MNC list saved to " + MCC_MNC_OUTPUT_FILE);
|
|
147
|
-
console.log("Total " + records.length + " records");
|
|
148
160
|
}
|
|
149
|
-
|
|
161
|
+
} finally {
|
|
162
|
+
dom.window.close();
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
async function writeData(records, statusCodes) {
|
|
167
|
+
let previous;
|
|
168
|
+
|
|
169
|
+
try {
|
|
170
|
+
previous = JSON.parse(await fs.readFile(MCC_MNC_OUTPUT_FILE, "utf8"));
|
|
171
|
+
} catch (error) {
|
|
172
|
+
if (error.code !== "ENOENT") {
|
|
173
|
+
throw error;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
if (!records.length) {
|
|
178
|
+
throw new Error("Refusing to save an empty list");
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
if (previous && records.length < previous.length * 0.8) {
|
|
182
|
+
throw new Error(
|
|
183
|
+
`Refusing suspicious list shrinkage: ${previous.length} to ${records.length} records`
|
|
184
|
+
);
|
|
185
|
+
}
|
|
150
186
|
|
|
151
187
|
statusCodes.sort();
|
|
152
188
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
189
|
+
const outputs = [
|
|
190
|
+
[MCC_MNC_OUTPUT_FILE, records],
|
|
191
|
+
[STATUS_CODES_OUTPUT_FILE, statusCodes],
|
|
192
|
+
];
|
|
193
|
+
|
|
194
|
+
// Finish every download and validation before replacing either data file.
|
|
195
|
+
try {
|
|
196
|
+
for (const [file, data] of outputs) {
|
|
197
|
+
await fs.writeFile(`${file}.tmp`, JSON.stringify(data, null, 2) + "\n");
|
|
161
198
|
}
|
|
162
|
-
|
|
199
|
+
|
|
200
|
+
for (const [file] of outputs) {
|
|
201
|
+
await fs.rename(`${file}.tmp`, file);
|
|
202
|
+
}
|
|
203
|
+
} finally {
|
|
204
|
+
for (const [file] of outputs) {
|
|
205
|
+
await fs.rm(`${file}.tmp`, { force: true });
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
console.log("MCC-MNC list saved to " + MCC_MNC_OUTPUT_FILE);
|
|
210
|
+
console.log("Total " + records.length + " records");
|
|
211
|
+
console.log("Status codes saved to " + STATUS_CODES_OUTPUT_FILE);
|
|
163
212
|
}
|
|
164
213
|
|
|
165
214
|
function getRecordType(node) {
|
|
@@ -169,81 +218,101 @@ function getRecordType(node) {
|
|
|
169
218
|
"International operators": "International",
|
|
170
219
|
};
|
|
171
220
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
);
|
|
221
|
+
return recordTypeMap[cleanup(node.textContent)] || null;
|
|
222
|
+
}
|
|
175
223
|
|
|
176
|
-
|
|
177
|
-
|
|
224
|
+
function getCountryInfo(node) {
|
|
225
|
+
const countryText = cleanup(node.textContent);
|
|
226
|
+
const match =
|
|
227
|
+
countryText &&
|
|
228
|
+
countryText.match(/^(.*?)\s+[–—-]\s+([A-Z]{2}(?:[-/][A-Z]{2})*)$/);
|
|
229
|
+
|
|
230
|
+
return {
|
|
231
|
+
name: match ? match[1] : null,
|
|
232
|
+
code: match ? match[2] : null,
|
|
233
|
+
};
|
|
234
|
+
}
|
|
178
235
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
sectionName === "External links" ||
|
|
183
|
-
sectionName === "National MNC Authorities"
|
|
184
|
-
) {
|
|
185
|
-
return null;
|
|
186
|
-
}
|
|
236
|
+
function getTableRows(table) {
|
|
237
|
+
const rows = [];
|
|
238
|
+
const spans = [];
|
|
187
239
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
240
|
+
for (const row of table.rows) {
|
|
241
|
+
const cells = Array.from(row.cells);
|
|
242
|
+
const cols = [];
|
|
243
|
+
let index = 0;
|
|
191
244
|
|
|
192
|
-
|
|
193
|
-
|
|
245
|
+
// Carry merged cells forward so column positions remain consistent.
|
|
246
|
+
while (cells.length || spans[index]) {
|
|
247
|
+
const span = spans[index];
|
|
194
248
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
249
|
+
if (span) {
|
|
250
|
+
cols.push(span.cell);
|
|
251
|
+
span.remaining--;
|
|
252
|
+
|
|
253
|
+
if (span.remaining === 0) {
|
|
254
|
+
delete spans[index];
|
|
255
|
+
}
|
|
199
256
|
|
|
200
|
-
|
|
201
|
-
|
|
257
|
+
index++;
|
|
258
|
+
continue;
|
|
259
|
+
}
|
|
202
260
|
|
|
203
|
-
|
|
204
|
-
const countryText = h4Node.textContent.trim();
|
|
205
|
-
const dashPos = countryText.indexOf("–");
|
|
261
|
+
const cell = cells.shift();
|
|
206
262
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
263
|
+
for (let column = 0; column < cell.colSpan; column++) {
|
|
264
|
+
cols.push(cell);
|
|
265
|
+
|
|
266
|
+
if (cell.rowSpan > 1) {
|
|
267
|
+
spans[index] = { cell: cell, remaining: cell.rowSpan - 1 };
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
index++;
|
|
271
|
+
}
|
|
210
272
|
}
|
|
273
|
+
|
|
274
|
+
rows.push(cols);
|
|
211
275
|
}
|
|
212
276
|
|
|
213
|
-
return
|
|
277
|
+
return rows;
|
|
214
278
|
}
|
|
215
279
|
|
|
216
|
-
function
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
280
|
+
function getCellText(cell, isMcc = false) {
|
|
281
|
+
const copy = cell.cloneNode(true);
|
|
282
|
+
|
|
283
|
+
if (isMcc) {
|
|
284
|
+
// Some MCC cells contain a hidden heading used as a link target.
|
|
285
|
+
for (const node of copy.querySelectorAll("div")) {
|
|
286
|
+
node.remove();
|
|
223
287
|
}
|
|
224
288
|
}
|
|
225
289
|
|
|
226
|
-
|
|
290
|
+
for (const node of copy.querySelectorAll("br")) {
|
|
291
|
+
node.replaceWith(" / ");
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
return cleanup(copy.textContent);
|
|
227
295
|
}
|
|
228
296
|
|
|
229
|
-
function
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
if (str.substr(0, 1) != "[" && str.substr(-1) === "]") {
|
|
237
|
-
// remove postfix references like ...[7]
|
|
238
|
-
let index = str.lastIndexOf("[");
|
|
239
|
-
str = str.substr(0, index - 1).trim();
|
|
297
|
+
function removeCiteReferences(content) {
|
|
298
|
+
const references = content.querySelectorAll(
|
|
299
|
+
"sup.reference, sup.mw-ref, .mw-editsection, a[href*='#cite_note']"
|
|
300
|
+
);
|
|
301
|
+
|
|
302
|
+
for (const reference of references) {
|
|
303
|
+
reference.remove();
|
|
240
304
|
}
|
|
241
|
-
str = str.replace(/“/g, '"');
|
|
242
|
-
return str.length ? str : null;
|
|
243
305
|
}
|
|
244
306
|
|
|
245
|
-
function
|
|
246
|
-
|
|
307
|
+
function cleanup(str) {
|
|
308
|
+
str = str.replace(/\[(?:\d+(?:[ ,–-]\d+)*|citation needed)\]/gi, "");
|
|
309
|
+
str = str.replace(/[“”]/g, '"');
|
|
310
|
+
str = str.replace(/\s+/g, " ").trim();
|
|
311
|
+
|
|
312
|
+
return str.length ? str : null;
|
|
247
313
|
}
|
|
248
314
|
|
|
249
|
-
fetch()
|
|
315
|
+
fetch().catch((error) => {
|
|
316
|
+
console.error(error.message);
|
|
317
|
+
process.exitCode = 1;
|
|
318
|
+
});
|
package/index.js
CHANGED
|
@@ -16,13 +16,13 @@ function filter(filters) {
|
|
|
16
16
|
return records;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
if (typeof filters !== "object") {
|
|
19
|
+
if (typeof filters !== "object" || Array.isArray(filters)) {
|
|
20
20
|
throw new TypeError("Invalid parameter (object expected)");
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
let statusCode, mcc, mnc, countryCode;
|
|
24
24
|
|
|
25
|
-
if (filters.statusCode) {
|
|
25
|
+
if (filters.statusCode !== undefined) {
|
|
26
26
|
statusCode = filters.statusCode;
|
|
27
27
|
if (statusCodeList.indexOf(statusCode) === -1) {
|
|
28
28
|
throw new TypeError(
|
|
@@ -31,7 +31,7 @@ function filter(filters) {
|
|
|
31
31
|
}
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
if (filters.mccmnc) {
|
|
34
|
+
if (filters.mccmnc !== undefined) {
|
|
35
35
|
let mccmnc;
|
|
36
36
|
if (
|
|
37
37
|
typeof filters.mccmnc === "string" ||
|
|
@@ -41,18 +41,18 @@ function filter(filters) {
|
|
|
41
41
|
} else {
|
|
42
42
|
throw new TypeError("Invalid mccmnc parameter (string expected)");
|
|
43
43
|
}
|
|
44
|
-
mcc = mccmnc.
|
|
45
|
-
mnc = mccmnc.
|
|
44
|
+
mcc = mccmnc.slice(0, 3);
|
|
45
|
+
mnc = mccmnc.slice(3);
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
if (filters.mcc &&
|
|
48
|
+
if (filters.mcc !== undefined && filters.mccmnc !== undefined) {
|
|
49
49
|
throw new TypeError("Don't use mccmnc and mcc parameter at once");
|
|
50
50
|
}
|
|
51
|
-
if (filters.mnc &&
|
|
51
|
+
if (filters.mnc !== undefined && filters.mccmnc !== undefined) {
|
|
52
52
|
throw new TypeError("Don't use mccmnc and mnc parameter at once");
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
if (filters.mcc) {
|
|
55
|
+
if (filters.mcc !== undefined) {
|
|
56
56
|
if (typeof filters.mcc === "string" || typeof filters.mcc === "number") {
|
|
57
57
|
mcc = String(filters.mcc);
|
|
58
58
|
} else {
|
|
@@ -60,7 +60,7 @@ function filter(filters) {
|
|
|
60
60
|
}
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
-
if (filters.mnc) {
|
|
63
|
+
if (filters.mnc !== undefined) {
|
|
64
64
|
if (typeof filters.mnc === "string" || typeof filters.mnc === "number") {
|
|
65
65
|
mnc = String(filters.mnc);
|
|
66
66
|
} else {
|
|
@@ -78,16 +78,16 @@ function filter(filters) {
|
|
|
78
78
|
|
|
79
79
|
let result = records;
|
|
80
80
|
|
|
81
|
-
if (statusCode) {
|
|
81
|
+
if (statusCode !== undefined) {
|
|
82
82
|
result = result.filter((record) => record["status"] === statusCode);
|
|
83
83
|
}
|
|
84
|
-
if (countryCode) {
|
|
84
|
+
if (countryCode !== undefined) {
|
|
85
85
|
result = result.filter((record) => record["countryCode"] === countryCode);
|
|
86
86
|
}
|
|
87
|
-
if (mcc) {
|
|
87
|
+
if (mcc !== undefined) {
|
|
88
88
|
result = result.filter((record) => record["mcc"] === mcc);
|
|
89
89
|
}
|
|
90
|
-
if (mnc) {
|
|
90
|
+
if (mnc !== undefined) {
|
|
91
91
|
result = result.filter((record) => record["mnc"] === mnc);
|
|
92
92
|
}
|
|
93
93
|
|
|
@@ -95,7 +95,7 @@ function filter(filters) {
|
|
|
95
95
|
}
|
|
96
96
|
|
|
97
97
|
function find(filters) {
|
|
98
|
-
// return the first element
|
|
98
|
+
// return the first element or undefined, as filter will always return an array
|
|
99
99
|
return filter(filters)[0];
|
|
100
100
|
}
|
|
101
101
|
|