@email-utils/validator-syntax 0.0.1-8 → 1.0.0-rc.1
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/LICENSE +21 -0
- package/Readme.md +1 -1
- package/THIRD_PARTY_NOTICES.md +37 -0
- package/dist/fixtures.cjs +2112 -0
- package/dist/fixtures.cjs.map +1 -0
- package/dist/fixtures.d.cts +121 -0
- package/dist/fixtures.d.mts +121 -0
- package/dist/fixtures.mjs +2103 -0
- package/dist/fixtures.mjs.map +1 -0
- package/dist/index.cjs +2141 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +87 -0
- package/dist/index.d.mts +87 -0
- package/dist/index.mjs +2138 -0
- package/dist/index.mjs.map +1 -0
- package/dist/result-BZjmlevS.d.cts +100 -0
- package/dist/result-BZjmlevS.d.mts +100 -0
- package/package.json +62 -73
- package/.babelrc +0 -8
- package/.eslintignore +0 -5
- package/.nvmrc +0 -1
- package/.nycrc.json +0 -11
- package/@types/index.d.ts +0 -30
- package/Readme.old.md +0 -103
- package/bin/tag.sh +0 -21
- package/dist/index.js +0 -273
- package/dist/index.js.map +0 -1
- package/src/index.ts +0 -344
- package/test/index.test.ts +0 -1612
- package/tsconfig.json +0 -22
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,2141 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const table = /* @__PURE__ */ new Uint8Array(128);
|
|
3
|
+
function mark(chars, flag) {
|
|
4
|
+
for (let i = 0; i < chars.length; i++) table[chars.charCodeAt(i)] |= flag;
|
|
5
|
+
}
|
|
6
|
+
const alnum = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
|
7
|
+
mark(alnum + "!#$%&'*+-/=?^_`{|}~", 1);
|
|
8
|
+
mark(alnum + "#$&'*+-/=?^_`{|}~", 2);
|
|
9
|
+
mark(alnum + "!#$%&'*+-/=?^_`{|}~.", 4);
|
|
10
|
+
mark(alnum + "-", 8);
|
|
11
|
+
/** Whether the character with this code is in the class `flag`. */
|
|
12
|
+
function inClass(code, flag) {
|
|
13
|
+
return code < 128 && (table[code] & flag) !== 0;
|
|
14
|
+
}
|
|
15
|
+
/** Space, tab, CR, and LF: the characters folding whitespace is made of. */
|
|
16
|
+
function isWhitespace(code) {
|
|
17
|
+
return code === 32 || code === 9 || code === 13 || code === 10;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* The code units in the non-ASCII code point at `i`, before `end`: 2 for a
|
|
21
|
+
* surrogate pair, 1 for anything else outside ASCII, and 0 for ASCII or a
|
|
22
|
+
* lone surrogate, which no UTF-8 text can hold.
|
|
23
|
+
*/
|
|
24
|
+
function nonAsciiAt(text, i, end) {
|
|
25
|
+
const code = text.charCodeAt(i);
|
|
26
|
+
if (code < 128 || code >= 56320 && code <= 57343) return 0;
|
|
27
|
+
if (code < 55296 || code > 56319) return 1;
|
|
28
|
+
const low = i + 1 < end ? text.charCodeAt(i + 1) : 0;
|
|
29
|
+
return low >= 56320 && low <= 57343 ? 2 : 0;
|
|
30
|
+
}
|
|
31
|
+
/** The length of `text` in UTF-8 octets, the unit RFC 6531 caps a local part in. */
|
|
32
|
+
function utf8Length(text) {
|
|
33
|
+
let octets = text.length;
|
|
34
|
+
for (let i = 0; i < text.length; i++) {
|
|
35
|
+
const code = text.charCodeAt(i);
|
|
36
|
+
if (code >= 2048 && (code < 55296 || code > 57343)) octets += 2;
|
|
37
|
+
else if (code >= 128) octets += 1;
|
|
38
|
+
}
|
|
39
|
+
return octets;
|
|
40
|
+
}
|
|
41
|
+
//#endregion
|
|
42
|
+
//#region src/options.ts
|
|
43
|
+
const presets = {
|
|
44
|
+
practical: {
|
|
45
|
+
local: 2,
|
|
46
|
+
domain: 8,
|
|
47
|
+
quotes: false,
|
|
48
|
+
literals: false,
|
|
49
|
+
comments: false,
|
|
50
|
+
obs: false,
|
|
51
|
+
localCap: 64,
|
|
52
|
+
domainCap: 253,
|
|
53
|
+
checkTld: true,
|
|
54
|
+
allowNoTld: false,
|
|
55
|
+
unicode: false,
|
|
56
|
+
idn: false
|
|
57
|
+
},
|
|
58
|
+
rfc5321: {
|
|
59
|
+
local: 1,
|
|
60
|
+
domain: 8,
|
|
61
|
+
quotes: true,
|
|
62
|
+
literals: true,
|
|
63
|
+
comments: false,
|
|
64
|
+
obs: false,
|
|
65
|
+
localCap: 64,
|
|
66
|
+
domainCap: 253,
|
|
67
|
+
checkTld: false,
|
|
68
|
+
allowNoTld: false,
|
|
69
|
+
unicode: false,
|
|
70
|
+
idn: false
|
|
71
|
+
},
|
|
72
|
+
rfc5322: {
|
|
73
|
+
local: 1,
|
|
74
|
+
domain: 1,
|
|
75
|
+
quotes: true,
|
|
76
|
+
literals: true,
|
|
77
|
+
comments: true,
|
|
78
|
+
obs: true,
|
|
79
|
+
localCap: Infinity,
|
|
80
|
+
domainCap: 253,
|
|
81
|
+
checkTld: false,
|
|
82
|
+
allowNoTld: false,
|
|
83
|
+
unicode: false,
|
|
84
|
+
idn: false
|
|
85
|
+
},
|
|
86
|
+
html5: {
|
|
87
|
+
local: 4,
|
|
88
|
+
domain: 8,
|
|
89
|
+
quotes: false,
|
|
90
|
+
literals: false,
|
|
91
|
+
comments: false,
|
|
92
|
+
obs: false,
|
|
93
|
+
localCap: Infinity,
|
|
94
|
+
domainCap: Infinity,
|
|
95
|
+
checkTld: false,
|
|
96
|
+
allowNoTld: true,
|
|
97
|
+
unicode: false,
|
|
98
|
+
idn: false
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
const overrides = [
|
|
102
|
+
"checkTld",
|
|
103
|
+
"allowNoTld",
|
|
104
|
+
"allowComments",
|
|
105
|
+
"allowUnicode",
|
|
106
|
+
"allowIdn",
|
|
107
|
+
"allowIpLiteral"
|
|
108
|
+
];
|
|
109
|
+
const unsupported = {
|
|
110
|
+
practical: [],
|
|
111
|
+
rfc5321: ["allowComments"],
|
|
112
|
+
rfc5322: [],
|
|
113
|
+
html5: [
|
|
114
|
+
"allowComments",
|
|
115
|
+
"allowUnicode",
|
|
116
|
+
"allowIdn",
|
|
117
|
+
"allowIpLiteral"
|
|
118
|
+
]
|
|
119
|
+
};
|
|
120
|
+
/**
|
|
121
|
+
* Resolves `options` into the rules they select.
|
|
122
|
+
*
|
|
123
|
+
* @throws TypeError when `options` isn't an object, names an unknown option
|
|
124
|
+
* or preset, gives a non-boolean override, or turns on something the
|
|
125
|
+
* preset's grammar has no room for.
|
|
126
|
+
*/
|
|
127
|
+
function resolve(options) {
|
|
128
|
+
if (options === void 0) return presets.practical;
|
|
129
|
+
if (typeof options !== "object" || options === null) throw new TypeError("Expected the options to be an object");
|
|
130
|
+
for (const key of Object.keys(options)) if (key !== "preset" && !overrides.includes(key)) throw new TypeError(`Unknown option: ${key}`);
|
|
131
|
+
const preset = options.preset ?? "practical";
|
|
132
|
+
if (!Object.hasOwn(presets, preset)) throw new TypeError(`Unknown preset: ${preset}`);
|
|
133
|
+
const base = presets[preset];
|
|
134
|
+
for (const key of overrides) {
|
|
135
|
+
const value = options[key];
|
|
136
|
+
if (value !== void 0 && typeof value !== "boolean") throw new TypeError(`Expected ${key} to be a boolean`);
|
|
137
|
+
}
|
|
138
|
+
for (const key of unsupported[preset]) if (options[key] === true) throw new TypeError(`${key} can’t be true with the ${preset} preset`);
|
|
139
|
+
if (overrides.every((key) => options[key] === void 0)) return base;
|
|
140
|
+
return {
|
|
141
|
+
...base,
|
|
142
|
+
checkTld: options.checkTld ?? base.checkTld,
|
|
143
|
+
allowNoTld: options.allowNoTld ?? base.allowNoTld,
|
|
144
|
+
comments: options.allowComments ?? base.comments,
|
|
145
|
+
unicode: options.allowUnicode ?? base.unicode,
|
|
146
|
+
idn: options.allowIdn ?? base.idn,
|
|
147
|
+
literals: options.allowIpLiteral ?? base.literals
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
//#endregion
|
|
151
|
+
//#region src/idn.ts
|
|
152
|
+
const ldh = /^[\da-z-]+$/;
|
|
153
|
+
/**
|
|
154
|
+
* The A-label for a U-label, or `undefined` when UTS #46 rejects it or maps
|
|
155
|
+
* it to something other than one IDN label (plain ASCII, or two labels, as
|
|
156
|
+
* `。` becomes a dot).
|
|
157
|
+
*
|
|
158
|
+
* @remarks
|
|
159
|
+
* Converts by way of the WHATWG URL host parser, which every runtime the
|
|
160
|
+
* package supports has and which applies UTS #46 with its bidi and joiner
|
|
161
|
+
* checks. It leaves hyphens and lengths alone, so the caller checks those.
|
|
162
|
+
*/
|
|
163
|
+
function toALabel(label) {
|
|
164
|
+
let host;
|
|
165
|
+
try {
|
|
166
|
+
host = new URL(`http://x.${label}`).hostname;
|
|
167
|
+
} catch {
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
const aLabel = host.slice(2);
|
|
171
|
+
return aLabel.startsWith("xn--") && ldh.test(aLabel) ? aLabel : void 0;
|
|
172
|
+
}
|
|
173
|
+
//#endregion
|
|
174
|
+
//#region src/ip.ts
|
|
175
|
+
const octet = /^\d{1,3}$/;
|
|
176
|
+
const hexGroup = /^[\dA-Fa-f]{1,4}$/;
|
|
177
|
+
/** An IPv4 address: four dot-separated decimal octets, each 0–255. */
|
|
178
|
+
function isIPv4(text) {
|
|
179
|
+
const parts = text.split(".");
|
|
180
|
+
return parts.length === 4 && parts.every((part) => octet.test(part) && Number(part) <= 255);
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* An IPv6 address as RFC 5321 writes it: eight hex groups, or a `::` with no
|
|
184
|
+
* more than six groups beside it, and either may end in an IPv4 address in
|
|
185
|
+
* place of the last two groups.
|
|
186
|
+
*/
|
|
187
|
+
function isIPv6(text) {
|
|
188
|
+
const colon = text.lastIndexOf(":");
|
|
189
|
+
const tail = text.slice(colon + 1);
|
|
190
|
+
if (tail.includes(".")) {
|
|
191
|
+
if (!isIPv4(tail)) return false;
|
|
192
|
+
text = `${text.slice(0, colon + 1)}0:0`;
|
|
193
|
+
}
|
|
194
|
+
const halves = text.split("::");
|
|
195
|
+
if (halves.length > 2) return false;
|
|
196
|
+
const groups = halves.flatMap((half) => half === "" ? [] : half.split(":"));
|
|
197
|
+
return groups.every((group) => hexGroup.test(group)) && (halves.length === 1 ? groups.length === 8 : groups.length <= 6);
|
|
198
|
+
}
|
|
199
|
+
/** The text of an RFC 5321 address literal: IPv4, or `IPv6:` and IPv6. */
|
|
200
|
+
function isAddressLiteral(text) {
|
|
201
|
+
return /^IPv6:/i.test(text) ? isIPv6(text.slice(5)) : isIPv4(text);
|
|
202
|
+
}
|
|
203
|
+
//#endregion
|
|
204
|
+
//#region node_modules/tlds/index.json
|
|
205
|
+
var tlds_default = [
|
|
206
|
+
"aaa",
|
|
207
|
+
"aarp",
|
|
208
|
+
"abb",
|
|
209
|
+
"abbott",
|
|
210
|
+
"abbvie",
|
|
211
|
+
"abc",
|
|
212
|
+
"able",
|
|
213
|
+
"abogado",
|
|
214
|
+
"abudhabi",
|
|
215
|
+
"ac",
|
|
216
|
+
"academy",
|
|
217
|
+
"accenture",
|
|
218
|
+
"accountant",
|
|
219
|
+
"accountants",
|
|
220
|
+
"aco",
|
|
221
|
+
"actor",
|
|
222
|
+
"ad",
|
|
223
|
+
"ads",
|
|
224
|
+
"adult",
|
|
225
|
+
"ae",
|
|
226
|
+
"aeg",
|
|
227
|
+
"aero",
|
|
228
|
+
"aetna",
|
|
229
|
+
"af",
|
|
230
|
+
"afl",
|
|
231
|
+
"africa",
|
|
232
|
+
"ag",
|
|
233
|
+
"agakhan",
|
|
234
|
+
"agency",
|
|
235
|
+
"ai",
|
|
236
|
+
"aig",
|
|
237
|
+
"airbus",
|
|
238
|
+
"airforce",
|
|
239
|
+
"airtel",
|
|
240
|
+
"akdn",
|
|
241
|
+
"al",
|
|
242
|
+
"alibaba",
|
|
243
|
+
"alipay",
|
|
244
|
+
"allfinanz",
|
|
245
|
+
"allstate",
|
|
246
|
+
"ally",
|
|
247
|
+
"alsace",
|
|
248
|
+
"alstom",
|
|
249
|
+
"am",
|
|
250
|
+
"amazon",
|
|
251
|
+
"americanexpress",
|
|
252
|
+
"americanfamily",
|
|
253
|
+
"amex",
|
|
254
|
+
"amfam",
|
|
255
|
+
"amica",
|
|
256
|
+
"amsterdam",
|
|
257
|
+
"analytics",
|
|
258
|
+
"android",
|
|
259
|
+
"anquan",
|
|
260
|
+
"anz",
|
|
261
|
+
"ao",
|
|
262
|
+
"aol",
|
|
263
|
+
"apartments",
|
|
264
|
+
"app",
|
|
265
|
+
"apple",
|
|
266
|
+
"aq",
|
|
267
|
+
"aquarelle",
|
|
268
|
+
"ar",
|
|
269
|
+
"arab",
|
|
270
|
+
"aramco",
|
|
271
|
+
"archi",
|
|
272
|
+
"army",
|
|
273
|
+
"arpa",
|
|
274
|
+
"art",
|
|
275
|
+
"arte",
|
|
276
|
+
"as",
|
|
277
|
+
"asda",
|
|
278
|
+
"asia",
|
|
279
|
+
"associates",
|
|
280
|
+
"at",
|
|
281
|
+
"athleta",
|
|
282
|
+
"attorney",
|
|
283
|
+
"au",
|
|
284
|
+
"auction",
|
|
285
|
+
"audi",
|
|
286
|
+
"audible",
|
|
287
|
+
"audio",
|
|
288
|
+
"auspost",
|
|
289
|
+
"author",
|
|
290
|
+
"auto",
|
|
291
|
+
"autos",
|
|
292
|
+
"aw",
|
|
293
|
+
"aws",
|
|
294
|
+
"ax",
|
|
295
|
+
"axa",
|
|
296
|
+
"az",
|
|
297
|
+
"azure",
|
|
298
|
+
"ba",
|
|
299
|
+
"baby",
|
|
300
|
+
"baidu",
|
|
301
|
+
"banamex",
|
|
302
|
+
"band",
|
|
303
|
+
"bank",
|
|
304
|
+
"bar",
|
|
305
|
+
"barcelona",
|
|
306
|
+
"barclaycard",
|
|
307
|
+
"barclays",
|
|
308
|
+
"barefoot",
|
|
309
|
+
"bargains",
|
|
310
|
+
"baseball",
|
|
311
|
+
"basketball",
|
|
312
|
+
"bauhaus",
|
|
313
|
+
"bayern",
|
|
314
|
+
"bb",
|
|
315
|
+
"bbc",
|
|
316
|
+
"bbt",
|
|
317
|
+
"bbva",
|
|
318
|
+
"bcg",
|
|
319
|
+
"bcn",
|
|
320
|
+
"bd",
|
|
321
|
+
"be",
|
|
322
|
+
"beats",
|
|
323
|
+
"beauty",
|
|
324
|
+
"beer",
|
|
325
|
+
"berlin",
|
|
326
|
+
"best",
|
|
327
|
+
"bestbuy",
|
|
328
|
+
"bet",
|
|
329
|
+
"bf",
|
|
330
|
+
"bg",
|
|
331
|
+
"bh",
|
|
332
|
+
"bharti",
|
|
333
|
+
"bi",
|
|
334
|
+
"bible",
|
|
335
|
+
"bid",
|
|
336
|
+
"bike",
|
|
337
|
+
"bing",
|
|
338
|
+
"bingo",
|
|
339
|
+
"bio",
|
|
340
|
+
"biz",
|
|
341
|
+
"bj",
|
|
342
|
+
"black",
|
|
343
|
+
"blackfriday",
|
|
344
|
+
"blockbuster",
|
|
345
|
+
"blog",
|
|
346
|
+
"bloomberg",
|
|
347
|
+
"blue",
|
|
348
|
+
"bm",
|
|
349
|
+
"bms",
|
|
350
|
+
"bmw",
|
|
351
|
+
"bn",
|
|
352
|
+
"bnpparibas",
|
|
353
|
+
"bo",
|
|
354
|
+
"boats",
|
|
355
|
+
"boehringer",
|
|
356
|
+
"bofa",
|
|
357
|
+
"bom",
|
|
358
|
+
"bond",
|
|
359
|
+
"boo",
|
|
360
|
+
"book",
|
|
361
|
+
"booking",
|
|
362
|
+
"bosch",
|
|
363
|
+
"bostik",
|
|
364
|
+
"boston",
|
|
365
|
+
"bot",
|
|
366
|
+
"boutique",
|
|
367
|
+
"box",
|
|
368
|
+
"br",
|
|
369
|
+
"bradesco",
|
|
370
|
+
"bridgestone",
|
|
371
|
+
"broadway",
|
|
372
|
+
"broker",
|
|
373
|
+
"brother",
|
|
374
|
+
"brussels",
|
|
375
|
+
"bs",
|
|
376
|
+
"bt",
|
|
377
|
+
"build",
|
|
378
|
+
"builders",
|
|
379
|
+
"business",
|
|
380
|
+
"buy",
|
|
381
|
+
"buzz",
|
|
382
|
+
"bv",
|
|
383
|
+
"bw",
|
|
384
|
+
"by",
|
|
385
|
+
"bz",
|
|
386
|
+
"bzh",
|
|
387
|
+
"ca",
|
|
388
|
+
"cab",
|
|
389
|
+
"cafe",
|
|
390
|
+
"cal",
|
|
391
|
+
"call",
|
|
392
|
+
"calvinklein",
|
|
393
|
+
"cam",
|
|
394
|
+
"camera",
|
|
395
|
+
"camp",
|
|
396
|
+
"canon",
|
|
397
|
+
"capetown",
|
|
398
|
+
"capital",
|
|
399
|
+
"capitalone",
|
|
400
|
+
"car",
|
|
401
|
+
"caravan",
|
|
402
|
+
"cards",
|
|
403
|
+
"care",
|
|
404
|
+
"career",
|
|
405
|
+
"careers",
|
|
406
|
+
"cars",
|
|
407
|
+
"casa",
|
|
408
|
+
"case",
|
|
409
|
+
"cash",
|
|
410
|
+
"casino",
|
|
411
|
+
"cat",
|
|
412
|
+
"catering",
|
|
413
|
+
"catholic",
|
|
414
|
+
"cba",
|
|
415
|
+
"cbn",
|
|
416
|
+
"cbre",
|
|
417
|
+
"cc",
|
|
418
|
+
"cd",
|
|
419
|
+
"center",
|
|
420
|
+
"ceo",
|
|
421
|
+
"cern",
|
|
422
|
+
"cf",
|
|
423
|
+
"cfa",
|
|
424
|
+
"cfd",
|
|
425
|
+
"cg",
|
|
426
|
+
"ch",
|
|
427
|
+
"chanel",
|
|
428
|
+
"channel",
|
|
429
|
+
"charity",
|
|
430
|
+
"chase",
|
|
431
|
+
"chat",
|
|
432
|
+
"cheap",
|
|
433
|
+
"chintai",
|
|
434
|
+
"christmas",
|
|
435
|
+
"chrome",
|
|
436
|
+
"church",
|
|
437
|
+
"ci",
|
|
438
|
+
"cipriani",
|
|
439
|
+
"circle",
|
|
440
|
+
"cisco",
|
|
441
|
+
"citadel",
|
|
442
|
+
"citi",
|
|
443
|
+
"citic",
|
|
444
|
+
"city",
|
|
445
|
+
"ck",
|
|
446
|
+
"cl",
|
|
447
|
+
"claims",
|
|
448
|
+
"cleaning",
|
|
449
|
+
"click",
|
|
450
|
+
"clinic",
|
|
451
|
+
"clinique",
|
|
452
|
+
"clothing",
|
|
453
|
+
"cloud",
|
|
454
|
+
"club",
|
|
455
|
+
"clubmed",
|
|
456
|
+
"cm",
|
|
457
|
+
"cn",
|
|
458
|
+
"co",
|
|
459
|
+
"coach",
|
|
460
|
+
"codes",
|
|
461
|
+
"coffee",
|
|
462
|
+
"college",
|
|
463
|
+
"cologne",
|
|
464
|
+
"com",
|
|
465
|
+
"commbank",
|
|
466
|
+
"community",
|
|
467
|
+
"company",
|
|
468
|
+
"compare",
|
|
469
|
+
"computer",
|
|
470
|
+
"comsec",
|
|
471
|
+
"condos",
|
|
472
|
+
"construction",
|
|
473
|
+
"consulting",
|
|
474
|
+
"contact",
|
|
475
|
+
"contractors",
|
|
476
|
+
"cooking",
|
|
477
|
+
"cool",
|
|
478
|
+
"coop",
|
|
479
|
+
"corsica",
|
|
480
|
+
"country",
|
|
481
|
+
"coupon",
|
|
482
|
+
"coupons",
|
|
483
|
+
"courses",
|
|
484
|
+
"cpa",
|
|
485
|
+
"cr",
|
|
486
|
+
"credit",
|
|
487
|
+
"creditcard",
|
|
488
|
+
"creditunion",
|
|
489
|
+
"cricket",
|
|
490
|
+
"crown",
|
|
491
|
+
"crs",
|
|
492
|
+
"cruise",
|
|
493
|
+
"cruises",
|
|
494
|
+
"cu",
|
|
495
|
+
"cuisinella",
|
|
496
|
+
"cv",
|
|
497
|
+
"cw",
|
|
498
|
+
"cx",
|
|
499
|
+
"cy",
|
|
500
|
+
"cymru",
|
|
501
|
+
"cyou",
|
|
502
|
+
"cz",
|
|
503
|
+
"dad",
|
|
504
|
+
"dance",
|
|
505
|
+
"data",
|
|
506
|
+
"date",
|
|
507
|
+
"dating",
|
|
508
|
+
"datsun",
|
|
509
|
+
"day",
|
|
510
|
+
"dclk",
|
|
511
|
+
"dds",
|
|
512
|
+
"de",
|
|
513
|
+
"deal",
|
|
514
|
+
"dealer",
|
|
515
|
+
"deals",
|
|
516
|
+
"degree",
|
|
517
|
+
"delivery",
|
|
518
|
+
"dell",
|
|
519
|
+
"deloitte",
|
|
520
|
+
"delta",
|
|
521
|
+
"democrat",
|
|
522
|
+
"dental",
|
|
523
|
+
"dentist",
|
|
524
|
+
"desi",
|
|
525
|
+
"design",
|
|
526
|
+
"dev",
|
|
527
|
+
"dhl",
|
|
528
|
+
"diamonds",
|
|
529
|
+
"diet",
|
|
530
|
+
"digital",
|
|
531
|
+
"direct",
|
|
532
|
+
"directory",
|
|
533
|
+
"discount",
|
|
534
|
+
"discover",
|
|
535
|
+
"dish",
|
|
536
|
+
"diy",
|
|
537
|
+
"dj",
|
|
538
|
+
"dk",
|
|
539
|
+
"dm",
|
|
540
|
+
"dnp",
|
|
541
|
+
"do",
|
|
542
|
+
"docs",
|
|
543
|
+
"doctor",
|
|
544
|
+
"dog",
|
|
545
|
+
"domains",
|
|
546
|
+
"dot",
|
|
547
|
+
"download",
|
|
548
|
+
"drive",
|
|
549
|
+
"dtv",
|
|
550
|
+
"dubai",
|
|
551
|
+
"dupont",
|
|
552
|
+
"durban",
|
|
553
|
+
"dvag",
|
|
554
|
+
"dvr",
|
|
555
|
+
"dz",
|
|
556
|
+
"earth",
|
|
557
|
+
"eat",
|
|
558
|
+
"ec",
|
|
559
|
+
"eco",
|
|
560
|
+
"edeka",
|
|
561
|
+
"edu",
|
|
562
|
+
"education",
|
|
563
|
+
"ee",
|
|
564
|
+
"eg",
|
|
565
|
+
"email",
|
|
566
|
+
"emerck",
|
|
567
|
+
"energy",
|
|
568
|
+
"engineer",
|
|
569
|
+
"engineering",
|
|
570
|
+
"enterprises",
|
|
571
|
+
"epson",
|
|
572
|
+
"equipment",
|
|
573
|
+
"er",
|
|
574
|
+
"ericsson",
|
|
575
|
+
"erni",
|
|
576
|
+
"es",
|
|
577
|
+
"esq",
|
|
578
|
+
"estate",
|
|
579
|
+
"et",
|
|
580
|
+
"eu",
|
|
581
|
+
"eurovision",
|
|
582
|
+
"eus",
|
|
583
|
+
"events",
|
|
584
|
+
"exchange",
|
|
585
|
+
"expert",
|
|
586
|
+
"exposed",
|
|
587
|
+
"express",
|
|
588
|
+
"extraspace",
|
|
589
|
+
"fage",
|
|
590
|
+
"fail",
|
|
591
|
+
"fairwinds",
|
|
592
|
+
"faith",
|
|
593
|
+
"family",
|
|
594
|
+
"fan",
|
|
595
|
+
"fans",
|
|
596
|
+
"farm",
|
|
597
|
+
"farmers",
|
|
598
|
+
"fashion",
|
|
599
|
+
"fast",
|
|
600
|
+
"fedex",
|
|
601
|
+
"feedback",
|
|
602
|
+
"ferrari",
|
|
603
|
+
"ferrero",
|
|
604
|
+
"fi",
|
|
605
|
+
"fidelity",
|
|
606
|
+
"fido",
|
|
607
|
+
"film",
|
|
608
|
+
"final",
|
|
609
|
+
"finance",
|
|
610
|
+
"financial",
|
|
611
|
+
"fire",
|
|
612
|
+
"firestone",
|
|
613
|
+
"firmdale",
|
|
614
|
+
"fish",
|
|
615
|
+
"fishing",
|
|
616
|
+
"fit",
|
|
617
|
+
"fitness",
|
|
618
|
+
"fj",
|
|
619
|
+
"fk",
|
|
620
|
+
"flickr",
|
|
621
|
+
"flights",
|
|
622
|
+
"flir",
|
|
623
|
+
"florist",
|
|
624
|
+
"flowers",
|
|
625
|
+
"fly",
|
|
626
|
+
"fm",
|
|
627
|
+
"fo",
|
|
628
|
+
"foo",
|
|
629
|
+
"food",
|
|
630
|
+
"football",
|
|
631
|
+
"ford",
|
|
632
|
+
"forex",
|
|
633
|
+
"forsale",
|
|
634
|
+
"forum",
|
|
635
|
+
"foundation",
|
|
636
|
+
"fox",
|
|
637
|
+
"fr",
|
|
638
|
+
"free",
|
|
639
|
+
"fresenius",
|
|
640
|
+
"frl",
|
|
641
|
+
"frogans",
|
|
642
|
+
"frontier",
|
|
643
|
+
"ftr",
|
|
644
|
+
"fujitsu",
|
|
645
|
+
"fun",
|
|
646
|
+
"fund",
|
|
647
|
+
"furniture",
|
|
648
|
+
"futbol",
|
|
649
|
+
"fyi",
|
|
650
|
+
"ga",
|
|
651
|
+
"gal",
|
|
652
|
+
"gallery",
|
|
653
|
+
"gallo",
|
|
654
|
+
"gallup",
|
|
655
|
+
"game",
|
|
656
|
+
"games",
|
|
657
|
+
"gap",
|
|
658
|
+
"garden",
|
|
659
|
+
"gay",
|
|
660
|
+
"gb",
|
|
661
|
+
"gbiz",
|
|
662
|
+
"gd",
|
|
663
|
+
"gdn",
|
|
664
|
+
"ge",
|
|
665
|
+
"gea",
|
|
666
|
+
"gent",
|
|
667
|
+
"genting",
|
|
668
|
+
"george",
|
|
669
|
+
"gf",
|
|
670
|
+
"gg",
|
|
671
|
+
"ggee",
|
|
672
|
+
"gh",
|
|
673
|
+
"gi",
|
|
674
|
+
"gift",
|
|
675
|
+
"gifts",
|
|
676
|
+
"gives",
|
|
677
|
+
"giving",
|
|
678
|
+
"gl",
|
|
679
|
+
"glass",
|
|
680
|
+
"gle",
|
|
681
|
+
"global",
|
|
682
|
+
"globo",
|
|
683
|
+
"gm",
|
|
684
|
+
"gmail",
|
|
685
|
+
"gmbh",
|
|
686
|
+
"gmo",
|
|
687
|
+
"gmx",
|
|
688
|
+
"gn",
|
|
689
|
+
"godaddy",
|
|
690
|
+
"gold",
|
|
691
|
+
"goldpoint",
|
|
692
|
+
"golf",
|
|
693
|
+
"goo",
|
|
694
|
+
"goodyear",
|
|
695
|
+
"goog",
|
|
696
|
+
"google",
|
|
697
|
+
"gop",
|
|
698
|
+
"got",
|
|
699
|
+
"gov",
|
|
700
|
+
"gp",
|
|
701
|
+
"gq",
|
|
702
|
+
"gr",
|
|
703
|
+
"grainger",
|
|
704
|
+
"graphics",
|
|
705
|
+
"gratis",
|
|
706
|
+
"green",
|
|
707
|
+
"gripe",
|
|
708
|
+
"grocery",
|
|
709
|
+
"group",
|
|
710
|
+
"gs",
|
|
711
|
+
"gt",
|
|
712
|
+
"gu",
|
|
713
|
+
"gucci",
|
|
714
|
+
"guge",
|
|
715
|
+
"guide",
|
|
716
|
+
"guitars",
|
|
717
|
+
"guru",
|
|
718
|
+
"gw",
|
|
719
|
+
"gy",
|
|
720
|
+
"hair",
|
|
721
|
+
"hamburg",
|
|
722
|
+
"hangout",
|
|
723
|
+
"haus",
|
|
724
|
+
"hbo",
|
|
725
|
+
"hdfc",
|
|
726
|
+
"hdfcbank",
|
|
727
|
+
"health",
|
|
728
|
+
"healthcare",
|
|
729
|
+
"help",
|
|
730
|
+
"helsinki",
|
|
731
|
+
"here",
|
|
732
|
+
"hermes",
|
|
733
|
+
"hiphop",
|
|
734
|
+
"hisamitsu",
|
|
735
|
+
"hitachi",
|
|
736
|
+
"hiv",
|
|
737
|
+
"hk",
|
|
738
|
+
"hkt",
|
|
739
|
+
"hm",
|
|
740
|
+
"hn",
|
|
741
|
+
"hockey",
|
|
742
|
+
"holdings",
|
|
743
|
+
"holiday",
|
|
744
|
+
"homedepot",
|
|
745
|
+
"homegoods",
|
|
746
|
+
"homes",
|
|
747
|
+
"homesense",
|
|
748
|
+
"honda",
|
|
749
|
+
"horse",
|
|
750
|
+
"hospital",
|
|
751
|
+
"host",
|
|
752
|
+
"hosting",
|
|
753
|
+
"hot",
|
|
754
|
+
"hotels",
|
|
755
|
+
"hotmail",
|
|
756
|
+
"house",
|
|
757
|
+
"how",
|
|
758
|
+
"hr",
|
|
759
|
+
"hsbc",
|
|
760
|
+
"ht",
|
|
761
|
+
"hu",
|
|
762
|
+
"hughes",
|
|
763
|
+
"hyatt",
|
|
764
|
+
"hyundai",
|
|
765
|
+
"ibm",
|
|
766
|
+
"icbc",
|
|
767
|
+
"ice",
|
|
768
|
+
"icu",
|
|
769
|
+
"id",
|
|
770
|
+
"ie",
|
|
771
|
+
"ieee",
|
|
772
|
+
"ifm",
|
|
773
|
+
"ikano",
|
|
774
|
+
"il",
|
|
775
|
+
"im",
|
|
776
|
+
"imamat",
|
|
777
|
+
"imdb",
|
|
778
|
+
"immo",
|
|
779
|
+
"immobilien",
|
|
780
|
+
"in",
|
|
781
|
+
"inc",
|
|
782
|
+
"industries",
|
|
783
|
+
"infiniti",
|
|
784
|
+
"info",
|
|
785
|
+
"ing",
|
|
786
|
+
"ink",
|
|
787
|
+
"institute",
|
|
788
|
+
"insurance",
|
|
789
|
+
"insure",
|
|
790
|
+
"int",
|
|
791
|
+
"international",
|
|
792
|
+
"intuit",
|
|
793
|
+
"investments",
|
|
794
|
+
"io",
|
|
795
|
+
"ipiranga",
|
|
796
|
+
"iq",
|
|
797
|
+
"ir",
|
|
798
|
+
"irish",
|
|
799
|
+
"is",
|
|
800
|
+
"ismaili",
|
|
801
|
+
"ist",
|
|
802
|
+
"istanbul",
|
|
803
|
+
"it",
|
|
804
|
+
"itau",
|
|
805
|
+
"itv",
|
|
806
|
+
"jaguar",
|
|
807
|
+
"java",
|
|
808
|
+
"jcb",
|
|
809
|
+
"je",
|
|
810
|
+
"jeep",
|
|
811
|
+
"jetzt",
|
|
812
|
+
"jewelry",
|
|
813
|
+
"jio",
|
|
814
|
+
"jll",
|
|
815
|
+
"jm",
|
|
816
|
+
"jmp",
|
|
817
|
+
"jnj",
|
|
818
|
+
"jo",
|
|
819
|
+
"jobs",
|
|
820
|
+
"joburg",
|
|
821
|
+
"jot",
|
|
822
|
+
"joy",
|
|
823
|
+
"jp",
|
|
824
|
+
"jpmorgan",
|
|
825
|
+
"jprs",
|
|
826
|
+
"juegos",
|
|
827
|
+
"juniper",
|
|
828
|
+
"kaufen",
|
|
829
|
+
"kddi",
|
|
830
|
+
"ke",
|
|
831
|
+
"kerryhotels",
|
|
832
|
+
"kerryproperties",
|
|
833
|
+
"kfh",
|
|
834
|
+
"kg",
|
|
835
|
+
"kh",
|
|
836
|
+
"ki",
|
|
837
|
+
"kia",
|
|
838
|
+
"kids",
|
|
839
|
+
"kim",
|
|
840
|
+
"kindle",
|
|
841
|
+
"kitchen",
|
|
842
|
+
"kiwi",
|
|
843
|
+
"km",
|
|
844
|
+
"kn",
|
|
845
|
+
"koeln",
|
|
846
|
+
"komatsu",
|
|
847
|
+
"kosher",
|
|
848
|
+
"kp",
|
|
849
|
+
"kpmg",
|
|
850
|
+
"kpn",
|
|
851
|
+
"kr",
|
|
852
|
+
"krd",
|
|
853
|
+
"kred",
|
|
854
|
+
"kuokgroup",
|
|
855
|
+
"kw",
|
|
856
|
+
"ky",
|
|
857
|
+
"kyoto",
|
|
858
|
+
"kz",
|
|
859
|
+
"la",
|
|
860
|
+
"lacaixa",
|
|
861
|
+
"lamborghini",
|
|
862
|
+
"lamer",
|
|
863
|
+
"land",
|
|
864
|
+
"landrover",
|
|
865
|
+
"lanxess",
|
|
866
|
+
"lasalle",
|
|
867
|
+
"lat",
|
|
868
|
+
"latino",
|
|
869
|
+
"latrobe",
|
|
870
|
+
"law",
|
|
871
|
+
"lawyer",
|
|
872
|
+
"lb",
|
|
873
|
+
"lc",
|
|
874
|
+
"lds",
|
|
875
|
+
"lease",
|
|
876
|
+
"leclerc",
|
|
877
|
+
"lefrak",
|
|
878
|
+
"legal",
|
|
879
|
+
"lego",
|
|
880
|
+
"lexus",
|
|
881
|
+
"lgbt",
|
|
882
|
+
"li",
|
|
883
|
+
"lidl",
|
|
884
|
+
"life",
|
|
885
|
+
"lifeinsurance",
|
|
886
|
+
"lifestyle",
|
|
887
|
+
"lighting",
|
|
888
|
+
"like",
|
|
889
|
+
"lilly",
|
|
890
|
+
"limited",
|
|
891
|
+
"limo",
|
|
892
|
+
"lincoln",
|
|
893
|
+
"link",
|
|
894
|
+
"live",
|
|
895
|
+
"living",
|
|
896
|
+
"lk",
|
|
897
|
+
"llc",
|
|
898
|
+
"llp",
|
|
899
|
+
"loan",
|
|
900
|
+
"loans",
|
|
901
|
+
"locker",
|
|
902
|
+
"locus",
|
|
903
|
+
"lol",
|
|
904
|
+
"london",
|
|
905
|
+
"lotte",
|
|
906
|
+
"lotto",
|
|
907
|
+
"love",
|
|
908
|
+
"lpl",
|
|
909
|
+
"lplfinancial",
|
|
910
|
+
"lr",
|
|
911
|
+
"ls",
|
|
912
|
+
"lt",
|
|
913
|
+
"ltd",
|
|
914
|
+
"ltda",
|
|
915
|
+
"lu",
|
|
916
|
+
"lundbeck",
|
|
917
|
+
"luxe",
|
|
918
|
+
"luxury",
|
|
919
|
+
"lv",
|
|
920
|
+
"ly",
|
|
921
|
+
"ma",
|
|
922
|
+
"madrid",
|
|
923
|
+
"maif",
|
|
924
|
+
"maison",
|
|
925
|
+
"makeup",
|
|
926
|
+
"man",
|
|
927
|
+
"management",
|
|
928
|
+
"mango",
|
|
929
|
+
"map",
|
|
930
|
+
"market",
|
|
931
|
+
"marketing",
|
|
932
|
+
"markets",
|
|
933
|
+
"marriott",
|
|
934
|
+
"marshalls",
|
|
935
|
+
"mattel",
|
|
936
|
+
"mba",
|
|
937
|
+
"mc",
|
|
938
|
+
"mckinsey",
|
|
939
|
+
"md",
|
|
940
|
+
"me",
|
|
941
|
+
"med",
|
|
942
|
+
"media",
|
|
943
|
+
"meet",
|
|
944
|
+
"melbourne",
|
|
945
|
+
"meme",
|
|
946
|
+
"memorial",
|
|
947
|
+
"men",
|
|
948
|
+
"menu",
|
|
949
|
+
"merckmsd",
|
|
950
|
+
"mg",
|
|
951
|
+
"mh",
|
|
952
|
+
"miami",
|
|
953
|
+
"microsoft",
|
|
954
|
+
"mil",
|
|
955
|
+
"mini",
|
|
956
|
+
"mint",
|
|
957
|
+
"mit",
|
|
958
|
+
"mitsubishi",
|
|
959
|
+
"mk",
|
|
960
|
+
"ml",
|
|
961
|
+
"mlb",
|
|
962
|
+
"mls",
|
|
963
|
+
"mm",
|
|
964
|
+
"mma",
|
|
965
|
+
"mn",
|
|
966
|
+
"mo",
|
|
967
|
+
"mobi",
|
|
968
|
+
"mobile",
|
|
969
|
+
"moda",
|
|
970
|
+
"moe",
|
|
971
|
+
"moi",
|
|
972
|
+
"mom",
|
|
973
|
+
"monash",
|
|
974
|
+
"money",
|
|
975
|
+
"monster",
|
|
976
|
+
"mormon",
|
|
977
|
+
"mortgage",
|
|
978
|
+
"moscow",
|
|
979
|
+
"moto",
|
|
980
|
+
"motorcycles",
|
|
981
|
+
"mov",
|
|
982
|
+
"movie",
|
|
983
|
+
"mp",
|
|
984
|
+
"mq",
|
|
985
|
+
"mr",
|
|
986
|
+
"ms",
|
|
987
|
+
"msd",
|
|
988
|
+
"mt",
|
|
989
|
+
"mtn",
|
|
990
|
+
"mtr",
|
|
991
|
+
"mu",
|
|
992
|
+
"museum",
|
|
993
|
+
"music",
|
|
994
|
+
"mv",
|
|
995
|
+
"mw",
|
|
996
|
+
"mx",
|
|
997
|
+
"my",
|
|
998
|
+
"mz",
|
|
999
|
+
"na",
|
|
1000
|
+
"nab",
|
|
1001
|
+
"nagoya",
|
|
1002
|
+
"name",
|
|
1003
|
+
"navy",
|
|
1004
|
+
"nba",
|
|
1005
|
+
"nc",
|
|
1006
|
+
"ne",
|
|
1007
|
+
"nec",
|
|
1008
|
+
"net",
|
|
1009
|
+
"netbank",
|
|
1010
|
+
"netflix",
|
|
1011
|
+
"network",
|
|
1012
|
+
"neustar",
|
|
1013
|
+
"new",
|
|
1014
|
+
"news",
|
|
1015
|
+
"next",
|
|
1016
|
+
"nextdirect",
|
|
1017
|
+
"nexus",
|
|
1018
|
+
"nf",
|
|
1019
|
+
"nfl",
|
|
1020
|
+
"ng",
|
|
1021
|
+
"ngo",
|
|
1022
|
+
"nhk",
|
|
1023
|
+
"ni",
|
|
1024
|
+
"nico",
|
|
1025
|
+
"nike",
|
|
1026
|
+
"nikon",
|
|
1027
|
+
"ninja",
|
|
1028
|
+
"nissan",
|
|
1029
|
+
"nissay",
|
|
1030
|
+
"nl",
|
|
1031
|
+
"no",
|
|
1032
|
+
"nokia",
|
|
1033
|
+
"norton",
|
|
1034
|
+
"now",
|
|
1035
|
+
"nowruz",
|
|
1036
|
+
"nowtv",
|
|
1037
|
+
"np",
|
|
1038
|
+
"nr",
|
|
1039
|
+
"nra",
|
|
1040
|
+
"nrw",
|
|
1041
|
+
"ntt",
|
|
1042
|
+
"nu",
|
|
1043
|
+
"nyc",
|
|
1044
|
+
"nz",
|
|
1045
|
+
"obi",
|
|
1046
|
+
"observer",
|
|
1047
|
+
"office",
|
|
1048
|
+
"okinawa",
|
|
1049
|
+
"olayan",
|
|
1050
|
+
"olayangroup",
|
|
1051
|
+
"ollo",
|
|
1052
|
+
"om",
|
|
1053
|
+
"omega",
|
|
1054
|
+
"one",
|
|
1055
|
+
"ong",
|
|
1056
|
+
"onl",
|
|
1057
|
+
"online",
|
|
1058
|
+
"ooo",
|
|
1059
|
+
"open",
|
|
1060
|
+
"oracle",
|
|
1061
|
+
"orange",
|
|
1062
|
+
"org",
|
|
1063
|
+
"organic",
|
|
1064
|
+
"origins",
|
|
1065
|
+
"osaka",
|
|
1066
|
+
"otsuka",
|
|
1067
|
+
"ott",
|
|
1068
|
+
"ovh",
|
|
1069
|
+
"pa",
|
|
1070
|
+
"page",
|
|
1071
|
+
"panasonic",
|
|
1072
|
+
"paris",
|
|
1073
|
+
"pars",
|
|
1074
|
+
"partners",
|
|
1075
|
+
"parts",
|
|
1076
|
+
"party",
|
|
1077
|
+
"pay",
|
|
1078
|
+
"pccw",
|
|
1079
|
+
"pe",
|
|
1080
|
+
"pet",
|
|
1081
|
+
"pf",
|
|
1082
|
+
"pfizer",
|
|
1083
|
+
"pg",
|
|
1084
|
+
"ph",
|
|
1085
|
+
"pharmacy",
|
|
1086
|
+
"phd",
|
|
1087
|
+
"philips",
|
|
1088
|
+
"phone",
|
|
1089
|
+
"photo",
|
|
1090
|
+
"photography",
|
|
1091
|
+
"photos",
|
|
1092
|
+
"physio",
|
|
1093
|
+
"pics",
|
|
1094
|
+
"pictet",
|
|
1095
|
+
"pictures",
|
|
1096
|
+
"pid",
|
|
1097
|
+
"pin",
|
|
1098
|
+
"ping",
|
|
1099
|
+
"pink",
|
|
1100
|
+
"pioneer",
|
|
1101
|
+
"pizza",
|
|
1102
|
+
"pk",
|
|
1103
|
+
"pl",
|
|
1104
|
+
"place",
|
|
1105
|
+
"play",
|
|
1106
|
+
"playstation",
|
|
1107
|
+
"plumbing",
|
|
1108
|
+
"plus",
|
|
1109
|
+
"pm",
|
|
1110
|
+
"pn",
|
|
1111
|
+
"pnc",
|
|
1112
|
+
"pohl",
|
|
1113
|
+
"poker",
|
|
1114
|
+
"politie",
|
|
1115
|
+
"porn",
|
|
1116
|
+
"post",
|
|
1117
|
+
"pr",
|
|
1118
|
+
"praxi",
|
|
1119
|
+
"press",
|
|
1120
|
+
"prime",
|
|
1121
|
+
"pro",
|
|
1122
|
+
"prod",
|
|
1123
|
+
"productions",
|
|
1124
|
+
"prof",
|
|
1125
|
+
"progressive",
|
|
1126
|
+
"promo",
|
|
1127
|
+
"properties",
|
|
1128
|
+
"property",
|
|
1129
|
+
"protection",
|
|
1130
|
+
"pru",
|
|
1131
|
+
"prudential",
|
|
1132
|
+
"ps",
|
|
1133
|
+
"pt",
|
|
1134
|
+
"pub",
|
|
1135
|
+
"pw",
|
|
1136
|
+
"pwc",
|
|
1137
|
+
"py",
|
|
1138
|
+
"qa",
|
|
1139
|
+
"qpon",
|
|
1140
|
+
"quebec",
|
|
1141
|
+
"quest",
|
|
1142
|
+
"racing",
|
|
1143
|
+
"radio",
|
|
1144
|
+
"re",
|
|
1145
|
+
"read",
|
|
1146
|
+
"realestate",
|
|
1147
|
+
"realtor",
|
|
1148
|
+
"realty",
|
|
1149
|
+
"recipes",
|
|
1150
|
+
"red",
|
|
1151
|
+
"redumbrella",
|
|
1152
|
+
"rehab",
|
|
1153
|
+
"reise",
|
|
1154
|
+
"reisen",
|
|
1155
|
+
"reit",
|
|
1156
|
+
"reliance",
|
|
1157
|
+
"ren",
|
|
1158
|
+
"rent",
|
|
1159
|
+
"rentals",
|
|
1160
|
+
"repair",
|
|
1161
|
+
"report",
|
|
1162
|
+
"republican",
|
|
1163
|
+
"rest",
|
|
1164
|
+
"restaurant",
|
|
1165
|
+
"review",
|
|
1166
|
+
"reviews",
|
|
1167
|
+
"rexroth",
|
|
1168
|
+
"rich",
|
|
1169
|
+
"richardli",
|
|
1170
|
+
"ricoh",
|
|
1171
|
+
"ril",
|
|
1172
|
+
"rio",
|
|
1173
|
+
"rip",
|
|
1174
|
+
"ro",
|
|
1175
|
+
"rocks",
|
|
1176
|
+
"rodeo",
|
|
1177
|
+
"rogers",
|
|
1178
|
+
"room",
|
|
1179
|
+
"rs",
|
|
1180
|
+
"rsvp",
|
|
1181
|
+
"ru",
|
|
1182
|
+
"rugby",
|
|
1183
|
+
"ruhr",
|
|
1184
|
+
"run",
|
|
1185
|
+
"rw",
|
|
1186
|
+
"rwe",
|
|
1187
|
+
"ryukyu",
|
|
1188
|
+
"sa",
|
|
1189
|
+
"saarland",
|
|
1190
|
+
"safe",
|
|
1191
|
+
"safety",
|
|
1192
|
+
"sakura",
|
|
1193
|
+
"sale",
|
|
1194
|
+
"salon",
|
|
1195
|
+
"samsclub",
|
|
1196
|
+
"samsung",
|
|
1197
|
+
"sandvik",
|
|
1198
|
+
"sandvikcoromant",
|
|
1199
|
+
"sanofi",
|
|
1200
|
+
"sap",
|
|
1201
|
+
"sarl",
|
|
1202
|
+
"sas",
|
|
1203
|
+
"save",
|
|
1204
|
+
"saxo",
|
|
1205
|
+
"sb",
|
|
1206
|
+
"sbi",
|
|
1207
|
+
"sbs",
|
|
1208
|
+
"sc",
|
|
1209
|
+
"scb",
|
|
1210
|
+
"schaeffler",
|
|
1211
|
+
"schmidt",
|
|
1212
|
+
"scholarships",
|
|
1213
|
+
"school",
|
|
1214
|
+
"schule",
|
|
1215
|
+
"schwarz",
|
|
1216
|
+
"science",
|
|
1217
|
+
"scot",
|
|
1218
|
+
"sd",
|
|
1219
|
+
"se",
|
|
1220
|
+
"search",
|
|
1221
|
+
"seat",
|
|
1222
|
+
"secure",
|
|
1223
|
+
"security",
|
|
1224
|
+
"seek",
|
|
1225
|
+
"select",
|
|
1226
|
+
"sener",
|
|
1227
|
+
"services",
|
|
1228
|
+
"seven",
|
|
1229
|
+
"sew",
|
|
1230
|
+
"sex",
|
|
1231
|
+
"sexy",
|
|
1232
|
+
"sfr",
|
|
1233
|
+
"sg",
|
|
1234
|
+
"sh",
|
|
1235
|
+
"shangrila",
|
|
1236
|
+
"sharp",
|
|
1237
|
+
"shell",
|
|
1238
|
+
"shia",
|
|
1239
|
+
"shiksha",
|
|
1240
|
+
"shoes",
|
|
1241
|
+
"shop",
|
|
1242
|
+
"shopping",
|
|
1243
|
+
"shouji",
|
|
1244
|
+
"show",
|
|
1245
|
+
"si",
|
|
1246
|
+
"silk",
|
|
1247
|
+
"sina",
|
|
1248
|
+
"singles",
|
|
1249
|
+
"site",
|
|
1250
|
+
"sj",
|
|
1251
|
+
"sk",
|
|
1252
|
+
"ski",
|
|
1253
|
+
"skin",
|
|
1254
|
+
"sky",
|
|
1255
|
+
"skype",
|
|
1256
|
+
"sl",
|
|
1257
|
+
"sling",
|
|
1258
|
+
"sm",
|
|
1259
|
+
"smart",
|
|
1260
|
+
"smile",
|
|
1261
|
+
"sn",
|
|
1262
|
+
"sncf",
|
|
1263
|
+
"so",
|
|
1264
|
+
"soccer",
|
|
1265
|
+
"social",
|
|
1266
|
+
"softbank",
|
|
1267
|
+
"software",
|
|
1268
|
+
"sohu",
|
|
1269
|
+
"solar",
|
|
1270
|
+
"solutions",
|
|
1271
|
+
"song",
|
|
1272
|
+
"sony",
|
|
1273
|
+
"soy",
|
|
1274
|
+
"spa",
|
|
1275
|
+
"space",
|
|
1276
|
+
"sport",
|
|
1277
|
+
"spot",
|
|
1278
|
+
"sr",
|
|
1279
|
+
"srl",
|
|
1280
|
+
"ss",
|
|
1281
|
+
"st",
|
|
1282
|
+
"stada",
|
|
1283
|
+
"staples",
|
|
1284
|
+
"star",
|
|
1285
|
+
"statebank",
|
|
1286
|
+
"statefarm",
|
|
1287
|
+
"stc",
|
|
1288
|
+
"stcgroup",
|
|
1289
|
+
"stockholm",
|
|
1290
|
+
"storage",
|
|
1291
|
+
"store",
|
|
1292
|
+
"stream",
|
|
1293
|
+
"studio",
|
|
1294
|
+
"study",
|
|
1295
|
+
"style",
|
|
1296
|
+
"su",
|
|
1297
|
+
"sucks",
|
|
1298
|
+
"supplies",
|
|
1299
|
+
"supply",
|
|
1300
|
+
"support",
|
|
1301
|
+
"surf",
|
|
1302
|
+
"surgery",
|
|
1303
|
+
"suzuki",
|
|
1304
|
+
"sv",
|
|
1305
|
+
"swatch",
|
|
1306
|
+
"swiss",
|
|
1307
|
+
"sx",
|
|
1308
|
+
"sy",
|
|
1309
|
+
"sydney",
|
|
1310
|
+
"systems",
|
|
1311
|
+
"sz",
|
|
1312
|
+
"tab",
|
|
1313
|
+
"taipei",
|
|
1314
|
+
"talk",
|
|
1315
|
+
"taobao",
|
|
1316
|
+
"target",
|
|
1317
|
+
"tatamotors",
|
|
1318
|
+
"tatar",
|
|
1319
|
+
"tattoo",
|
|
1320
|
+
"tax",
|
|
1321
|
+
"taxi",
|
|
1322
|
+
"tc",
|
|
1323
|
+
"tci",
|
|
1324
|
+
"td",
|
|
1325
|
+
"tdk",
|
|
1326
|
+
"team",
|
|
1327
|
+
"tech",
|
|
1328
|
+
"technology",
|
|
1329
|
+
"tel",
|
|
1330
|
+
"temasek",
|
|
1331
|
+
"tennis",
|
|
1332
|
+
"teva",
|
|
1333
|
+
"tf",
|
|
1334
|
+
"tg",
|
|
1335
|
+
"th",
|
|
1336
|
+
"thd",
|
|
1337
|
+
"theater",
|
|
1338
|
+
"theatre",
|
|
1339
|
+
"tiaa",
|
|
1340
|
+
"tickets",
|
|
1341
|
+
"tienda",
|
|
1342
|
+
"tips",
|
|
1343
|
+
"tires",
|
|
1344
|
+
"tirol",
|
|
1345
|
+
"tj",
|
|
1346
|
+
"tjmaxx",
|
|
1347
|
+
"tjx",
|
|
1348
|
+
"tk",
|
|
1349
|
+
"tkmaxx",
|
|
1350
|
+
"tl",
|
|
1351
|
+
"tm",
|
|
1352
|
+
"tmall",
|
|
1353
|
+
"tn",
|
|
1354
|
+
"to",
|
|
1355
|
+
"today",
|
|
1356
|
+
"tokyo",
|
|
1357
|
+
"tools",
|
|
1358
|
+
"top",
|
|
1359
|
+
"toray",
|
|
1360
|
+
"toshiba",
|
|
1361
|
+
"total",
|
|
1362
|
+
"tours",
|
|
1363
|
+
"town",
|
|
1364
|
+
"toyota",
|
|
1365
|
+
"toys",
|
|
1366
|
+
"tr",
|
|
1367
|
+
"trade",
|
|
1368
|
+
"trading",
|
|
1369
|
+
"training",
|
|
1370
|
+
"travel",
|
|
1371
|
+
"travelers",
|
|
1372
|
+
"travelersinsurance",
|
|
1373
|
+
"trust",
|
|
1374
|
+
"trv",
|
|
1375
|
+
"tt",
|
|
1376
|
+
"tube",
|
|
1377
|
+
"tui",
|
|
1378
|
+
"tunes",
|
|
1379
|
+
"tushu",
|
|
1380
|
+
"tv",
|
|
1381
|
+
"tvs",
|
|
1382
|
+
"tw",
|
|
1383
|
+
"tz",
|
|
1384
|
+
"ua",
|
|
1385
|
+
"ubank",
|
|
1386
|
+
"ubs",
|
|
1387
|
+
"ug",
|
|
1388
|
+
"uk",
|
|
1389
|
+
"unicom",
|
|
1390
|
+
"university",
|
|
1391
|
+
"uno",
|
|
1392
|
+
"uol",
|
|
1393
|
+
"ups",
|
|
1394
|
+
"us",
|
|
1395
|
+
"uy",
|
|
1396
|
+
"uz",
|
|
1397
|
+
"va",
|
|
1398
|
+
"vacations",
|
|
1399
|
+
"vana",
|
|
1400
|
+
"vanguard",
|
|
1401
|
+
"vc",
|
|
1402
|
+
"ve",
|
|
1403
|
+
"vegas",
|
|
1404
|
+
"ventures",
|
|
1405
|
+
"verisign",
|
|
1406
|
+
"vermögensberater",
|
|
1407
|
+
"vermögensberatung",
|
|
1408
|
+
"versicherung",
|
|
1409
|
+
"vet",
|
|
1410
|
+
"vg",
|
|
1411
|
+
"vi",
|
|
1412
|
+
"viajes",
|
|
1413
|
+
"video",
|
|
1414
|
+
"vig",
|
|
1415
|
+
"viking",
|
|
1416
|
+
"villas",
|
|
1417
|
+
"vin",
|
|
1418
|
+
"vip",
|
|
1419
|
+
"virgin",
|
|
1420
|
+
"visa",
|
|
1421
|
+
"vision",
|
|
1422
|
+
"viva",
|
|
1423
|
+
"vivo",
|
|
1424
|
+
"vlaanderen",
|
|
1425
|
+
"vn",
|
|
1426
|
+
"vodka",
|
|
1427
|
+
"volvo",
|
|
1428
|
+
"vote",
|
|
1429
|
+
"voting",
|
|
1430
|
+
"voto",
|
|
1431
|
+
"voyage",
|
|
1432
|
+
"vu",
|
|
1433
|
+
"wales",
|
|
1434
|
+
"walmart",
|
|
1435
|
+
"walter",
|
|
1436
|
+
"wang",
|
|
1437
|
+
"wanggou",
|
|
1438
|
+
"watch",
|
|
1439
|
+
"watches",
|
|
1440
|
+
"weather",
|
|
1441
|
+
"weatherchannel",
|
|
1442
|
+
"webcam",
|
|
1443
|
+
"weber",
|
|
1444
|
+
"website",
|
|
1445
|
+
"wed",
|
|
1446
|
+
"wedding",
|
|
1447
|
+
"weibo",
|
|
1448
|
+
"weir",
|
|
1449
|
+
"wf",
|
|
1450
|
+
"whoswho",
|
|
1451
|
+
"wien",
|
|
1452
|
+
"wiki",
|
|
1453
|
+
"williamhill",
|
|
1454
|
+
"win",
|
|
1455
|
+
"windows",
|
|
1456
|
+
"wine",
|
|
1457
|
+
"winners",
|
|
1458
|
+
"wme",
|
|
1459
|
+
"wolterskluwer",
|
|
1460
|
+
"woodside",
|
|
1461
|
+
"work",
|
|
1462
|
+
"works",
|
|
1463
|
+
"world",
|
|
1464
|
+
"wow",
|
|
1465
|
+
"ws",
|
|
1466
|
+
"wtc",
|
|
1467
|
+
"wtf",
|
|
1468
|
+
"xbox",
|
|
1469
|
+
"xerox",
|
|
1470
|
+
"xihuan",
|
|
1471
|
+
"xin",
|
|
1472
|
+
"xxx",
|
|
1473
|
+
"xyz",
|
|
1474
|
+
"yachts",
|
|
1475
|
+
"yahoo",
|
|
1476
|
+
"yamaxun",
|
|
1477
|
+
"yandex",
|
|
1478
|
+
"ye",
|
|
1479
|
+
"yodobashi",
|
|
1480
|
+
"yoga",
|
|
1481
|
+
"yokohama",
|
|
1482
|
+
"you",
|
|
1483
|
+
"youtube",
|
|
1484
|
+
"yt",
|
|
1485
|
+
"yun",
|
|
1486
|
+
"za",
|
|
1487
|
+
"zappos",
|
|
1488
|
+
"zara",
|
|
1489
|
+
"zero",
|
|
1490
|
+
"zip",
|
|
1491
|
+
"zm",
|
|
1492
|
+
"zone",
|
|
1493
|
+
"zuerich",
|
|
1494
|
+
"zw",
|
|
1495
|
+
"ελ",
|
|
1496
|
+
"ευ",
|
|
1497
|
+
"бг",
|
|
1498
|
+
"бел",
|
|
1499
|
+
"дети",
|
|
1500
|
+
"ею",
|
|
1501
|
+
"католик",
|
|
1502
|
+
"ком",
|
|
1503
|
+
"мкд",
|
|
1504
|
+
"мон",
|
|
1505
|
+
"москва",
|
|
1506
|
+
"онлайн",
|
|
1507
|
+
"орг",
|
|
1508
|
+
"рус",
|
|
1509
|
+
"рф",
|
|
1510
|
+
"сайт",
|
|
1511
|
+
"срб",
|
|
1512
|
+
"укр",
|
|
1513
|
+
"қаз",
|
|
1514
|
+
"հայ",
|
|
1515
|
+
"ישראל",
|
|
1516
|
+
"קום",
|
|
1517
|
+
"ابوظبي",
|
|
1518
|
+
"ارامكو",
|
|
1519
|
+
"الاردن",
|
|
1520
|
+
"البحرين",
|
|
1521
|
+
"الجزائر",
|
|
1522
|
+
"السعودية",
|
|
1523
|
+
"العليان",
|
|
1524
|
+
"المغرب",
|
|
1525
|
+
"امارات",
|
|
1526
|
+
"ایران",
|
|
1527
|
+
"بارت",
|
|
1528
|
+
"بازار",
|
|
1529
|
+
"بيتك",
|
|
1530
|
+
"بھارت",
|
|
1531
|
+
"تونس",
|
|
1532
|
+
"سودان",
|
|
1533
|
+
"سورية",
|
|
1534
|
+
"شبكة",
|
|
1535
|
+
"عراق",
|
|
1536
|
+
"عرب",
|
|
1537
|
+
"عمان",
|
|
1538
|
+
"فلسطين",
|
|
1539
|
+
"قطر",
|
|
1540
|
+
"كاثوليك",
|
|
1541
|
+
"كوم",
|
|
1542
|
+
"مصر",
|
|
1543
|
+
"مليسيا",
|
|
1544
|
+
"موريتانيا",
|
|
1545
|
+
"موقع",
|
|
1546
|
+
"همراه",
|
|
1547
|
+
"پاکستان",
|
|
1548
|
+
"ڀارت",
|
|
1549
|
+
"कॉम",
|
|
1550
|
+
"नेट",
|
|
1551
|
+
"भारत",
|
|
1552
|
+
"भारतम्",
|
|
1553
|
+
"भारोत",
|
|
1554
|
+
"संगठन",
|
|
1555
|
+
"বাংলা",
|
|
1556
|
+
"ভারত",
|
|
1557
|
+
"ভাৰত",
|
|
1558
|
+
"ਭਾਰਤ",
|
|
1559
|
+
"ભારત",
|
|
1560
|
+
"ଭାରତ",
|
|
1561
|
+
"இந்தியா",
|
|
1562
|
+
"இலங்கை",
|
|
1563
|
+
"சிங்கப்பூர்",
|
|
1564
|
+
"భారత్",
|
|
1565
|
+
"ಭಾರತ",
|
|
1566
|
+
"ഭാരതം",
|
|
1567
|
+
"ලංකා",
|
|
1568
|
+
"คอม",
|
|
1569
|
+
"ไทย",
|
|
1570
|
+
"ລາວ",
|
|
1571
|
+
"გე",
|
|
1572
|
+
"みんな",
|
|
1573
|
+
"アマゾン",
|
|
1574
|
+
"クラウド",
|
|
1575
|
+
"グーグル",
|
|
1576
|
+
"コム",
|
|
1577
|
+
"ストア",
|
|
1578
|
+
"セール",
|
|
1579
|
+
"ファッション",
|
|
1580
|
+
"ポイント",
|
|
1581
|
+
"世界",
|
|
1582
|
+
"中信",
|
|
1583
|
+
"中国",
|
|
1584
|
+
"中國",
|
|
1585
|
+
"中文网",
|
|
1586
|
+
"亚马逊",
|
|
1587
|
+
"企业",
|
|
1588
|
+
"佛山",
|
|
1589
|
+
"信息",
|
|
1590
|
+
"健康",
|
|
1591
|
+
"八卦",
|
|
1592
|
+
"公司",
|
|
1593
|
+
"公益",
|
|
1594
|
+
"台湾",
|
|
1595
|
+
"台灣",
|
|
1596
|
+
"商城",
|
|
1597
|
+
"商店",
|
|
1598
|
+
"商标",
|
|
1599
|
+
"嘉里",
|
|
1600
|
+
"嘉里大酒店",
|
|
1601
|
+
"在线",
|
|
1602
|
+
"大拿",
|
|
1603
|
+
"天主教",
|
|
1604
|
+
"娱乐",
|
|
1605
|
+
"家電",
|
|
1606
|
+
"广东",
|
|
1607
|
+
"微博",
|
|
1608
|
+
"慈善",
|
|
1609
|
+
"我爱你",
|
|
1610
|
+
"手机",
|
|
1611
|
+
"招聘",
|
|
1612
|
+
"政务",
|
|
1613
|
+
"政府",
|
|
1614
|
+
"新加坡",
|
|
1615
|
+
"新闻",
|
|
1616
|
+
"时尚",
|
|
1617
|
+
"書籍",
|
|
1618
|
+
"机构",
|
|
1619
|
+
"淡马锡",
|
|
1620
|
+
"游戏",
|
|
1621
|
+
"澳門",
|
|
1622
|
+
"点看",
|
|
1623
|
+
"移动",
|
|
1624
|
+
"组织机构",
|
|
1625
|
+
"网址",
|
|
1626
|
+
"网店",
|
|
1627
|
+
"网站",
|
|
1628
|
+
"网络",
|
|
1629
|
+
"联通",
|
|
1630
|
+
"谷歌",
|
|
1631
|
+
"购物",
|
|
1632
|
+
"通販",
|
|
1633
|
+
"集团",
|
|
1634
|
+
"電訊盈科",
|
|
1635
|
+
"飞利浦",
|
|
1636
|
+
"食品",
|
|
1637
|
+
"餐厅",
|
|
1638
|
+
"香格里拉",
|
|
1639
|
+
"香港",
|
|
1640
|
+
"닷넷",
|
|
1641
|
+
"닷컴",
|
|
1642
|
+
"삼성",
|
|
1643
|
+
"한국"
|
|
1644
|
+
];
|
|
1645
|
+
//#endregion
|
|
1646
|
+
//#region src/tld.ts
|
|
1647
|
+
let known;
|
|
1648
|
+
/** Whether `tld` is in the IANA set, as a U-label or A-label, ignoring case. */
|
|
1649
|
+
function isKnownTld(tld) {
|
|
1650
|
+
known ??= buildSet();
|
|
1651
|
+
return known.has(tld.toLowerCase());
|
|
1652
|
+
}
|
|
1653
|
+
function buildSet() {
|
|
1654
|
+
const set = new Set(tlds_default);
|
|
1655
|
+
for (const tld of tlds_default) if (!/^[a-z\d]+$/.test(tld)) {
|
|
1656
|
+
const aLabel = toALabel(tld);
|
|
1657
|
+
if (aLabel !== void 0) set.add(aLabel);
|
|
1658
|
+
}
|
|
1659
|
+
return set;
|
|
1660
|
+
}
|
|
1661
|
+
//#endregion
|
|
1662
|
+
//#region src/parse.ts
|
|
1663
|
+
const messages = {
|
|
1664
|
+
"syntax.address.empty": "The address is empty",
|
|
1665
|
+
"syntax.address.no_at": "The address has no @",
|
|
1666
|
+
"syntax.address.too_long": "The address is longer than 254 characters",
|
|
1667
|
+
"syntax.local.empty": "Nothing comes before the @",
|
|
1668
|
+
"syntax.local.too_long": "The local part is longer than 64 characters",
|
|
1669
|
+
"syntax.local.invalid_char": "The local part has a character it can’t hold",
|
|
1670
|
+
"syntax.local.consecutive_dots": "The local part has two dots in a row",
|
|
1671
|
+
"syntax.local.unquoted_space": "The local part has a space outside quotes",
|
|
1672
|
+
"syntax.domain.empty": "Nothing comes after the @",
|
|
1673
|
+
"syntax.domain.no_dot": "The domain has no dot",
|
|
1674
|
+
"syntax.domain.label_invalid": "A domain label is empty, too long, or starts or ends with a hyphen",
|
|
1675
|
+
"syntax.domain.literal_invalid": "The domain literal isn’t accepted",
|
|
1676
|
+
"syntax.domain.too_long": "The domain is longer than 253 characters",
|
|
1677
|
+
"syntax.domain.invalid_char": "The domain has a character it can’t hold",
|
|
1678
|
+
"syntax.comment.not_allowed": "Comments aren’t allowed here",
|
|
1679
|
+
"syntax.comment.unterminated": "A comment is missing its closing parenthesis",
|
|
1680
|
+
"syntax.tld.unknown": "The TLD isn’t in the IANA set"
|
|
1681
|
+
};
|
|
1682
|
+
function fail(reason, index) {
|
|
1683
|
+
const message = messages[reason];
|
|
1684
|
+
return index === void 0 ? {
|
|
1685
|
+
ok: false,
|
|
1686
|
+
reason,
|
|
1687
|
+
message
|
|
1688
|
+
} : {
|
|
1689
|
+
ok: false,
|
|
1690
|
+
reason,
|
|
1691
|
+
message,
|
|
1692
|
+
index
|
|
1693
|
+
};
|
|
1694
|
+
}
|
|
1695
|
+
const NORMAL = 0;
|
|
1696
|
+
const QUOTED = 1;
|
|
1697
|
+
const COMMENT = 2;
|
|
1698
|
+
const LITERAL = 3;
|
|
1699
|
+
/**
|
|
1700
|
+
* Finds the `@` that splits `email`: the last one outside a quoted string,
|
|
1701
|
+
* comment, or domain literal, or -1 when there's none.
|
|
1702
|
+
*
|
|
1703
|
+
* @remarks
|
|
1704
|
+
* A quoted string opens only at the start of a word, and a literal only at
|
|
1705
|
+
* the start of the domain; both, and comments, take backslash escapes. One
|
|
1706
|
+
* left open runs to the end, taking any `@` with it.
|
|
1707
|
+
*/
|
|
1708
|
+
function findAt(email, rules) {
|
|
1709
|
+
let state = NORMAL;
|
|
1710
|
+
let wordStart = true;
|
|
1711
|
+
let domainStart = false;
|
|
1712
|
+
let depth = 0;
|
|
1713
|
+
let at = -1;
|
|
1714
|
+
for (let i = 0; i < email.length; i++) {
|
|
1715
|
+
const code = email.charCodeAt(i);
|
|
1716
|
+
if (state === NORMAL) {
|
|
1717
|
+
if (code === 64) {
|
|
1718
|
+
at = i;
|
|
1719
|
+
wordStart = true;
|
|
1720
|
+
domainStart = true;
|
|
1721
|
+
} else if (code === 40 && rules.comments) {
|
|
1722
|
+
state = COMMENT;
|
|
1723
|
+
depth = 1;
|
|
1724
|
+
} else if (!isWhitespace(code)) {
|
|
1725
|
+
if (code === 34 && rules.quotes && wordStart) state = QUOTED;
|
|
1726
|
+
else if (code === 91 && rules.literals && domainStart) state = LITERAL;
|
|
1727
|
+
wordStart = code === 46;
|
|
1728
|
+
domainStart = false;
|
|
1729
|
+
}
|
|
1730
|
+
} else if (code === 92) i++;
|
|
1731
|
+
else if (state === COMMENT) {
|
|
1732
|
+
if (code === 40) depth++;
|
|
1733
|
+
else if (code === 41 && --depth === 0) state = NORMAL;
|
|
1734
|
+
} else if (code === (state === QUOTED ? 34 : 93)) state = NORMAL;
|
|
1735
|
+
}
|
|
1736
|
+
return at;
|
|
1737
|
+
}
|
|
1738
|
+
/**
|
|
1739
|
+
* Parses `email` under `rules`.
|
|
1740
|
+
*
|
|
1741
|
+
* @throws TypeError when `email` isn't a string.
|
|
1742
|
+
*/
|
|
1743
|
+
function parse(email, rules) {
|
|
1744
|
+
if (typeof email !== "string") throw new TypeError(`Expected a string, got ${typeof email}`);
|
|
1745
|
+
if (email === "") return fail("syntax.address.empty");
|
|
1746
|
+
const at = findAt(email, rules);
|
|
1747
|
+
if (at < 0) return fail("syntax.address.no_at");
|
|
1748
|
+
const comments = [];
|
|
1749
|
+
const local = scanLocal(email, at, rules, comments);
|
|
1750
|
+
if (typeof local !== "string") return local;
|
|
1751
|
+
const localSize = rules.unicode ? utf8Length(local) : local.length;
|
|
1752
|
+
if (localSize > rules.localCap) return fail("syntax.local.too_long");
|
|
1753
|
+
const domain = scanDomain(email, at, rules, comments);
|
|
1754
|
+
if ("reason" in domain) return domain;
|
|
1755
|
+
if (domain.size > rules.domainCap) return fail("syntax.domain.too_long");
|
|
1756
|
+
if (localSize + 1 + domain.size > 254) return fail("syntax.address.too_long");
|
|
1757
|
+
const { tld } = domain;
|
|
1758
|
+
if (tld === void 0 && !domain.literal && !rules.allowNoTld) return fail("syntax.domain.no_dot");
|
|
1759
|
+
if (tld !== void 0 && rules.checkTld && !isKnownTld(tld)) return fail("syntax.tld.unknown");
|
|
1760
|
+
return {
|
|
1761
|
+
ok: true,
|
|
1762
|
+
value: tld === void 0 ? {
|
|
1763
|
+
local,
|
|
1764
|
+
domain: domain.domain,
|
|
1765
|
+
comments
|
|
1766
|
+
} : {
|
|
1767
|
+
local,
|
|
1768
|
+
domain: domain.domain,
|
|
1769
|
+
tld,
|
|
1770
|
+
comments
|
|
1771
|
+
}
|
|
1772
|
+
};
|
|
1773
|
+
}
|
|
1774
|
+
/**
|
|
1775
|
+
* Scans the local part, `email` up to `at`, and returns it without comments
|
|
1776
|
+
* or folding whitespace.
|
|
1777
|
+
*/
|
|
1778
|
+
function scanLocal(email, at, rules, comments) {
|
|
1779
|
+
let local = "";
|
|
1780
|
+
let words = 0;
|
|
1781
|
+
let afterWord = false;
|
|
1782
|
+
let closed = false;
|
|
1783
|
+
let dot = -1;
|
|
1784
|
+
let space = -1;
|
|
1785
|
+
let edge = -1;
|
|
1786
|
+
let trailing = comments.length;
|
|
1787
|
+
let i = 0;
|
|
1788
|
+
while (i < at) {
|
|
1789
|
+
const code = email.charCodeAt(i);
|
|
1790
|
+
const quote = code === 34 && rules.quotes && (rules.obs || i === 0);
|
|
1791
|
+
const atom = inClass(code, rules.local);
|
|
1792
|
+
if (quote || atom || rules.unicode && nonAsciiAt(email, i, at) > 0) {
|
|
1793
|
+
if (edge >= 0) return fail("syntax.comment.not_allowed", edge);
|
|
1794
|
+
if (afterWord) return space >= 0 ? fail("syntax.local.unquoted_space", space) : fail("syntax.local.invalid_char", i);
|
|
1795
|
+
let next;
|
|
1796
|
+
if (quote) {
|
|
1797
|
+
next = skipQuoted(email, i, at, rules.obs, rules.unicode);
|
|
1798
|
+
if (next < 0) return fail("syntax.local.invalid_char", -1 - next);
|
|
1799
|
+
closed = !rules.obs;
|
|
1800
|
+
} else {
|
|
1801
|
+
next = atom ? i + 1 : i;
|
|
1802
|
+
while (next < at && inClass(email.charCodeAt(next), rules.local)) next++;
|
|
1803
|
+
if (rules.unicode) next = skipUnicode(email, next, at, rules.local);
|
|
1804
|
+
}
|
|
1805
|
+
local += unfold(email.slice(i, next));
|
|
1806
|
+
words++;
|
|
1807
|
+
afterWord = true;
|
|
1808
|
+
dot = -1;
|
|
1809
|
+
space = -1;
|
|
1810
|
+
trailing = comments.length;
|
|
1811
|
+
i = next;
|
|
1812
|
+
} else if (code === 46) {
|
|
1813
|
+
if (edge >= 0) return fail("syntax.comment.not_allowed", edge);
|
|
1814
|
+
if (!afterWord || closed) return dot >= 0 ? fail("syntax.local.consecutive_dots", i) : fail("syntax.local.invalid_char", i);
|
|
1815
|
+
local += ".";
|
|
1816
|
+
afterWord = false;
|
|
1817
|
+
dot = i;
|
|
1818
|
+
space = -1;
|
|
1819
|
+
i++;
|
|
1820
|
+
} else if (code === 40 && rules.comments) {
|
|
1821
|
+
if (!rules.obs && words > 0) {
|
|
1822
|
+
if (!afterWord) return fail("syntax.comment.not_allowed", i);
|
|
1823
|
+
edge = edge < 0 ? i : edge;
|
|
1824
|
+
}
|
|
1825
|
+
const next = skipComment(email, i, at, rules.unicode);
|
|
1826
|
+
if (next < 0) return fail("syntax.local.invalid_char", -1 - next);
|
|
1827
|
+
comments.push({
|
|
1828
|
+
text: email.slice(i + 1, next - 1),
|
|
1829
|
+
position: words === 0 ? "before-local" : "inside-local"
|
|
1830
|
+
});
|
|
1831
|
+
i = next;
|
|
1832
|
+
} else if (code === 40) return fail("syntax.comment.not_allowed", i);
|
|
1833
|
+
else if (rules.obs && isWhitespace(code)) {
|
|
1834
|
+
const next = skipSpace(email, i, at);
|
|
1835
|
+
if (next < 0) return fail("syntax.local.invalid_char", i);
|
|
1836
|
+
space = space < 0 ? i : space;
|
|
1837
|
+
i = next;
|
|
1838
|
+
} else return code === 32 ? fail("syntax.local.unquoted_space", i) : fail("syntax.local.invalid_char", i);
|
|
1839
|
+
}
|
|
1840
|
+
if (words === 0) return fail("syntax.local.empty");
|
|
1841
|
+
if (dot >= 0) return fail("syntax.local.invalid_char", dot);
|
|
1842
|
+
settle(comments, trailing, "after-local");
|
|
1843
|
+
return local;
|
|
1844
|
+
}
|
|
1845
|
+
/**
|
|
1846
|
+
* Scans the domain, `email` after `at`, and returns it without comments or
|
|
1847
|
+
* folding whitespace.
|
|
1848
|
+
*/
|
|
1849
|
+
function scanDomain(email, at, rules, comments) {
|
|
1850
|
+
const end = email.length;
|
|
1851
|
+
let domain = "";
|
|
1852
|
+
let labels = 0;
|
|
1853
|
+
let afterLabel = false;
|
|
1854
|
+
let literal = false;
|
|
1855
|
+
let dot = -1;
|
|
1856
|
+
let space = -1;
|
|
1857
|
+
let edge = -1;
|
|
1858
|
+
let trailing = comments.length;
|
|
1859
|
+
let tld = "";
|
|
1860
|
+
let growth = 0;
|
|
1861
|
+
let i = at + 1;
|
|
1862
|
+
while (i < end) {
|
|
1863
|
+
const code = email.charCodeAt(i);
|
|
1864
|
+
const opensLiteral = code === 91 && rules.literals && labels === 0;
|
|
1865
|
+
const ldh = inClass(code, rules.domain);
|
|
1866
|
+
if (opensLiteral || ldh || rules.idn && nonAsciiAt(email, i, end) > 0) {
|
|
1867
|
+
if (edge >= 0) return fail("syntax.comment.not_allowed", edge);
|
|
1868
|
+
if (afterLabel) return fail("syntax.domain.invalid_char", space >= 0 ? space : i);
|
|
1869
|
+
let next;
|
|
1870
|
+
if (opensLiteral) {
|
|
1871
|
+
next = rules.obs ? skipLiteral(email, i, end) : skipAddressLiteral(email, i, end);
|
|
1872
|
+
if (next < 0) return fail("syntax.domain.literal_invalid", i);
|
|
1873
|
+
literal = true;
|
|
1874
|
+
} else {
|
|
1875
|
+
next = ldh ? i + 1 : i;
|
|
1876
|
+
while (next < end && inClass(email.charCodeAt(next), rules.domain)) next++;
|
|
1877
|
+
const ascii = next;
|
|
1878
|
+
if (rules.idn) next = skipUnicode(email, next, end, rules.domain);
|
|
1879
|
+
let size = next - i;
|
|
1880
|
+
if (next > ascii) {
|
|
1881
|
+
const aLabel = toALabel(email.slice(i, next));
|
|
1882
|
+
if (aLabel === void 0) return fail("syntax.domain.label_invalid", i);
|
|
1883
|
+
size = aLabel.length;
|
|
1884
|
+
growth += size - (next - i);
|
|
1885
|
+
}
|
|
1886
|
+
const bad = checkLabel(email, i, next, size);
|
|
1887
|
+
if (bad >= 0) return fail("syntax.domain.label_invalid", bad);
|
|
1888
|
+
}
|
|
1889
|
+
tld = unfold(email.slice(i, next));
|
|
1890
|
+
domain += tld;
|
|
1891
|
+
labels++;
|
|
1892
|
+
afterLabel = true;
|
|
1893
|
+
dot = -1;
|
|
1894
|
+
space = -1;
|
|
1895
|
+
trailing = comments.length;
|
|
1896
|
+
i = next;
|
|
1897
|
+
} else if (code === 46) {
|
|
1898
|
+
if (edge >= 0) return fail("syntax.comment.not_allowed", edge);
|
|
1899
|
+
if (!afterLabel || literal) return literal ? fail("syntax.domain.invalid_char", i) : fail("syntax.domain.label_invalid", i);
|
|
1900
|
+
domain += ".";
|
|
1901
|
+
afterLabel = false;
|
|
1902
|
+
dot = i;
|
|
1903
|
+
space = -1;
|
|
1904
|
+
i++;
|
|
1905
|
+
} else if (code === 40 && rules.comments) {
|
|
1906
|
+
if (!rules.obs && labels > 0) {
|
|
1907
|
+
if (!afterLabel) return fail("syntax.comment.not_allowed", i);
|
|
1908
|
+
edge = edge < 0 ? i : edge;
|
|
1909
|
+
}
|
|
1910
|
+
const next = skipComment(email, i, end, rules.unicode);
|
|
1911
|
+
if (next < 0) return -1 - next === i ? fail("syntax.comment.unterminated", i) : fail("syntax.domain.invalid_char", -1 - next);
|
|
1912
|
+
comments.push({
|
|
1913
|
+
text: email.slice(i + 1, next - 1),
|
|
1914
|
+
position: labels === 0 ? "before-domain" : "inside-domain"
|
|
1915
|
+
});
|
|
1916
|
+
i = next;
|
|
1917
|
+
} else if (code === 40) return fail("syntax.comment.not_allowed", i);
|
|
1918
|
+
else if (rules.obs && isWhitespace(code)) {
|
|
1919
|
+
const next = skipSpace(email, i, end);
|
|
1920
|
+
if (next < 0) return fail("syntax.domain.invalid_char", i);
|
|
1921
|
+
space = space < 0 ? i : space;
|
|
1922
|
+
i = next;
|
|
1923
|
+
} else return fail("syntax.domain.invalid_char", i);
|
|
1924
|
+
}
|
|
1925
|
+
if (labels === 0) return fail("syntax.domain.empty");
|
|
1926
|
+
if (dot >= 0) return fail("syntax.domain.label_invalid", dot);
|
|
1927
|
+
settle(comments, trailing, "after-domain");
|
|
1928
|
+
const size = domain.length + growth;
|
|
1929
|
+
return literal || labels === 1 ? {
|
|
1930
|
+
domain,
|
|
1931
|
+
literal,
|
|
1932
|
+
size
|
|
1933
|
+
} : {
|
|
1934
|
+
domain,
|
|
1935
|
+
tld,
|
|
1936
|
+
literal,
|
|
1937
|
+
size
|
|
1938
|
+
};
|
|
1939
|
+
}
|
|
1940
|
+
/**
|
|
1941
|
+
* Carries an atom or label on from `i`, where its ASCII run stopped, through
|
|
1942
|
+
* any non-ASCII characters and the class-`flag` characters after them.
|
|
1943
|
+
*/
|
|
1944
|
+
function skipUnicode(email, i, end, flag) {
|
|
1945
|
+
let width = i < end ? nonAsciiAt(email, i, end) : 0;
|
|
1946
|
+
while (width > 0) {
|
|
1947
|
+
i += width;
|
|
1948
|
+
while (i < end && inClass(email.charCodeAt(i), flag)) i++;
|
|
1949
|
+
width = i < end ? nonAsciiAt(email, i, end) : 0;
|
|
1950
|
+
}
|
|
1951
|
+
return i;
|
|
1952
|
+
}
|
|
1953
|
+
/**
|
|
1954
|
+
* Checks the hostname label from `start` to `end`, `size` characters long as
|
|
1955
|
+
* an A-label: returns the index of a leading or trailing hyphen, the start of
|
|
1956
|
+
* a label over 63 characters, or -1.
|
|
1957
|
+
*/
|
|
1958
|
+
function checkLabel(email, start, end, size) {
|
|
1959
|
+
if (email.charCodeAt(start) === 45) return start;
|
|
1960
|
+
if (size > 63) return start;
|
|
1961
|
+
return email.charCodeAt(end - 1) === 45 ? end - 1 : -1;
|
|
1962
|
+
}
|
|
1963
|
+
/** Marks the comments from `from` on, which no word follows, as trailing. */
|
|
1964
|
+
function settle(comments, from, position) {
|
|
1965
|
+
for (let c = from; c < comments.length; c++) {
|
|
1966
|
+
const comment = comments[c];
|
|
1967
|
+
if (comment.position.startsWith("inside")) comment.position = position;
|
|
1968
|
+
}
|
|
1969
|
+
}
|
|
1970
|
+
/** Removes the CRLFs of folding whitespace, keeping the space or tab after. */
|
|
1971
|
+
function unfold(text) {
|
|
1972
|
+
return text.includes("\r") ? text.replaceAll("\r\n", "") : text;
|
|
1973
|
+
}
|
|
1974
|
+
/**
|
|
1975
|
+
* Skips one character of folding whitespace: a space, a tab, or a CRLF with
|
|
1976
|
+
* a space or tab after it. A lone CR or LF breaks it.
|
|
1977
|
+
*/
|
|
1978
|
+
function skipSpace(email, i, end) {
|
|
1979
|
+
const code = email.charCodeAt(i);
|
|
1980
|
+
if (code === 32 || code === 9) return i + 1;
|
|
1981
|
+
return code === 13 && i + 2 < end && email.charCodeAt(i + 1) === 10 && (email.charCodeAt(i + 2) === 32 || email.charCodeAt(i + 2) === 9) ? i + 2 : -1 - i;
|
|
1982
|
+
}
|
|
1983
|
+
/** Whether a backslash may escape `code`: any ASCII with `obs`, else VCHAR and space. */
|
|
1984
|
+
function escapable(code, obs) {
|
|
1985
|
+
return obs ? code < 128 : code >= 32 && code <= 126;
|
|
1986
|
+
}
|
|
1987
|
+
/**
|
|
1988
|
+
* Skips the quoted string opening at `open`. `obs` allows folding whitespace
|
|
1989
|
+
* and control characters other than NUL; without it, the string follows
|
|
1990
|
+
* RFC 5321: printable ASCII and spaces only. `unicode` adds non-ASCII.
|
|
1991
|
+
*/
|
|
1992
|
+
function skipQuoted(email, open, end, obs, unicode) {
|
|
1993
|
+
let i = open + 1;
|
|
1994
|
+
while (i < end) {
|
|
1995
|
+
const code = email.charCodeAt(i);
|
|
1996
|
+
if (code === 34) return i + 1;
|
|
1997
|
+
if (code === 92) {
|
|
1998
|
+
if (!escapable(email.charCodeAt(i + 1), obs)) return -2 - i;
|
|
1999
|
+
i += 2;
|
|
2000
|
+
} else if (obs && isWhitespace(code)) {
|
|
2001
|
+
i = skipSpace(email, i, end);
|
|
2002
|
+
if (i < 0) return i;
|
|
2003
|
+
} else if (obs ? code === 0 || code > 127 : code < 32 || code > 126) {
|
|
2004
|
+
const width = unicode ? nonAsciiAt(email, i, end) : 0;
|
|
2005
|
+
if (width === 0) return -1 - i;
|
|
2006
|
+
i += width;
|
|
2007
|
+
} else i++;
|
|
2008
|
+
}
|
|
2009
|
+
return -1 - open;
|
|
2010
|
+
}
|
|
2011
|
+
/**
|
|
2012
|
+
* Skips the comment opening at `open`, nested comments included. Its text
|
|
2013
|
+
* may hold any ASCII but NUL, with folding whitespace, and non-ASCII with
|
|
2014
|
+
* `unicode`; returns `-1 - open` when it never closes.
|
|
2015
|
+
*/
|
|
2016
|
+
function skipComment(email, open, end, unicode) {
|
|
2017
|
+
let depth = 1;
|
|
2018
|
+
let i = open + 1;
|
|
2019
|
+
while (i < end) {
|
|
2020
|
+
const code = email.charCodeAt(i);
|
|
2021
|
+
if (code === 40 || code === 41) {
|
|
2022
|
+
depth += code === 40 ? 1 : -1;
|
|
2023
|
+
i++;
|
|
2024
|
+
if (depth === 0) return i;
|
|
2025
|
+
} else if (code === 92) {
|
|
2026
|
+
if (i + 1 >= end) break;
|
|
2027
|
+
if (!escapable(email.charCodeAt(i + 1), true)) return -2 - i;
|
|
2028
|
+
i += 2;
|
|
2029
|
+
} else if (isWhitespace(code)) {
|
|
2030
|
+
i = skipSpace(email, i, end);
|
|
2031
|
+
if (i < 0) return i;
|
|
2032
|
+
} else if (code === 0 || code > 127) {
|
|
2033
|
+
const width = unicode ? nonAsciiAt(email, i, end) : 0;
|
|
2034
|
+
if (width === 0) return -1 - i;
|
|
2035
|
+
i += width;
|
|
2036
|
+
} else i++;
|
|
2037
|
+
}
|
|
2038
|
+
return -1 - open;
|
|
2039
|
+
}
|
|
2040
|
+
/**
|
|
2041
|
+
* Skips the RFC 5322 domain literal opening at `open`: any ASCII but NUL,
|
|
2042
|
+
* `[`, and `]`, with escapes and folding whitespace. Returns -1 when it's
|
|
2043
|
+
* malformed or never closes.
|
|
2044
|
+
*/
|
|
2045
|
+
function skipLiteral(email, open, end) {
|
|
2046
|
+
let i = open + 1;
|
|
2047
|
+
while (i < end) {
|
|
2048
|
+
const code = email.charCodeAt(i);
|
|
2049
|
+
if (code === 93) return i + 1;
|
|
2050
|
+
if (code === 92) {
|
|
2051
|
+
if (i + 1 >= end || !escapable(email.charCodeAt(i + 1), true)) return -1;
|
|
2052
|
+
i += 2;
|
|
2053
|
+
} else if (isWhitespace(code)) {
|
|
2054
|
+
i = skipSpace(email, i, end);
|
|
2055
|
+
if (i < 0) return -1;
|
|
2056
|
+
} else if (code === 0 || code === 91 || code > 127) return -1;
|
|
2057
|
+
else i++;
|
|
2058
|
+
}
|
|
2059
|
+
return -1;
|
|
2060
|
+
}
|
|
2061
|
+
/**
|
|
2062
|
+
* Skips the RFC 5321 address literal opening at `open`: an IPv4 address or
|
|
2063
|
+
* `IPv6:` and an IPv6 address. Returns -1 for anything else.
|
|
2064
|
+
*/
|
|
2065
|
+
function skipAddressLiteral(email, open, end) {
|
|
2066
|
+
const close = email.indexOf("]", open + 1);
|
|
2067
|
+
return close >= 0 && close < end && isAddressLiteral(email.slice(open + 1, close)) ? close + 1 : -1;
|
|
2068
|
+
}
|
|
2069
|
+
//#endregion
|
|
2070
|
+
//#region src/index.ts
|
|
2071
|
+
/**
|
|
2072
|
+
* Is the address well-formed? A quote-aware parser with four presets:
|
|
2073
|
+
* `practical` (the default), `rfc5321`, `rfc5322`, and `html5`.
|
|
2074
|
+
*
|
|
2075
|
+
* @packageDocumentation
|
|
2076
|
+
*/
|
|
2077
|
+
/**
|
|
2078
|
+
* Parses `email` into its local part, domain, TLD, and comments, or returns
|
|
2079
|
+
* the first check it fails.
|
|
2080
|
+
*
|
|
2081
|
+
* @remarks
|
|
2082
|
+
* The local part is checked before the domain, each left to right, then the
|
|
2083
|
+
* lengths, then a dotless domain, then the TLD. `index`, where a failure has
|
|
2084
|
+
* one, points at the offending character.
|
|
2085
|
+
*
|
|
2086
|
+
* @example
|
|
2087
|
+
* ```ts
|
|
2088
|
+
* const result = parseAddress('ada.lovelace@example.co.uk');
|
|
2089
|
+
* if (result.ok) {
|
|
2090
|
+
* result.value.tld; // 'uk'
|
|
2091
|
+
* } else {
|
|
2092
|
+
* result.reason; // e.g. 'syntax.local.invalid_char'
|
|
2093
|
+
* }
|
|
2094
|
+
* ```
|
|
2095
|
+
*
|
|
2096
|
+
* @throws TypeError when `email` isn't a string, or `options` are malformed.
|
|
2097
|
+
*/
|
|
2098
|
+
function parseAddress(email, options) {
|
|
2099
|
+
return parse(email, resolve(options));
|
|
2100
|
+
}
|
|
2101
|
+
/**
|
|
2102
|
+
* Whether `email` is well-formed: exactly `parseAddress(email, options).ok`.
|
|
2103
|
+
*
|
|
2104
|
+
* @example
|
|
2105
|
+
* ```ts
|
|
2106
|
+
* isValidSyntax('ada@example.com'); // true
|
|
2107
|
+
* isValidSyntax('"ada"@example.com'); // false
|
|
2108
|
+
* isValidSyntax('"ada"@example.com', { preset: 'rfc5321' }); // true
|
|
2109
|
+
* ```
|
|
2110
|
+
*
|
|
2111
|
+
* @throws TypeError when `email` isn't a string, or `options` are malformed.
|
|
2112
|
+
*/
|
|
2113
|
+
function isValidSyntax(email, options) {
|
|
2114
|
+
return parse(email, resolve(options)).ok;
|
|
2115
|
+
}
|
|
2116
|
+
/**
|
|
2117
|
+
* Binds `options` once, checking them up front, and returns
|
|
2118
|
+
* {@link parseAddress} and {@link isValidSyntax} with them applied.
|
|
2119
|
+
*
|
|
2120
|
+
* @example
|
|
2121
|
+
* ```ts
|
|
2122
|
+
* const strict = createSyntaxValidator({ preset: 'rfc5321' });
|
|
2123
|
+
* strict.parse('a b@example.com'); // { ok: false, reason: 'syntax.local.unquoted_space', … }
|
|
2124
|
+
* strict.isValid('"a b"@example.com'); // true
|
|
2125
|
+
* ```
|
|
2126
|
+
*
|
|
2127
|
+
* @throws TypeError when `options` are malformed.
|
|
2128
|
+
*/
|
|
2129
|
+
function createSyntaxValidator(options) {
|
|
2130
|
+
const rules = resolve(options);
|
|
2131
|
+
return {
|
|
2132
|
+
parse: (email) => parse(email, rules),
|
|
2133
|
+
isValid: (email) => parse(email, rules).ok
|
|
2134
|
+
};
|
|
2135
|
+
}
|
|
2136
|
+
//#endregion
|
|
2137
|
+
exports.createSyntaxValidator = createSyntaxValidator;
|
|
2138
|
+
exports.isValidSyntax = isValidSyntax;
|
|
2139
|
+
exports.parseAddress = parseAddress;
|
|
2140
|
+
|
|
2141
|
+
//# sourceMappingURL=index.cjs.map
|