@augment-vir/node 30.6.2 → 30.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.
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Nested contents read from a file system directory.
3
+ *
4
+ * @category Node : File
5
+ * @category Package : @augment-vir/node
6
+ * @package [`@augment-vir/node`](https://www.npmjs.com/package/@augment-vir/node)
7
+ */
8
+ export type DirContents = {
9
+ [Path in string]: string | DirContents;
10
+ };
11
+ /**
12
+ * Read all contents within a directory and store them in an object. Optionally recursive.
13
+ *
14
+ * @category Node : File
15
+ * @category Package : @augment-vir/node
16
+ * @package [`@augment-vir/node`](https://www.npmjs.com/package/@augment-vir/node)
17
+ */
18
+ export declare function readAllDirContents(dir: string, { recursive, excludeList, }: {
19
+ recursive?: boolean;
20
+ excludeList?: ReadonlyArray<string | RegExp> | undefined;
21
+ }): Promise<DirContents>;
22
+ /**
23
+ * Deletes and entire directory and resets it to the given contents.
24
+ *
25
+ * @category Node : File
26
+ * @category Package : @augment-vir/node
27
+ * @package [`@augment-vir/node`](https://www.npmjs.com/package/@augment-vir/node)
28
+ */
29
+ export declare function resetDirContents(rootDir: string, contents: Readonly<DirContents>): Promise<void>;
30
+ /**
31
+ * Write {@link DirContents} to a directory.
32
+ *
33
+ * @category Node : File
34
+ * @category Package : @augment-vir/node
35
+ * @package [`@augment-vir/node`](https://www.npmjs.com/package/@augment-vir/node)
36
+ */
37
+ export declare function writeDirContents(rootDir: string, contents: Readonly<DirContents>): Promise<void>;
@@ -0,0 +1,77 @@
1
+ import { check } from '@augment-vir/assert';
2
+ import { getObjectTypedEntries } from '@augment-vir/common';
3
+ import { readdir, readFile, rm, stat } from 'node:fs/promises';
4
+ import { join } from 'node:path';
5
+ import { writeFileAndDir } from './write.js';
6
+ /**
7
+ * Read all contents within a directory and store them in an object. Optionally recursive.
8
+ *
9
+ * @category Node : File
10
+ * @category Package : @augment-vir/node
11
+ * @package [`@augment-vir/node`](https://www.npmjs.com/package/@augment-vir/node)
12
+ */
13
+ export async function readAllDirContents(dir, { recursive = false, excludeList, }) {
14
+ const fileNames = (await readdir(dir)).sort();
15
+ const allFileContents = await Promise.all(fileNames.map(async (fileName) => {
16
+ const filePath = join(dir, fileName);
17
+ if (excludeList?.some((excludeItem) => {
18
+ if (check.isString(excludeItem)) {
19
+ return filePath.includes(excludeItem);
20
+ }
21
+ else {
22
+ return filePath.match(excludeItem);
23
+ }
24
+ })) {
25
+ return undefined;
26
+ }
27
+ const isFile = (await stat(filePath)).isFile();
28
+ const contents = isFile
29
+ ? (await readFile(filePath)).toString()
30
+ : recursive
31
+ ? await readAllDirContents(filePath, { recursive, excludeList })
32
+ : undefined;
33
+ if (check.isObject(contents) && !Object.keys(contents).length) {
34
+ return undefined;
35
+ }
36
+ return contents;
37
+ }));
38
+ return fileNames.reduce((accum, fileName, index) => {
39
+ if (allFileContents[index] != undefined) {
40
+ const fileContents = allFileContents[index];
41
+ accum[fileName] = fileContents;
42
+ }
43
+ return accum;
44
+ }, {});
45
+ }
46
+ /**
47
+ * Deletes and entire directory and resets it to the given contents.
48
+ *
49
+ * @category Node : File
50
+ * @category Package : @augment-vir/node
51
+ * @package [`@augment-vir/node`](https://www.npmjs.com/package/@augment-vir/node)
52
+ */
53
+ export async function resetDirContents(rootDir, contents) {
54
+ await rm(rootDir, {
55
+ force: true,
56
+ recursive: true,
57
+ });
58
+ await writeDirContents(rootDir, contents);
59
+ }
60
+ /**
61
+ * Write {@link DirContents} to a directory.
62
+ *
63
+ * @category Node : File
64
+ * @category Package : @augment-vir/node
65
+ * @package [`@augment-vir/node`](https://www.npmjs.com/package/@augment-vir/node)
66
+ */
67
+ export async function writeDirContents(rootDir, contents) {
68
+ await Promise.all(getObjectTypedEntries(contents).map(async ([relativePath, content,]) => {
69
+ const fullPath = join(rootDir, relativePath);
70
+ if (check.isString(content)) {
71
+ await writeFileAndDir(fullPath, content);
72
+ }
73
+ else {
74
+ await writeDirContents(fullPath, content);
75
+ }
76
+ }));
77
+ }
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Input for extractRelevantArgs.
3
+ *
4
+ * @category Node : Terminal : Util
5
+ * @category Package : @augment-vir/node
6
+ * @package [`@augment-vir/node`](https://www.npmjs.com/package/@augment-vir/node)
7
+ */
8
+ export type RelevantArgsInput = {
9
+ /** Raw arguments passed to the CLI. Typically this will simply be process.argv. */
10
+ rawArgs: ReadonlyArray<string>;
11
+ /**
12
+ * Executable bin name for your script. This should be the "bin" name in your package.json, or
13
+ * simply your package name if you have no custom bin name defined.
14
+ *
15
+ * See https://docs.npmjs.com/cli/v10/configuring-npm/package-json#bin for details on the bin
16
+ * field of package.json
17
+ */
18
+ binName: string | undefined;
19
+ /**
20
+ * The name or path of your script file that will be executed via the CLI. This should almost
21
+ * always simply be __filename in CJS or `import.meta.filename` in ESM.
22
+ */
23
+ fileName: string;
24
+ /**
25
+ * If set to true, this function with throw an error if the given file or bin name was not found
26
+ * in the given arguments list.
27
+ */
28
+ errorIfNotFound?: boolean | undefined;
29
+ };
30
+ /**
31
+ * Trims arguments list to remove all arguments that take place before the script's file name or
32
+ * executable bin name.
33
+ *
34
+ * @category Node : Terminal
35
+ * @category Package : @augment-vir/node
36
+ * @example
37
+ *
38
+ * ```ts
39
+ * extractRelevantArgs({
40
+ * rawArgs: [
41
+ * 'npx',
42
+ * 'ts-node',
43
+ * './my-script.ts',
44
+ * 'arg1',
45
+ * '--arg2',
46
+ * ], // typically will be process.argv
47
+ * binName: 'my-script', // should be your package.json "bin" property name, can be undefined
48
+ * fileName: 'my-script.ts', // should be __filename from the script that will be executed
49
+ * });
50
+ * // will output ['arg1', '--arg2']
51
+ * ```
52
+ *
53
+ * @package [`@augment-vir/node`](https://www.npmjs.com/package/@augment-vir/node)
54
+ */
55
+ export declare function extractRelevantArgs({ rawArgs, binName, fileName, errorIfNotFound, }: Readonly<RelevantArgsInput>): string[];
@@ -0,0 +1,49 @@
1
+ import { basename } from 'node:path';
2
+ /**
3
+ * Trims arguments list to remove all arguments that take place before the script's file name or
4
+ * executable bin name.
5
+ *
6
+ * @category Node : Terminal
7
+ * @category Package : @augment-vir/node
8
+ * @example
9
+ *
10
+ * ```ts
11
+ * extractRelevantArgs({
12
+ * rawArgs: [
13
+ * 'npx',
14
+ * 'ts-node',
15
+ * './my-script.ts',
16
+ * 'arg1',
17
+ * '--arg2',
18
+ * ], // typically will be process.argv
19
+ * binName: 'my-script', // should be your package.json "bin" property name, can be undefined
20
+ * fileName: 'my-script.ts', // should be __filename from the script that will be executed
21
+ * });
22
+ * // will output ['arg1', '--arg2']
23
+ * ```
24
+ *
25
+ * @package [`@augment-vir/node`](https://www.npmjs.com/package/@augment-vir/node)
26
+ */
27
+ export function extractRelevantArgs({ rawArgs, binName, fileName, errorIfNotFound, }) {
28
+ const baseFileName = basename(fileName);
29
+ if (!baseFileName) {
30
+ throw new Error(`Given file name produced no base file name (with path.basename()): '${fileName}'`);
31
+ }
32
+ const lastIrrelevantArgIndex = rawArgs.findIndex((arg) => {
33
+ const baseArgName = basename(arg);
34
+ const matchesFileName = baseArgName === baseFileName;
35
+ const matchesBinName = binName ? baseArgName === binName : false;
36
+ return matchesFileName || matchesBinName;
37
+ });
38
+ if (lastIrrelevantArgIndex === -1) {
39
+ if (errorIfNotFound) {
40
+ throw new Error('Failed to find position of file or bin name in provided args list.');
41
+ }
42
+ else {
43
+ return [...rawArgs];
44
+ }
45
+ }
46
+ else {
47
+ return rawArgs.slice(lastIrrelevantArgIndex + 1);
48
+ }
49
+ }
@@ -0,0 +1,22 @@
1
+ /** This file cannot be tested because it calls `process.exit`. */
2
+ /**
3
+ * A map of file extensions to their known runners for {@link runCliScript}.
4
+ *
5
+ * @category Node : Terminal : Util
6
+ * @category Package : @augment-vir/node
7
+ * @package [`@augment-vir/node`](https://www.npmjs.com/package/@augment-vir/node)
8
+ */
9
+ export declare const ExtensionToRunner: Record<string, string>;
10
+ /**
11
+ * Runs a script path as if it had been run directly, as much as possible.
12
+ *
13
+ * @category Node : Terminal : Util
14
+ * @category Package : @augment-vir/node
15
+ * @package [`@augment-vir/node`](https://www.npmjs.com/package/@augment-vir/node)
16
+ */
17
+ export declare function runCliScript(path: string,
18
+ /**
19
+ * This should be the bin name of the package that is calling this function. Set to `undefined`
20
+ * if there isn't one.
21
+ */
22
+ binName: string | undefined): Promise<void>;
@@ -0,0 +1,49 @@
1
+ /* node:coverage disable */
2
+ /** This file cannot be tested because it calls `process.exit`. */
3
+ import { extname } from 'node:path';
4
+ import { extractRelevantArgs } from './relevant-args.js';
5
+ import { runShellCommand } from './shell.js';
6
+ /**
7
+ * A map of file extensions to their known runners for {@link runCliScript}.
8
+ *
9
+ * @category Node : Terminal : Util
10
+ * @category Package : @augment-vir/node
11
+ * @package [`@augment-vir/node`](https://www.npmjs.com/package/@augment-vir/node)
12
+ */
13
+ export const ExtensionToRunner = {
14
+ '.ts': 'tsx',
15
+ '.js': 'node',
16
+ '.sh': 'bash',
17
+ };
18
+ /**
19
+ * Runs a script path as if it had been run directly, as much as possible.
20
+ *
21
+ * @category Node : Terminal : Util
22
+ * @category Package : @augment-vir/node
23
+ * @package [`@augment-vir/node`](https://www.npmjs.com/package/@augment-vir/node)
24
+ */
25
+ export async function runCliScript(path,
26
+ /**
27
+ * This should be the bin name of the package that is calling this function. Set to `undefined`
28
+ * if there isn't one.
29
+ */
30
+ binName) {
31
+ const args = extractRelevantArgs({
32
+ rawArgs: process.argv,
33
+ binName,
34
+ fileName: import.meta.filename,
35
+ });
36
+ const extension = extname(path);
37
+ const runner = ExtensionToRunner[extension];
38
+ if (!runner) {
39
+ throw new Error("No runner configured for file extension '${extension}' in '${path}'");
40
+ }
41
+ const results = await runShellCommand([
42
+ runner,
43
+ path,
44
+ ...args,
45
+ ].join(' '), {
46
+ hookUpToConsole: true,
47
+ });
48
+ process.exit(results.exitCode || 0);
49
+ }
@@ -2,6 +2,7 @@ export declare const monoRepoDirPath: string;
2
2
  export declare const notCommittedDirPath: string;
3
3
  export declare const nodePackageDir: string;
4
4
  export declare const testFilesDir: string;
5
+ export declare const dirContentsTestDir: string;
5
6
  export declare const longRunningFilePath: string;
6
7
  export declare const longRunningFileWithStderr: string;
7
8
  export declare const workspaceQueryDir: string;
@@ -4,6 +4,7 @@ export const notCommittedDirPath = join(monoRepoDirPath, '.not-committed');
4
4
  export const nodePackageDir = dirname(import.meta.dirname);
5
5
  export const testFilesDir = join(nodePackageDir, 'test-files');
6
6
  const longRunningFileDir = join(testFilesDir, 'long-running-test-file');
7
+ export const dirContentsTestDir = join(testFilesDir, 'dir-contents-test');
7
8
  export const longRunningFilePath = join(longRunningFileDir, 'long-running-file.ts');
8
9
  export const longRunningFileWithStderr = join(longRunningFileDir, 'long-running-file-with-stderr.ts');
9
10
  export const workspaceQueryDir = join(testFilesDir, 'workspace-query');
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export * from './augments/docker.js';
2
+ export * from './augments/fs/dir-contents.js';
2
3
  export * from './augments/fs/download.js';
3
4
  export * from './augments/fs/json.js';
4
5
  export * from './augments/fs/read-dir.js';
@@ -13,4 +14,6 @@ export * from './augments/path/os-path.js';
13
14
  export * from './augments/path/root.js';
14
15
  export * from './augments/prisma.js';
15
16
  export * from './augments/terminal/question.js';
17
+ export * from './augments/terminal/relevant-args.js';
18
+ export * from './augments/terminal/run-cli-script.js';
16
19
  export * from './augments/terminal/shell.js';
package/dist/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  export * from './augments/docker.js';
2
+ export * from './augments/fs/dir-contents.js';
2
3
  export * from './augments/fs/download.js';
3
4
  export * from './augments/fs/json.js';
4
5
  export * from './augments/fs/read-dir.js';
@@ -13,4 +14,6 @@ export * from './augments/path/os-path.js';
13
14
  export * from './augments/path/root.js';
14
15
  export * from './augments/prisma.js';
15
16
  export * from './augments/terminal/question.js';
17
+ export * from './augments/terminal/relevant-args.js';
18
+ export * from './augments/terminal/run-cli-script.js';
16
19
  export * from './augments/terminal/shell.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@augment-vir/node",
3
- "version": "30.6.2",
3
+ "version": "30.8.0",
4
4
  "description": "A collection of augments, helpers types, functions, and classes only for Node.js (backend) JavaScript environments.",
5
5
  "keywords": [
6
6
  "augment",
@@ -37,16 +37,16 @@
37
37
  "test:update": "npm test"
38
38
  },
39
39
  "dependencies": {
40
- "@augment-vir/assert": "^30.6.2",
41
- "@augment-vir/common": "^30.6.2",
42
- "@date-vir/duration": "^6.0.1",
40
+ "@augment-vir/assert": "^30.8.0",
41
+ "@augment-vir/common": "^30.8.0",
42
+ "@date-vir/duration": "^7.0.1",
43
43
  "ansi-styles": "^6.2.1",
44
44
  "terminate": "^2.8.0",
45
45
  "type-fest": "^4.26.1",
46
46
  "typed-event-target": "^4.0.2"
47
47
  },
48
48
  "devDependencies": {
49
- "@augment-vir/test": "^30.6.2",
49
+ "@augment-vir/test": "^30.8.0",
50
50
  "@prisma/client": "^5.22.0",
51
51
  "@types/node": "^22.9.0",
52
52
  "@web/dev-server-esbuild": "^1.0.3",