@k03mad/ip2geo 9.3.0 → 9.6.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.
@@ -1,3 +1,7 @@
1
1
  {
2
- "eslint.experimental.useFlatConfig": true
2
+ "cSpell.words": [
3
+ "consts",
4
+ "geoip",
5
+ "nvmrc"
6
+ ]
3
7
  }
package/app/cli.js CHANGED
@@ -7,7 +7,7 @@ import {DEFAULT_CACHE_FILE_DIR, DEFAULT_CACHE_FILE_NEWLINE, DEFAULT_CACHE_FILE_S
7
7
  import {pruneCache} from './helpers/cache.js';
8
8
  import {codeText, nameText} from './helpers/colors.js';
9
9
 
10
- const {blue, red, green} = chalk;
10
+ const {blue, red, green, dim, bold} = chalk;
11
11
 
12
12
  const args = process.argv.slice(2);
13
13
  const argsExtra = args.filter(arg => !arg.startsWith('-'));
@@ -43,6 +43,7 @@ if (isHelp) {
43
43
 
44
44
  if (isPrune) {
45
45
  const cacheFolder = argsExtra[0] || DEFAULT_CACHE_FILE_DIR;
46
+ log(blue(cacheFolder));
46
47
 
47
48
  try {
48
49
  const {duplicates, empty, longLinesFiles} = await pruneCache(
@@ -51,27 +52,22 @@ if (isPrune) {
51
52
  DEFAULT_CACHE_FILE_NEWLINE,
52
53
  );
53
54
 
54
- const message = [
55
+ log([
55
56
  '',
56
- `Removed duplicate cache entries: ${green(duplicates)}`,
57
- `Removed empty cache entries: ${green(empty)}`,
58
- ];
59
-
60
- if (longLinesFiles.size > 0) {
61
- message.push(
62
- '',
63
- red('Something went wrong with these cache files (lines too long):'),
64
- ...[...longLinesFiles].map(elem => blue(`— ${elem}`)),
65
- );
57
+ green(`Removed duplicate cache entries: ${bold(duplicates.length)}`),
58
+ ...duplicates.map(elem => dim(`— ${elem}`)),
59
+ green(`Removed empty cache entries: ${bold(empty.length)}`),
60
+ ...empty.map(elem => dim(`— ${elem}`)),
61
+ ]);
62
+
63
+ if (longLinesFiles.length > 0) {
64
+ log([
65
+ red(`Required manual check, some cache files has too long lines: ${bold(longLinesFiles.length)}`),
66
+ ...longLinesFiles.map(({file, elem}) => dim(`— ${file}\n|— ${elem}`)),
67
+ ]);
66
68
  }
67
-
68
- log(message);
69
69
  } catch (err) {
70
- if (err.code !== 'ENOENT') {
71
- logErrorExit(err);
72
- }
73
-
74
- log(`Cache folder empty: ${cacheFolder}`);
70
+ logErrorExit(red(err));
75
71
  }
76
72
  } else {
77
73
  const output = argsExtra.length === 0
@@ -2,6 +2,7 @@ import fs from 'node:fs/promises';
2
2
  import path from 'node:path';
3
3
 
4
4
  import _debug from 'debug';
5
+ import {isIP} from 'is-ip';
5
6
 
6
7
  const debug = _debug('mad:geoip');
7
8
 
@@ -161,6 +162,27 @@ export const writeToMapCache = (body, cacheMap, cacheMapMaxEntries) => {
161
162
  export const pruneCache = async (cacheDir, cacheFileSeparator, cacheFileNewline) => {
162
163
  const files = await fs.readdir(cacheDir);
163
164
 
165
+ await Promise.all(files.map(async file => {
166
+ const fullFilePath = path.join(cacheDir, file);
167
+
168
+ const [stat, data] = await Promise.all([
169
+ fs.lstat(fullFilePath),
170
+ fs.readFile(fullFilePath, {encoding: 'utf8'}),
171
+ ]);
172
+
173
+ const firstIp = data
174
+ .split(cacheFileNewline)
175
+ .find(Boolean)
176
+ .split(cacheFileSeparator)[0];
177
+
178
+ if (
179
+ stat.isDirectory()
180
+ || !isIP(firstIp)
181
+ ) {
182
+ throw new Error(`Folder has subfolders or files without IPs, wrong cache folder arg?\n${fullFilePath}`);
183
+ }
184
+ }));
185
+
164
186
  const cacheLineToNum = line => Number(
165
187
  line.split(cacheFileSeparator)[0]
166
188
  .split('.')
@@ -168,9 +190,8 @@ export const pruneCache = async (cacheDir, cacheFileSeparator, cacheFileNewline)
168
190
  .join(''),
169
191
  );
170
192
 
171
- let duplicates = 0;
172
- let empty = 0;
173
-
193
+ const duplicates = new Set();
194
+ const empty = [];
174
195
  const longLinesFiles = new Set();
175
196
 
176
197
  await Promise.all(files.map(async file => {
@@ -183,10 +204,14 @@ export const pruneCache = async (cacheDir, cacheFileSeparator, cacheFileNewline)
183
204
  const splitted = elem.split(cacheFileSeparator);
184
205
 
185
206
  if (splitted.length > outputKeys.length) {
186
- longLinesFiles.add(fullFilePath);
207
+ longLinesFiles.add({file: fullFilePath, elem});
208
+ }
209
+
210
+ if (splitted.filter(Boolean).length > 1) {
211
+ return true;
187
212
  }
188
213
 
189
- return splitted.filter(Boolean).length > 1;
214
+ empty.push(elem);
190
215
  });
191
216
 
192
217
  const uniq = [...new Set(dataArrRemoveEmpty)]
@@ -195,9 +220,13 @@ export const pruneCache = async (cacheDir, cacheFileSeparator, cacheFileNewline)
195
220
  const fileContent = uniq.join(cacheFileNewline).trim();
196
221
  await (fileContent ? fs.writeFile(fullFilePath, fileContent) : fs.rm(fullFilePath));
197
222
 
198
- empty += dataArr.length - dataArrRemoveEmpty.length;
199
- duplicates += dataArrRemoveEmpty.length - uniq.length;
223
+ dataArrRemoveEmpty
224
+ .forEach((elem, i, arr) => arr.indexOf(elem) !== i && duplicates.add(elem));
200
225
  }));
201
226
 
202
- return {duplicates, empty, longLinesFiles};
227
+ return {
228
+ duplicates: [...duplicates],
229
+ empty,
230
+ longLinesFiles: [...longLinesFiles],
231
+ };
203
232
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@k03mad/ip2geo",
3
- "version": "9.3.0",
3
+ "version": "9.6.0",
4
4
  "description": "GeoIP library",
5
5
  "maintainers": [
6
6
  "Kirill Molchanov <k03.mad@gmail.com"
@@ -20,14 +20,15 @@
20
20
  },
21
21
  "dependencies": {
22
22
  "@k03mad/request": "6.1.0",
23
- "@k03mad/simple-log": "2.3.0",
23
+ "@k03mad/simple-log": "4.0.0",
24
24
  "chalk": "5.3.0",
25
- "debug": "4.3.6"
25
+ "debug": "4.3.6",
26
+ "is-ip": "5.0.1"
26
27
  },
27
28
  "devDependencies": {
28
- "@k03mad/eslint-config": "23.0.0",
29
+ "@k03mad/eslint-config": "23.1.0",
29
30
  "eslint": "8.57.0",
30
- "husky": "9.1.4",
31
+ "husky": "9.1.5",
31
32
  "mocha": "10.7.3",
32
33
  "npm-run-all": "4.1.5"
33
34
  },