jg-fs 1.0.0 → 1.1.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.
Files changed (45) hide show
  1. package/API.md +1716 -0
  2. package/CHANGELOG.md +23 -13
  3. package/README.md +6 -21
  4. package/dist/async/directories/directories.d.ts +14 -0
  5. package/dist/async/directories/directories.js +20 -2
  6. package/dist/async/directories/directories.js.map +1 -1
  7. package/dist/async/files/files.d.ts +46 -8
  8. package/dist/async/files/files.js +48 -10
  9. package/dist/async/files/files.js.map +1 -1
  10. package/dist/async/files/index.d.ts +1 -1
  11. package/dist/async/files/index.js +1 -1
  12. package/dist/async/files/index.js.map +1 -1
  13. package/dist/async/general/general.d.ts +4 -0
  14. package/dist/async/general/general.js +4 -0
  15. package/dist/async/general/general.js.map +1 -1
  16. package/dist/index.d.ts +2 -2
  17. package/dist/index.js +1 -1
  18. package/dist/index.js.map +1 -1
  19. package/dist/shared/index.d.ts +2 -2
  20. package/dist/shared/index.js +1 -1
  21. package/dist/shared/index.js.map +1 -1
  22. package/dist/shared/paths.d.ts +2 -0
  23. package/dist/shared/paths.js +2 -0
  24. package/dist/shared/paths.js.map +1 -1
  25. package/dist/shared/types.d.ts +6 -0
  26. package/dist/shared/types.js.map +1 -1
  27. package/dist/shared/validations.d.ts +5 -3
  28. package/dist/shared/validations.js +30 -14
  29. package/dist/shared/validations.js.map +1 -1
  30. package/dist/sync/directories/directories.d.ts +14 -0
  31. package/dist/sync/directories/directories.js +20 -2
  32. package/dist/sync/directories/directories.js.map +1 -1
  33. package/dist/sync/files/files.d.ts +46 -8
  34. package/dist/sync/files/files.js +48 -10
  35. package/dist/sync/files/files.js.map +1 -1
  36. package/dist/sync/files/index.d.ts +1 -1
  37. package/dist/sync/files/index.js +1 -1
  38. package/dist/sync/files/index.js.map +1 -1
  39. package/dist/sync/general/general.d.ts +4 -0
  40. package/dist/sync/general/general.js +4 -0
  41. package/dist/sync/general/general.js.map +1 -1
  42. package/dist/sync/index.d.ts +2 -2
  43. package/dist/sync/index.js +1 -1
  44. package/dist/sync/index.js.map +1 -1
  45. package/package.json +10 -6
@@ -1 +1 @@
1
- {"version":3,"file":"directories.js","sourceRoot":"","sources":["../../../src/sync/directories/directories.ts"],"names":[],"mappings":"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","sourcesContent":["import { cpSync, mkdirSync, readdirSync, rmSync, symlinkSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { Exception } from 'jg-exception';\n\nimport {\n buildDirectoryElementsOptions,\n ERRORS,\n groupDirectoryElements,\n notADirectory,\n type IDirectoryElementsOptions,\n type IDirectoryPathElements,\n type IPathElement,\n} from '../../shared/index.js';\nimport { getPathElement } from '../general/index.js';\n\n/**\n * Checks whether a path exists and is a directory.\n * @param path The path.\n * @returns Whether the path is a directory.\n * @example\n * isDirectory('dist'); // true\n */\nexport const isDirectory = (path: string): boolean => getPathElement(path)?.isDirectory ?? false;\n\n/**\n * Deletes a directory and everything in it. A missing directory is not an error.\n * @param path The directory's path.\n * @example\n * deleteDirectory('dist');\n */\nexport const deleteDirectory = (path: string): void =>\n rmSync(path, { recursive: true, force: true });\n\n/**\n * Creates a directory, with any missing parents. An existing directory is kept, or replaced with\n * an empty one when `deleteIfExists` is set.\n * @param path The directory's path.\n * @param deleteIfExists Whether to delete an existing directory and its contents first.\n * @example\n * createDirectory('dist/assets'); // creates missing parents too\n * createDirectory('dist', true); // replaces it with an empty directory\n * @throws\n * - DIRECTORY_ALREADY_EXISTS: if something other than a directory exists at the path\n */\nexport const createDirectory = (path: string, deleteIfExists?: boolean): void => {\n const element = getPathElement(path);\n if (element !== null && !element.isDirectory) {\n throw new Exception(\n `The path '${path}' already exists and is not a directory.`,\n ERRORS.DIRECTORY_ALREADY_EXISTS,\n );\n }\n if (element !== null && deleteIfExists) {\n deleteDirectory(path);\n }\n mkdirSync(path, { recursive: true });\n};\n\n/**\n * Copies a directory and everything in it, replacing the destination completely.\n * @param srcPath The directory to copy.\n * @param destPath Where to copy it.\n * @example\n * copyDirectory('templates', 'dist/templates');\n * @throws\n * - NOT_A_DIRECTORY: if the srcPath is not a directory\n */\nexport const copyDirectory = (srcPath: string, destPath: string): void => {\n if (!isDirectory(srcPath)) {\n throw notADirectory(srcPath);\n }\n deleteDirectory(destPath);\n cpSync(srcPath, destPath, { recursive: true });\n};\n\n/**\n * Creates a symbolic link to a directory.\n * @param target The directory the link points to.\n * @param path Where to create the link.\n * @example\n * createDirectorySymLink('releases/1.4.0', 'current');\n * @throws\n * - NON_EXISTENT_DIRECTORY: if the target directory doesn't exist\n * - NOT_A_DIRECTORY: if the target directory is not considered a directory by the OS\n */\nexport const createDirectorySymLink = (target: string, path: string): void => {\n const element = getPathElement(target);\n if (element === null) {\n throw new Exception(\n `The target directory '${target}' does not exist.`,\n ERRORS.NON_EXISTENT_DIRECTORY,\n );\n }\n if (!element.isDirectory) {\n throw notADirectory(target);\n }\n symlinkSync(target, path, 'dir');\n};\n\n/**\n * Lists a directory's contents as paths joined to the directory's path.\n * @param path The directory's path.\n * @param recursive Whether to include the contents of subdirectories.\n * @returns The content paths.\n * @example\n * readDirectory('dist'); // ['dist/index.js', 'dist/assets']\n * readDirectory('dist', true); // includes the contents of dist/assets\n * @throws\n * - NOT_A_DIRECTORY: if the path doesn't exist or is not a directory\n */\nexport const readDirectory = (path: string, recursive: boolean = false): string[] => {\n if (!isDirectory(path)) {\n throw notADirectory(path);\n }\n return readdirSync(path, { encoding: 'utf-8', recursive }).map((contentPath) =>\n join(path, contentPath),\n );\n};\n\n/**\n * Lists a directory's elements grouped by kind: directories, files (filtered by extension), and\n * symbolic links, each group sorted. Entries removed while the directory is read are left out.\n * @param path The directory's path.\n * @param options The extensions to include and how to sort.\n * @returns The grouped elements.\n * @example\n * const { files } = getDirectoryElements('content', { includeExts: ['.md'], sortByKey: 'creation', sortOrder: 'desc' });\n * @throws\n * - NOT_A_DIRECTORY: if the path doesn't exist or is not a directory\n */\nexport const getDirectoryElements = (\n path: string,\n options?: Partial<IDirectoryElementsOptions>,\n): IDirectoryPathElements => {\n const elements = readDirectory(path)\n .map(getPathElement)\n .filter((element): element is IPathElement => element !== null);\n return groupDirectoryElements(elements, buildDirectoryElementsOptions(options));\n};\n"]}
1
+ {"version":3,"file":"directories.js","sourceRoot":"","sources":["../../../src/sync/directories/directories.ts"],"names":[],"mappings":"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","sourcesContent":["import { cpSync, mkdirSync, readdirSync, rmSync, symlinkSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { Exception } from 'jg-exception';\n\nimport {\n buildDirectoryElementsOptions,\n ERRORS,\n groupDirectoryElements,\n notADirectory,\n type IDirectoryElementsOptions,\n type IDirectoryPathElements,\n type IPathElement,\n} from '../../shared/index.js';\nimport { getPathElement } from '../general/index.js';\n\n/**\n * Checks whether a path exists and is a directory.\n * @param path The path.\n * @returns Whether the path is a directory.\n * @example\n * import { isDirectory } from 'jg-fs/sync';\n *\n * isDirectory('dist'); // true\n */\nexport const isDirectory = (path: string): boolean => getPathElement(path)?.isDirectory ?? false;\n\n/**\n * Deletes a directory and everything in it. A missing directory is not an error.\n * @param path The directory's path.\n * @example\n * import { deleteDirectory } from 'jg-fs/sync';\n *\n * deleteDirectory('dist');\n */\nexport const deleteDirectory = (path: string): void =>\n rmSync(path, { recursive: true, force: true });\n\n/**\n * Creates a directory, with any missing parents. An existing directory is kept, or replaced with\n * an empty one when `deleteIfExists` is set.\n * @param path The directory's path.\n * @param deleteIfExists Whether to delete an existing directory and its contents first.\n * @example\n * import { createDirectory } from 'jg-fs/sync';\n *\n * createDirectory('dist/assets'); // creates missing parents too\n * createDirectory('dist', true); // replaces it with an empty directory\n * @throws\n * - DIRECTORY_ALREADY_EXISTS: if something other than a directory exists at the path\n */\nexport const createDirectory = (path: string, deleteIfExists?: boolean): void => {\n const element = getPathElement(path);\n if (element !== null && !element.isDirectory) {\n throw new Exception(`The path '${path}' already exists and is not a directory.`, {\n code: ERRORS.DIRECTORY_ALREADY_EXISTS,\n });\n }\n if (element !== null && deleteIfExists) {\n deleteDirectory(path);\n }\n mkdirSync(path, { recursive: true });\n};\n\n/**\n * Copies a directory and everything in it, replacing the destination completely.\n * @param srcPath The directory to copy.\n * @param destPath Where to copy it.\n * @example\n * import { copyDirectory } from 'jg-fs/sync';\n *\n * copyDirectory('templates', 'dist/templates');\n * @throws\n * - NOT_A_DIRECTORY: if the srcPath is not a directory\n */\nexport const copyDirectory = (srcPath: string, destPath: string): void => {\n if (!isDirectory(srcPath)) {\n throw notADirectory(srcPath);\n }\n deleteDirectory(destPath);\n cpSync(srcPath, destPath, { recursive: true });\n};\n\n/**\n * Creates a symbolic link to a directory.\n * @param target The directory the link points to.\n * @param path Where to create the link.\n * @example\n * import { createDirectorySymLink } from 'jg-fs/sync';\n *\n * createDirectorySymLink('releases/1.4.0', 'current');\n * @throws\n * - NON_EXISTENT_DIRECTORY: if the target directory doesn't exist\n * - NOT_A_DIRECTORY: if the target directory is not considered a directory by the OS\n */\nexport const createDirectorySymLink = (target: string, path: string): void => {\n const element = getPathElement(target);\n if (element === null) {\n throw new Exception(`The target directory '${target}' does not exist.`, {\n code: ERRORS.NON_EXISTENT_DIRECTORY,\n });\n }\n if (!element.isDirectory) {\n throw notADirectory(target);\n }\n symlinkSync(target, path, 'dir');\n};\n\n/**\n * Lists a directory's contents as paths joined to the directory's path.\n * @param path The directory's path.\n * @param recursive Whether to include the contents of subdirectories.\n * @returns The content paths.\n * @example\n * import { readDirectory } from 'jg-fs/sync';\n *\n * readDirectory('dist'); // ['dist/index.js', 'dist/assets']\n * readDirectory('dist', true); // includes the contents of dist/assets\n * @throws\n * - NOT_A_DIRECTORY: if the path doesn't exist or is not a directory\n */\nexport const readDirectory = (path: string, recursive: boolean = false): string[] => {\n if (!isDirectory(path)) {\n throw notADirectory(path);\n }\n return readdirSync(path, { encoding: 'utf-8', recursive }).map((contentPath) =>\n join(path, contentPath),\n );\n};\n\n/**\n * Lists a directory's elements grouped by kind: directories, files (filtered by extension), and\n * symbolic links, each group sorted. Entries removed while the directory is read are left out.\n * @param path The directory's path.\n * @param options The extensions to include and how to sort.\n * @returns The grouped elements.\n * @example\n * import { getDirectoryElements } from 'jg-fs/sync';\n *\n * const { files } = getDirectoryElements('content', { includeExts: ['.md'], sortByKey: 'creation', sortOrder: 'desc' });\n * @throws\n * - NOT_A_DIRECTORY: if the path doesn't exist or is not a directory\n */\nexport const getDirectoryElements = (\n path: string,\n options?: Partial<IDirectoryElementsOptions>,\n): IDirectoryPathElements => {\n const elements = readDirectory(path)\n .map(getPathElement)\n .filter((element): element is IPathElement => element !== null);\n return groupDirectoryElements(elements, buildDirectoryElementsOptions(options));\n};\n"]}
@@ -1,11 +1,13 @@
1
1
  import { Buffer } from 'node:buffer';
