@nemigo/helpers 0.7.0 → 0.8.0

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.
@@ -1,10 +1,8 @@
1
- import type { Timestamp } from "./types.js";
1
+ import type { Timestamp } from "../types.js";
2
2
  /**
3
3
  * Создаёт задержку на указанное количество миллисекунд
4
- *
5
- * @param ms - Количество миллисекунд для задержки
6
4
  */
7
- export declare const delay: (ms: Timestamp) => Promise<void>;
5
+ export declare const delay: (ms: Timestamp, success?: boolean) => Promise<void>;
8
6
  /**
9
7
  * Создаёт debounce-функцию, которая откладывает выполнение до тех пор, пока не пройдёт указанное время без новых вызовов
10
8
  *
@@ -1,10 +1,7 @@
1
1
  /**
2
2
  * Создаёт задержку на указанное количество миллисекунд
3
- *
4
- * @param ms - Количество миллисекунд для задержки
5
3
  */
6
- export const delay = (ms) => new Promise((ready) => setTimeout(ready, ms));
7
- //...
4
+ export const delay = (ms, success = false) => new Promise((resolve, reject) => setTimeout(success ? resolve : reject, ms));
8
5
  /**
9
6
  * Создаёт debounce-функцию, которая откладывает выполнение до тех пор, пока не пройдёт указанное время без новых вызовов
10
7
  *
@@ -0,0 +1,7 @@
1
+ export declare abstract class AsyncSpace<TX> {
2
+ private async_storage;
3
+ getTX(): TX[];
4
+ space<T>(call: (tx: TX[]) => Promise<T>, auto?: boolean): Promise<T>;
5
+ commit(): Promise<void>;
6
+ protected abstract submit(tx: TX[]): Promise<void>;
7
+ }
@@ -0,0 +1,30 @@
1
+ import { AsyncLocalStorage } from "async_hooks";
2
+ export class AsyncSpace {
3
+ async_storage = new AsyncLocalStorage();
4
+ getTX() {
5
+ const ctx = this.async_storage.getStore();
6
+ if (ctx)
7
+ return ctx;
8
+ throw new Error("getTX() called outside of space()");
9
+ }
10
+ async space(call, auto = true) {
11
+ const ctx = this.async_storage.getStore();
12
+ if (ctx)
13
+ return call(ctx);
14
+ //...
15
+ const tx = [];
16
+ const result = await this.async_storage.run(tx, () => call(tx));
17
+ if (auto && tx.length > 0) {
18
+ await this.submit(tx);
19
+ tx.length = 0;
20
+ }
21
+ return result;
22
+ }
23
+ async commit() {
24
+ const ctx = this.async_storage.getStore();
25
+ if (!ctx)
26
+ throw new Error("commit() called outside of space()");
27
+ await this.submit(ctx);
28
+ ctx.length = 0;
29
+ }
30
+ }
package/dist/files.d.ts CHANGED
@@ -6,6 +6,14 @@ export declare const fileToBase64: (file: File) => Promise<string>;
6
6
  * @returns true, если файл является изображением
7
7
  */
8
8
  export declare const isImage: (file: File) => boolean;
9
+ /**
10
+ * Проверяет, является ли файл видео
11
+ */
12
+ export declare const isVideo: (file: File) => boolean;
13
+ /**
14
+ * Проверяет, является ли файл аудио
15
+ */
16
+ export declare const isAudio: (file: File) => boolean;
9
17
  /**
10
18
  * Преобразует размер файла в человекочитаемый формат
11
19
  *
package/dist/files.js CHANGED
@@ -12,6 +12,14 @@ export const fileToBase64 = (file) => new Promise((resolve, reject) => {
12
12
  * @returns true, если файл является изображением
13
13
  */
14
14
  export const isImage = (file) => file.type.startsWith("image/") && !file.type.includes("svg");
