inibase 1.0.0-rc.12 → 1.0.0-rc.15

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/file.ts DELETED
@@ -1,674 +0,0 @@
1
- import { createWriteStream, createReadStream, WriteStream } from "node:fs";
2
- import { open, unlink, rename, stat } from "node:fs/promises";
3
- import { Interface, createInterface } from "node:readline";
4
- import { parse } from "node:path";
5
- import { ComparisonOperator, FieldType } from ".";
6
- import {
7
- detectFieldType,
8
- isArrayOfArrays,
9
- isNumber,
10
- encodeID,
11
- comparePassword,
12
- } from "./utils";
13
-
14
- const doesSupportReadLines = () => {
15
- const [major, minor, patch] = process.versions.node.split(".").map(Number);
16
- return major >= 18 && minor >= 11;
17
- };
18
-
19
- export const isExists = async (path: string) => {
20
- try {
21
- await stat(path);
22
- return true;
23
- } catch {
24
- return false;
25
- }
26
- };
27
-
28
- const delimiters = [",", "|", "&", "$", "#", "@", "^", "%", ":", "!", ";"];
29
-
30
- export const encode = (
31
- input:
32
- | string
33
- | number
34
- | boolean
35
- | null
36
- | (string | number | boolean | null)[],
37
- secretKey?: string | Buffer
38
- ) => {
39
- const secureString = (input: string | number | boolean | null) => {
40
- if (["true", "false"].includes(String(input))) return input ? 1 : 0;
41
- return typeof input === "string"
42
- ? decodeURIComponent(input)
43
- .replaceAll("<", "&lt;")
44
- .replaceAll(">", "&gt;")
45
- .replaceAll(",", "%2C")
46
- .replaceAll("|", "%7C")
47
- .replaceAll("&", "%26")
48
- .replaceAll("$", "%24")
49
- .replaceAll("#", "%23")
50
- .replaceAll("@", "%40")
51
- .replaceAll("^", "%5E")
52
- .replaceAll("%", "%25")
53
- .replaceAll(":", "%3A")
54
- .replaceAll("!", "%21")
55
- .replaceAll(";", "%3B")
56
- .replaceAll("\n", "\\n")
57
- .replaceAll("\r", "\\r")
58
- : input;
59
- },
60
- secureArray = (arr_str: any[] | any): any[] | any =>
61
- Array.isArray(arr_str) ? arr_str.map(secureArray) : secureString(arr_str),
62
- joinMultidimensionalArray = (
63
- arr: any[] | any[][],
64
- delimiter_index = 0
65
- ): string => {
66
- delimiter_index++;
67
- if (isArrayOfArrays(arr))
68
- arr = arr.map((ar: any[]) =>
69
- joinMultidimensionalArray(ar, delimiter_index)
70
- );
71
- delimiter_index--;
72
- return arr.join(delimiters[delimiter_index]);
73
- };
74
- return Array.isArray(input)
75
- ? joinMultidimensionalArray(secureArray(input))
76
- : secureString(input);
77
- };
78
-
79
- export const decode = (
80
- input: string | null | number,
81
- fieldType?: FieldType | FieldType[],
82
- fieldChildrenType?: FieldType | FieldType[],
83
- secretKey?: string | Buffer
84
- ): string | number | boolean | null | (string | number | null | boolean)[] => {
85
- if (!fieldType) return null;
86
- const unSecureString = (input: string) =>
87
- decodeURIComponent(input)
88
- .replaceAll("&lt;", "<")
89
- .replaceAll("&gt;", ">")
90
- .replaceAll("%2C", ",")
91
- .replaceAll("%7C", "|")
92
- .replaceAll("%26", "&")
93
- .replaceAll("%24", "$")
94
- .replaceAll("%23", "#")
95
- .replaceAll("%40", "@")
96
- .replaceAll("%5E", "^")
97
- .replaceAll("%25", "%")
98
- .replaceAll("%3A", ":")
99
- .replaceAll("%21", "!")
100
- .replaceAll("%3B", ";")
101
- .replaceAll("\\n", "\n")
102
- .replaceAll("\\r", "\r") || null,
103
- unSecureArray = (arr_str: any[] | any): any[] | any =>
104
- Array.isArray(arr_str)
105
- ? arr_str.map(unSecureArray)
106
- : unSecureString(arr_str),
107
- reverseJoinMultidimensionalArray = (
108
- joinedString: string | any[] | any[][]
109
- ): any | any[] | any[][] => {
110
- const reverseJoinMultidimensionalArrayHelper = (
111
- arr: any | any[] | any[][],
112
- delimiter: string
113
- ) =>
114
- Array.isArray(arr)
115
- ? arr.map((ar: any) =>
116
- reverseJoinMultidimensionalArrayHelper(ar, delimiter)
117
- )
118
- : arr.split(delimiter);
119
-
120
- const availableDelimiters = delimiters.filter((delimiter) =>
121
- joinedString.includes(delimiter)
122
- );
123
- for (const delimiter of availableDelimiters) {
124
- joinedString = Array.isArray(joinedString)
125
- ? reverseJoinMultidimensionalArrayHelper(joinedString, delimiter)
126
- : joinedString.split(delimiter);
127
- }
128
- return joinedString;
129
- },
130
- decodeHelper = (value: string | number | any[]) => {
131
- if (Array.isArray(value) && fieldType !== "array")
132
- return value.map(decodeHelper);
133
- switch (fieldType as FieldType) {
134
- case "table":
135
- case "number":
136
- return isNumber(value) ? Number(value) : null;
137
- case "boolean":
138
- return typeof value === "string" ? value === "true" : Boolean(value);
139
- case "array":
140
- if (!Array.isArray(value)) return [value];
141
-
142
- if (fieldChildrenType)
143
- return value.map(
144
- (v) =>
145
- decode(
146
- v,
147
- Array.isArray(fieldChildrenType)
148
- ? detectFieldType(v, fieldChildrenType)
149
- : fieldChildrenType,
150
- undefined,
151
- secretKey
152
- ) as string | number | boolean | null
153
- );
154
- else return value;
155
- case "id":
156
- return isNumber(value) ? encodeID(value as number, secretKey) : value;
157
- default:
158
- return value;
159
- }
160
- };
161
- if (input === null || input === "") return null;
162
- if (Array.isArray(fieldType))
163
- fieldType = detectFieldType(String(input), fieldType);
164
- return decodeHelper(
165
- typeof input === "string"
166
- ? input.includes(",")
167
- ? unSecureArray(reverseJoinMultidimensionalArray(input))
168
- : unSecureString(input)
169
- : input
170
- );
171
- };
172
-
173
- export const get = async (
174
- filePath: string,
175
- lineNumbers?: number | number[],
176
- fieldType?: FieldType | FieldType[],
177
- fieldChildrenType?: FieldType | FieldType[],
178
- secretKey?: string | Buffer
179
- ): Promise<
180
- [
181
- Record<
182
- number,
183
- | string
184
- | number
185
- | boolean
186
- | (string | number | boolean | (string | number | boolean)[])[]
187
- > | null,
188
- number
189
- ]
190
- > => {
191
- let rl: Interface;
192
- if (doesSupportReadLines()) rl = (await open(filePath)).readLines();
193
- else
194
- rl = createInterface({
195
- input: createReadStream(filePath),
196
- crlfDelay: Infinity,
197
- });
198
- let lines: Record<
199
- number,
200
- | string
201
- | number
202
- | boolean
203
- | (string | number | boolean | (string | number | boolean)[] | null)[]
204
- | null
205
- > = {},
206
- lineCount = 0;
207
-
208
- if (!lineNumbers) {
209
- for await (const line of rl)
210
- lineCount++,
211
- (lines[lineCount] = decode(
212
- line,
213
- fieldType,
214
- fieldChildrenType,
215
- secretKey
216
- ));
217
- } else if (lineNumbers === -1) {
218
- let lastLine: string;
219
- for await (const line of rl) lineCount++, (lastLine = line);
220
- if (lastLine)
221
- lines = {
222
- [lineCount]: decode(lastLine, fieldType, fieldChildrenType, secretKey),
223
- };
224
- } else {
225
- let lineNumbersArray = [
226
- ...(Array.isArray(lineNumbers) ? lineNumbers : [lineNumbers]),
227
- ];
228
- for await (const line of rl) {
229
- lineCount++;
230
- if (!lineNumbersArray.includes(lineCount)) continue;
231
- lines[lineCount] = decode(line, fieldType, fieldChildrenType, secretKey);
232
- lineNumbersArray[lineNumbersArray.indexOf(lineCount)] = 0;
233
- if (!lineNumbersArray.filter((lineN) => lineN !== 0).length) break;
234
- }
235
- }
236
-
237
- return [lines ?? null, lineCount];
238
- };
239
-
240
- export const replace = async (
241
- filePath: string,
242
- replacements:
243
- | string
244
- | number
245
- | boolean
246
- | null
247
- | (string | number | boolean | null)[]
248
- | Record<
249
- number,
250
- string | boolean | number | null | (string | boolean | number | null)[]
251
- >,
252
- secretKey?: string | Buffer
253
- ) => {
254
- if (await isExists(filePath)) {
255
- let rl: Interface, writeStream: WriteStream;
256
- if (doesSupportReadLines()) {
257
- const file = await open(filePath, "w+");
258
- rl = file.readLines();
259
- writeStream = file.createWriteStream();
260
- } else {
261
- rl = createInterface({
262
- input: createReadStream(filePath),
263
- crlfDelay: Infinity,
264
- });
265
- writeStream = createWriteStream(filePath);
266
- }
267
- if (typeof replacements === "object" && !Array.isArray(replacements)) {
268
- let lineCount = 0;
269
- for await (const line of rl) {
270
- lineCount++;
271
- writeStream.write(
272
- (lineCount in replacements
273
- ? encode(replacements[lineCount], secretKey)
274
- : line) + "\n"
275
- );
276
- }
277
- } else
278
- for await (const _line of rl)
279
- writeStream.write(encode(replacements, secretKey) + "\n");
280
-
281
- writeStream.end();
282
- } else if (typeof replacements === "object" && !Array.isArray(replacements)) {
283
- let writeStream: WriteStream;
284
- if (doesSupportReadLines())
285
- writeStream = (await open(filePath, "w")).createWriteStream();
286
- else writeStream = createWriteStream(filePath);
287
- const largestLinesNumbers =
288
- Math.max(...Object.keys(replacements).map(Number)) + 1;
289
- for (let lineCount = 1; lineCount < largestLinesNumbers; lineCount++) {
290
- writeStream.write(
291
- (lineCount in replacements
292
- ? encode(replacements[lineCount], secretKey)
293
- : "") + "\n"
294
- );
295
- }
296
- writeStream.end();
297
- }
298
- };
299
-
300
- export const remove = async (
301
- filePath: string,
302
- linesToDelete: number | number[]
303
- ): Promise<void> => {
304
- let lineCount = 0;
305
-
306
- const tempFilePath = `${filePath}-${Date.now()}.tmp`,
307
- linesToDeleteArray = [
308
- ...(Array.isArray(linesToDelete) ? linesToDelete : [linesToDelete]),
309
- ];
310
-
311
- let rl: Interface, writeStream: WriteStream;
312
- if (doesSupportReadLines()) {
313
- rl = (await open(filePath)).readLines();
314
- writeStream = (await open(tempFilePath, "w+")).createWriteStream();
315
- } else {
316
- rl = createInterface({
317
- input: createReadStream(filePath),
318
- crlfDelay: Infinity,
319
- });
320
- writeStream = createWriteStream(tempFilePath);
321
- }
322
-
323
- for await (const line of rl) {
324
- lineCount++;
325
- if (!linesToDeleteArray.includes(lineCount)) {
326
- writeStream.write(`${line}\n`);
327
- }
328
- }
329
- writeStream.end(async () => {
330
- await unlink(filePath); // Remove the original file
331
- await rename(tempFilePath, filePath); // Rename the temp file to the original file name
332
- });
333
- };
334
-
335
- export const count = async (filePath: string): Promise<number> => {
336
- let lineCount = 0,
337
- rl: Interface;
338
- if (doesSupportReadLines()) rl = (await open(filePath)).readLines();
339
- else
340
- rl = createInterface({
341
- input: createReadStream(filePath),
342
- crlfDelay: Infinity,
343
- });
344
-
345
- for await (const line of rl) lineCount++;
346
-
347
- return lineCount;
348
- };
349
-
350
- export const search = async (
351
- filePath: string,
352
- operator: ComparisonOperator | ComparisonOperator[],
353
- comparedAtValue:
354
- | string
355
- | number
356
- | boolean
357
- | null
358
- | (string | number | boolean | null)[],
359
- logicalOperator?: "and" | "or",
360
- fieldType?: FieldType | FieldType[],
361
- fieldChildrenType?: FieldType | FieldType[],
362
- limit?: number,
363
- offset?: number,
364
- readWholeFile?: boolean,
365
- secretKey?: string | Buffer
366
- ): Promise<
367
- [
368
- Record<
369
- number,
370
- Record<
371
- string,
372
- string | number | boolean | (string | number | boolean | null)[] | null
373
- >
374
- > | null,
375
- number
376
- ]
377
- > => {
378
- const handleComparisonOperator = (
379
- operator: ComparisonOperator,
380
- originalValue:
381
- | string
382
- | number
383
- | boolean
384
- | null
385
- | (string | number | boolean | null)[],
386
- comparedAtValue:
387
- | string
388
- | number
389
- | boolean
390
- | null
391
- | (string | number | boolean | null)[],
392
- fieldType?: FieldType | FieldType[],
393
- fieldChildrenType?: FieldType | FieldType[]
394
- ): boolean => {
395
- if (Array.isArray(fieldType))
396
- fieldType = detectFieldType(String(originalValue), fieldType);
397
- if (Array.isArray(comparedAtValue) && !["[]", "![]"].includes(operator))
398
- return comparedAtValue.some((comparedAtValueSingle) =>
399
- handleComparisonOperator(
400
- operator,
401
- originalValue,
402
- comparedAtValueSingle,
403
- fieldType
404
- )
405
- );
406
- // check if not array or object // it can't be array or object!
407
- switch (operator) {
408
- case "=":
409
- switch (fieldType) {
410
- case "password":
411
- return typeof originalValue === "string" &&
412
- typeof comparedAtValue === "string"
413
- ? comparePassword(originalValue, comparedAtValue)
414
- : false;
415
- case "boolean":
416
- return Number(originalValue) - Number(comparedAtValue) === 0;
417
- default:
418
- return originalValue === comparedAtValue;
419
- }
420
- case "!=":
421
- return !handleComparisonOperator(
422
- "=",
423
- originalValue,
424
- comparedAtValue,
425
- fieldType
426
- );
427
- case ">":
428
- return originalValue > comparedAtValue;
429
- case "<":
430
- return originalValue < comparedAtValue;
431
- case ">=":
432
- return originalValue >= comparedAtValue;
433
- case "<=":
434
- return originalValue <= comparedAtValue;
435
- case "[]":
436
- return (
437
- (Array.isArray(originalValue) &&
438
- Array.isArray(comparedAtValue) &&
439
- originalValue.some(comparedAtValue.includes)) ||
440
- (Array.isArray(originalValue) &&
441
- !Array.isArray(comparedAtValue) &&
442
- originalValue.includes(comparedAtValue)) ||
443
- (!Array.isArray(originalValue) &&
444
- Array.isArray(comparedAtValue) &&
445
- comparedAtValue.includes(originalValue))
446
- );
447
- case "![]":
448
- return !handleComparisonOperator(
449
- "[]",
450
- originalValue,
451
- comparedAtValue,
452
- fieldType
453
- );
454
- case "*":
455
- return new RegExp(
456
- `^${(String(comparedAtValue).includes("%")
457
- ? String(comparedAtValue)
458
- : "%" + String(comparedAtValue) + "%"
459
- ).replace(/%/g, ".*")}$`,
460
- "i"
461
- ).test(String(originalValue));
462
- case "!*":
463
- return !handleComparisonOperator(
464
- "*",
465
- originalValue,
466
- comparedAtValue,
467
- fieldType
468
- );
469
- default:
470
- throw new Error(operator);
471
- }
472
- };
473
-
474
- let RETURN: Record<
475
- number,
476
- Record<
477
- string,
478
- string | number | boolean | null | (string | number | boolean | null)[]
479
- >
480
- > = {},
481
- lineCount = 0,
482
- foundItems = 0;
483
- let rl: Interface;
484
- if (doesSupportReadLines()) rl = (await open(filePath)).readLines();
485
- else
486
- rl = createInterface({
487
- input: createReadStream(filePath),
488
- crlfDelay: Infinity,
489
- });
490
-
491
- const columnName = parse(filePath).name;
492
-
493
- for await (const line of rl) {
494
- lineCount++;
495
- const decodedLine = decode(line, fieldType, fieldChildrenType, secretKey);
496
- if (
497
- (Array.isArray(operator) &&
498
- Array.isArray(comparedAtValue) &&
499
- ((logicalOperator &&
500
- logicalOperator === "or" &&
501
- operator.some((single_operator, index) =>
502
- handleComparisonOperator(
503
- single_operator,
504
- decodedLine,
505
- comparedAtValue[index],
506
- fieldType
507
- )
508
- )) ||
509
- operator.every((single_operator, index) =>
510
- handleComparisonOperator(
511
- single_operator,
512
- decodedLine,
513
- comparedAtValue[index],
514
- fieldType
515
- )
516
- ))) ||
517
- (!Array.isArray(operator) &&
518
- handleComparisonOperator(
519
- operator,
520
- decodedLine,
521
- comparedAtValue,
522
- fieldType
523
- ))
524
- ) {
525
- foundItems++;
526
- if (offset && foundItems < offset) continue;
527
- if (limit && foundItems > limit)
528
- if (readWholeFile) continue;
529
- else break;
530
- if (!RETURN[lineCount]) RETURN[lineCount] = {};
531
- RETURN[lineCount][columnName] = decodedLine;
532
- }
533
- }
534
- if (foundItems) {
535
- return [RETURN, readWholeFile ? foundItems : foundItems - 1];
536
- } else return [null, 0];
537
- };
538
-
539
- export const sum = async (
540
- filePath: string,
541
- lineNumbers?: number | number[]
542
- ): Promise<number> => {
543
- let rl: Interface;
544
- if (doesSupportReadLines()) rl = (await open(filePath)).readLines();
545
- else
546
- rl = createInterface({
547
- input: createReadStream(filePath),
548
- crlfDelay: Infinity,
549
- });
550
- let sum = 0;
551
-
552
- if (lineNumbers) {
553
- let lineCount = 0;
554
-
555
- let lineNumbersArray = [
556
- ...(Array.isArray(lineNumbers) ? lineNumbers : [lineNumbers]),
557
- ];
558
- for await (const line of rl) {
559
- lineCount++;
560
- if (!lineNumbersArray.includes(lineCount)) continue;
561
- sum += +decode(line, "number");
562
- lineNumbersArray[lineNumbersArray.indexOf(lineCount)] = 0;
563
- if (!lineNumbersArray.filter((lineN) => lineN !== 0).length) break;
564
- }
565
- } else for await (const line of rl) sum += +decode(line, "number");
566
-
567
- return sum;
568
- };
569
-
570
- export const max = async (
571
- filePath: string,
572
- lineNumbers?: number | number[]
573
- ): Promise<number> => {
574
- let rl: Interface;
575
- if (doesSupportReadLines()) rl = (await open(filePath)).readLines();
576
- else
577
- rl = createInterface({
578
- input: createReadStream(filePath),
579
- crlfDelay: Infinity,
580
- });
581
- let max = 0;
582
-
583
- if (lineNumbers) {
584
- let lineCount = 0;
585
-
586
- let lineNumbersArray = [
587
- ...(Array.isArray(lineNumbers) ? lineNumbers : [lineNumbers]),
588
- ];
589
- for await (const line of rl) {
590
- lineCount++;
591
- if (!lineNumbersArray.includes(lineCount)) continue;
592
- const lineContentNum = +decode(line, "number");
593
- if (lineContentNum > max) max = lineContentNum;
594
- lineNumbersArray[lineNumbersArray.indexOf(lineCount)] = 0;
595
- if (!lineNumbersArray.filter((lineN) => lineN !== 0).length) break;
596
- }
597
- } else
598
- for await (const line of rl) {
599
- const lineContentNum = +decode(line, "number");
600
- if (lineContentNum > max) max = lineContentNum;
601
- }
602
-
603
- return max;
604
- };
605
-
606
- export const min = async (
607
- filePath: string,
608
- lineNumbers?: number | number[]
609
- ): Promise<number> => {
610
- let rl: Interface;
611
- if (doesSupportReadLines()) rl = (await open(filePath)).readLines();
612
- else
613
- rl = createInterface({
614
- input: createReadStream(filePath),
615
- crlfDelay: Infinity,
616
- });
617
- let min = 0;
618
-
619
- if (lineNumbers) {
620
- let lineCount = 0;
621
-
622
- let lineNumbersArray = [
623
- ...(Array.isArray(lineNumbers) ? lineNumbers : [lineNumbers]),
624
- ];
625
- for await (const line of rl) {
626
- lineCount++;
627
- if (!lineNumbersArray.includes(lineCount)) continue;
628
- const lineContentNum = +decode(line, "number");
629
- if (lineContentNum < min) min = lineContentNum;
630
- lineNumbersArray[lineNumbersArray.indexOf(lineCount)] = 0;
631
- if (!lineNumbersArray.filter((lineN) => lineN !== 0).length) break;
632
- }
633
- } else
634
- for await (const line of rl) {
635
- const lineContentNum = +decode(line, "number");
636
- if (lineContentNum < min) min = lineContentNum;
637
- }
638
-
639
- return min;
640
- };
641
-
642
- export const sort = async (
643
- filePath: string,
644
- sortDirection: 1 | -1 | "asc" | "desc",
645
- lineNumbers?: number | number[],
646
- _lineNumbersPerChunk: number = 100000
647
- ): Promise<void> => {
648
- let rl: Interface;
649
- if (doesSupportReadLines()) rl = (await open(filePath)).readLines();
650
- else
651
- rl = createInterface({
652
- input: createReadStream(filePath),
653
- crlfDelay: Infinity,
654
- });
655
- let lineCount = 0;
656
-
657
- for await (const line of rl) {
658
- lineCount++;
659
- }
660
- };
661
-
662
- export default class File {
663
- static get = get;
664
- static remove = remove;
665
- static search = search;
666
- static replace = replace;
667
- static count = count;
668
- static encode = encode;
669
- static decode = decode;
670
- static isExists = isExists;
671
- static sum = sum;
672
- static min = min;
673
- static max = max;
674
- }