postal-code-scraper 1.0.2 → 1.0.4

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.
Files changed (56) hide show
  1. package/README.md +56 -62
  2. package/dist/index.cjs +392 -0
  3. package/dist/index.d.cts +43 -0
  4. package/dist/index.d.ts +43 -3
  5. package/dist/index.js +355 -25
  6. package/package.json +17 -6
  7. package/.mocharc.json +0 -4
  8. package/build/test/src/index.js +0 -26
  9. package/build/test/src/index.js.map +0 -1
  10. package/build/test/src/scraper/fetchers.js +0 -49
  11. package/build/test/src/scraper/fetchers.js.map +0 -1
  12. package/build/test/src/scraper/parsers.js +0 -63
  13. package/build/test/src/scraper/parsers.js.map +0 -1
  14. package/build/test/src/scraper/queue.js +0 -69
  15. package/build/test/src/scraper/queue.js.map +0 -1
  16. package/build/test/src/scraper/scrapers.js +0 -148
  17. package/build/test/src/scraper/scrapers.js.map +0 -1
  18. package/build/test/src/types.js +0 -3
  19. package/build/test/src/types.js.map +0 -1
  20. package/build/test/src/utils/id-generator.js +0 -33
  21. package/build/test/src/utils/id-generator.js.map +0 -1
  22. package/build/test/src/utils/logger.js +0 -87
  23. package/build/test/src/utils/logger.js.map +0 -1
  24. package/build/test/tests/postal-code-scraper.test.js +0 -14
  25. package/build/test/tests/postal-code-scraper.test.js.map +0 -1
  26. package/dist/scraper/fetchers.d.ts +0 -9
  27. package/dist/scraper/fetchers.js +0 -48
  28. package/dist/scraper/parsers.d.ts +0 -7
  29. package/dist/scraper/parsers.js +0 -62
  30. package/dist/scraper/queue.d.ts +0 -12
  31. package/dist/scraper/queue.js +0 -67
  32. package/dist/scraper/scrapers.d.ts +0 -19
  33. package/dist/scraper/scrapers.js +0 -149
  34. package/dist/types.d.ts +0 -32
  35. package/dist/types.js +0 -2
  36. package/dist/utils/env-config.d.ts +0 -1
  37. package/dist/utils/env-config.js +0 -7
  38. package/dist/utils/id-generator.d.ts +0 -4
  39. package/dist/utils/id-generator.js +0 -26
  40. package/dist/utils/logger.d.ts +0 -33
  41. package/dist/utils/logger.js +0 -86
  42. package/dist/utils/string-utils.d.ts +0 -1
  43. package/dist/utils/string-utils.js +0 -13
  44. package/src/index.ts +0 -3
  45. package/src/scraper/fetchers.ts +0 -30
  46. package/src/scraper/parsers.ts +0 -67
  47. package/src/scraper/queue.ts +0 -55
  48. package/src/scraper/scrapers.ts +0 -143
  49. package/src/types.ts +0 -37
  50. package/src/utils/env-config.ts +0 -3
  51. package/src/utils/id-generator.ts +0 -35
  52. package/src/utils/logger.ts +0 -105
  53. package/src/utils/string-utils.ts +0 -9
  54. package/tests/postal-code-scraper.test.ts +0 -100
  55. package/tests/tsconfig.json +0 -13
  56. package/tsconfig.json +0 -15