15
+ /**
16
+ * Проверяет, является ли файл видео
17
+ */
18
+ export const isVideo = (file) => file.type.startsWith("video/");
19
+ /**
20
+ * Проверяет, является ли файл аудио
21
+ */
22
+ export const isAudio = (file) => file.type.startsWith("audio/");
15
23
  //...
16
24
  const UNITS = [
17
25
  "B",
package/dist/format.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { caseNumber } from "./cases.js";
2
- import { toRound } from "./phymath.js";
2
+ import { toRound } from "./phymath/index.js";
3
3
  export const FormatNumberRegExp = /\B(?=(\d{3})+(?!\d))/g;
4
4
  /**
5
5
  * Форматирование числа по тысячам
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { CanBeArray } from "./types.js";
1
+ import type { CanBeArray, CanBeReadonly } from "./types.js";
2
2
  /**
3
3
  * Добавляет ведущие нули к числу для достижения указанной длины
4
4
  *
@@ -32,11 +32,11 @@ export interface Partition<T> {
32
32
  /**
33
33
  * Разделяет массив на два по условию
34
34
  */
35
- export declare const partition: <T>(arr: T[], filter: (item: T) => boolean, initial?: Partition<T>) => Partition<T>;
35
+ export declare const partition: <T>(arr: CanBeReadonly<T>, filter: (item: T) => boolean, initial?: Partition<T>) => Partition<T>;
36
36
  /**
37
37
  * Удаляет `null` и `undefined` и оставляет только уникальные строки
38
38
  */
39
- export declare const setify: (arr: (string | undefined | null)[]) => string[];
39
+ export declare const setify: (arr: CanBeReadonly<string | undefined | null>) => string[];
40
40
  /**
41
41
  * Удаляет дубликаты объектов из массива на основе указанного ключа
42
42
  *
@@ -46,5 +46,9 @@ export declare const setify: (arr: (string | undefined | null)[]) => string[];
46
46
  * @param {K} [key="id"] - Ключ, по которому будут удаляться дубликаты
47
47
  * @returns {T[]} Новый массив без дубликатов
48
48
  */
49
- export declare const unify: <T, K extends keyof T>(arr: T[], key?: K) => T[];
49
+ export declare const unify: <T, K extends keyof T>(arr: CanBeReadonly<T>, key?: K) => T[];
50
50
  export declare const useConditionGuard: (condition: unknown, ...args: any[]) => boolean;
51
+ /**
52
+ * Сортирует ключи объекта в алфавитном порядке и возвращает новый объект с отсортированными ключами
53
+ */
54
+ export declare function sortObjectByKeys<T>(obj: T): T;
package/dist/index.js CHANGED
@@ -23,12 +23,16 @@ export const isSameType = (a, b) => Object.prototype.toString.call(a) === Object
23
23
  /**
24
24
  * Разделяет массив на два по условию
25
25
  */
26
- export const partition = (arr, filter, initial = { result: [], excluded: [] }) => arr.reduce((acc, item) => (acc[filter(item) ? "result" : "excluded"].push(item), acc), initial);
26
+ export const partition = (arr, filter, initial = { result: [], excluded: [] }) =>
27
+ // @ts-expect-error <оно себя неадекватно ведёт>
28
+ arr.reduce((acc, item) => (acc[filter(item) ? "result" : "excluded"].push(item), acc), initial);
27
29
  //...
28
30
  /**
29
31
  * Удаляет `null` и `undefined` и оставляет только уникальные строки
30
32
  */
31
- export const setify = (arr) => [...new Set(arr.filter((item) => typeof item === "string"))];
33
+ export const setify = (arr) =>
34
+ // @ts-expect-error <оно себя неадекватно ведёт>
35
+ [...new Set(arr.filter((item) => typeof item === "string"))];
32
36
  /**
33
37
  * Удаляет дубликаты объектов из массива на основе указанного ключа
34
38
  *
@@ -38,7 +42,9 @@ export const setify = (arr) => [...new Set(arr.filter((item) => typeof item ===
38
42
  * @param {K} [key="id"] - Ключ, по которому будут удаляться дубликаты
39
43
  * @returns {T[]} Новый массив без дубликатов
40
44
  */
41
- export const unify = (arr, key = "id") => [...new Map(arr.map((item) => [item[key], item])).values()];
45
+ export const unify = (arr, key = "id") =>
46
+ // @ts-expect-error <оно себя неадекватно ведёт>
47
+ [...new Map(arr.map((item) => [item[key], item])).values()];
42
48
  //...
43
49
  export const useConditionGuard = (condition, ...args) => {
44
50
  switch (typeof condition) {
@@ -50,3 +56,14 @@ export const useConditionGuard = (condition, ...args) => {
50
56
  return !!condition;
51
57
  }
52
58
  };
59
+ //...
60
+ /**
61
+ * Сортирует ключи объекта в алфавитном порядке и возвращает новый объект с отсортированными ключами
62
+ */
63
+ export function sortObjectByKeys(obj) {
64
+ const keys = Object.keys(obj).sort();
65
+ const result = {};
66
+ for (const key of keys)
67
+ result[key] = obj[key];
68
+ return result;
69
+ }
package/dist/script.d.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import type { Timestamp } from "./types.js";
2
+ import type { ExecException } from "node:child_process";
1
3
  /**
2
4
  * Ищет значение флага в массиве аргументов процесса
3
5
  *
@@ -11,3 +13,35 @@
11
13
  declare function getProcessFlag(cmd: string[], name: string, strict: boolean): string | null;
12
14
  declare function getProcessFlag(cmd: string[], name: string, strict?: true): string;
13
15
  export { getProcessFlag };
16
+ export interface ExecuteLogger {
17
+ /**
18
+ * Перед выполнением команды
19
+ */
20
+ before?: (path: string) => string;
21
+ /**
22
+ * При возникновении ошибки
23
+ */
24
+ onerror?: (error: ExecException) => string;
25
+ /**
26
+ * При истечении таймаута
27
+ */
28
+ ontimeout?: () => string;
29
+ }
30
+ export interface ExecuteOptions {
31
+ logger?: ExecuteLogger;
32
+ /**
33
+ * @default 5min
34
+ */
35
+ timeout?: Timestamp;
36
+ }
37
+ /**
38
+ * Запускает дочерний процесс с указанной командой в заданной директории
39
+ *
40
+ * @param path - Директория, в которой будет выполнена команда
41
+ * @param command - Команда для выполнения
42
+ * @param logger - Хуки для логирования {@link ChildLogger}
43
+ * @param [timeout=5min] - Таймаут выполнения команды в миллисекундах (по умолчанию 5 минут)
44
+ *
45
+ * @throws {Error} Если команда завершается с ошибкой или истекает таймаут
46
+ */
47
+ export declare const execute: (path: string, command: string, { logger, timeout }?: ExecuteOptions) => Promise<void>;
package/dist/script.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { exec } from "node:child_process";
1
2
  function getProcessFlag(cmd, name, strict = true) {
2
3
  const argv = cmd.slice(2);
3
4
  const index = argv.indexOf(name);
@@ -12,3 +13,46 @@ function getProcessFlag(cmd, name, strict = true) {
12
13
  return null;
13
14
  }
14
15
  export { getProcessFlag };
16
+ /**
17
+ * Запускает дочерний процесс с указанной командой в заданной директории
18
+ *
19
+ * @param path - Директория, в которой будет выполнена команда
20
+ * @param command - Команда для выполнения
21
+ * @param logger - Хуки для логирования {@link ChildLogger}
22
+ * @param [timeout=5min] - Таймаут выполнения команды в миллисекундах (по умолчанию 5 минут)
23
+ *
24
+ * @throws {Error} Если команда завершается с ошибкой или истекает таймаут
25
+ */
26
+ export const execute = async (path, command, { logger = {}, timeout = 5 * 60 * 1000 } = {}) => new Promise((resolve, reject) => {
27
+ if (logger.before)
28
+ console.log(logger.before(path));
29
+ let timer = null;
30
+ let process = null;
31
+ const cleanup = () => {
32
+ if (!timer)
33
+ return;
34
+ clearTimeout(timer);
35
+ timer = null;
36
+ };
37
+ timer = setTimeout(() => {
38
+ process?.kill("SIGTERM");
39
+ if (logger.ontimeout)
40
+ console.error(logger.ontimeout());
41
+ reject(new Error("TIMEOUT"));
42
+ }, timeout);
43
+ process = exec(command, { cwd: path }, (error, stdout, stderr) => {
44
+ cleanup();
45
+ if (stderr)
46
+ console.warn(stderr);
47
+ if (stdout)
48
+ console.log(stdout);
49
+ if (error) {
50
+ if (logger.onerror)
51
+ console.error(logger.onerror(error));
52
+ reject(error);
53
+ return;
54
+ }
55
+ resolve();
56
+ });
57
+ process.on("exit", cleanup);
58
+ });
package/dist/types.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export type * from "./phymath.types.js";
1
+ export type * from "./phymath/types.js";
2
2
  import type { ZIP } from "./zipper.js";
3
3
  export type { ZIP };
4
4
  /**
@@ -29,6 +29,10 @@ export type CanBeNullable<T = unknown> = T | null | undefined;
29
29
  * Значение может быть массивом или одиночным элементом
30
30
  */
31
31
  export type CanBeArray<T = unknown> = T | T[];
32
+ /**
33
+ * Массив может быть readonly
34
+ */
35
+ export type CanBeReadonly<T = unknown> = readonly T[] | T[];
32
36
  /**
33
37
  * Значение может быть промиссом
34
38
  */
package/package.json CHANGED
@@ -1,12 +1,16 @@
1
1
  {
2
2
  "name": "@nemigo/helpers",
3
- "version": "0.7.0",
3
+ "version": "0.8.0",
4
4
  "private": false,
5
5
  "author": {
6
6
  "name": "Vlad Logvin",
7
7
  "email": "vlad.logvin84@gmail.com"
8
8
  },
9
9
  "type": "module",
10
+ "engines": {
11
+ "node": ">=22",
12
+ "pnpm": ">=10.9.0"
13
+ },
10
14
  "scripts": {
11
15
  "build": "svelte-package && rimraf .svelte-kit",
12
16
  "check": "tsc --noemit",
@@ -20,8 +24,12 @@
20
24
  "default": "./dist/index.js"
21
25
  },
22
26
  "./async": {
23
- "types": "./dist/async.d.ts",
24
- "default": "./dist/async.js"
27
+ "types": "./dist/async/index.d.ts",
28
+ "default": "./dist/async/index.js"
29
+ },
30
+ "./async/space": {
31
+ "types": "./dist/async/space.d.ts",
32
+ "default": "./dist/async/space.js"
25
33
  },
26
34
  "./cases": {
27
35
  "types": "./dist/cases.d.ts",
@@ -84,12 +92,12 @@
84
92
  "default": "./dist/omitter.js"
85
93
  },
86
94
  "./phymath": {
87
- "types": "./dist/phymath.d.ts",
88
- "default": "./dist/phymath.js"
95
+ "types": "./dist/phymath/index.d.ts",
96
+ "default": "./dist/phymath/index.js"
89
97
  },
90
98
  "./phymath/types": {
91
- "types": "./dist/phymath.types.d.ts",
92
- "default": "./dist/phymath.types.js"
99
+ "types": "./dist/phymath/types.d.ts",
100
+ "default": "./dist/phymath/types.js"
93
101
  },
94
102
  "./promoter": {
95
103
  "types": "./dist/promoter.d.ts",
File without changes
File without changes
File without changes
File without changes