@fgv/ts-json-base 5.0.2 → 5.1.0-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.
- package/dist/packlets/converters/converters.js +36 -14
- package/dist/packlets/file-tree/directoryItem.js +35 -4
- package/dist/packlets/file-tree/fileItem.js +37 -9
- package/dist/packlets/file-tree/fileTreeAccessors.js +24 -1
- package/dist/packlets/file-tree/filterSpec.js +74 -0
- package/dist/packlets/file-tree/fsTree.js +73 -12
- package/dist/packlets/file-tree/in-memory/inMemoryTree.js +204 -21
- package/dist/packlets/file-tree/in-memory/treeBuilder.js +23 -0
- package/dist/packlets/file-tree/index.browser.js +1 -0
- package/dist/packlets/file-tree/index.js +1 -0
- package/dist/packlets/json-file/file.js +1 -1
- package/dist/packlets/json-file/jsonFsHelper.js +1 -1
- package/dist/packlets/validators/validators.js +8 -8
- package/dist/ts-json-base.d.ts +290 -61
- package/dist/tsdoc-metadata.json +1 -1
- package/lib/packlets/converters/converters.d.ts +20 -13
- package/lib/packlets/converters/converters.js +36 -13
- package/lib/packlets/file-tree/directoryItem.d.ts +13 -5
- package/lib/packlets/file-tree/directoryItem.js +34 -3
- package/lib/packlets/file-tree/fileItem.d.ts +26 -13
- package/lib/packlets/file-tree/fileItem.js +36 -8
- package/lib/packlets/file-tree/fileTreeAccessors.d.ts +141 -1
- package/lib/packlets/file-tree/fileTreeAccessors.js +26 -0
- package/lib/packlets/file-tree/filterSpec.d.ts +10 -0
- package/lib/packlets/file-tree/filterSpec.js +77 -0
- package/lib/packlets/file-tree/fsTree.d.ts +29 -13
- package/lib/packlets/file-tree/fsTree.js +72 -11
- package/lib/packlets/file-tree/in-memory/inMemoryTree.d.ts +29 -13
- package/lib/packlets/file-tree/in-memory/inMemoryTree.js +203 -20
- package/lib/packlets/file-tree/in-memory/treeBuilder.d.ts +9 -0
- package/lib/packlets/file-tree/in-memory/treeBuilder.js +23 -0
- package/lib/packlets/file-tree/index.browser.d.ts +1 -0
- package/lib/packlets/file-tree/index.browser.js +1 -0
- package/lib/packlets/file-tree/index.d.ts +1 -0
- package/lib/packlets/file-tree/index.js +1 -0
- package/lib/packlets/json-file/file.d.ts +1 -1
- package/lib/packlets/json-file/file.js +1 -1
- package/lib/packlets/json-file/jsonFsHelper.d.ts +1 -1
- package/lib/packlets/json-file/jsonFsHelper.js +1 -1
- package/lib/packlets/validators/validators.d.ts +9 -9
- package/lib/packlets/validators/validators.js +8 -8
- package/package.json +18 -18
|
@@ -1,6 +1,42 @@
|
|
|
1
|
-
import { Result } from '@fgv/ts-utils';
|
|
1
|
+
import { DetailedResult, Result } from '@fgv/ts-utils';
|
|
2
2
|
import { Converter, Validator } from '@fgv/ts-utils';
|
|
3
3
|
import { JsonValue } from '../json';
|
|
4
|
+
/**
|
|
5
|
+
* Indicates the persistence capability of a save operation.
|
|
6
|
+
* - `persistent`: Changes are saved to durable storage (e.g., file system).
|
|
7
|
+
* - `transient`: Changes are saved in memory only and will be lost on reload.
|
|
8
|
+
* @public
|
|
9
|
+
*/
|
|
10
|
+
export type SaveCapability = 'persistent' | 'transient';
|
|
11
|
+
/**
|
|
12
|
+
* Indicates the reason a save operation cannot be performed.
|
|
13
|
+
* - `not-supported`: The accessors do not support mutation.
|
|
14
|
+
* - `read-only`: The file or file system is read-only.
|
|
15
|
+
* - `not-mutable`: Mutability is disabled in configuration.
|
|
16
|
+
* - `path-excluded`: The path is excluded by the mutability filter.
|
|
17
|
+
* - `permission-denied`: Insufficient permissions to write.
|
|
18
|
+
* @public
|
|
19
|
+
*/
|
|
20
|
+
export type SaveFailureReason = 'not-supported' | 'read-only' | 'not-mutable' | 'path-excluded' | 'permission-denied';
|
|
21
|
+
/**
|
|
22
|
+
* Detail type for getIsMutable results.
|
|
23
|
+
* @public
|
|
24
|
+
*/
|
|
25
|
+
export type SaveDetail = SaveCapability | SaveFailureReason;
|
|
26
|
+
/**
|
|
27
|
+
* Filter specification for controlling which paths are mutable.
|
|
28
|
+
* @public
|
|
29
|
+
*/
|
|
30
|
+
export interface IFilterSpec {
|
|
31
|
+
/**
|
|
32
|
+
* Paths or patterns to include. If specified, only matching paths are mutable.
|
|
33
|
+
*/
|
|
34
|
+
include?: (string | RegExp)[];
|
|
35
|
+
/**
|
|
36
|
+
* Paths or patterns to exclude. Matching paths are not mutable.
|
|
37
|
+
*/
|
|
38
|
+
exclude?: (string | RegExp)[];
|
|
39
|
+
}
|
|
4
40
|
/**
|
|
5
41
|
* Type of item in a file tree.
|
|
6
42
|
* @public
|
|
@@ -18,6 +54,13 @@ export type ContentTypeFactory<TCT extends string = string> = (filePath: string,
|
|
|
18
54
|
export interface IFileTreeInitParams<TCT extends string = string> {
|
|
19
55
|
prefix?: string;
|
|
20
56
|
inferContentType?: ContentTypeFactory<TCT>;
|
|
57
|
+
/**
|
|
58
|
+
* Controls mutability of the file tree.
|
|
59
|
+
* - `undefined` or `false`: No files are mutable.
|
|
60
|
+
* - `true`: All files are mutable.
|
|
61
|
+
* - `IFilterSpec`: Only files matching the filter are mutable.
|
|
62
|
+
*/
|
|
63
|
+
mutable?: boolean | IFilterSpec;
|
|
21
64
|
}
|
|
22
65
|
/**
|
|
23
66
|
* Interface for a file in a file tree.
|
|
@@ -68,6 +111,27 @@ export interface IFileTreeFileItem<TCT extends string = string> {
|
|
|
68
111
|
* `Failure` with an error message otherwise.
|
|
69
112
|
*/
|
|
70
113
|
getRawContents(): Result<string>;
|
|
114
|
+
/**
|
|
115
|
+
* Indicates whether this file can be saved.
|
|
116
|
+
* @returns `DetailedSuccess` with {@link FileTree.SaveCapability} if the file can be saved,
|
|
117
|
+
* or `DetailedFailure` with {@link FileTree.SaveFailureReason} if it cannot.
|
|
118
|
+
* @remarks This property is optional. If not present, the file is not mutable.
|
|
119
|
+
*/
|
|
120
|
+
getIsMutable(): DetailedResult<boolean, SaveDetail>;
|
|
121
|
+
/**
|
|
122
|
+
* Sets the contents of the file from a JSON value.
|
|
123
|
+
* @param json - The JSON value to serialize and save.
|
|
124
|
+
* @returns `Success` if the file was saved, or `Failure` with an error message.
|
|
125
|
+
* @remarks This method is optional. If not present, the file is not mutable.
|
|
126
|
+
*/
|
|
127
|
+
setContents(json: JsonValue): Result<JsonValue>;
|
|
128
|
+
/**
|
|
129
|
+
* Sets the raw contents of the file.
|
|
130
|
+
* @param contents - The string contents to save.
|
|
131
|
+
* @returns `Success` if the file was saved, or `Failure` with an error message.
|
|
132
|
+
* @remarks This method is optional. If not present, the file is not mutable.
|
|
133
|
+
*/
|
|
134
|
+
setRawContents(contents: string): Result<string>;
|
|
71
135
|
}
|
|
72
136
|
/**
|
|
73
137
|
* Interface for a directory in a file tree.
|
|
@@ -92,6 +156,21 @@ export interface IFileTreeDirectoryItem<TCT extends string = string> {
|
|
|
92
156
|
* or `Failure` with an error message otherwise.
|
|
93
157
|
*/
|
|
94
158
|
getChildren(): Result<ReadonlyArray<FileTreeItem<TCT>>>;
|
|
159
|
+
/**
|
|
160
|
+
* Creates a new file as a child of this directory.
|
|
161
|
+
* @param name - The file name to create.
|
|
162
|
+
* @param contents - The string contents to write.
|
|
163
|
+
* @returns `Success` with the new file item, or `Failure` with an error message.
|
|
164
|
+
* @remarks This method is optional. Only available on mutable directory items.
|
|
165
|
+
*/
|
|
166
|
+
createChildFile?(name: string, contents: string): Result<IFileTreeFileItem<TCT>>;
|
|
167
|
+
/**
|
|
168
|
+
* Creates a new subdirectory as a child of this directory.
|
|
169
|
+
* @param name - The directory name to create.
|
|
170
|
+
* @returns `Success` with the new directory item, or `Failure` with an error message.
|
|
171
|
+
* @remarks This method is optional. Only available on mutable directory items.
|
|
172
|
+
*/
|
|
173
|
+
createChildDirectory?(name: string): Result<IFileTreeDirectoryItem<TCT>>;
|
|
95
174
|
}
|
|
96
175
|
/**
|
|
97
176
|
* Type for an item in a file tree.
|
|
@@ -155,4 +234,65 @@ export interface IFileTreeAccessors<TCT extends string = string> {
|
|
|
155
234
|
*/
|
|
156
235
|
getChildren(path: string): Result<ReadonlyArray<FileTreeItem<TCT>>>;
|
|
157
236
|
}
|
|
237
|
+
/**
|
|
238
|
+
* Extended accessors interface that supports mutation operations.
|
|
239
|
+
* @public
|
|
240
|
+
*/
|
|
241
|
+
export interface IMutableFileTreeAccessors<TCT extends string = string> extends IFileTreeAccessors<TCT> {
|
|
242
|
+
/**
|
|
243
|
+
* Checks if a file at the given path can be saved.
|
|
244
|
+
* @param path - The path to check.
|
|
245
|
+
* @returns `DetailedSuccess` with {@link FileTree.SaveCapability} if the file can be saved,
|
|
246
|
+
* or `DetailedFailure` with {@link FileTree.SaveFailureReason} if it cannot.
|
|
247
|
+
*/
|
|
248
|
+
fileIsMutable(path: string): DetailedResult<boolean, SaveDetail>;
|
|
249
|
+
/**
|
|
250
|
+
* Saves the contents to a file at the given path.
|
|
251
|
+
* @param path - The path of the file to save.
|
|
252
|
+
* @param contents - The string contents to save.
|
|
253
|
+
* @returns `Success` if the file was saved, or `Failure` with an error message.
|
|
254
|
+
*/
|
|
255
|
+
saveFileContents(path: string, contents: string): Result<string>;
|
|
256
|
+
/**
|
|
257
|
+
* Creates a directory at the given path, including any missing parent directories.
|
|
258
|
+
* @param path - The path of the directory to create.
|
|
259
|
+
* @returns `Success` with the absolute path if created, or `Failure` with an error message.
|
|
260
|
+
*/
|
|
261
|
+
createDirectory?(path: string): Result<string>;
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Extended accessors interface that supports persistence operations.
|
|
265
|
+
* @public
|
|
266
|
+
*/
|
|
267
|
+
export interface IPersistentFileTreeAccessors<TCT extends string = string> extends IMutableFileTreeAccessors<TCT> {
|
|
268
|
+
/**
|
|
269
|
+
* Synchronize all dirty files to persistent storage.
|
|
270
|
+
* @returns Promise resolving to success or failure
|
|
271
|
+
*/
|
|
272
|
+
syncToDisk(): Promise<Result<void>>;
|
|
273
|
+
/**
|
|
274
|
+
* Check if there are unsaved changes.
|
|
275
|
+
* @returns True if there are dirty files
|
|
276
|
+
*/
|
|
277
|
+
isDirty(): boolean;
|
|
278
|
+
/**
|
|
279
|
+
* Get paths of all files with unsaved changes.
|
|
280
|
+
* @returns Array of dirty file paths
|
|
281
|
+
*/
|
|
282
|
+
getDirtyPaths(): string[];
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* Type guard to check if accessors support mutation.
|
|
286
|
+
* @param accessors - The accessors to check.
|
|
287
|
+
* @returns `true` if the accessors implement {@link FileTree.IMutableFileTreeAccessors}.
|
|
288
|
+
* @public
|
|
289
|
+
*/
|
|
290
|
+
export declare function isMutableAccessors<TCT extends string = string>(accessors: IFileTreeAccessors<TCT>): accessors is IMutableFileTreeAccessors<TCT>;
|
|
291
|
+
/**
|
|
292
|
+
* Type guard to check if accessors support persistence.
|
|
293
|
+
* @param accessors - The accessors to check.
|
|
294
|
+
* @returns `true` if the accessors implement {@link FileTree.IPersistentFileTreeAccessors}.
|
|
295
|
+
* @public
|
|
296
|
+
*/
|
|
297
|
+
export declare function isPersistentAccessors<TCT extends string = string>(accessors: IFileTreeAccessors<TCT>): accessors is IPersistentFileTreeAccessors<TCT>;
|
|
158
298
|
//# sourceMappingURL=fileTreeAccessors.d.ts.map
|
|
@@ -21,4 +21,30 @@
|
|
|
21
21
|
* SOFTWARE.
|
|
22
22
|
*/
|
|
23
23
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
24
|
+
exports.isMutableAccessors = isMutableAccessors;
|
|
25
|
+
exports.isPersistentAccessors = isPersistentAccessors;
|
|
26
|
+
/**
|
|
27
|
+
* Type guard to check if accessors support mutation.
|
|
28
|
+
* @param accessors - The accessors to check.
|
|
29
|
+
* @returns `true` if the accessors implement {@link FileTree.IMutableFileTreeAccessors}.
|
|
30
|
+
* @public
|
|
31
|
+
*/
|
|
32
|
+
function isMutableAccessors(accessors) {
|
|
33
|
+
const mutable = accessors;
|
|
34
|
+
return typeof mutable.fileIsMutable === 'function' && typeof mutable.saveFileContents === 'function';
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Type guard to check if accessors support persistence.
|
|
38
|
+
* @param accessors - The accessors to check.
|
|
39
|
+
* @returns `true` if the accessors implement {@link FileTree.IPersistentFileTreeAccessors}.
|
|
40
|
+
* @public
|
|
41
|
+
*/
|
|
42
|
+
function isPersistentAccessors(accessors) {
|
|
43
|
+
const persistent = accessors;
|
|
44
|
+
/* c8 ignore next 6 - no current accessor implements IPersistentFileTreeAccessors */
|
|
45
|
+
return (isMutableAccessors(accessors) &&
|
|
46
|
+
typeof persistent.syncToDisk === 'function' &&
|
|
47
|
+
typeof persistent.isDirty === 'function' &&
|
|
48
|
+
typeof persistent.getDirtyPaths === 'function');
|
|
49
|
+
}
|
|
24
50
|
//# sourceMappingURL=fileTreeAccessors.js.map
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { IFilterSpec } from './fileTreeAccessors';
|
|
2
|
+
/**
|
|
3
|
+
* Checks if a path is allowed by a mutability configuration.
|
|
4
|
+
* @param path - The path to check.
|
|
5
|
+
* @param mutable - The mutability configuration.
|
|
6
|
+
* @returns `true` if the path is mutable according to the configuration.
|
|
7
|
+
* @public
|
|
8
|
+
*/
|
|
9
|
+
export declare function isPathMutable(path: string, mutable: boolean | IFilterSpec | undefined): boolean;
|
|
10
|
+
//# sourceMappingURL=filterSpec.d.ts.map
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* Copyright (c) 2025 Erik Fortune
|
|
4
|
+
*
|
|
5
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
* in the Software without restriction, including without limitation the rights
|
|
8
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
* furnished to do so, subject to the following conditions:
|
|
11
|
+
*
|
|
12
|
+
* The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
* copies or substantial portions of the Software.
|
|
14
|
+
*
|
|
15
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
* SOFTWARE.
|
|
22
|
+
*/
|
|
23
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
24
|
+
exports.isPathMutable = isPathMutable;
|
|
25
|
+
/**
|
|
26
|
+
* Checks if a path matches a single pattern (string or RegExp).
|
|
27
|
+
* @param path - The path to check.
|
|
28
|
+
* @param pattern - The pattern to match against.
|
|
29
|
+
* @returns `true` if the path matches the pattern.
|
|
30
|
+
* @internal
|
|
31
|
+
*/
|
|
32
|
+
function matchesPattern(path, pattern) {
|
|
33
|
+
if (typeof pattern === 'string') {
|
|
34
|
+
return path === pattern || path.startsWith(pattern + '/') || path.includes(pattern);
|
|
35
|
+
}
|
|
36
|
+
return pattern.test(path);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Checks if a path matches any pattern in an array.
|
|
40
|
+
* @param path - The path to check.
|
|
41
|
+
* @param patterns - The patterns to match against.
|
|
42
|
+
* @returns `true` if the path matches any pattern.
|
|
43
|
+
* @internal
|
|
44
|
+
*/
|
|
45
|
+
function matchesAny(path, patterns) {
|
|
46
|
+
if (!patterns || patterns.length === 0) {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
return patterns.some((pattern) => matchesPattern(path, pattern));
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Checks if a path is allowed by a mutability configuration.
|
|
53
|
+
* @param path - The path to check.
|
|
54
|
+
* @param mutable - The mutability configuration.
|
|
55
|
+
* @returns `true` if the path is mutable according to the configuration.
|
|
56
|
+
* @public
|
|
57
|
+
*/
|
|
58
|
+
function isPathMutable(path, mutable) {
|
|
59
|
+
if (mutable === undefined || mutable === false) {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
if (mutable === true) {
|
|
63
|
+
return true;
|
|
64
|
+
}
|
|
65
|
+
const { include, exclude } = mutable;
|
|
66
|
+
// If exclude patterns are specified and path matches, it's not mutable
|
|
67
|
+
if (matchesAny(path, exclude)) {
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
// If include patterns are specified, path must match at least one
|
|
71
|
+
if (include && include.length > 0) {
|
|
72
|
+
return matchesAny(path, include);
|
|
73
|
+
}
|
|
74
|
+
// No include patterns means all paths (not excluded) are mutable
|
|
75
|
+
return true;
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=filterSpec.js.map
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { FileTreeItem,
|
|
2
|
-
import { Result } from '@fgv/ts-utils';
|
|
1
|
+
import { FileTreeItem, IFileTreeInitParams, IMutableFileTreeAccessors, SaveDetail } from './fileTreeAccessors';
|
|
2
|
+
import { DetailedResult, Result } from '@fgv/ts-utils';
|
|
3
3
|
/**
|
|
4
|
-
* Implementation of {@link FileTree.
|
|
5
|
-
* file system to access files and directories.
|
|
4
|
+
* Implementation of {@link FileTree.IMutableFileTreeAccessors} that uses the
|
|
5
|
+
* file system to access and modify files and directories.
|
|
6
6
|
* @public
|
|
7
7
|
*/
|
|
8
|
-
export declare class FsFileTreeAccessors<TCT extends string = string> implements
|
|
8
|
+
export declare class FsFileTreeAccessors<TCT extends string = string> implements IMutableFileTreeAccessors<TCT> {
|
|
9
9
|
/**
|
|
10
10
|
* Optional path prefix to prepend to all paths.
|
|
11
11
|
*/
|
|
@@ -15,6 +15,10 @@ export declare class FsFileTreeAccessors<TCT extends string = string> implements
|
|
|
15
15
|
* @public
|
|
16
16
|
*/
|
|
17
17
|
protected readonly _inferContentType: (filePath: string) => Result<TCT | undefined>;
|
|
18
|
+
/**
|
|
19
|
+
* The mutability configuration.
|
|
20
|
+
*/
|
|
21
|
+
private readonly _mutable;
|
|
18
22
|
/**
|
|
19
23
|
* Construct a new instance of the {@link FileTree.FsFileTreeAccessors | FsFileTreeAccessors} class.
|
|
20
24
|
* @param params - Optional {@link FileTree.IFileTreeInitParams | initialization parameters}.
|
|
@@ -22,36 +26,48 @@ export declare class FsFileTreeAccessors<TCT extends string = string> implements
|
|
|
22
26
|
*/
|
|
23
27
|
constructor(params?: IFileTreeInitParams<TCT>);
|
|
24
28
|
/**
|
|
25
|
-
* {@
|
|
29
|
+
* {@inheritDoc FileTree.IFileTreeAccessors.resolveAbsolutePath}
|
|
26
30
|
*/
|
|
27
31
|
resolveAbsolutePath(...paths: string[]): string;
|
|
28
32
|
/**
|
|
29
|
-
* {@
|
|
33
|
+
* {@inheritDoc FileTree.IFileTreeAccessors.getExtension}
|
|
30
34
|
*/
|
|
31
35
|
getExtension(itemPath: string): string;
|
|
32
36
|
/**
|
|
33
|
-
* {@
|
|
37
|
+
* {@inheritDoc FileTree.IFileTreeAccessors.getBaseName}
|
|
34
38
|
*/
|
|
35
39
|
getBaseName(itemPath: string, suffix?: string): string;
|
|
36
40
|
/**
|
|
37
|
-
* {@
|
|
41
|
+
* {@inheritDoc FileTree.IFileTreeAccessors.joinPaths}
|
|
38
42
|
*/
|
|
39
43
|
joinPaths(...paths: string[]): string;
|
|
40
44
|
/**
|
|
41
|
-
* {@
|
|
45
|
+
* {@inheritDoc FileTree.IFileTreeAccessors.getItem}
|
|
42
46
|
*/
|
|
43
47
|
getItem(itemPath: string): Result<FileTreeItem<TCT>>;
|
|
44
48
|
/**
|
|
45
|
-
* {@
|
|
49
|
+
* {@inheritDoc FileTree.IFileTreeAccessors.getFileContents}
|
|
46
50
|
*/
|
|
47
51
|
getFileContents(filePath: string): Result<string>;
|
|
48
52
|
/**
|
|
49
|
-
* {@
|
|
53
|
+
* {@inheritDoc FileTree.IFileTreeAccessors.getFileContentType}
|
|
50
54
|
*/
|
|
51
55
|
getFileContentType(filePath: string, provided?: string): Result<TCT | undefined>;
|
|
52
56
|
/**
|
|
53
|
-
* {@
|
|
57
|
+
* {@inheritDoc FileTree.IFileTreeAccessors.getChildren}
|
|
54
58
|
*/
|
|
55
59
|
getChildren(dirPath: string): Result<ReadonlyArray<FileTreeItem<TCT>>>;
|
|
60
|
+
/**
|
|
61
|
+
* {@inheritDoc FileTree.IMutableFileTreeAccessors.fileIsMutable}
|
|
62
|
+
*/
|
|
63
|
+
fileIsMutable(path: string): DetailedResult<boolean, SaveDetail>;
|
|
64
|
+
/**
|
|
65
|
+
* {@inheritDoc FileTree.IMutableFileTreeAccessors.saveFileContents}
|
|
66
|
+
*/
|
|
67
|
+
saveFileContents(path: string, contents: string): Result<string>;
|
|
68
|
+
/**
|
|
69
|
+
* {@inheritDoc FileTree.IMutableFileTreeAccessors.createDirectory}
|
|
70
|
+
*/
|
|
71
|
+
createDirectory(dirPath: string): Result<string>;
|
|
56
72
|
}
|
|
57
73
|
//# sourceMappingURL=fsTree.d.ts.map
|
|
@@ -30,9 +30,10 @@ const fs_1 = __importDefault(require("fs"));
|
|
|
30
30
|
const ts_utils_1 = require("@fgv/ts-utils");
|
|
31
31
|
const directoryItem_1 = require("./directoryItem");
|
|
32
32
|
const fileItem_1 = require("./fileItem");
|
|
33
|
+
const filterSpec_1 = require("./filterSpec");
|
|
33
34
|
/**
|
|
34
|
-
* Implementation of {@link FileTree.
|
|
35
|
-
* file system to access files and directories.
|
|
35
|
+
* Implementation of {@link FileTree.IMutableFileTreeAccessors} that uses the
|
|
36
|
+
* file system to access and modify files and directories.
|
|
36
37
|
* @public
|
|
37
38
|
*/
|
|
38
39
|
class FsFileTreeAccessors {
|
|
@@ -42,12 +43,14 @@ class FsFileTreeAccessors {
|
|
|
42
43
|
* @public
|
|
43
44
|
*/
|
|
44
45
|
constructor(params) {
|
|
45
|
-
var _a;
|
|
46
|
+
var _a, _b;
|
|
46
47
|
this.prefix = params === null || params === void 0 ? void 0 : params.prefix;
|
|
47
48
|
this._inferContentType = (_a = params === null || params === void 0 ? void 0 : params.inferContentType) !== null && _a !== void 0 ? _a : fileItem_1.FileItem.defaultInferContentType;
|
|
49
|
+
/* c8 ignore next 1 - defensive default when params is undefined */
|
|
50
|
+
this._mutable = (_b = params === null || params === void 0 ? void 0 : params.mutable) !== null && _b !== void 0 ? _b : false;
|
|
48
51
|
}
|
|
49
52
|
/**
|
|
50
|
-
* {@
|
|
53
|
+
* {@inheritDoc FileTree.IFileTreeAccessors.resolveAbsolutePath}
|
|
51
54
|
*/
|
|
52
55
|
resolveAbsolutePath(...paths) {
|
|
53
56
|
if (this.prefix && !path_1.default.isAbsolute(paths[0])) {
|
|
@@ -56,25 +59,25 @@ class FsFileTreeAccessors {
|
|
|
56
59
|
return path_1.default.resolve(...paths);
|
|
57
60
|
}
|
|
58
61
|
/**
|
|
59
|
-
* {@
|
|
62
|
+
* {@inheritDoc FileTree.IFileTreeAccessors.getExtension}
|
|
60
63
|
*/
|
|
61
64
|
getExtension(itemPath) {
|
|
62
65
|
return path_1.default.extname(itemPath);
|
|
63
66
|
}
|
|
64
67
|
/**
|
|
65
|
-
* {@
|
|
68
|
+
* {@inheritDoc FileTree.IFileTreeAccessors.getBaseName}
|
|
66
69
|
*/
|
|
67
70
|
getBaseName(itemPath, suffix) {
|
|
68
71
|
return path_1.default.basename(itemPath, suffix);
|
|
69
72
|
}
|
|
70
73
|
/**
|
|
71
|
-
* {@
|
|
74
|
+
* {@inheritDoc FileTree.IFileTreeAccessors.joinPaths}
|
|
72
75
|
*/
|
|
73
76
|
joinPaths(...paths) {
|
|
74
77
|
return path_1.default.join(...paths);
|
|
75
78
|
}
|
|
76
79
|
/**
|
|
77
|
-
* {@
|
|
80
|
+
* {@inheritDoc FileTree.IFileTreeAccessors.getItem}
|
|
78
81
|
*/
|
|
79
82
|
getItem(itemPath) {
|
|
80
83
|
return (0, ts_utils_1.captureResult)(() => {
|
|
@@ -90,13 +93,13 @@ class FsFileTreeAccessors {
|
|
|
90
93
|
});
|
|
91
94
|
}
|
|
92
95
|
/**
|
|
93
|
-
* {@
|
|
96
|
+
* {@inheritDoc FileTree.IFileTreeAccessors.getFileContents}
|
|
94
97
|
*/
|
|
95
98
|
getFileContents(filePath) {
|
|
96
99
|
return (0, ts_utils_1.captureResult)(() => fs_1.default.readFileSync(this.resolveAbsolutePath(filePath), 'utf8'));
|
|
97
100
|
}
|
|
98
101
|
/**
|
|
99
|
-
* {@
|
|
102
|
+
* {@inheritDoc FileTree.IFileTreeAccessors.getFileContentType}
|
|
100
103
|
*/
|
|
101
104
|
getFileContentType(filePath, provided) {
|
|
102
105
|
if (provided !== undefined) {
|
|
@@ -106,7 +109,7 @@ class FsFileTreeAccessors {
|
|
|
106
109
|
return this._inferContentType(filePath);
|
|
107
110
|
}
|
|
108
111
|
/**
|
|
109
|
-
* {@
|
|
112
|
+
* {@inheritDoc FileTree.IFileTreeAccessors.getChildren}
|
|
110
113
|
*/
|
|
111
114
|
getChildren(dirPath) {
|
|
112
115
|
return (0, ts_utils_1.captureResult)(() => {
|
|
@@ -124,6 +127,64 @@ class FsFileTreeAccessors {
|
|
|
124
127
|
return children;
|
|
125
128
|
});
|
|
126
129
|
}
|
|
130
|
+
/**
|
|
131
|
+
* {@inheritDoc FileTree.IMutableFileTreeAccessors.fileIsMutable}
|
|
132
|
+
*/
|
|
133
|
+
fileIsMutable(path) {
|
|
134
|
+
const absolutePath = this.resolveAbsolutePath(path);
|
|
135
|
+
// Check if mutability is disabled
|
|
136
|
+
if (this._mutable === false) {
|
|
137
|
+
return (0, ts_utils_1.failWithDetail)(`${absolutePath}: mutability is disabled`, 'not-mutable');
|
|
138
|
+
}
|
|
139
|
+
// Check if path is excluded by filter
|
|
140
|
+
if (!(0, filterSpec_1.isPathMutable)(absolutePath, this._mutable)) {
|
|
141
|
+
return (0, ts_utils_1.failWithDetail)(`${absolutePath}: path is excluded by filter`, 'path-excluded');
|
|
142
|
+
}
|
|
143
|
+
// Check file system permissions
|
|
144
|
+
try {
|
|
145
|
+
// Check if file exists
|
|
146
|
+
if (fs_1.default.existsSync(absolutePath)) {
|
|
147
|
+
fs_1.default.accessSync(absolutePath, fs_1.default.constants.W_OK);
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
// Check if parent directory is writable
|
|
151
|
+
const parentDir = absolutePath.substring(0, absolutePath.lastIndexOf('/'));
|
|
152
|
+
if (parentDir && fs_1.default.existsSync(parentDir)) {
|
|
153
|
+
fs_1.default.accessSync(parentDir, fs_1.default.constants.W_OK);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return (0, ts_utils_1.succeedWithDetail)(true, 'persistent');
|
|
157
|
+
}
|
|
158
|
+
catch (_a) {
|
|
159
|
+
return (0, ts_utils_1.failWithDetail)(`${absolutePath}: permission denied`, 'permission-denied');
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* {@inheritDoc FileTree.IMutableFileTreeAccessors.saveFileContents}
|
|
164
|
+
*/
|
|
165
|
+
saveFileContents(path, contents) {
|
|
166
|
+
return this.fileIsMutable(path).asResult.onSuccess(() => {
|
|
167
|
+
const absolutePath = this.resolveAbsolutePath(path);
|
|
168
|
+
return (0, ts_utils_1.captureResult)(() => {
|
|
169
|
+
fs_1.default.writeFileSync(absolutePath, contents, 'utf8');
|
|
170
|
+
return contents;
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* {@inheritDoc FileTree.IMutableFileTreeAccessors.createDirectory}
|
|
176
|
+
*/
|
|
177
|
+
createDirectory(dirPath) {
|
|
178
|
+
const absolutePath = this.resolveAbsolutePath(dirPath);
|
|
179
|
+
// Check if mutability is disabled
|
|
180
|
+
if (this._mutable === false) {
|
|
181
|
+
return (0, ts_utils_1.fail)(`${absolutePath}: mutability is disabled`);
|
|
182
|
+
}
|
|
183
|
+
return (0, ts_utils_1.captureResult)(() => {
|
|
184
|
+
fs_1.default.mkdirSync(absolutePath, { recursive: true });
|
|
185
|
+
return absolutePath;
|
|
186
|
+
});
|
|
187
|
+
}
|
|
127
188
|
}
|
|
128
189
|
exports.FsFileTreeAccessors = FsFileTreeAccessors;
|
|
129
190
|
//# sourceMappingURL=fsTree.js.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Result } from '@fgv/ts-utils';
|
|
2
|
-
import { FileTreeItem,
|
|
1
|
+
import { DetailedResult, Result } from '@fgv/ts-utils';
|
|
2
|
+
import { FileTreeItem, IFileTreeInitParams, IMutableFileTreeAccessors, SaveDetail } from '../fileTreeAccessors';
|
|
3
3
|
/**
|
|
4
4
|
* Represents a single file in an in-memory {@link FileTree | file tree}.
|
|
5
5
|
* @public
|
|
@@ -19,13 +19,16 @@ export interface IInMemoryFile<TCT extends string = string> {
|
|
|
19
19
|
readonly contentType?: TCT;
|
|
20
20
|
}
|
|
21
21
|
/**
|
|
22
|
-
* Implementation of {@link FileTree.
|
|
23
|
-
* tree to access files and directories.
|
|
22
|
+
* Implementation of {@link FileTree.IMutableFileTreeAccessors} that uses an in-memory
|
|
23
|
+
* tree to access and modify files and directories.
|
|
24
24
|
* @public
|
|
25
25
|
*/
|
|
26
|
-
export declare class InMemoryTreeAccessors<TCT extends string = string> implements
|
|
26
|
+
export declare class InMemoryTreeAccessors<TCT extends string = string> implements IMutableFileTreeAccessors<TCT> {
|
|
27
27
|
private readonly _tree;
|
|
28
28
|
private readonly _inferContentType;
|
|
29
|
+
private readonly _mutable;
|
|
30
|
+
private readonly _mutableByPath;
|
|
31
|
+
private readonly _mutableRoot;
|
|
29
32
|
/**
|
|
30
33
|
* Protected constructor for derived classes.
|
|
31
34
|
* @param files - An array of {@link FileTree.IInMemoryFile | in-memory files} to include in the tree.
|
|
@@ -48,36 +51,49 @@ export declare class InMemoryTreeAccessors<TCT extends string = string> implemen
|
|
|
48
51
|
*/
|
|
49
52
|
static create<TCT extends string = string>(files: IInMemoryFile<TCT>[], params?: IFileTreeInitParams<TCT>): Result<InMemoryTreeAccessors<TCT>>;
|
|
50
53
|
/**
|
|
51
|
-
* {@
|
|
54
|
+
* {@inheritDoc FileTree.IFileTreeAccessors.resolveAbsolutePath}
|
|
52
55
|
*/
|
|
53
56
|
resolveAbsolutePath(...paths: string[]): string;
|
|
54
57
|
/**
|
|
55
|
-
* {@
|
|
58
|
+
* {@inheritDoc FileTree.IFileTreeAccessors.getExtension}
|
|
56
59
|
*/
|
|
57
60
|
getExtension(path: string): string;
|
|
58
61
|
/**
|
|
59
|
-
* {@
|
|
62
|
+
* {@inheritDoc FileTree.IFileTreeAccessors.getBaseName}
|
|
60
63
|
*/
|
|
61
64
|
getBaseName(path: string, suffix?: string): string;
|
|
62
65
|
/**
|
|
63
|
-
* {@
|
|
66
|
+
* {@inheritDoc FileTree.IFileTreeAccessors.joinPaths}
|
|
64
67
|
*/
|
|
65
68
|
joinPaths(...paths: string[]): string;
|
|
66
69
|
/**
|
|
67
|
-
* {@
|
|
70
|
+
* {@inheritDoc FileTree.IFileTreeAccessors.getItem}
|
|
68
71
|
*/
|
|
69
72
|
getItem(itemPath: string): Result<FileTreeItem<TCT>>;
|
|
70
73
|
/**
|
|
71
|
-
* {@
|
|
74
|
+
* {@inheritDoc FileTree.IFileTreeAccessors.getFileContents}
|
|
72
75
|
*/
|
|
73
76
|
getFileContents(path: string): Result<string>;
|
|
74
77
|
/**
|
|
75
|
-
* {@
|
|
78
|
+
* {@inheritDoc FileTree.IFileTreeAccessors.getFileContentType}
|
|
76
79
|
*/
|
|
77
80
|
getFileContentType(path: string, provided?: string): Result<TCT | undefined>;
|
|
78
81
|
/**
|
|
79
|
-
* {@
|
|
82
|
+
* {@inheritDoc FileTree.IFileTreeAccessors.getChildren}
|
|
80
83
|
*/
|
|
81
84
|
getChildren(path: string): Result<ReadonlyArray<FileTreeItem<TCT>>>;
|
|
85
|
+
private _addMutableFile;
|
|
86
|
+
/**
|
|
87
|
+
* {@inheritDoc FileTree.IMutableFileTreeAccessors.createDirectory}
|
|
88
|
+
*/
|
|
89
|
+
createDirectory(dirPath: string): Result<string>;
|
|
90
|
+
/**
|
|
91
|
+
* {@inheritDoc FileTree.IMutableFileTreeAccessors.fileIsMutable}
|
|
92
|
+
*/
|
|
93
|
+
fileIsMutable(path: string): DetailedResult<boolean, SaveDetail>;
|
|
94
|
+
/**
|
|
95
|
+
* {@inheritDoc FileTree.IMutableFileTreeAccessors.saveFileContents}
|
|
96
|
+
*/
|
|
97
|
+
saveFileContents(path: string, contents: string): Result<string>;
|
|
82
98
|
}
|
|
83
99
|
//# sourceMappingURL=inMemoryTree.d.ts.map
|