package/src/types.ts DELETED
@@ -1,37 +0,0 @@
1
- export type Region = {
2
- path: string;
3
- name: string;
4
- prettyName: string;
5
- };
6
-
7
- export type ScraperConfig = {
8
- usePrettyName?: boolean;
9
- directory?: string;
10
- concurrency?: number;
11
- maxRetries?: number;
12
- headless?: boolean;
13
- logger?: any;
14
- };
15
-
16
- export type ProcessingQueueItem = {
17
- region: Region;
18
- currData: RegionData;
19
- };
20
-
21
- export interface LookupData {
22
- postalCodeMap: {
23
- [postalCode: string]: string;
24
- };
25
- regions: {
26
- [code: string]: string[];
27
- };
28
- }
29
-
30
- export interface PostalCodeData {
31
- rawData: RegionData;
32
- postalCodeLookup: LookupData;
33
- }
34
-
35
- export interface RegionData {
36
- [key: string]: RegionData | string[];
37
- }
@@ -1,3 +0,0 @@
1
- export const getBaseUrl = () => {
2
- return "https://worldpostalcode.com";
3
- };
@@ -1,35 +0,0 @@
1
- export interface RegionIdGenerator {
2
- (regions: string[]): string;
3
- }
4
-
5
- export const createRegionIdGenerator = (): RegionIdGenerator => {
6
- const regionRegistry = new Map<string, string>();
7
- const counterMap = new Map<string, number>();
8
-
9
- return (regions: string[]): string => {
10
- const normalized = regions.map((region) =>
11
- region
12
- .trim()
13
- .toLowerCase()
14
- .normalize("NFD")
15
- .replace(/[\u0300-\u036f]/g, "")
16
- .replace(/\s+/g, "_")
17
- );
18
-
19
- const compositeKey = normalized.join("|");
20
-
21
- if (regionRegistry.has(compositeKey)) {
22
- return regionRegistry.get(compositeKey)!;
23
- }
24
-
25
- const baseName = normalized[normalized.length - 1];
26
- const count = (counterMap.get(baseName) || 0) + 1;
27
- counterMap.set(baseName, count);
28
-
29
- const newId = `${baseName}_${count}`;
30
-
31
- regionRegistry.set(compositeKey, newId);
32
-
33
- return newId;
34
- };
35
- };
@@ -1,105 +0,0 @@
1
- export type LogMethod = "error" | "warn" | "info" | "debug";
2
- export type LogLevel = LogMethod | "silent";
3
-
4
- export interface LoggerInterface {
5
- debug(message: string, ...args: any[]): void;
6
- info(message: string, ...args: any[]): void;
7
- warn(message: string, ...args: any[]): void;
8
- error(message: string, ...args: any[]): void;
9
- }
10
-
11
- export class Logger implements LoggerInterface {
12
- private static logLevel: LogLevel = "info";
13
- private static useColors: boolean = true;
14
- private static prefix: string = "[POSTAL-CODE-SCRAPER]";
15
- private static instance: LoggerInterface;
16
-
17
- static configure(config: { level?: LogLevel; colors?: boolean; prefix?: string; logger?: LoggerInterface }): void {
18
- if (config.level) this.logLevel = config.level;
19
- if (config.colors !== undefined) this.useColors = config.colors;
20
- if (config.prefix) this.prefix = config.prefix;
21
- if (config.logger) this.instance = config.logger;
22
- }
23
-
24
- static getInstance(): LoggerInterface {
25
- return this.instance || new Logger();
26
- }
27
-
28
- static debug(message: string, ...args: any[]): void {
29
- this.log("debug", message, args);
30
- }
31
-
32
- static info(message: string, ...args: any[]): void {
33
- this.log("info", message, args);
34
- }
35
-
36
- static warn(message: string, ...args: any[]): void {
37
- this.log("warn", message, args);
38
- }
39
-
40
- static error(message: string, ...args: any[]): void {
41
- this.log("error", message, args);
42
- }
43
-
44
- private static shouldLog(level: LogLevel): boolean {
45
- if (this.logLevel === "silent") return false;
46
-
47
- const levels: LogMethod[] = ["error", "warn", "info", "debug"];
48
- return levels.indexOf(level as LogMethod) <= levels.indexOf(this.logLevel as LogMethod);
49
- }
50
-
51
- private static log(level: LogMethod, message: string, args: any[]): void {
52
- if (!this.shouldLog(level)) return;
53
-
54
- const logger = this.getInstance();
55
- const formatted = this.formatMessage(level, message);
56
-
57
- logger[level](formatted, ...args);
58
- }
59
-
60
- private static formatMessage(level: LogMethod, message: string): string {
61
- const timestamp = new Date().toISOString();
62
- const levelColor = this.getLevelColor(level);
63
- const messageColor = this.useColors ? "\x1b[37m" : "";
64
-
65
- return [
66
- this.useColors ? "\x1b[90m" : "",
67
- `${this.prefix} `,
68
- `${timestamp} `,
69
- levelColor,
70
- `[${level.toUpperCase()}]`,
71
- this.useColors ? "\x1b[0m" : "",
72
- messageColor,
73
- ` ${message}`,
74
- this.useColors ? "\x1b[0m" : "",
75
- ].join("");
76
- }
77
-
78
- private static getLevelColor(level: LogMethod): string {
79
- if (!this.useColors) return "";
80
-
81
- return {
82
- error: "\x1b[31m", // Red
83
- warn: "\x1b[33m", // Yellow
84
- info: "\x1b[36m", // Cyan
85
- debug: "\x1b[35m", // Magenta
86
- }[level];
87
- }
88
-
89
- // Instance methods to implement LoggerInterface
90
- debug(message: string, ...args: any[]): void {
91
- console.debug(message, ...args);
92
- }
93
-
94
- info(message: string, ...args: any[]): void {
95
- console.log(message, ...args);
96
- }
97
-
98
- warn(message: string, ...args: any[]): void {
99
- console.warn(message, ...args);
100
- }
101
-
102
- error(message: string, ...args: any[]): void {
103
- console.error(message, ...args);
104
- }
105
- }
@@ -1,9 +0,0 @@
1
- export const normalizeString = (str: string): string => {
2
- return str
3
- .trim()
4
- .toLowerCase()
5
- .normalize("NFD")
6
- .replace(/[\u0300-\u036f]/g, "")
7
- .replace(/\s+/g, "-")
8
- .replace(/[^a-z0-9.-]/g, "");
9
- };
@@ -1,100 +0,0 @@
1
- import { expect } from "chai";
2
- import sinon from "sinon";
3
- import { PostalCodeScraper, ScraperConfig } from "../src";
4
- import path from "path";
5
- import fs from "fs";
6
-
7
- const TEST_DATA_DIR = "./tests/test-data";
8
-
9
- describe("PostalCodeScraper", () => {
10
- let scraper: PostalCodeScraper;
11
- let config: ScraperConfig;
12
-
13
- before(async function () {
14
- this.timeout(20000);
15
- config = {
16
- headless: true,
17
- concurrency: 10,
18
- logger: console,
19
- directory: TEST_DATA_DIR,
20
- };
21
-
22
- scraper = new PostalCodeScraper(config);
23
- await scraper.scrapeCountry("romania");
24
- });
25
-
26
- afterEach(async () => {
27
- sinon.restore();
28
- });
29
-
30
- after(() => {
31
- fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
32
- });
33
-
34
- describe("Country Scraping", function () {
35
- it("should handle country found", async () => {
36
- const postalCodesFile = path.join(TEST_DATA_DIR, "romania-postal-codes.json");
37
- const lookupFile = path.join(TEST_DATA_DIR, "romania-lookup.json");
38
-
39
- expect(fs.existsSync(postalCodesFile), "Postal codes file should exist").to.be.true;
40
- expect(fs.existsSync(lookupFile), "Lookup file should exist").to.be.true;
41
- });
42
-
43
- it("should handle country not found", async () => {
44
- const loggerSpy = sinon.spy(console, "warn");
45
- await scraper.scrapeCountry("NonExistentCountry");
46
- expect(loggerSpy.calledOnce).to.be.true;
47
- });
48
- });
49
-
50
- describe("Data Processing", () => {
51
- it("should generate valid postal code data", async () => {
52
- const postalCodesFile = path.join(TEST_DATA_DIR, "romania-postal-codes.json");
53
- const postalCodesContent = JSON.parse(fs.readFileSync(postalCodesFile, "utf8"));
54
-
55
- const expectedPostalCodes = {
56
- alba: {
57
- abrud: ["515100"],
58
- },
59
- };
60
-
61
- expect(postalCodesContent).to.have.property("alba");
62
- expect(postalCodesContent.alba).to.have.property("abrud");
63
- expect(postalCodesContent.alba.abrud).to.deep.equal(expectedPostalCodes.alba.abrud);
64
- });
65
-
66
- it("should generate valid postal code lookup", () => {
67
- const lookupFile = path.join(TEST_DATA_DIR, "romania-lookup.json");
68
- const lookupContent = JSON.parse(fs.readFileSync(lookupFile, "utf8"));
69
-
70
- const expectedLookup = {
71
- postalCodeMap: {
72
- "450145": "zalau_1",
73
- },
74
- regions: {
75
- zalau_1: ["salaj", "zalau"],
76
- },
77
- };
78
-
79
- expect(lookupContent).to.have.property("postalCodeMap");
80
- expect(lookupContent.postalCodeMap).to.have.property("450145");
81
- expect(lookupContent.regions.zalau_1).to.deep.equal(expectedLookup.regions.zalau_1);
82
- expect(lookupContent).to.have.property("regions");
83
- expect(lookupContent.regions).to.have.property("zalau_1");
84
- expect(lookupContent.regions.zalau_1).to.deep.equal(expectedLookup.regions.zalau_1);
85
- });
86
- });
87
-
88
- describe("Error Handling", () => {
89
- it("should retry failed fetches", async () => {
90
- const fetcherStub = sinon.stub((scraper as any).fetcher, "fetchWithRetry").rejects(new Error("Network error"));
91
-
92
- try {
93
- await (scraper as any).getCountriesDetails();
94
- } catch (err) {
95
- expect(err).to.be.an("error");
96
- expect(fetcherStub.callCount).to.equal(config.maxRetries);
97
- }
98
- });
99
- });
100
- });
@@ -1,13 +0,0 @@
1
- {
2
- "extends": "../tsconfig.json",
3
-
4
- "compilerOptions": {
5
- "outDir": "../build/test",
6
- "rootDir": "../",
7
- "rootDirs": ["../src", "./"],
8
- "noEmitOnError": true,
9
- "declaration": false,
10
- "sourceMap": true
11
- },
12
- "include": ["./**/*", "../src/**/*"]
13
- }
package/tsconfig.json DELETED
@@ -1,15 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "rootDir": "./src",
4
- "outDir": "./dist",
5
- "forceConsistentCasingInFileNames": true,
6
- "strict": true,
7
- "skipLibCheck": true,
8
- "declaration": true,
9
- "target": "ES6",
10
- "module": "CommonJS",
11
- "esModuleInterop": true,
12
- "moduleResolution": "node"
13
- },
14
- "include": ["src/**/*"]
15
- }