inibase 1.0.0-rc.11 → 1.0.0-rc.13

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