@filen/utils 0.0.7 → 0.0.9
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/checklistParser.js +2 -1
- package/dist/misc.js +16 -12
- package/dist/notes.js +3 -6
- package/dist/run.js +19 -9
- package/dist/time.js +2 -6
- package/package.json +1 -1
package/dist/checklistParser.js
CHANGED
|
@@ -40,7 +40,8 @@ export class ChecklistParser {
|
|
|
40
40
|
html += `<ul data-checked="${item.checked}">`;
|
|
41
41
|
currentCheckedStatus = item.checked;
|
|
42
42
|
}
|
|
43
|
-
|
|
43
|
+
const trimmed = item.content.trim();
|
|
44
|
+
html += `<li>${trimmed.length > 0 ? trimmed : "<br>"}</li>`;
|
|
44
45
|
}
|
|
45
46
|
if (checklist.length > 0) {
|
|
46
47
|
html += "</ul>";
|
package/dist/misc.js
CHANGED
|
@@ -88,6 +88,7 @@ const RESERVED_NAMES_WINDOWS = new Set([
|
|
|
88
88
|
"LPT9"
|
|
89
89
|
]);
|
|
90
90
|
const textEncoder = new TextEncoder();
|
|
91
|
+
const textDecoder = new TextDecoder("utf-8", { fatal: false });
|
|
91
92
|
export function sanitizeFileName(filename, replacement = "_") {
|
|
92
93
|
let sanitizedFilename = filename.normalize("NFC");
|
|
93
94
|
sanitizedFilename = sanitizedFilename.replace(ZERO_WIDTH_AND_CONTROL_RE, "");
|
|
@@ -100,10 +101,9 @@ export function sanitizeFileName(filename, replacement = "_") {
|
|
|
100
101
|
sanitizedFilename += replacement;
|
|
101
102
|
}
|
|
102
103
|
const maxByteLength = 255;
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
sanitizedFilename =
|
|
106
|
-
byteLength = textEncoder.encode(sanitizedFilename).length;
|
|
104
|
+
const encoded = textEncoder.encode(sanitizedFilename);
|
|
105
|
+
if (encoded.length > maxByteLength) {
|
|
106
|
+
sanitizedFilename = textDecoder.decode(encoded.subarray(0, maxByteLength)).replace(/\uFFFD/g, "");
|
|
107
107
|
}
|
|
108
108
|
if (!sanitizedFilename) {
|
|
109
109
|
return "file";
|
|
@@ -139,27 +139,31 @@ export function extractLinksFromString(text) {
|
|
|
139
139
|
}
|
|
140
140
|
return results;
|
|
141
141
|
}
|
|
142
|
+
const HAS_UPPERCASE_RE = /[A-Z]/;
|
|
143
|
+
const HAS_LOWERCASE_RE = /[a-z]/;
|
|
144
|
+
const HAS_SPECIAL_CHARS_RE = /[!@#$%^&*(),.?":{}|<>]/;
|
|
145
|
+
const YOUTUBE_VIDEO_ID_RE = /(?:\?v=|\/embed\/|\/watch\?v=|\/\w+\/\w+\/|youtu.be\/)([\w-]{11})/;
|
|
142
146
|
export function parseYouTubeVideoId(url) {
|
|
143
|
-
const
|
|
144
|
-
const match = url.match(regExp);
|
|
147
|
+
const match = url.match(YOUTUBE_VIDEO_ID_RE);
|
|
145
148
|
if (match && match.length === 2 && match[1]) {
|
|
146
149
|
return match[1];
|
|
147
150
|
}
|
|
148
151
|
return null;
|
|
149
152
|
}
|
|
153
|
+
const FILEN_PUBLIC_LINK_RE = /https?:\/\/(?:app|drive)\.filen\.io\/#\/([df])\/([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})(?:%23|#)([A-Za-z0-9]{32,})/;
|
|
154
|
+
const HEX_64_RE = /^[0-9A-Fa-f]{64}$/;
|
|
150
155
|
export function parseFilenPublicLink(url) {
|
|
151
156
|
if (!url || url.length === 0) {
|
|
152
157
|
return null;
|
|
153
158
|
}
|
|
154
|
-
const
|
|
155
|
-
const match = filenRegex.exec(url);
|
|
159
|
+
const match = FILEN_PUBLIC_LINK_RE.exec(url);
|
|
156
160
|
if (!match || match.length < 4 || !match[1] || !match[2] || !match[3]) {
|
|
157
161
|
return null;
|
|
158
162
|
}
|
|
159
163
|
const pathType = match[1];
|
|
160
164
|
const uuid = match[2];
|
|
161
165
|
let key = match[3];
|
|
162
|
-
if (
|
|
166
|
+
if (HEX_64_RE.test(key)) {
|
|
163
167
|
try {
|
|
164
168
|
key = Buffer.from(key, "hex").toString("utf8");
|
|
165
169
|
}
|
|
@@ -185,9 +189,9 @@ export function parseXStatusId(url) {
|
|
|
185
189
|
return part.trim();
|
|
186
190
|
}
|
|
187
191
|
export function ratePasswordStrength(password) {
|
|
188
|
-
const hasUppercase =
|
|
189
|
-
const hasLowercase =
|
|
190
|
-
const hasSpecialChars =
|
|
192
|
+
const hasUppercase = HAS_UPPERCASE_RE.test(password);
|
|
193
|
+
const hasLowercase = HAS_LOWERCASE_RE.test(password);
|
|
194
|
+
const hasSpecialChars = HAS_SPECIAL_CHARS_RE.test(password);
|
|
191
195
|
const length = password.length;
|
|
192
196
|
let strength = "weak";
|
|
193
197
|
if (length >= 10 && hasUppercase && hasLowercase && hasSpecialChars) {
|
package/dist/notes.js
CHANGED
|
@@ -12,12 +12,9 @@ export function createNotePreviewFromContentText(type, content) {
|
|
|
12
12
|
}
|
|
13
13
|
if (type === "checklist") {
|
|
14
14
|
const ex = content
|
|
15
|
-
.
|
|
16
|
-
.
|
|
17
|
-
.
|
|
18
|
-
.join("")
|
|
19
|
-
.split("\n")
|
|
20
|
-
.join("")
|
|
15
|
+
.replaceAll('<ul data-checked="false">', "")
|
|
16
|
+
.replaceAll('<ul data-checked="true">', "")
|
|
17
|
+
.replaceAll("\n", "")
|
|
21
18
|
.split("<li>");
|
|
22
19
|
for (const listPoint of ex) {
|
|
23
20
|
const listPointEx = listPoint.split("</li>");
|
package/dist/run.js
CHANGED
|
@@ -183,12 +183,10 @@ export async function runRetry(fn, options) {
|
|
|
183
183
|
const maxAttempts = options?.maxAttempts ?? 3;
|
|
184
184
|
const delayMs = options?.delayMs ?? 1000;
|
|
185
185
|
const backoff = options?.backoff ?? "exponential";
|
|
186
|
+
const runOptions = { onError: options?.onError, throw: false };
|
|
186
187
|
let lastError = null;
|
|
187
188
|
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
188
|
-
const result = await run(defer => fn(defer, attempt),
|
|
189
|
-
...options,
|
|
190
|
-
throw: false
|
|
191
|
-
});
|
|
189
|
+
const result = await run(defer => fn(defer, attempt), runOptions);
|
|
192
190
|
if (result.success) {
|
|
193
191
|
return result;
|
|
194
192
|
}
|
|
@@ -220,16 +218,15 @@ export class TimeoutError extends Error {
|
|
|
220
218
|
}
|
|
221
219
|
}
|
|
222
220
|
export async function runTimeout(fn, timeoutMs, options) {
|
|
223
|
-
|
|
221
|
+
let timeoutId = null;
|
|
224
222
|
try {
|
|
225
223
|
const result = await Promise.race([
|
|
226
224
|
run(fn, options),
|
|
227
225
|
new Promise((_, reject) => {
|
|
228
|
-
|
|
229
|
-
|
|
226
|
+
timeoutId = setTimeout(() => {
|
|
227
|
+
timeoutId = null;
|
|
230
228
|
reject(new TimeoutError(`Operation timed out after ${timeoutMs}ms`));
|
|
231
229
|
}, timeoutMs);
|
|
232
|
-
controller.signal.addEventListener("abort", () => clearTimeout(timeoutId));
|
|
233
230
|
})
|
|
234
231
|
]);
|
|
235
232
|
return result;
|
|
@@ -245,11 +242,17 @@ export async function runTimeout(fn, timeoutMs, options) {
|
|
|
245
242
|
error: e
|
|
246
243
|
};
|
|
247
244
|
}
|
|
245
|
+
finally {
|
|
246
|
+
if (timeoutId !== null) {
|
|
247
|
+
clearTimeout(timeoutId);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
248
250
|
}
|
|
249
251
|
export function runDebounced(fn, delayMs, options) {
|
|
250
252
|
let timeoutId = null;
|
|
251
253
|
let pendingResolve = null;
|
|
252
254
|
let pendingPromise = null;
|
|
255
|
+
let executing = false;
|
|
253
256
|
return (...args) => {
|
|
254
257
|
if (timeoutId) {
|
|
255
258
|
clearTimeout(timeoutId);
|
|
@@ -260,8 +263,15 @@ export function runDebounced(fn, delayMs, options) {
|
|
|
260
263
|
});
|
|
261
264
|
}
|
|
262
265
|
timeoutId = setTimeout(async () => {
|
|
266
|
+
if (executing || !pendingResolve) {
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
executing = true;
|
|
263
270
|
const result = await run(defer => fn(defer, ...args), options);
|
|
264
|
-
|
|
271
|
+
executing = false;
|
|
272
|
+
if (pendingResolve) {
|
|
273
|
+
pendingResolve(result);
|
|
274
|
+
}
|
|
265
275
|
pendingPromise = null;
|
|
266
276
|
pendingResolve = null;
|
|
267
277
|
timeoutId = null;
|
package/dist/time.js
CHANGED
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
export function isTimestampSameDay(timestamp1, timestamp2) {
|
|
2
2
|
const diff = timestamp1 - timestamp2;
|
|
3
|
-
if (diff
|
|
4
|
-
|
|
5
|
-
const day2 = Math.floor(timestamp2 / 86400000);
|
|
6
|
-
if (day1 === day2) {
|
|
7
|
-
return true;
|
|
8
|
-
}
|
|
3
|
+
if (diff < -86400000 || diff > 86400000) {
|
|
4
|
+
return false;
|
|
9
5
|
}
|
|
10
6
|
const date1 = new Date(timestamp1);
|
|
11
7
|
const date2 = new Date(timestamp2);
|