is-academic-email 1.0.0 → 1.0.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/data.json.br ADDED
Binary file
@@ -0,0 +1,16 @@
1
+ export type SwotDataPacked = {
2
+ institutions: Record<string, string[]>;
3
+ stoplist: string[];
4
+ tlds: string[];
5
+ };
6
+ export type SwotData = {
7
+ institutions: Map<string, string[]>;
8
+ stoplist: Set<string>;
9
+ tlds: Set<string>;
10
+ };
11
+ export declare function isUnderTLD(emailOrDomain: string): boolean;
12
+ export declare function isStoplisted(emailOrDomain: string): boolean;
13
+ export declare function findSchoolNames(emailOrDomain: string): string[];
14
+ export declare function isAcademic(email: string): boolean;
15
+ export { SWOT_METADATA } from './swot-metadata';
16
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAOA,MAAM,MAAM,cAAc,GAAG;IAC3B,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IACvC,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG;IACrB,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IACpC,QAAQ,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACtB,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CACnB,CAAC;AA4CF,wBAAgB,UAAU,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAEzD;AAED,wBAAgB,YAAY,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAE3D;AAED,wBAAgB,eAAe,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,EAAE,CAS/D;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAOjD;AAED,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,70 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { brotliDecompressSync } from 'node:zlib';
4
+ import { fileURLToPath } from 'node:url';
5
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
6
+ function loadData() {
7
+ const dataPath = path.join(__dirname, '..', 'data.json.br');
8
+ let packed;
9
+ try {
10
+ const compressed = fs.readFileSync(dataPath);
11
+ const decompressed = brotliDecompressSync(compressed);
12
+ packed = JSON.parse(decompressed.toString('utf8'));
13
+ }
14
+ catch {
15
+ packed = { institutions: {}, stoplist: [], tlds: [] };
16
+ }
17
+ return {
18
+ institutions: new Map(Object.entries(packed.institutions)),
19
+ stoplist: new Set(packed.stoplist.map((s) => s.toLowerCase())),
20
+ tlds: new Set(packed.tlds.map((s) => s.toLowerCase())),
21
+ };
22
+ }
23
+ const DATA = loadData();
24
+ function domainParts(emailOrDomain) {
25
+ const raw = emailOrDomain.trim().toLowerCase();
26
+ const host = raw
27
+ .substring(raw.indexOf('@') + 1)
28
+ .replace(/^[a-z]+:\/\//, '')
29
+ .replace(/^[^/]*@/, '')
30
+ .split('/')[0]
31
+ .split(':')[0];
32
+ if (!host)
33
+ return [];
34
+ return host.split('.').reverse();
35
+ }
36
+ function checkSet(set, parts) {
37
+ let subj = '';
38
+ for (const part of parts) {
39
+ subj = subj ? `${part}.${subj}` : part;
40
+ if (set.has(subj))
41
+ return true;
42
+ }
43
+ return false;
44
+ }
45
+ export function isUnderTLD(emailOrDomain) {
46
+ return checkSet(DATA.tlds, domainParts(emailOrDomain));
47
+ }
48
+ export function isStoplisted(emailOrDomain) {
49
+ return checkSet(DATA.stoplist, domainParts(emailOrDomain));
50
+ }
51
+ export function findSchoolNames(emailOrDomain) {
52
+ const parts = domainParts(emailOrDomain);
53
+ let subj = '';
54
+ for (const part of parts) {
55
+ subj = subj ? `${part}.${subj}` : part;
56
+ const names = DATA.institutions.get(subj);
57
+ if (names && names.length)
58
+ return names.slice();
59
+ }
60
+ return [];
61
+ }
62
+ export function isAcademic(email) {
63
+ const valid = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
64
+ if (!valid)
65
+ return false;
66
+ return (!isStoplisted(email) &&
67
+ (isUnderTLD(email) || findSchoolNames(email).length > 0));
68
+ }
69
+ export { SWOT_METADATA } from './swot-metadata';
70
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ export declare const SWOT_METADATA: {
2
+ readonly commit: "8866dac84c80b27b3918c3a15d6f8707dbf84740";
3
+ readonly date: "2025-09-07 16:53:42 +0300";
4
+ readonly url: "https://github.com/jetbrains/swot";
5
+ readonly updatedAt: "2025-09-07T16:49:40.654Z";
6
+ };
7
+ //# sourceMappingURL=swot-metadata.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"swot-metadata.d.ts","sourceRoot":"","sources":["../src/swot-metadata.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,aAAa;;;;;CAKhB,CAAC"}
@@ -0,0 +1,8 @@
1
+ // This file was automatically generated on 2025-09-07T16:49:43.499Z
2
+ export const SWOT_METADATA = {
3
+ "commit": "8866dac84c80b27b3918c3a15d6f8707dbf84740",
4
+ "date": "2025-09-07 16:53:42 +0300",
5
+ "url": "https://github.com/jetbrains/swot",
6
+ "updatedAt": "2025-09-07T16:49:40.654Z"
7
+ };
8
+ //# sourceMappingURL=swot-metadata.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"swot-metadata.js","sourceRoot":"","sources":["../src/swot-metadata.ts"],"names":[],"mappings":"AAAA,oEAAoE;AACpE,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,QAAQ,EAAE,0CAA0C;IACpD,MAAM,EAAE,2BAA2B;IACnC,KAAK,EAAE,mCAAmC;IAC1C,WAAW,EAAE,0BAA0B;CAC/B,CAAC"}
package/package.json CHANGED
@@ -1,12 +1,37 @@
1
1
  {
2
2
  "name": "is-academic-email",
3
- "version": "1.0.0",
4
- "description": "",
5
- "main": "index.js",
6
- "keywords": [],
7
- "author": "",
8
- "license": "MIT",
3
+ "version": "1.0.1",
4
+ "description": "Fast academic email validation using the JetBrains swot database",
5
+ "repository": {
6
+ "url": "https://github.com/amplitudesxd/is-academic-email"
7
+ },
8
+ "main": "dist/index.js",
9
+ "module": "dist/index.js",
10
+ "types": "dist/index.d.ts",
11
+ "type": "module",
12
+ "exports": {
13
+ ".": {
14
+ "import": "./dist/index.js",
15
+ "types": "./dist/index.d.ts"
16
+ }
17
+ },
18
+ "files": [
19
+ "dist",
20
+ "data.json.br"
21
+ ],
9
22
  "scripts": {
10
- "test": "echo \"Error: no test specified\" && exit 1"
23
+ "bundle-data": "tsx scripts/bundle-data.ts",
24
+ "build": "pnpm run bundle-data && tsc"
25
+ },
26
+ "author": "amplitudesxd",
27
+ "license": "MIT",
28
+ "packageManager": "pnpm@10.15.1",
29
+ "devDependencies": {
30
+ "typescript": "^5.9.2",
31
+ "@types/node": "^24.3.1",
32
+ "tsx": "^4.20.5"
33
+ },
34
+ "engines": {
35
+ "node": ">=18"
11
36
  }
12
- }
37
+ }