2
2
  import { type WriteFileOptions } from 'node:fs';
3
- import { type IReadBufferFileOptions, type IReadFileOptions, type IReadStringFileOptions } from '../../shared/index.js';
3
+ import { type IReadBufferFileOptions, type IReadFileOptions, type IReadJsonFileOptions, type IReadStringFileOptions } from '../../shared/index.js';
4
4
  /**
5
5
  * Checks whether a path exists and is a regular file.
6
6
  * @param path The path.
7
7
  * @returns Whether the path is a file.
8
8
  * @example
9
+ * import { isFile } from 'jg-fs/sync';
10
+ *
9
11
  * isFile('package.json'); // true
10
12
  */
11
13
  export declare const isFile: (path: string) => boolean;
@@ -15,6 +17,9 @@ export declare const isFile: (path: string) => boolean;
15
17
  * @param data The content.
16
18
  * @param options Node.js's writeFile options, such as the encoding or mode.
17
19
  * @example
20
+ * import { writeFile } from 'jg-fs/sync';
21
+ *
22
+ * const csv = 'id,name\n1,Ada\n';
18
23
  * writeFile('out/report.csv', csv, { encoding: 'utf-8' });
19
24
  */
20
25
  export declare const writeFile: (path: string, data: string | NodeJS.ArrayBufferView, options?: WriteFileOptions) => void;
