inibase 1.0.0-rc.0 → 1.0.0-rc.11
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/README.md +45 -62
- package/file.ts +325 -103
- package/index.test.ts +247 -0
- package/index.ts +893 -627
- package/package.json +7 -6
- package/tsconfig.json +2 -1
- package/utils.server.ts +79 -0
- package/utils.ts +166 -64
package/file.ts
CHANGED
|
@@ -1,26 +1,195 @@
|
|
|
1
|
-
import { createWriteStream,
|
|
2
|
-
import { open } from "fs/promises";
|
|
3
|
-
import {
|
|
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";
|
|
4
5
|
import { ComparisonOperator, FieldType } from ".";
|
|
5
|
-
import
|
|
6
|
+
import { detectFieldType, isArrayOfArrays, isNumber } from "./utils";
|
|
7
|
+
import { encodeID, comparePassword } from "./utils.server";
|
|
6
8
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
(extension ? `.${extension}` : "")
|
|
11
|
-
);
|
|
9
|
+
const doesSupportReadLines = () => {
|
|
10
|
+
const [major, minor, patch] = process.versions.node.split(".").map(Number);
|
|
11
|
+
return major >= 18 && minor >= 11;
|
|
12
12
|
};
|
|
13
13
|
|
|
14
|
-
export const
|
|
15
|
-
|
|
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("<", "<")
|
|
39
|
+
.replaceAll(">", ">")
|
|
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("<", "<")
|
|
84
|
+
.replaceAll(">", ">")
|
|
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
|
+
);
|
|
16
166
|
};
|
|
17
167
|
|
|
18
168
|
export const get = async (
|
|
19
169
|
filePath: string,
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
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
|
+
});
|
|
24
193
|
let lines: Record<
|
|
25
194
|
number,
|
|
26
195
|
| string
|
|
@@ -32,27 +201,36 @@ export const get = async (
|
|
|
32
201
|
lineCount = 0;
|
|
33
202
|
|
|
34
203
|
if (!lineNumbers) {
|
|
35
|
-
for await (const line of
|
|
36
|
-
lineCount++,
|
|
204
|
+
for await (const line of rl)
|
|
205
|
+
lineCount++,
|
|
206
|
+
(lines[lineCount] = decode(
|
|
207
|
+
line,
|
|
208
|
+
fieldType,
|
|
209
|
+
fieldChildrenType,
|
|
210
|
+
secretKey
|
|
211
|
+
));
|
|
37
212
|
} else if (lineNumbers === -1) {
|
|
38
|
-
let lastLine;
|
|
39
|
-
for await (const line of
|
|
40
|
-
if (lastLine)
|
|
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
|
+
};
|
|
41
219
|
} else {
|
|
42
220
|
let lineNumbersArray = [
|
|
43
221
|
...(Array.isArray(lineNumbers) ? lineNumbers : [lineNumbers]),
|
|
44
222
|
];
|
|
45
|
-
for await (const line of
|
|
223
|
+
for await (const line of rl) {
|
|
46
224
|
lineCount++;
|
|
47
225
|
if (!lineNumbersArray.includes(lineCount)) continue;
|
|
48
226
|
const indexOfLineCount = lineNumbersArray.indexOf(lineCount);
|
|
49
|
-
lines[lineCount] =
|
|
227
|
+
lines[lineCount] = decode(line, fieldType, fieldChildrenType, secretKey);
|
|
50
228
|
lineNumbersArray[indexOfLineCount] = 0;
|
|
51
229
|
if (!lineNumbersArray.filter((lineN) => lineN !== 0).length) break;
|
|
52
230
|
}
|
|
53
231
|
}
|
|
54
232
|
|
|
55
|
-
return lines ?? null;
|
|
233
|
+
return [lines ?? null, lineCount];
|
|
56
234
|
};
|
|
57
235
|
|
|
58
236
|
export const replace = async (
|
|
@@ -66,35 +244,48 @@ export const replace = async (
|
|
|
66
244
|
| Record<
|
|
67
245
|
number,
|
|
68
246
|
string | boolean | number | null | (string | boolean | number | null)[]
|
|
69
|
-
|
|
247
|
+
>,
|
|
248
|
+
secretKey?: string | Buffer
|
|
70
249
|
) => {
|
|
71
|
-
if (
|
|
72
|
-
|
|
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();
|
|
73
255
|
writeStream = file.createWriteStream();
|
|
256
|
+
} else {
|
|
257
|
+
rl = createInterface({
|
|
258
|
+
input: createReadStream(filePath),
|
|
259
|
+
crlfDelay: Infinity,
|
|
260
|
+
});
|
|
261
|
+
writeStream = createWriteStream(filePath);
|
|
262
|
+
}
|
|
74
263
|
if (typeof replacements === "object" && !Array.isArray(replacements)) {
|
|
75
264
|
let lineCount = 0;
|
|
76
|
-
for await (const line of
|
|
265
|
+
for await (const line of rl) {
|
|
77
266
|
lineCount++;
|
|
78
267
|
writeStream.write(
|
|
79
268
|
(lineCount in replacements
|
|
80
|
-
?
|
|
269
|
+
? encode(replacements[lineCount], secretKey)
|
|
81
270
|
: line) + "\n"
|
|
82
271
|
);
|
|
83
272
|
}
|
|
84
273
|
} else
|
|
85
|
-
for await (const _line of
|
|
86
|
-
writeStream.write(
|
|
274
|
+
for await (const _line of rl)
|
|
275
|
+
writeStream.write(encode(replacements, secretKey) + "\n");
|
|
87
276
|
|
|
88
277
|
writeStream.end();
|
|
89
278
|
} else if (typeof replacements === "object" && !Array.isArray(replacements)) {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
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;
|
|
94
285
|
for (let lineCount = 1; lineCount < largestLinesNumbers; lineCount++) {
|
|
95
286
|
writeStream.write(
|
|
96
287
|
(lineCount in replacements
|
|
97
|
-
?
|
|
288
|
+
? encode(replacements[lineCount], secretKey)
|
|
98
289
|
: "") + "\n"
|
|
99
290
|
);
|
|
100
291
|
}
|
|
@@ -108,39 +299,52 @@ export const remove = async (
|
|
|
108
299
|
): Promise<void> => {
|
|
109
300
|
let lineCount = 0;
|
|
110
301
|
|
|
111
|
-
const tempFilePath = `${filePath}.tmp`,
|
|
302
|
+
const tempFilePath = `${filePath}-${Date.now()}.tmp`,
|
|
112
303
|
linesToDeleteArray = [
|
|
113
304
|
...(Array.isArray(linesToDelete) ? linesToDelete : [linesToDelete]),
|
|
114
|
-
]
|
|
115
|
-
writeStream = createWriteStream(tempFilePath),
|
|
116
|
-
file = await open(filePath);
|
|
305
|
+
];
|
|
117
306
|
|
|
118
|
-
|
|
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) {
|
|
119
320
|
lineCount++;
|
|
120
321
|
if (!linesToDeleteArray.includes(lineCount)) {
|
|
121
322
|
writeStream.write(`${line}\n`);
|
|
122
323
|
}
|
|
123
324
|
}
|
|
124
|
-
writeStream.end()
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
renameSync(tempFilePath, filePath); // Rename the temp file to the original file name
|
|
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
|
|
128
328
|
});
|
|
129
329
|
};
|
|
130
330
|
|
|
131
331
|
export const count = async (filePath: string): Promise<number> => {
|
|
132
|
-
let lineCount = 0
|
|
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
|
+
});
|
|
133
340
|
|
|
134
|
-
const
|
|
135
|
-
|
|
136
|
-
for await (const line of file.readLines()) lineCount++;
|
|
341
|
+
for await (const line of rl) lineCount++;
|
|
137
342
|
|
|
138
343
|
return lineCount;
|
|
139
344
|
};
|
|
140
345
|
|
|
141
346
|
export const search = async (
|
|
142
347
|
filePath: string,
|
|
143
|
-
fieldType: FieldType,
|
|
144
348
|
operator: ComparisonOperator | ComparisonOperator[],
|
|
145
349
|
comparedAtValue:
|
|
146
350
|
| string
|
|
@@ -149,9 +353,12 @@ export const search = async (
|
|
|
149
353
|
| null
|
|
150
354
|
| (string | number | boolean | null)[],
|
|
151
355
|
logicalOperator?: "and" | "or",
|
|
356
|
+
fieldType?: FieldType | FieldType[],
|
|
357
|
+
fieldChildrenType?: FieldType | FieldType[],
|
|
152
358
|
limit?: number,
|
|
153
359
|
offset?: number,
|
|
154
|
-
readWholeFile?: boolean
|
|
360
|
+
readWholeFile?: boolean,
|
|
361
|
+
secretKey?: string | Buffer
|
|
155
362
|
): Promise<
|
|
156
363
|
[
|
|
157
364
|
Record<
|
|
@@ -166,7 +373,7 @@ export const search = async (
|
|
|
166
373
|
> => {
|
|
167
374
|
const handleComparisonOperator = (
|
|
168
375
|
operator: ComparisonOperator,
|
|
169
|
-
|
|
376
|
+
originalValue:
|
|
170
377
|
| string
|
|
171
378
|
| number
|
|
172
379
|
| boolean
|
|
@@ -178,71 +385,80 @@ export const search = async (
|
|
|
178
385
|
| boolean
|
|
179
386
|
| null
|
|
180
387
|
| (string | number | boolean | null)[],
|
|
181
|
-
fieldType
|
|
388
|
+
fieldType?: FieldType | FieldType[],
|
|
389
|
+
fieldChildrenType?: FieldType | FieldType[]
|
|
182
390
|
): boolean => {
|
|
183
|
-
|
|
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!
|
|
184
403
|
switch (operator) {
|
|
185
404
|
case "=":
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
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
|
+
}
|
|
191
416
|
case "!=":
|
|
192
417
|
return !handleComparisonOperator(
|
|
193
418
|
"=",
|
|
194
|
-
|
|
419
|
+
originalValue,
|
|
195
420
|
comparedAtValue,
|
|
196
421
|
fieldType
|
|
197
422
|
);
|
|
198
423
|
case ">":
|
|
199
|
-
return
|
|
200
|
-
value !== null && comparedAtValue !== null && value > comparedAtValue
|
|
201
|
-
);
|
|
424
|
+
return originalValue > comparedAtValue;
|
|
202
425
|
case "<":
|
|
203
|
-
return
|
|
204
|
-
value !== null && comparedAtValue !== null && value < comparedAtValue
|
|
205
|
-
);
|
|
426
|
+
return originalValue < comparedAtValue;
|
|
206
427
|
case ">=":
|
|
207
|
-
return
|
|
208
|
-
value !== null && comparedAtValue !== null && value >= comparedAtValue
|
|
209
|
-
);
|
|
428
|
+
return originalValue >= comparedAtValue;
|
|
210
429
|
case "<=":
|
|
211
|
-
return
|
|
212
|
-
value !== null && comparedAtValue !== null && value <= comparedAtValue
|
|
213
|
-
);
|
|
430
|
+
return originalValue <= comparedAtValue;
|
|
214
431
|
case "[]":
|
|
215
432
|
return (
|
|
216
|
-
(Array.isArray(
|
|
433
|
+
(Array.isArray(originalValue) &&
|
|
217
434
|
Array.isArray(comparedAtValue) &&
|
|
218
|
-
|
|
219
|
-
(Array.isArray(
|
|
435
|
+
originalValue.some(comparedAtValue.includes)) ||
|
|
436
|
+
(Array.isArray(originalValue) &&
|
|
220
437
|
!Array.isArray(comparedAtValue) &&
|
|
221
|
-
|
|
222
|
-
(!Array.isArray(
|
|
438
|
+
originalValue.includes(comparedAtValue)) ||
|
|
439
|
+
(!Array.isArray(originalValue) &&
|
|
223
440
|
Array.isArray(comparedAtValue) &&
|
|
224
|
-
comparedAtValue.includes(
|
|
441
|
+
comparedAtValue.includes(originalValue))
|
|
225
442
|
);
|
|
226
443
|
case "![]":
|
|
227
444
|
return !handleComparisonOperator(
|
|
228
445
|
"[]",
|
|
229
|
-
|
|
446
|
+
originalValue,
|
|
230
447
|
comparedAtValue,
|
|
231
448
|
fieldType
|
|
232
449
|
);
|
|
233
450
|
case "*":
|
|
234
|
-
return (
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
);
|
|
451
|
+
return new RegExp(
|
|
452
|
+
`^${(String(comparedAtValue).includes("%")
|
|
453
|
+
? String(comparedAtValue)
|
|
454
|
+
: "%" + String(comparedAtValue) + "%"
|
|
455
|
+
).replace(/%/g, ".*")}$`,
|
|
456
|
+
"i"
|
|
457
|
+
).test(String(originalValue));
|
|
242
458
|
case "!*":
|
|
243
459
|
return !handleComparisonOperator(
|
|
244
460
|
"*",
|
|
245
|
-
|
|
461
|
+
originalValue,
|
|
246
462
|
comparedAtValue,
|
|
247
463
|
fieldType
|
|
248
464
|
);
|
|
@@ -260,16 +476,21 @@ export const search = async (
|
|
|
260
476
|
> = {},
|
|
261
477
|
lineCount = 0,
|
|
262
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
|
+
});
|
|
263
486
|
|
|
264
|
-
const
|
|
265
|
-
columnName = decodeFileName(parse(filePath).name);
|
|
487
|
+
const columnName = parse(filePath).name;
|
|
266
488
|
|
|
267
|
-
for await (const line of
|
|
489
|
+
for await (const line of rl) {
|
|
268
490
|
lineCount++;
|
|
269
|
-
const decodedLine =
|
|
491
|
+
const decodedLine = decode(line, fieldType, fieldChildrenType, secretKey);
|
|
270
492
|
if (
|
|
271
|
-
|
|
272
|
-
((Array.isArray(operator) &&
|
|
493
|
+
(Array.isArray(operator) &&
|
|
273
494
|
Array.isArray(comparedAtValue) &&
|
|
274
495
|
((logicalOperator &&
|
|
275
496
|
logicalOperator === "or" &&
|
|
@@ -289,13 +510,13 @@ export const search = async (
|
|
|
289
510
|
fieldType
|
|
290
511
|
)
|
|
291
512
|
))) ||
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
513
|
+
(!Array.isArray(operator) &&
|
|
514
|
+
handleComparisonOperator(
|
|
515
|
+
operator,
|
|
516
|
+
decodedLine,
|
|
517
|
+
comparedAtValue,
|
|
518
|
+
fieldType
|
|
519
|
+
))
|
|
299
520
|
) {
|
|
300
521
|
foundItems++;
|
|
301
522
|
if (offset && foundItems < offset) continue;
|
|
@@ -313,10 +534,11 @@ export const search = async (
|
|
|
313
534
|
|
|
314
535
|
export default class File {
|
|
315
536
|
static get = get;
|
|
316
|
-
static count = count;
|
|
317
537
|
static remove = remove;
|
|
318
538
|
static search = search;
|
|
319
539
|
static replace = replace;
|
|
320
|
-
static
|
|
321
|
-
static
|
|
540
|
+
static count = count;
|
|
541
|
+
static encode = encode;
|
|
542
|
+
static decode = decode;
|
|
543
|
+
static isExists = isExists;
|
|
322
544
|
}
|