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