@@ -23,6 +28,8 @@ export declare const writeFile: (path: string, data: string | NodeJS.ArrayBuffer
23
28
  * @param path The file's path.
24
29
  * @param data The text.
25
30
  * @example
31
+ * import { writeTextFile } from 'jg-fs/sync';
32
+ *
26
33
  * writeTextFile('notes/today.md', '# Today');
27
34
  * @throws
28
35
  * - FILE_CONTENT_IS_EMPTY_OR_INVALID: if the data isn't a string
@@ -34,16 +41,21 @@ export declare const writeTextFile: (path: string, data: string) => void;
34
41
  * @param data The value, or its JSON text.
35
42
  * @param space The indentation for stringified values.
36
43
  * @example
37
- * writeJSONFile('config.json', { port: 8080 });
44
+ * import { writeJsonFile } from 'jg-fs/sync';
45
+ *
46
+ * writeJsonFile('config.json', { port: 8080 });
38
47
  * @throws
39
48
  * - FILE_CONTENT_IS_EMPTY_OR_INVALID: if the JSON content cannot be stringified or is empty
40
49
  */
41
- export declare const writeJSONFile: <T = Record<string, unknown>>(path: string, data: T | string, space?: number) => void;
50
+ export declare const writeJsonFile: <T = Record<string, unknown>>(path: string, data: T | string, space?: number) => void;
42
51
  /**
43
52
  * Writes a binary file. An empty Buffer writes an empty file.
44
53
  * @param path The file's path.
45
54
  * @param data The content.
46
55
  * @example
56
+ * import { writeBufferFile } from 'jg-fs/sync';
57
+ *
58
+ * const imageBuffer = Buffer.from('iVBORw0KGgo=', 'base64');
47
59
  * writeBufferFile('avatar.png', imageBuffer);
48
60
  * @throws
49
61
  * - FILE_CONTENT_IS_EMPTY_OR_INVALID: if the data isn't a Buffer
@@ -55,6 +67,8 @@ export declare const writeBufferFile: (path: string, data: Buffer) => void;
55
67
  * @param options Node.js's readFile options, such as the encoding.
56
68
  * @returns The content.
57
69
  * @example
70
+ * import { readFile } from 'jg-fs/sync';
71
+ *
58
72
  * readFile('notes.md', 'utf-8'); // a string
59
73
  * readFile('avatar.png'); // a Buffer
60
74
  * @throws
@@ -68,27 +82,39 @@ export declare function readFile(path: string, options?: IReadFileOptions): stri
68
82
  * @param path The file's path.
69
83
  * @returns The text.
70
84
  * @example
85
+ * import { readTextFile } from 'jg-fs/sync';
86
+ *
71
87
  * const markdown = readTextFile('README.md');
72
88
  * @throws
73
89
  * - NOT_A_FILE: if the path doesn't exist or is not a file
74
90
  */
75
91
  export declare const readTextFile: (path: string) => string;
76
92
  /**
77
- * Reads and parses a JSON file.
93
+ * Reads and parses a JSON file, and validates it with the schema when there is one. Without a
94
+ * schema, the value is `unknown`, or the type you pass.
78
95
  * @param path The file's path.
96
+ * @param options The schema, such as a Zod schema, whose errors propagate unchanged.
79
97
  * @returns The parsed value.
80
98
  * @example
81
- * const config = readJSONFile<{ port: number }>('config.json');
99
+ * import { readJsonFile } from 'jg-fs/sync';
100
+ *
101
+ * const config = readJsonFile('config.json', { schema: Config }); // Config's type
102
+ * @example
103
+ * import { readJsonFile } from 'jg-fs/sync';
104
+ *
105
+ * const value = readJsonFile('data.json'); // unknown
82
106
  * @throws
83
107
  * - NOT_A_FILE: if the path doesn't exist or is not a file
84
108
  * - FILE_CONTENT_IS_EMPTY_OR_INVALID: if the file's JSON content cannot be parsed
85
109
  */
86
- export declare const readJSONFile: <T = Record<string, unknown>>(path: string) => T;
110
+ export declare const readJsonFile: <T = unknown>(path: string, options?: IReadJsonFileOptions<T>) => T;
87
111
  /**
88
112
  * Reads a binary file. An empty file reads as an empty Buffer.
89
113
  * @param path The file's path.
90
114
  * @returns The content.
91
115
  * @example
116
+ * import { readBufferFile } from 'jg-fs/sync';
117
+ *
92
118
  * const image = readBufferFile('avatar.png');
93
119
  * @throws
94
120
  * - NOT_A_FILE: if the path doesn't exist or is not a file
@@ -99,6 +125,8 @@ export declare const readBufferFile: (path: string) => Buffer;
99
125
  * @param srcPath The file to copy.
100
126
  * @param destPath Where to copy it.
101
127
  * @example
128
+ * import { copyFile } from 'jg-fs/sync';
129
+ *
102
130
  * copyFile('config.example.json', 'config.json');
103
131
  * @throws
104
132
  * - NOT_A_FILE: if the srcPath doesn't exist or is not a file
@@ -108,6 +136,8 @@ export declare const copyFile: (srcPath: string, destPath: string) => void;
108
136
  * Deletes a file.
109
137
  * @param path The file's path.
110
138
  * @example
139
+ * import { deleteFile } from 'jg-fs/sync';
140
+ *
111
141
  * deleteFile('cache.json');
112
142
  * @throws
113
143
  * - NOT_A_FILE: if the path doesn't exist or is not a file
@@ -118,6 +148,8 @@ export declare const deleteFile: (path: string) => void;
118
148
  * @param target The file the link points to.
119
149
  * @param path Where to create the link.
120
150
  * @example
151
+ * import { createFileSymLink } from 'jg-fs/sync';
152
+ *
121
153
  * createFileSymLink('config.production.json', 'config.json');
122
154
  * @throws
123
155
  * - NON_EXISTENT_FILE: if the target file does not exist
@@ -135,8 +167,11 @@ export declare const createFileSymLink: (target: string, path: string) => void;
135
167
  * @param data The content.
136
168
  * @param mode The permission bits of the written file, such as `0o600`.
137
169
  * @example
170
+ * import { writeFileAtomic } from 'jg-fs/sync';
171
+ *
172
+ * const state = { step: 2 };
138
173
  * writeFileAtomic('state.json', JSON.stringify(state)); // readers never see a partial file
139
- * writeFileAtomic('secrets.env', contents, 0o600);
174
+ * writeFileAtomic('secrets.env', 'TOKEN=abc\n', 0o600); // only the owner can read it
140
175
  */
141
176
  export declare const writeFileAtomic: (path: string, data: string | NodeJS.ArrayBufferView, mode?: number) => void;
142
177
  /**
@@ -148,7 +183,10 @@ export declare const writeFileAtomic: (path: string, data: string | NodeJS.Array
148
183
  * @param maxBytes The largest size accepted, in bytes.
149
184
  * @returns The content.
150
185
  * @example
151
- * const upload = readBoundedFile(join(uploadsDirectory, name), 5 * 1024 * 1024); // at most 5 MB
186
+ * import { join } from 'node:path';
187
+ * import { readBoundedFile } from 'jg-fs/sync';
188
+ *
189
+ * const upload = readBoundedFile(join('uploads', 'avatar.png'), 5 * 1024 * 1024); // at most 5 MB
152
190
  * @throws
153
191
  * - NOT_A_FILE: if the path doesn't exist, its final component is a symbolic link, or it isn't a regular file
154
192
  * - FILE_TOO_LARGE: if the file holds more than maxBytes bytes
@@ -3,7 +3,7 @@ import { randomUUID } from 'node:crypto';
3
3
  import { closeSync, copyFileSync, fchmodSync, fstatSync, fsyncSync, mkdirSync, openSync, readFileSync, readSync, renameSync, rmSync, symlinkSync, unlinkSync, writeFileSync, } from 'node:fs';
4
4
  import { dirname, join } from 'node:path';
5
5
  import { Exception } from 'jg-exception';
6
- import { assertBufferData, assertTextData, BOUNDED_READ_CHUNK_SIZE, ERRORS, fileTooLarge, notAFile, parseJSONContent, serializeJSONData, } from '../../shared/index.js';
6
+ import { assertBufferData, assertTextData, BOUNDED_READ_CHUNK_SIZE, ERRORS, fileTooLarge, notAFile, parseJsonContent, serializeJsonData, } from '../../shared/index.js';
7
7
  import { getPathElement } from '../general/index.js';
8
8
  import { openWithoutFollowing, readPermissionBits, syncDirectory } from './utilities.js';
9
9
  /**
@@ -11,6 +11,8 @@ import { openWithoutFollowing, readPermissionBits, syncDirectory } from './utili
11
11
  * @param path The path.
12
12
  * @returns Whether the path is a file.
13
13
  * @example
14
+ * import { isFile } from 'jg-fs/sync';
15
+ *
14
16
  * isFile('package.json'); // true
15
17
  */
16
18
  export const isFile = (path) => getPathElement(path)?.isFile ?? false;
@@ -20,6 +22,9 @@ export const isFile = (path) => getPathElement(path)?.isFile ?? false;
20
22
  * @param data The content.
21
23
  * @param options Node.js's writeFile options, such as the encoding or mode.
22
24
  * @example
25
+ * import { writeFile } from 'jg-fs/sync';
26
+ *
27
+ * const csv = 'id,name\n1,Ada\n';
23
28
  * writeFile('out/report.csv', csv, { encoding: 'utf-8' });
24
29
  */
25
30
  export const writeFile = (path, data, options) => {
@@ -31,6 +36,8 @@ export const writeFile = (path, data, options) => {
31
36
  * @param path The file's path.
32
37
  * @param data The text.
33
38
  * @example
39
+ * import { writeTextFile } from 'jg-fs/sync';
40
+ *
34
41
  * writeTextFile('notes/today.md', '# Today');
35
42
  * @throws
36
43
  * - FILE_CONTENT_IS_EMPTY_OR_INVALID: if the data isn't a string
@@ -45,18 +52,23 @@ export const writeTextFile = (path, data) => {
45
52
  * @param data The value, or its JSON text.
46
53
  * @param space The indentation for stringified values.
47
54
  * @example
48
- * writeJSONFile('config.json', { port: 8080 });
55
+ * import { writeJsonFile } from 'jg-fs/sync';
56
+ *
57
+ * writeJsonFile('config.json', { port: 8080 });
49
58
  * @throws
50
59
  * - FILE_CONTENT_IS_EMPTY_OR_INVALID: if the JSON content cannot be stringified or is empty
51
60
  */
52
- export const writeJSONFile = (path, data, space = 2) => {
53
- writeFile(path, serializeJSONData(path, data, space), { encoding: 'utf-8' });
61
+ export const writeJsonFile = (path, data, space = 2) => {
62
+ writeFile(path, serializeJsonData(path, data, space), { encoding: 'utf-8' });
54
63
  };
55
64
  /**
56
65
  * Writes a binary file. An empty Buffer writes an empty file.
57
66
  * @param path The file's path.
58
67
  * @param data The content.
59
68
  * @example
69
+ * import { writeBufferFile } from 'jg-fs/sync';
70
+ *
71
+ * const imageBuffer = Buffer.from('iVBORw0KGgo=', 'base64');
60
72
  * writeBufferFile('avatar.png', imageBuffer);
61
73
  * @throws
62
74
  * - FILE_CONTENT_IS_EMPTY_OR_INVALID: if the data isn't a Buffer
@@ -76,27 +88,39 @@ export function readFile(path, options = null) {
76
88
  * @param path The file's path.
77
89
  * @returns The text.
78
90
  * @example
91
+ * import { readTextFile } from 'jg-fs/sync';
92
+ *
79
93
  * const markdown = readTextFile('README.md');
80
94
  * @throws
81
95
  * - NOT_A_FILE: if the path doesn't exist or is not a file
82
96
  */
83
97
  export const readTextFile = (path) => readFile(path, { encoding: 'utf-8' });
84
98
  /**
85
- * Reads and parses a JSON file.
99
+ * Reads and parses a JSON file, and validates it with the schema when there is one. Without a
100
+ * schema, the value is `unknown`, or the type you pass.
86
101
  * @param path The file's path.
102
+ * @param options The schema, such as a Zod schema, whose errors propagate unchanged.
87
103
  * @returns The parsed value.
88
104
  * @example
89
- * const config = readJSONFile<{ port: number }>('config.json');
105
+ * import { readJsonFile } from 'jg-fs/sync';
106
+ *
107
+ * const config = readJsonFile('config.json', { schema: Config }); // Config's type
108
+ * @example
109
+ * import { readJsonFile } from 'jg-fs/sync';
110
+ *
111
+ * const value = readJsonFile('data.json'); // unknown
90
112
  * @throws
91
113
  * - NOT_A_FILE: if the path doesn't exist or is not a file
92
114
  * - FILE_CONTENT_IS_EMPTY_OR_INVALID: if the file's JSON content cannot be parsed
93
115
  */
94
- export const readJSONFile = (path) => parseJSONContent(path, readTextFile(path));
116
+ export const readJsonFile = (path, options = {}) => parseJsonContent(path, readTextFile(path), options.schema);
95
117
  /**
96
118
  * Reads a binary file. An empty file reads as an empty Buffer.
97
119
  * @param path The file's path.
98
120
  * @returns The content.
99
121
  * @example
122
+ * import { readBufferFile } from 'jg-fs/sync';
123
+ *
100
124
  * const image = readBufferFile('avatar.png');
101
125
  * @throws
102
126
  * - NOT_A_FILE: if the path doesn't exist or is not a file
@@ -107,6 +131,8 @@ export const readBufferFile = (path) => readFile(path, null);
107
131
  * @param srcPath The file to copy.
108
132
  * @param destPath Where to copy it.
109
133
  * @example
134
+ * import { copyFile } from 'jg-fs/sync';
135
+ *
110
136
  * copyFile('config.example.json', 'config.json');
111
137
  * @throws
112
138
  * - NOT_A_FILE: if the srcPath doesn't exist or is not a file
@@ -121,6 +147,8 @@ export const copyFile = (srcPath, destPath) => {
121
147
  * Deletes a file.
122
148
  * @param path The file's path.
123
149
  * @example
150
+ * import { deleteFile } from 'jg-fs/sync';
151
+ *
124
152
  * deleteFile('cache.json');
125
153
  * @throws
126
154
  * - NOT_A_FILE: if the path doesn't exist or is not a file
@@ -136,6 +164,8 @@ export const deleteFile = (path) => {
136
164
  * @param target The file the link points to.
137
165
  * @param path Where to create the link.
138
166
  * @example
167
+ * import { createFileSymLink } from 'jg-fs/sync';
168
+ *
139
169
  * createFileSymLink('config.production.json', 'config.json');
140
170
  * @throws
141
171
  * - NON_EXISTENT_FILE: if the target file does not exist
@@ -144,7 +174,9 @@ export const deleteFile = (path) => {
144
174
  export const createFileSymLink = (target, path) => {
145
175
  const element = getPathElement(target);
146
176
  if (element === null) {
147
- throw new Exception(`The target file '${target}' does not exist.`, ERRORS.NON_EXISTENT_FILE);
177
+ throw new Exception(`The target file '${target}' does not exist.`, {
178
+ code: ERRORS.NON_EXISTENT_FILE,
179
+ });
148
180
  }
149
181
  if (!element.isFile) {
150
182
  throw notAFile(target);
@@ -162,8 +194,11 @@ export const createFileSymLink = (target, path) => {
162
194
  * @param data The content.
163
195
  * @param mode The permission bits of the written file, such as `0o600`.
164
196
  * @example
197
+ * import { writeFileAtomic } from 'jg-fs/sync';
198
+ *
199
+ * const state = { step: 2 };
165
200
  * writeFileAtomic('state.json', JSON.stringify(state)); // readers never see a partial file
166
- * writeFileAtomic('secrets.env', contents, 0o600);
201
+ * writeFileAtomic('secrets.env', 'TOKEN=abc\n', 0o600); // only the owner can read it
167
202
  */
168
203
  export const writeFileAtomic = (path, data, mode) => {
169
204
  const directory = dirname(path);
@@ -205,7 +240,10 @@ export const writeFileAtomic = (path, data, mode) => {
205
240
  * @param maxBytes The largest size accepted, in bytes.
206
241
  * @returns The content.
207
242
  * @example
208
- * const upload = readBoundedFile(join(uploadsDirectory, name), 5 * 1024 * 1024); // at most 5 MB
243
+ * import { join } from 'node:path';
244
+ * import { readBoundedFile } from 'jg-fs/sync';
245
+ *
246
+ * const upload = readBoundedFile(join('uploads', 'avatar.png'), 5 * 1024 * 1024); // at most 5 MB
209
247
  * @throws
210
248
  * - NOT_A_FILE: if the path doesn't exist, its final component is a symbolic link, or it isn't a regular file
211
249
  * - FILE_TOO_LARGE: if the file holds more than maxBytes bytes
@@ -1 +1 @@
1
- {"version":3,"file":"files.js","sourceRoot":"","sources":["../../../src/sync/files/files.ts"],"names":[],"mappings":"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","sourcesContent":["import { Buffer } from 'node:buffer';\nimport { randomUUID } from 'node:crypto';\nimport {\n closeSync,\n copyFileSync,\n fchmodSync,\n fstatSync,\n fsyncSync,\n mkdirSync,\n openSync,\n readFileSync,\n readSync,\n renameSync,\n rmSync,\n symlinkSync,\n unlinkSync,\n writeFileSync,\n type WriteFileOptions,\n} from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { Exception } from 'jg-exception';\n\nimport {\n assertBufferData,\n assertTextData,\n BOUNDED_READ_CHUNK_SIZE,\n ERRORS,\n fileTooLarge,\n notAFile,\n parseJSONContent,\n serializeJSONData,\n type IReadBufferFileOptions,\n type IReadFileOptions,\n type IReadStringFileOptions,\n} from '../../shared/index.js';\nimport { getPathElement } from '../general/index.js';\n\nimport { openWithoutFollowing, readPermissionBits, syncDirectory } from './utilities.js';\n\n/**\n * Checks whether a path exists and is a regular file.\n * @param path The path.\n * @returns Whether the path is a file.\n * @example\n * isFile('package.json'); // true\n */\nexport const isFile = (path: string): boolean => getPathElement(path)?.isFile ?? false;\n\n/**\n * Writes a file, creating its directory first when it doesn't exist.\n * @param path The file's path.\n * @param data The content.\n * @param options Node.js's writeFile options, such as the encoding or mode.\n * @example\n * writeFile('out/report.csv', csv, { encoding: 'utf-8' });\n */\nexport const writeFile = (\n path: string,\n data: string | NodeJS.ArrayBufferView,\n options?: WriteFileOptions,\n): void => {\n mkdirSync(dirname(path), { recursive: true });\n writeFileSync(path, data, options);\n};\n\n/**\n * Writes a UTF-8 text file. An empty string writes an empty file.\n * @param path The file's path.\n * @param data The text.\n * @example\n * writeTextFile('notes/today.md', '# Today');\n * @throws\n * - FILE_CONTENT_IS_EMPTY_OR_INVALID: if the data isn't a string\n */\nexport const writeTextFile = (path: string, data: string): void => {\n assertTextData(path, data);\n writeFile(path, data, { encoding: 'utf-8' });\n};\n\n/**\n * Writes a JSON file. A string is written as given; anything else is stringified.\n * @param path The file's path.\n * @param data The value, or its JSON text.\n * @param space The indentation for stringified values.\n * @example\n * writeJSONFile('config.json', { port: 8080 });\n * @throws\n * - FILE_CONTENT_IS_EMPTY_OR_INVALID: if the JSON content cannot be stringified or is empty\n */\nexport const writeJSONFile = <T = Record<string, unknown>>(\n path: string,\n data: T | string,\n space: number = 2,\n): void => {\n writeFile(path, serializeJSONData(path, data, space), { encoding: 'utf-8' });\n};\n\n/**\n * Writes a binary file. An empty Buffer writes an empty file.\n * @param path The file's path.\n * @param data The content.\n * @example\n * writeBufferFile('avatar.png', imageBuffer);\n * @throws\n * - FILE_CONTENT_IS_EMPTY_OR_INVALID: if the data isn't a Buffer\n */\nexport const writeBufferFile = (path: string, data: Buffer): void => {\n assertBufferData(path, data);\n writeFile(path, data);\n};\n\n/**\n * Reads a file as a string when an encoding is given, or as a Buffer otherwise.\n * @param path The file's path.\n * @param options Node.js's readFile options, such as the encoding.\n * @returns The content.\n * @example\n * readFile('notes.md', 'utf-8'); // a string\n * readFile('avatar.png'); // a Buffer\n * @throws\n * - NOT_A_FILE: if the path doesn't exist or is not a file\n */\nexport function readFile(path: string, options: IReadStringFileOptions): string;\nexport function readFile(path: string, options?: IReadBufferFileOptions): Buffer;\nexport function readFile(path: string, options?: IReadFileOptions): string | Buffer;\nexport function readFile(path: string, options: IReadFileOptions = null): string | Buffer {\n if (!isFile(path)) {\n throw notAFile(path);\n }\n return readFileSync(path, options as Parameters<typeof readFileSync>[1]);\n}\n\n/**\n * Reads a UTF-8 text file. An empty file reads as an empty string.\n * @param path The file's path.\n * @returns The text.\n * @example\n * const markdown = readTextFile('README.md');\n * @throws\n * - NOT_A_FILE: if the path doesn't exist or is not a file\n */\nexport const readTextFile = (path: string): string => readFile(path, { encoding: 'utf-8' });\n\n/**\n * Reads and parses a JSON file.\n * @param path The file's path.\n * @returns The parsed value.\n * @example\n * const config = readJSONFile<{ port: number }>('config.json');\n * @throws\n * - NOT_A_FILE: if the path doesn't exist or is not a file\n * - FILE_CONTENT_IS_EMPTY_OR_INVALID: if the file's JSON content cannot be parsed\n */\nexport const readJSONFile = <T = Record<string, unknown>>(path: string): T =>\n parseJSONContent<T>(path, readTextFile(path));\n\n/**\n * Reads a binary file. An empty file reads as an empty Buffer.\n * @param path The file's path.\n * @returns The content.\n * @example\n * const image = readBufferFile('avatar.png');\n * @throws\n * - NOT_A_FILE: if the path doesn't exist or is not a file\n */\nexport const readBufferFile = (path: string): Buffer => readFile(path, null);\n\n/**\n * Copies a file, replacing the destination when it exists.\n * @param srcPath The file to copy.\n * @param destPath Where to copy it.\n * @example\n * copyFile('config.example.json', 'config.json');\n * @throws\n * - NOT_A_FILE: if the srcPath doesn't exist or is not a file\n */\nexport const copyFile = (srcPath: string, destPath: string): void => {\n if (!isFile(srcPath)) {\n throw notAFile(srcPath);\n }\n copyFileSync(srcPath, destPath);\n};\n\n/**\n * Deletes a file.\n * @param path The file's path.\n * @example\n * deleteFile('cache.json');\n * @throws\n * - NOT_A_FILE: if the path doesn't exist or is not a file\n */\nexport const deleteFile = (path: string): void => {\n if (!isFile(path)) {\n throw notAFile(path);\n }\n unlinkSync(path);\n};\n\n/**\n * Creates a symbolic link to a file.\n * @param target The file the link points to.\n * @param path Where to create the link.\n * @example\n * createFileSymLink('config.production.json', 'config.json');\n * @throws\n * - NON_EXISTENT_FILE: if the target file does not exist\n * - NOT_A_FILE: if the target is not a file\n */\nexport const createFileSymLink = (target: string, path: string): void => {\n const element = getPathElement(target);\n if (element === null) {\n throw new Exception(`The target file '${target}' does not exist.`, ERRORS.NON_EXISTENT_FILE);\n }\n if (!element.isFile) {\n throw notAFile(target);\n }\n symlinkSync(target, path, 'file');\n};\n\n/**\n * Writes a file atomically: readers see either the previous content or the complete new content,\n * never a partial write. The data goes to a temporary file in the same directory, which is flushed\n * to disk and renamed over the path; on POSIX, the directory is flushed too. An explicit mode wins;\n * without one, a replaced file keeps its permission bits and a new file gets the platform default.\n * The temporary file is never more widely readable than the final mode. When writing fails before\n * the rename, the temporary file is removed and the destination is untouched.\n * @param path The file's path.\n * @param data The content.\n * @param mode The permission bits of the written file, such as `0o600`.\n * @example\n * writeFileAtomic('state.json', JSON.stringify(state)); // readers never see a partial file\n * writeFileAtomic('secrets.env', contents, 0o600);\n */\nexport const writeFileAtomic = (\n path: string,\n data: string | NodeJS.ArrayBufferView,\n mode?: number,\n): void => {\n const directory = dirname(path);\n mkdirSync(directory, { recursive: true });\n const finalMode = mode ?? readPermissionBits(path);\n const tempPath = join(directory, `.${randomUUID()}.tmp`);\n let isRenamed = false;\n try {\n // a known final mode is applied with chmod, so the umask can't change it\n const descriptor = openSync(tempPath, 'wx', finalMode === undefined ? 0o666 : 0o600);\n try {\n if (finalMode !== undefined) {\n fchmodSync(descriptor, finalMode);\n }\n writeFileSync(descriptor, data);\n fsyncSync(descriptor);\n } finally {\n closeSync(descriptor);\n }\n renameSync(tempPath, path);\n isRenamed = true;\n } finally {\n if (!isRenamed) {\n rmSync(tempPath, { force: true });\n }\n }\n if (process.platform !== 'win32') {\n syncDirectory(directory);\n }\n};\n\n/**\n * Reads a regular file of at most `maxBytes` bytes. It never follows a symbolic link in the\n * path's last component, though links in parent directories are followed, so callers that need\n * containment combine it with `isPathWithin`. It reads at most `maxBytes + 1` bytes, even when the\n * file grows while it's read.\n * @param path The file's path.\n * @param maxBytes The largest size accepted, in bytes.\n * @returns The content.\n * @example\n * const upload = readBoundedFile(join(uploadsDirectory, name), 5 * 1024 * 1024); // at most 5 MB\n * @throws\n * - NOT_A_FILE: if the path doesn't exist, its final component is a symbolic link, or it isn't a regular file\n * - FILE_TOO_LARGE: if the file holds more than maxBytes bytes\n */\nexport const readBoundedFile = (path: string, maxBytes: number): Buffer => {\n const descriptor = openWithoutFollowing(path);\n try {\n const stats = fstatSync(descriptor);\n if (!stats.isFile()) {\n throw notAFile(path);\n }\n if (stats.size > maxBytes) {\n throw fileTooLarge(path, maxBytes);\n }\n const chunks: Buffer[] = [];\n let totalBytes = 0;\n while (totalBytes <= maxBytes) {\n const chunk = Buffer.allocUnsafe(\n Math.min(BOUNDED_READ_CHUNK_SIZE, maxBytes + 1 - totalBytes),\n );\n const bytesRead = readSync(descriptor, chunk, 0, chunk.length, totalBytes);\n if (bytesRead === 0) {\n break;\n }\n chunks.push(chunk.subarray(0, bytesRead));\n totalBytes += bytesRead;\n }\n if (totalBytes > maxBytes) {\n throw fileTooLarge(path, maxBytes);\n }\n return Buffer.concat(chunks, totalBytes);\n } finally {\n closeSync(descriptor);\n }\n};\n"]}
1
+ {"version":3,"file":"files.js","sourceRoot":"","sources":["../../../src/sync/files/files.ts"],"names":[],"mappings":"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","sourcesContent":["import { Buffer } from 'node:buffer';\nimport { randomUUID } from 'node:crypto';\nimport {\n closeSync,\n copyFileSync,\n fchmodSync,\n fstatSync,\n fsyncSync,\n mkdirSync,\n openSync,\n readFileSync,\n readSync,\n renameSync,\n rmSync,\n symlinkSync,\n unlinkSync,\n writeFileSync,\n type WriteFileOptions,\n} from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { Exception } from 'jg-exception';\n\nimport {\n assertBufferData,\n assertTextData,\n BOUNDED_READ_CHUNK_SIZE,\n ERRORS,\n fileTooLarge,\n notAFile,\n parseJsonContent,\n serializeJsonData,\n type IReadBufferFileOptions,\n type IReadFileOptions,\n type IReadJsonFileOptions,\n type IReadStringFileOptions,\n} from '../../shared/index.js';\nimport { getPathElement } from '../general/index.js';\n\nimport { openWithoutFollowing, readPermissionBits, syncDirectory } from './utilities.js';\n\n/**\n * Checks whether a path exists and is a regular file.\n * @param path The path.\n * @returns Whether the path is a file.\n * @example\n * import { isFile } from 'jg-fs/sync';\n *\n * isFile('package.json'); // true\n */\nexport const isFile = (path: string): boolean => getPathElement(path)?.isFile ?? false;\n\n/**\n * Writes a file, creating its directory first when it doesn't exist.\n * @param path The file's path.\n * @param data The content.\n * @param options Node.js's writeFile options, such as the encoding or mode.\n * @example\n * import { writeFile } from 'jg-fs/sync';\n *\n * const csv = 'id,name\\n1,Ada\\n';\n * writeFile('out/report.csv', csv, { encoding: 'utf-8' });\n */\nexport const writeFile = (\n path: string,\n data: string | NodeJS.ArrayBufferView,\n options?: WriteFileOptions,\n): void => {\n mkdirSync(dirname(path), { recursive: true });\n writeFileSync(path, data, options);\n};\n\n/**\n * Writes a UTF-8 text file. An empty string writes an empty file.\n * @param path The file's path.\n * @param data The text.\n * @example\n * import { writeTextFile } from 'jg-fs/sync';\n *\n * writeTextFile('notes/today.md', '# Today');\n * @throws\n * - FILE_CONTENT_IS_EMPTY_OR_INVALID: if the data isn't a string\n */\nexport const writeTextFile = (path: string, data: string): void => {\n assertTextData(path, data);\n writeFile(path, data, { encoding: 'utf-8' });\n};\n\n/**\n * Writes a JSON file. A string is written as given; anything else is stringified.\n * @param path The file's path.\n * @param data The value, or its JSON text.\n * @param space The indentation for stringified values.\n * @example\n * import { writeJsonFile } from 'jg-fs/sync';\n *\n * writeJsonFile('config.json', { port: 8080 });\n * @throws\n * - FILE_CONTENT_IS_EMPTY_OR_INVALID: if the JSON content cannot be stringified or is empty\n */\nexport const writeJsonFile = <T = Record<string, unknown>>(\n path: string,\n data: T | string,\n space: number = 2,\n): void => {\n writeFile(path, serializeJsonData(path, data, space), { encoding: 'utf-8' });\n};\n\n/**\n * Writes a binary file. An empty Buffer writes an empty file.\n * @param path The file's path.\n * @param data The content.\n * @example\n * import { writeBufferFile } from 'jg-fs/sync';\n *\n * const imageBuffer = Buffer.from('iVBORw0KGgo=', 'base64');\n * writeBufferFile('avatar.png', imageBuffer);\n * @throws\n * - FILE_CONTENT_IS_EMPTY_OR_INVALID: if the data isn't a Buffer\n */\nexport const writeBufferFile = (path: string, data: Buffer): void => {\n assertBufferData(path, data);\n writeFile(path, data);\n};\n\n/**\n * Reads a file as a string when an encoding is given, or as a Buffer otherwise.\n * @param path The file's path.\n * @param options Node.js's readFile options, such as the encoding.\n * @returns The content.\n * @example\n * import { readFile } from 'jg-fs/sync';\n *\n * readFile('notes.md', 'utf-8'); // a string\n * readFile('avatar.png'); // a Buffer\n * @throws\n * - NOT_A_FILE: if the path doesn't exist or is not a file\n */\nexport function readFile(path: string, options: IReadStringFileOptions): string;\nexport function readFile(path: string, options?: IReadBufferFileOptions): Buffer;\nexport function readFile(path: string, options?: IReadFileOptions): string | Buffer;\nexport function readFile(path: string, options: IReadFileOptions = null): string | Buffer {\n if (!isFile(path)) {\n throw notAFile(path);\n }\n return readFileSync(path, options as Parameters<typeof readFileSync>[1]);\n}\n\n/**\n * Reads a UTF-8 text file. An empty file reads as an empty string.\n * @param path The file's path.\n * @returns The text.\n * @example\n * import { readTextFile } from 'jg-fs/sync';\n *\n * const markdown = readTextFile('README.md');\n * @throws\n * - NOT_A_FILE: if the path doesn't exist or is not a file\n */\nexport const readTextFile = (path: string): string => readFile(path, { encoding: 'utf-8' });\n\n/**\n * Reads and parses a JSON file, and validates it with the schema when there is one. Without a\n * schema, the value is `unknown`, or the type you pass.\n * @param path The file's path.\n * @param options The schema, such as a Zod schema, whose errors propagate unchanged.\n * @returns The parsed value.\n * @example\n * import { readJsonFile } from 'jg-fs/sync';\n *\n * const config = readJsonFile('config.json', { schema: Config }); // Config's type\n * @example\n * import { readJsonFile } from 'jg-fs/sync';\n *\n * const value = readJsonFile('data.json'); // unknown\n * @throws\n * - NOT_A_FILE: if the path doesn't exist or is not a file\n * - FILE_CONTENT_IS_EMPTY_OR_INVALID: if the file's JSON content cannot be parsed\n */\nexport const readJsonFile = <T = unknown>(path: string, options: IReadJsonFileOptions<T> = {}): T =>\n parseJsonContent(path, readTextFile(path), options.schema);\n\n/**\n * Reads a binary file. An empty file reads as an empty Buffer.\n * @param path The file's path.\n * @returns The content.\n * @example\n * import { readBufferFile } from 'jg-fs/sync';\n *\n * const image = readBufferFile('avatar.png');\n * @throws\n * - NOT_A_FILE: if the path doesn't exist or is not a file\n */\nexport const readBufferFile = (path: string): Buffer => readFile(path, null);\n\n/**\n * Copies a file, replacing the destination when it exists.\n * @param srcPath The file to copy.\n * @param destPath Where to copy it.\n * @example\n * import { copyFile } from 'jg-fs/sync';\n *\n * copyFile('config.example.json', 'config.json');\n * @throws\n * - NOT_A_FILE: if the srcPath doesn't exist or is not a file\n */\nexport const copyFile = (srcPath: string, destPath: string): void => {\n if (!isFile(srcPath)) {\n throw notAFile(srcPath);\n }\n copyFileSync(srcPath, destPath);\n};\n\n/**\n * Deletes a file.\n * @param path The file's path.\n * @example\n * import { deleteFile } from 'jg-fs/sync';\n *\n * deleteFile('cache.json');\n * @throws\n * - NOT_A_FILE: if the path doesn't exist or is not a file\n */\nexport const deleteFile = (path: string): void => {\n if (!isFile(path)) {\n throw notAFile(path);\n }\n unlinkSync(path);\n};\n\n/**\n * Creates a symbolic link to a file.\n * @param target The file the link points to.\n * @param path Where to create the link.\n * @example\n * import { createFileSymLink } from 'jg-fs/sync';\n *\n * createFileSymLink('config.production.json', 'config.json');\n * @throws\n * - NON_EXISTENT_FILE: if the target file does not exist\n * - NOT_A_FILE: if the target is not a file\n */\nexport const createFileSymLink = (target: string, path: string): void => {\n const element = getPathElement(target);\n if (element === null) {\n throw new Exception(`The target file '${target}' does not exist.`, {\n code: ERRORS.NON_EXISTENT_FILE,\n });\n }\n if (!element.isFile) {\n throw notAFile(target);\n }\n symlinkSync(target, path, 'file');\n};\n\n/**\n * Writes a file atomically: readers see either the previous content or the complete new content,\n * never a partial write. The data goes to a temporary file in the same directory, which is flushed\n * to disk and renamed over the path; on POSIX, the directory is flushed too. An explicit mode wins;\n * without one, a replaced file keeps its permission bits and a new file gets the platform default.\n * The temporary file is never more widely readable than the final mode. When writing fails before\n * the rename, the temporary file is removed and the destination is untouched.\n * @param path The file's path.\n * @param data The content.\n * @param mode The permission bits of the written file, such as `0o600`.\n * @example\n * import { writeFileAtomic } from 'jg-fs/sync';\n *\n * const state = { step: 2 };\n * writeFileAtomic('state.json', JSON.stringify(state)); // readers never see a partial file\n * writeFileAtomic('secrets.env', 'TOKEN=abc\\n', 0o600); // only the owner can read it\n */\nexport const writeFileAtomic = (\n path: string,\n data: string | NodeJS.ArrayBufferView,\n mode?: number,\n): void => {\n const directory = dirname(path);\n mkdirSync(directory, { recursive: true });\n const finalMode = mode ?? readPermissionBits(path);\n const tempPath = join(directory, `.${randomUUID()}.tmp`);\n let isRenamed = false;\n try {\n // a known final mode is applied with chmod, so the umask can't change it\n const descriptor = openSync(tempPath, 'wx', finalMode === undefined ? 0o666 : 0o600);\n try {\n if (finalMode !== undefined) {\n fchmodSync(descriptor, finalMode);\n }\n writeFileSync(descriptor, data);\n fsyncSync(descriptor);\n } finally {\n closeSync(descriptor);\n }\n renameSync(tempPath, path);\n isRenamed = true;\n } finally {\n if (!isRenamed) {\n rmSync(tempPath, { force: true });\n }\n }\n if (process.platform !== 'win32') {\n syncDirectory(directory);\n }\n};\n\n/**\n * Reads a regular file of at most `maxBytes` bytes. It never follows a symbolic link in the\n * path's last component, though links in parent directories are followed, so callers that need\n * containment combine it with `isPathWithin`. It reads at most `maxBytes + 1` bytes, even when the\n * file grows while it's read.\n * @param path The file's path.\n * @param maxBytes The largest size accepted, in bytes.\n * @returns The content.\n * @example\n * import { join } from 'node:path';\n * import { readBoundedFile } from 'jg-fs/sync';\n *\n * const upload = readBoundedFile(join('uploads', 'avatar.png'), 5 * 1024 * 1024); // at most 5 MB\n * @throws\n * - NOT_A_FILE: if the path doesn't exist, its final component is a symbolic link, or it isn't a regular file\n * - FILE_TOO_LARGE: if the file holds more than maxBytes bytes\n */\nexport const readBoundedFile = (path: string, maxBytes: number): Buffer => {\n const descriptor = openWithoutFollowing(path);\n try {\n const stats = fstatSync(descriptor);\n if (!stats.isFile()) {\n throw notAFile(path);\n }\n if (stats.size > maxBytes) {\n throw fileTooLarge(path, maxBytes);\n }\n const chunks: Buffer[] = [];\n let totalBytes = 0;\n while (totalBytes <= maxBytes) {\n const chunk = Buffer.allocUnsafe(\n Math.min(BOUNDED_READ_CHUNK_SIZE, maxBytes + 1 - totalBytes),\n );\n const bytesRead = readSync(descriptor, chunk, 0, chunk.length, totalBytes);\n if (bytesRead === 0) {\n break;\n }\n chunks.push(chunk.subarray(0, bytesRead));\n totalBytes += bytesRead;\n }\n if (totalBytes > maxBytes) {\n throw fileTooLarge(path, maxBytes);\n }\n return Buffer.concat(chunks, totalBytes);\n } finally {\n closeSync(descriptor);\n }\n};\n"]}
@@ -1 +1 @@
1
- export { copyFile, createFileSymLink, deleteFile, isFile, readBoundedFile, readBufferFile, readFile, readJSONFile, readTextFile, writeBufferFile, writeFile, writeFileAtomic, writeJSONFile, writeTextFile, } from './files.js';
1
+ export { copyFile, createFileSymLink, deleteFile, isFile, readBoundedFile, readBufferFile, readFile, readJsonFile, readTextFile, writeBufferFile, writeFile, writeFileAtomic, writeJsonFile, writeTextFile, } from './files.js';
@@ -1,3 +1,3 @@
1
1
  // file actions
2
- export { copyFile, createFileSymLink, deleteFile, isFile, readBoundedFile, readBufferFile, readFile, readJSONFile, readTextFile, writeBufferFile, writeFile, writeFileAtomic, writeJSONFile, writeTextFile, } from './files.js';
2
+ export { copyFile, createFileSymLink, deleteFile, isFile, readBoundedFile, readBufferFile, readFile, readJsonFile, readTextFile, writeBufferFile, writeFile, writeFileAtomic, writeJsonFile, writeTextFile, } from './files.js';
3
3
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/sync/files/index.ts"],"names":[],"mappings":"AAAA,eAAe;AACf,OAAO,EACL,QAAQ,EACR,iBAAiB,EACjB,UAAU,EACV,MAAM,EACN,eAAe,EACf,cAAc,EACd,QAAQ,EACR,YAAY,EACZ,YAAY,EACZ,eAAe,EACf,SAAS,EACT,eAAe,EACf,aAAa,EACb,aAAa,GACd,MAAM,YAAY,CAAC","sourcesContent":["// file actions\nexport {\n copyFile,\n createFileSymLink,\n deleteFile,\n isFile,\n readBoundedFile,\n readBufferFile,\n readFile,\n readJSONFile,\n readTextFile,\n writeBufferFile,\n writeFile,\n writeFileAtomic,\n writeJSONFile,\n writeTextFile,\n} from './files.js';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/sync/files/index.ts"],"names":[],"mappings":"AAAA,eAAe;AACf,OAAO,EACL,QAAQ,EACR,iBAAiB,EACjB,UAAU,EACV,MAAM,EACN,eAAe,EACf,cAAc,EACd,QAAQ,EACR,YAAY,EACZ,YAAY,EACZ,eAAe,EACf,SAAS,EACT,eAAe,EACf,aAAa,EACb,aAAa,GACd,MAAM,YAAY,CAAC","sourcesContent":["// file actions\nexport {\n copyFile,\n createFileSymLink,\n deleteFile,\n isFile,\n readBoundedFile,\n readBufferFile,\n readFile,\n readJsonFile,\n readTextFile,\n writeBufferFile,\n writeFile,\n writeFileAtomic,\n writeJsonFile,\n writeTextFile,\n} from './files.js';\n"]}
@@ -4,6 +4,8 @@ import { type IPathElement } from '../../shared/index.js';
4
4
  * @param path The path.
5
5
  * @returns Whether the path exists.
6
6
  * @example
7
+ * import { pathExists } from 'jg-fs/sync';
8
+ *
7
9
  * pathExists('config.json'); // true when the file exists
8
10
  */
9
11
  export declare const pathExists: (path: string) => boolean;
@@ -12,6 +14,8 @@ export declare const pathExists: (path: string) => boolean;
12
14
  * @param path The path.
13
15
  * @returns The path's details, or `null` when it doesn't exist.
14
16
  * @example
17
+ * import { getPathElement } from 'jg-fs/sync';
18
+ *
15
19
  * const element = getPathElement('logo.png');
16
20
  * element?.size; // the size in bytes, or undefined when the path doesn't exist
17
21
  */
@@ -5,6 +5,8 @@ import { toPathElement } from '../../shared/index.js';
5
5
  * @param path The path.
6
6
  * @returns Whether the path exists.
7
7
  * @example
8
+ * import { pathExists } from 'jg-fs/sync';
9
+ *
8
10
  * pathExists('config.json'); // true when the file exists
9
11
  */
10
12
  export const pathExists = (path) => {
@@ -21,6 +23,8 @@ export const pathExists = (path) => {
21
23
  * @param path The path.
22
24
  * @returns The path's details, or `null` when it doesn't exist.
23
25
  * @example
26
+ * import { getPathElement } from 'jg-fs/sync';
27
+ *
24
28
  * const element = getPathElement('logo.png');
25
29
  * element?.size; // the size in bytes, or undefined when the path doesn't exist
26
30
  */
@@ -1 +1 @@
1
- {"version":3,"file":"general.js","sourceRoot":"","sources":["../../../src/sync/general/general.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAEhD,OAAO,EAAE,aAAa,EAAqB,MAAM,uBAAuB,CAAC;AAEzE;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,IAAY,EAAW,EAAE;IAClD,IAAI,CAAC;QACH,UAAU,CAAC,IAAI,CAAC,CAAC;QACjB,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,IAAY,EAAuB,EAAE;IAClE,IAAI,CAAC;QACH,OAAO,aAAa,CAAC,IAAI,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;IAC9C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC,CAAC","sourcesContent":["import { accessSync, lstatSync } from 'node:fs';\n\nimport { toPathElement, type IPathElement } from '../../shared/index.js';\n\n/**\n * Checks whether a path exists, whether it's a file, a directory, or anything else.\n * @param path The path.\n * @returns Whether the path exists.\n * @example\n * pathExists('config.json'); // true when the file exists\n */\nexport const pathExists = (path: string): boolean => {\n try {\n accessSync(path);\n return true;\n } catch {\n return false;\n }\n};\n\n/**\n * Reads a path's details without following a symbolic link at the path.\n * @param path The path.\n * @returns The path's details, or `null` when it doesn't exist.\n * @example\n * const element = getPathElement('logo.png');\n * element?.size; // the size in bytes, or undefined when the path doesn't exist\n */\nexport const getPathElement = (path: string): IPathElement | null => {\n try {\n return toPathElement(path, lstatSync(path));\n } catch {\n return null;\n }\n};\n"]}
1
+ {"version":3,"file":"general.js","sourceRoot":"","sources":["../../../src/sync/general/general.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAEhD,OAAO,EAAE,aAAa,EAAqB,MAAM,uBAAuB,CAAC;AAEzE;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,IAAY,EAAW,EAAE;IAClD,IAAI,CAAC;QACH,UAAU,CAAC,IAAI,CAAC,CAAC;QACjB,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC,CAAC;AAEF;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,IAAY,EAAuB,EAAE;IAClE,IAAI,CAAC;QACH,OAAO,aAAa,CAAC,IAAI,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;IAC9C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC,CAAC","sourcesContent":["import { accessSync, lstatSync } from 'node:fs';\n\nimport { toPathElement, type IPathElement } from '../../shared/index.js';\n\n/**\n * Checks whether a path exists, whether it's a file, a directory, or anything else.\n * @param path The path.\n * @returns Whether the path exists.\n * @example\n * import { pathExists } from 'jg-fs/sync';\n *\n * pathExists('config.json'); // true when the file exists\n */\nexport const pathExists = (path: string): boolean => {\n try {\n accessSync(path);\n return true;\n } catch {\n return false;\n }\n};\n\n/**\n * Reads a path's details without following a symbolic link at the path.\n * @param path The path.\n * @returns The path's details, or `null` when it doesn't exist.\n * @example\n * import { getPathElement } from 'jg-fs/sync';\n *\n * const element = getPathElement('logo.png');\n * element?.size; // the size in bytes, or undefined when the path doesn't exist\n */\nexport const getPathElement = (path: string): IPathElement | null => {\n try {\n return toPathElement(path, lstatSync(path));\n } catch {\n return null;\n }\n};\n"]}
@@ -1,6 +1,6 @@
1
1
  export { ERRORS } from '../shared/index.js';
2
- export type { IDirectoryElementsKeySort, IDirectoryElementsOptions, IDirectoryPathElements, IPathElement, } from '../shared/index.js';
2
+ export type { IDirectoryElementsKeySort, IDirectoryElementsOptions, IDirectoryPathElements, IPathElement, IReadJsonFileOptions, ISchema, } from '../shared/index.js';
3
3
  export { isPathWithin } from '../shared/index.js';
4
4
  export { getPathElement, pathExists } from './general/index.js';
5
5
  export { copyDirectory, createDirectory, createDirectorySymLink, deleteDirectory, getDirectoryElements, isDirectory, readDirectory, } from './directories/index.js';
6
- export { copyFile, createFileSymLink, deleteFile, isFile, readBoundedFile, readBufferFile, readFile, readJSONFile, readTextFile, writeBufferFile, writeFile, writeFileAtomic, writeJSONFile, writeTextFile, } from './files/index.js';
6
+ export { copyFile, createFileSymLink, deleteFile, isFile, readBoundedFile, readBufferFile, readFile, readJsonFile, readTextFile, writeBufferFile, writeFile, writeFileAtomic, writeJsonFile, writeTextFile, } from './files/index.js';
@@ -6,5 +6,5 @@ export { getPathElement, pathExists } from './general/index.js';
6
6
  // directory actions
7
7
  export { copyDirectory, createDirectory, createDirectorySymLink, deleteDirectory, getDirectoryElements, isDirectory, readDirectory, } from './directories/index.js';
8
8
  // file actions
9
- export { copyFile, createFileSymLink, deleteFile, isFile, readBoundedFile, readBufferFile, readFile, readJSONFile, readTextFile, writeBufferFile, writeFile, writeFileAtomic, writeJSONFile, writeTextFile, } from './files/index.js';
9
+ export { copyFile, createFileSymLink, deleteFile, isFile, readBoundedFile, readBufferFile, readFile, readJsonFile, readTextFile, writeBufferFile, writeFile, writeFileAtomic, writeJsonFile, writeTextFile, } from './files/index.js';
10
10
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/sync/index.ts"],"names":[],"mappings":"AAAA,SAAS;AACT,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAU5C,kBAAkB;AAClB,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAEhE,oBAAoB;AACpB,OAAO,EACL,aAAa,EACb,eAAe,EACf,sBAAsB,EACtB,eAAe,EACf,oBAAoB,EACpB,WAAW,EACX,aAAa,GACd,MAAM,wBAAwB,CAAC;AAEhC,eAAe;AACf,OAAO,EACL,QAAQ,EACR,iBAAiB,EACjB,UAAU,EACV,MAAM,EACN,eAAe,EACf,cAAc,EACd,QAAQ,EACR,YAAY,EACZ,YAAY,EACZ,eAAe,EACf,SAAS,EACT,eAAe,EACf,aAAa,EACb,aAAa,GACd,MAAM,kBAAkB,CAAC","sourcesContent":["// errors\nexport { ERRORS } from '../shared/index.js';\n\n// types\nexport type {\n IDirectoryElementsKeySort,\n IDirectoryElementsOptions,\n IDirectoryPathElements,\n IPathElement,\n} from '../shared/index.js';\n\n// general actions\nexport { isPathWithin } from '../shared/index.js';\nexport { getPathElement, pathExists } from './general/index.js';\n\n// directory actions\nexport {\n copyDirectory,\n createDirectory,\n createDirectorySymLink,\n deleteDirectory,\n getDirectoryElements,\n isDirectory,\n readDirectory,\n} from './directories/index.js';\n\n// file actions\nexport {\n copyFile,\n createFileSymLink,\n deleteFile,\n isFile,\n readBoundedFile,\n readBufferFile,\n readFile,\n readJSONFile,\n readTextFile,\n writeBufferFile,\n writeFile,\n writeFileAtomic,\n writeJSONFile,\n writeTextFile,\n} from './files/index.js';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/sync/index.ts"],"names":[],"mappings":"AAAA,SAAS;AACT,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAY5C,kBAAkB;AAClB,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAEhE,oBAAoB;AACpB,OAAO,EACL,aAAa,EACb,eAAe,EACf,sBAAsB,EACtB,eAAe,EACf,oBAAoB,EACpB,WAAW,EACX,aAAa,GACd,MAAM,wBAAwB,CAAC;AAEhC,eAAe;AACf,OAAO,EACL,QAAQ,EACR,iBAAiB,EACjB,UAAU,EACV,MAAM,EACN,eAAe,EACf,cAAc,EACd,QAAQ,EACR,YAAY,EACZ,YAAY,EACZ,eAAe,EACf,SAAS,EACT,eAAe,EACf,aAAa,EACb,aAAa,GACd,MAAM,kBAAkB,CAAC","sourcesContent":["// errors\nexport { ERRORS } from '../shared/index.js';\n\n// types\nexport type {\n IDirectoryElementsKeySort,\n IDirectoryElementsOptions,\n IDirectoryPathElements,\n IPathElement,\n IReadJsonFileOptions,\n ISchema,\n} from '../shared/index.js';\n\n// general actions\nexport { isPathWithin } from '../shared/index.js';\nexport { getPathElement, pathExists } from './general/index.js';\n\n// directory actions\nexport {\n copyDirectory,\n createDirectory,\n createDirectorySymLink,\n deleteDirectory,\n getDirectoryElements,\n isDirectory,\n readDirectory,\n} from './directories/index.js';\n\n// file actions\nexport {\n copyFile,\n createFileSymLink,\n deleteFile,\n isFile,\n readBoundedFile,\n readBufferFile,\n readFile,\n readJsonFile,\n readTextFile,\n writeBufferFile,\n writeFile,\n writeFileAtomic,\n writeJsonFile,\n writeTextFile,\n} from './files/index.js';\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jg-fs",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "Filesystem helpers for Node.js, async at the root and sync at jg-fs/sync: paths, directories, text, JSON, atomic and bounded files.",
5
5
  "author": "Jesus Graterol",
6
6
  "license": "MIT",
@@ -19,7 +19,8 @@
19
19
  "types": "./dist/index.d.ts",
20
20
  "files": [
21
21
  "dist",
22
- "CHANGELOG.md"
22
+ "CHANGELOG.md",
23
+ "API.md"
23
24
  ],
24
25
  "sideEffects": false,
25
26
  "engines": {
@@ -47,22 +48,25 @@
47
48
  "node"
48
49
  ],
49
50
  "dependencies": {
50
- "jg-exception": "^1.0.0",
51
- "jg-utilities": "^1.0.0"
51
+ "jg-exception": "^1.1.0",
52
+ "jg-utilities": "^1.1.0"
52
53
  },
53
54
  "devDependencies": {
54
55
  "@jg-packages/eslint-config": "0.0.0",
55
56
  "@jg-packages/tsconfig": "0.0.0",
56
57
  "@jg-packages/vitest-config": "0.0.0",
57
58
  "@types/node": "24.19.2",
59
+ "@vitest/coverage-v8": "5.0.5",
58
60
  "eslint": "10.12.0",
59
61
  "typescript": "6.0.3",
60
- "vitest": "5.0.5"
62
+ "vitest": "5.0.5",
63
+ "zod": "4.6.7"
61
64
  },
62
65
  "scripts": {
63
- "build": "node ../../internal/build-tools/src/clean-dist.ts && tsc -p tsconfig.build.json",
66
+ "build": "node ../../internal/build-tools/src/clean-dist.ts && tsc -p tsconfig.build.json && node ../../internal/api-reference/src/write-api-markdown.ts",
64
67
  "lint": "eslint .",
65
68
  "test": "pnpm test:unit && pnpm test:integration",
69
+ "test:coverage": "vitest run --coverage --project unit --project integration",
66
70
  "test:integration": "vitest run --project integration",
67
71
  "test:unit": "vitest run --project unit",
68
72
  "typecheck": "tsc -p tsconfig.json"