@alttiri/util-node-js
v2.2.0-20240821
Published
Some Node.js util functions for personal use
Downloads
151
Readme
util-node-js
Some Node.js util functions.
Mostly it's a draft version for personal use.
*.d.ts
type ANSIColor = "black" | "red" | "green" | "yellow" | "blue" | "magenta" | "cyan" | "white";
type ColoringFunc = (text: any) => string;
/**
* [ANSI_escape_code#SGR]{@link https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_(Select_Graphic_Rendition)_parameters}
* \```
* "32" - Green [ANSI]
* "36" - Cyan [ANSI]
* "38;5;208" - Orange #ff8700 [8-bit]
* "38;5;99" - Violet #875fff [8-bit]
* "38;2;173;255;47" - Green-Yellow #adff2f [24-bit]
* \```
* @example
* const COL_VIOLET_DARK = getColoring("38;5;92");
* console.log(COL_VIOLET_DARK("This text is 8-bit dark violet"));
*
* @param {string} mode
* @return {ColoringFunc}
*/
export declare function getColoring(mode: string): ColoringFunc;
export type AnsiColoringOpts = {
bright?: boolean;
bold?: boolean;
};
/**
* @example
* const ANSI_RED_BOLD = getAnsiColoring("RED", {bold: true});
* console.log(ANSI_RED_BOLD("This text is bold red"));
* @param {ANSIColor?} color = "white"
* @param {AnsiColoringOpts?} opts
* @param {boolean?} opts.bright = false
* @param {boolean?} opts.bold = false
* @return {ColoringFunc}
*/
export declare function getAnsiColoring(color?: ANSIColor, opts?: AnsiColoringOpts): ColoringFunc;
export declare const ANSI_BLUE: (text: any) => string;
export declare const ANSI_CYAN: (text: any) => string;
export declare const ANSI_GREEN: (text: any) => string;
export declare const ANSI_GRAY: (text: any) => string;
export declare const ANSI_GREEN_BOLD: (text: any) => string;
export declare const ANSI_RED_BOLD: (text: any) => string;
export declare const COL_ORANGE: (text: any) => string;
export declare const COL_VIOLET: (text: any) => string;
export declare const COL_GRAY: (text: any) => string;
export declare const saveCursorPosition: () => boolean;
export declare const restoreCursorPosition: () => boolean;
export declare const eraseCursorLine: () => boolean;
export declare const moveCursorToTop: (num?: number) => boolean;
export declare function stdWrite(text: string): Promise<void>;
export declare function exists(path: string, followSymbol?: boolean): Promise<boolean>;
/** Is the passed symlink looped — if referrers to a parent directory. */
export declare function isSymLooped(filepath: string): Promise<boolean>;
type FileInfo = {
path: string;
stats: Stats;
link?: LinkInfo;
};
type LinkInfo = {
pathTo: string;
content: string;
};
export declare function getFileInfo(filepath: string): Promise<FileInfo>;
export declare function readLink(filepath: string): Promise<{
pathTo: string;
content: string;
}>;
export type ConstructorOpts = {
printSuccess?: boolean;
testOnly?: number[];
stackDeep?: number;
autoReport?: boolean;
};
export type TestOpts = {
result: any;
expect: any;
stackDeep?: number;
name?: string;
printLink?: boolean;
autoReport?: boolean;
printSuccess?: boolean;
};
export type TesterMethods = {
/** @deprecated */
eq(name: string, result: any, expect: any): void;
t(opt: TestOpts): void;
report(): void;
};
export declare class Tester {
private readonly passed;
private readonly failed;
private readonly printSuccess;
private num;
private readonly testOnly;
private readonly stackDeep;
private timerId;
private readonly autoReport;
/** @deprecated */
eq(name: string, result: any, expect: any): void;
destructible(): TesterMethods;
constructor(opt?: ConstructorOpts);
t(opt: TestOpts): void;
private delayReport;
report(): void;
}
export type LineNumType = {
relFilePath: string;
lineNum?: string;
column?: string;
};
*.d.ts (fs-list)
export declare function toListEntryDirent(dirEntry: Dirent, settings: FileListingSetting): ListEntryDirent;
export declare function toListEntryDirentError(error: IOError, listEntry: ListEntryDirent): ListEntryDirentError;
export declare function toLinkInfo(entry: ListEntryDirent): Promise<ListEntryDirent | ListEntryDirentLink>;
export declare function toListEntryStatsError(entry: ListEntryBaseEx, err: IOError): ListEntryStats;
export declare function direntsToEntries(dirents: Dirent[], settings: FileListingSetting): Promise<(ListEntryDirent | ListEntryDirentLink)[]>;
/** 100 lines of code to handle edge cases to create the root entry */
export declare function getRootEntry({ filepath, _map, bigint }: FileListingSetting): Promise<ListEntryStatsAny>;
export declare function listFiles(initSettings: FileListingSettingInit & {
stats: false;
}): AsyncGenerator<ListEntryBaseEx>;
export declare function listFiles(initSettings: FileListingSettingInit & {
bigint: true;
}): AsyncGenerator<ListEntryStatsBigInt>;
/**
Returns an object:
\```ts
{
path: string,
dirent: Dirent,
stats?: Stats | BigIntStats,
link?: LinkInfo,
errors?: {
[name in "readdir" | "stats" | "readlink"]?: IOError
},
}
\```
The return object's keys info:
\```
- path — `string`.
The full path with the filename.
- dirent — `Dirent`.
A `Dirent` from `fs.readdir`.
For the root folder a "fake" `Dirent` is used:
- "DirentLike" — created based on `Stats`
- "DirentDummy" — if there were errors (`errors: {stats, readdir}`)
- stats? — `Stats | BigIntStats`.
Optional, exists only when the scan option `stats` is `true`.
Type depends on `bigint` option.
Is missed if there is `errors.stats` error.
- link? — `LinkInfo`.
Optional, exists only for symlinks.
`LinkInfo` is an alias for `{
pathTo: string,
content: string,
}`.
Is missed if there is `errors.readlink` error.
- errors? — an `object` with `IOError`s.
Optional, exists only one or more errors occurred.
Possible errors:
- "readdir"
- "stats"
- "readlink"
\```
@note `listFiles` does not follow symlinks.
@options
\```js
- filepath: string = process.cwd(), // filepath of a (root) directory to list
- recursively: boolean = true,
- yieldDir: boolean = false,
- yieldRoot: boolean = true, // (is used only if `yieldDir` is `true`)
- depthFirst: boolean = true, // travel strategy
- breadthFirstRoot: boolean = false, // breadth first strategy for the root folder (if `depthFirst` is `true`)
- stats: boolean = true,
- bigint: boolean = false, // (use only if `stats` is `true`)
- parallels: number = 4, // count of `fs.stats` executed in parallel
\```
*/
export declare function listFiles(initSettings: FileListingSettingInit): AsyncGenerator<ListEntryStats>;
export declare function _listFilesWithStat(settings: FileListingSetting, listEntries: ListEntryDirent): AsyncGenerator<ListEntryStatsAny>;
export type FileListingSettingInit = Partial<FileListingSetting>;
/** An entry of the listing of the content of a directory. */
export type FileListingSetting = {
/** filepath of a directory to list */
filepath: string;
recursively: boolean;
yieldDir: boolean;
yieldRoot: boolean;
/** travel strategy */
depthFirst: boolean;
/** breadth first strategy for the root folder (if `depthFirst` is `true`) */
breadthFirstRoot: boolean;
stats: boolean;
bigint: boolean;
/** The count of `fs.stats` executed in parallel */
parallels: number;
_currentDeep: number;
_map: Map<ListEntryDirent, Dirent[]>;
};
export declare function getDefaultSettings(): FileListingSetting;
*.d.ts (fs-list types)
/**
* The error object that happens while scanning.
* @example
* [Error: EPERM: operation not permitted, scandir "C:\\$Recycle.Bin\\S-1-5-18"] {
* errno: -4048,
* code: "EPERM",
* syscall: "scandir",
* path: "C:\\$Recycle.Bin\\S-1-5-18"
* }
* [Error: EACCES: permission denied, scandir '/boot/efi'] {
* errno: -13,
* code: 'EACCES',
* syscall: 'scandir',
* path: '/boot/efi'
* }
* // [note] It is missed for "read" (`createReadStream`) of a folder.
* [Error: EISDIR: illegal operation on a directory, read] {
* errno: -4068,
* code: 'EISDIR',
* syscall: 'read'
* }
*/
export interface IOError extends Error {
syscall: string;
code: string;
errno: number;
path: string;
}
import { Dirent, BigIntStats, Stats } from "node:fs";
import { IOError } from "./IOError.js";
/**
* The simplified type example:
* @example
* type ListEntrySimplifiedFullType = {
* path: string,
* dirent: Dirent,
* stats?: Stats | BigIntStats,
* link?: LinkInfo,
* errors?: {
* [name in "readdir" | "stats" | "readlink"]?: IOError
* },
* };
*/
export type ListEntryBase = ListEntryDirent | ListEntryDirentError;
export type ListEntryDirent = {
path: string;
dirent: Dirent;
};
export type ListEntryDirentError = {
path: string;
dirent: Dirent;
errors: DirError;
};
export type DirError = {
readdir: IOError;
};
export type StatError = {
stats: IOError;
};
export type LinkError = {
readlink: IOError;
};
export type LinkInfo = {
pathTo: string;
content: string;
};
export type LinkEntry = {
link: LinkInfo;
};
export type LinkEntryError = {
errors: LinkError;
};
export type LinkEntryBase = LinkEntry | LinkEntryError;
export type ListEntryDirentLink = ListEntryDirent & LinkEntryBase;
export type ListEntryBaseEx = ListEntryBase | ListEntryDirentLink;
export type StatEntry = {
stats: Stats;
};
export type StatEntryBigInt = {
stats: BigIntStats;
};
export type StatEntryAny = {
stats: Stats | BigIntStats;
};
export type StatEntryError = {
errors: StatError;
};
export type StatEntryBase = StatEntry | StatEntryError;
export type StatEntryBaseBigInt = StatEntryBigInt | StatEntryError;
export type StatEntryBaseAny = StatEntryAny | StatEntryError;
export type ListEntryStats = StatEntryBase & ListEntryBaseEx;
export type ListEntryStatsBigInt = StatEntryBaseBigInt & ListEntryBaseEx;
export type ListEntryStatsAny = StatEntryBaseAny & ListEntryBaseEx;
Installation
From NPM
npm install @alttiri/util-node-js
From GitHub Packages:
To install you need first to create .npmrc
file with @alttiri:registry=https://npm.pkg.github.com
content:
echo @alttiri:registry=https://npm.pkg.github.com >> .npmrc
only then run
npm install @alttiri/util-node-js
Note, that GitHub Packages requires to have also ~/.npmrc
file (.npmrc
in your home dir) with //npm.pkg.github.com/:_authToken=TOKEN
content, where TOKEN
is a token with the read:packages
permission, take it here https://github.com/settings/tokens/new.