inibase 1.0.0-rc.15 → 1.0.0-rc.17

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/dist/file.js CHANGED
@@ -1,7 +1,7 @@
1
- import { open, rename, stat, writeFile, } from "node:fs/promises";
1
+ import { open, stat, writeFile } from "node:fs/promises";
2
2
  import { createInterface } from "node:readline";
3
- import { parse } from "node:path";
4
- import { detectFieldType, isArrayOfArrays, isNumber, encodeID, comparePassword, } from "./utils";
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("<", "&lt;")
25
+ .replaceAll(">", "&gt;")
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("<", "&lt;")
26
- .replaceAll(">", "&gt;")
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("&lt;", "<")
56
+ .replaceAll("&gt;", ">")
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("&lt;", "<")
57
- .replaceAll("&gt;", ">")
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
- let fileHandle;
119
- try {
120
- fileHandle = await open(filePath, "r");
121
- const rl = doesSupportReadLines()
122
- ? fileHandle.readLines()
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
- let lines = {}, lineCount = 0;
128
- if (!lineNumbers) {
129
- for await (const line of rl)
130
- lineCount++,
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
- if (!lineNumbersArray.includes(lineCount))
149
- continue;
150
- lines[lineCount] = decode(line, fieldType, fieldChildrenType, secretKey);
151
- lineNumbersArray[lineNumbersArray.indexOf(lineCount)] = 0;
152
- if (!lineNumbersArray.filter((lineN) => lineN !== 0).length)
153
- break;
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
- return [lines ?? null, lineCount];
181
+ else
182
+ for await (const _line of rl)
183
+ writeStream.write(replacements + "\n");
184
+ writeStream.end(async () => await fileHandle.close());
157
185
  }
158
- finally {
159
- await fileHandle?.close();
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 replace = async (filePath, replacements, secretKey) => {
163
- if (await isExists(filePath)) {
164
- const tempFilePath = `${filePath.replace(".inib", "")}-${Date.now()}.tmp`;
165
- let fileHandle, tempFileHandle;
166
- try {
167
- fileHandle = await open(filePath, "r");
168
- tempFileHandle = await open(tempFilePath, "w");
169
- const rl = doesSupportReadLines()
170
- ? fileHandle.readLines()
171
- : createInterface({
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 if (typeof replacements === "object" && !Array.isArray(replacements)) {
204
- await writeFile(filePath, Object.keys(replacements)
205
- .map(Number)
206
- .sort((a, b) => a - b)
207
- .map((num) => replacements[num])
208
- .join("\n") + "\n");
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 tempFilePath = `${filePath.replace(".inib", "")}-${Date.now()}.tmp`, linesToDeleteArray = [
214
- ...(Array.isArray(linesToDelete) ? linesToDelete : [linesToDelete]),
215
- ];
216
- let fileHandle, tempFileHandle;
217
- try {
218
- fileHandle = await open(filePath, "r");
219
- tempFileHandle = await open(tempFilePath, "w");
220
- const rl = doesSupportReadLines()
221
- ? fileHandle.readLines()
222
- : createInterface({
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
- let fileHandle;
242
- try {
243
- fileHandle = await open(filePath, "r");
244
- const rl = doesSupportReadLines()
245
- ? fileHandle.readLines()
246
- : createInterface({
247
- input: fileHandle.createReadStream(),
248
- crlfDelay: Infinity,
249
- });
250
- for await (const line of rl)
251
- lineCount++;
252
- return lineCount;
253
- }
254
- finally {
255
- await fileHandle?.close();
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
- const handleComparisonOperator = (operator, originalValue, comparedAtValue, fieldType, fieldChildrenType) => {
260
- if (Array.isArray(fieldType))
261
- fieldType = detectFieldType(String(originalValue), fieldType);
262
- if (Array.isArray(comparedAtValue) && !["[]", "![]"].includes(operator))
263
- return comparedAtValue.some((comparedAtValueSingle) => handleComparisonOperator(operator, originalValue, comparedAtValueSingle, fieldType));
264
- // check if not array or object // it can't be array or object!
265
- switch (operator) {
266
- case "=":
267
- switch (fieldType) {
268
- case "password":
269
- return typeof originalValue === "string" &&
270
- typeof comparedAtValue === "string"
271
- ? comparePassword(originalValue, comparedAtValue)
272
- : false;
273
- case "boolean":
274
- return Number(originalValue) - Number(comparedAtValue) === 0;
275
- default:
276
- return originalValue === comparedAtValue;
277
- }
278
- case "!=":
279
- return !handleComparisonOperator("=", originalValue, comparedAtValue, fieldType);
280
- case ">":
281
- return originalValue > comparedAtValue;
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
- if (limit && foundItems > limit)
336
- if (readWholeFile)
337
- continue;
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
- let fileHandle;
357
- try {
358
- fileHandle = await open(filePath, "r");
359
- const rl = doesSupportReadLines()
360
- ? fileHandle.readLines()
361
- : createInterface({
362
- input: fileHandle.createReadStream(),
363
- crlfDelay: Infinity,
364
- });
365
- let sum = 0;
366
- if (lineNumbers) {
367
- let lineCount = 0;
368
- let lineNumbersArray = [
369
- ...(Array.isArray(lineNumbers) ? lineNumbers : [lineNumbers]),
370
- ];
371
- for await (const line of rl) {
372
- lineCount++;
373
- if (!lineNumbersArray.includes(lineCount))
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
- let fileHandle;
392
- try {
393
- fileHandle = await open(filePath, "r");
394
- const rl = doesSupportReadLines()
395
- ? fileHandle.readLines()
396
- : createInterface({
397
- input: fileHandle.createReadStream(),
398
- crlfDelay: Infinity,
399
- });
400
- let max = 0;
401
- if (lineNumbers) {
402
- let lineCount = 0;
403
- let lineNumbersArray = [
404
- ...(Array.isArray(lineNumbers) ? lineNumbers : [lineNumbers]),
405
- ];
406
- for await (const line of rl) {
407
- lineCount++;
408
- if (!lineNumbersArray.includes(lineCount))
409
- continue;
410
- const lineContentNum = +decode(line, "number");
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
- finally {
427
- await fileHandle?.close();
428
- }
429
- };
430
- export const min = async (filePath, lineNumbers) => {
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
- else
459
- for await (const line of rl) {
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 sort = async (filePath, sortDirection, lineNumbers, _lineNumbersPerChunk = 100000) => {
471
- let fileHandle;
472
- try {
473
- fileHandle = await open(filePath, "r");
474
- const rl = doesSupportReadLines()
475
- ? fileHandle.readLines()
476
- : createInterface({
477
- input: fileHandle.createReadStream(),
478
- crlfDelay: Infinity,
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
- finally {
486
- await fileHandle?.close();
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
  }