@fgv/ts-json-base 5.1.0-0 → 5.1.0-10
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/file-tree/directoryItem.js +78 -14
- package/dist/packlets/file-tree/fileItem.js +10 -0
- package/dist/packlets/file-tree/fileTreeAccessors.js +36 -1
- package/dist/packlets/file-tree/fsTree.js +34 -0
- package/dist/packlets/file-tree/in-memory/inMemoryTree.js +75 -0
- package/dist/packlets/file-tree/in-memory/treeBuilder.js +8 -0
- package/dist/ts-json-base.d.ts +190 -45
- package/dist/tsdoc-metadata.json +1 -1
- package/lib/packlets/file-tree/directoryItem.d.ts +21 -6
- package/lib/packlets/file-tree/directoryItem.js +77 -13
- package/lib/packlets/file-tree/fileItem.d.ts +6 -2
- package/lib/packlets/file-tree/fileItem.js +10 -0
- package/lib/packlets/file-tree/fileTreeAccessors.d.ts +104 -10
- package/lib/packlets/file-tree/fileTreeAccessors.js +38 -1
- package/lib/packlets/file-tree/fsTree.d.ts +8 -0
- package/lib/packlets/file-tree/fsTree.js +34 -0
- package/lib/packlets/file-tree/in-memory/inMemoryTree.d.ts +8 -0
- package/lib/packlets/file-tree/in-memory/inMemoryTree.js +75 -0
- package/lib/packlets/file-tree/in-memory/treeBuilder.d.ts +6 -0
- package/lib/packlets/file-tree/in-memory/treeBuilder.js +8 -0
- package/package.json +9 -8
|
@@ -63,7 +63,18 @@ export interface IFileTreeInitParams<TCT extends string = string> {
|
|
|
63
63
|
mutable?: boolean | IFilterSpec;
|
|
64
64
|
}
|
|
65
65
|
/**
|
|
66
|
-
*
|
|
66
|
+
* Options for deleting a child item from a directory.
|
|
67
|
+
* @public
|
|
68
|
+
*/
|
|
69
|
+
export interface IDeleteChildOptions {
|
|
70
|
+
/**
|
|
71
|
+
* If true, recursively delete directory children and their contents.
|
|
72
|
+
* Default: false (fail if directory is non-empty).
|
|
73
|
+
*/
|
|
74
|
+
recursive?: boolean;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Interface for a read-only file in a file tree.
|
|
67
78
|
* @public
|
|
68
79
|
*/
|
|
69
80
|
export interface IFileTreeFileItem<TCT extends string = string> {
|
|
@@ -111,30 +122,39 @@ export interface IFileTreeFileItem<TCT extends string = string> {
|
|
|
111
122
|
* `Failure` with an error message otherwise.
|
|
112
123
|
*/
|
|
113
124
|
getRawContents(): Result<string>;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Extended file item interface that supports mutation operations.
|
|
128
|
+
* Use {@link FileTree.isMutableFileItem | isMutableFileItem} type guard to narrow.
|
|
129
|
+
* @public
|
|
130
|
+
*/
|
|
131
|
+
export interface IMutableFileTreeFileItem<TCT extends string = string> extends IFileTreeFileItem<TCT> {
|
|
114
132
|
/**
|
|
115
133
|
* Indicates whether this file can be saved.
|
|
116
134
|
* @returns `DetailedSuccess` with {@link FileTree.SaveCapability} if the file can be saved,
|
|
117
135
|
* or `DetailedFailure` with {@link FileTree.SaveFailureReason} if it cannot.
|
|
118
|
-
* @remarks This property is optional. If not present, the file is not mutable.
|
|
119
136
|
*/
|
|
120
137
|
getIsMutable(): DetailedResult<boolean, SaveDetail>;
|
|
121
138
|
/**
|
|
122
139
|
* Sets the contents of the file from a JSON value.
|
|
123
140
|
* @param json - The JSON value to serialize and save.
|
|
124
141
|
* @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
142
|
*/
|
|
127
143
|
setContents(json: JsonValue): Result<JsonValue>;
|
|
128
144
|
/**
|
|
129
145
|
* Sets the raw contents of the file.
|
|
130
146
|
* @param contents - The string contents to save.
|
|
131
147
|
* @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
148
|
*/
|
|
134
149
|
setRawContents(contents: string): Result<string>;
|
|
150
|
+
/**
|
|
151
|
+
* Deletes this file from its backing store.
|
|
152
|
+
* @returns `Success` with `true` if the file was deleted, or `Failure` with an error message.
|
|
153
|
+
*/
|
|
154
|
+
delete(): Result<boolean>;
|
|
135
155
|
}
|
|
136
156
|
/**
|
|
137
|
-
* Interface for a directory in a file tree.
|
|
157
|
+
* Interface for a read-only directory in a file tree.
|
|
138
158
|
* @public
|
|
139
159
|
*/
|
|
140
160
|
export interface IFileTreeDirectoryItem<TCT extends string = string> {
|
|
@@ -156,27 +176,72 @@ export interface IFileTreeDirectoryItem<TCT extends string = string> {
|
|
|
156
176
|
* or `Failure` with an error message otherwise.
|
|
157
177
|
*/
|
|
158
178
|
getChildren(): Result<ReadonlyArray<FileTreeItem<TCT>>>;
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Extended directory item interface that supports mutation operations.
|
|
182
|
+
* Use {@link FileTree.isMutableDirectoryItem | isMutableDirectoryItem} type guard to narrow.
|
|
183
|
+
* @public
|
|
184
|
+
*/
|
|
185
|
+
export interface IMutableFileTreeDirectoryItem<TCT extends string = string> extends IFileTreeDirectoryItem<TCT> {
|
|
159
186
|
/**
|
|
160
187
|
* Creates a new file as a child of this directory.
|
|
161
188
|
* @param name - The file name to create.
|
|
162
189
|
* @param contents - The string contents to write.
|
|
163
190
|
* @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
191
|
*/
|
|
166
|
-
createChildFile
|
|
192
|
+
createChildFile(name: string, contents: string): Result<IMutableFileTreeFileItem<TCT>>;
|
|
167
193
|
/**
|
|
168
194
|
* Creates a new subdirectory as a child of this directory.
|
|
169
195
|
* @param name - The directory name to create.
|
|
170
196
|
* @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
197
|
*/
|
|
173
|
-
createChildDirectory
|
|
198
|
+
createChildDirectory(name: string): Result<IMutableFileTreeDirectoryItem<TCT>>;
|
|
199
|
+
/**
|
|
200
|
+
* Deletes a child item from this directory.
|
|
201
|
+
* @param name - The name of the child to delete.
|
|
202
|
+
* @param options - Optional {@link FileTree.IDeleteChildOptions | options} controlling deletion behavior.
|
|
203
|
+
* @returns `Success` with `true` if the child was deleted, or `Failure` with an error message.
|
|
204
|
+
*/
|
|
205
|
+
deleteChild(name: string, options?: IDeleteChildOptions): Result<boolean>;
|
|
206
|
+
/**
|
|
207
|
+
* Deletes this directory from its backing store.
|
|
208
|
+
* The directory must be empty or the operation will fail.
|
|
209
|
+
* @returns `Success` with `true` if the directory was deleted, or `Failure` with an error message.
|
|
210
|
+
*/
|
|
211
|
+
delete(): Result<boolean>;
|
|
174
212
|
}
|
|
175
213
|
/**
|
|
176
214
|
* Type for an item in a file tree.
|
|
177
215
|
* @public
|
|
178
216
|
*/
|
|
179
217
|
export type FileTreeItem<TCT extends string = string> = IFileTreeFileItem<TCT> | IFileTreeDirectoryItem<TCT>;
|
|
218
|
+
/**
|
|
219
|
+
* Type for a mutable item in a file tree.
|
|
220
|
+
* @public
|
|
221
|
+
*/
|
|
222
|
+
export type MutableFileTreeItem<TCT extends string = string> = IMutableFileTreeFileItem<TCT> | IMutableFileTreeDirectoryItem<TCT>;
|
|
223
|
+
/**
|
|
224
|
+
* A file item that may or may not be mutable at runtime.
|
|
225
|
+
*
|
|
226
|
+
* Use this type for parameters or fields where the code checks for mutability
|
|
227
|
+
* and handles the read-only case gracefully. Use {@link FileTree.IMutableFileTreeFileItem}
|
|
228
|
+
* when mutation is required.
|
|
229
|
+
*
|
|
230
|
+
* Narrow with {@link FileTree.isMutableFileItem} to access mutation methods.
|
|
231
|
+
* @public
|
|
232
|
+
*/
|
|
233
|
+
export type AnyFileTreeFileItem<TCT extends string = string> = IFileTreeFileItem<TCT> | IMutableFileTreeFileItem<TCT>;
|
|
234
|
+
/**
|
|
235
|
+
* A directory item that may or may not be mutable at runtime.
|
|
236
|
+
*
|
|
237
|
+
* Use this type for parameters or fields where the code checks for mutability
|
|
238
|
+
* and handles the read-only case gracefully. Use {@link FileTree.IMutableFileTreeDirectoryItem}
|
|
239
|
+
* when mutation is required.
|
|
240
|
+
*
|
|
241
|
+
* Narrow with {@link FileTree.isMutableDirectoryItem} to access mutation methods.
|
|
242
|
+
* @public
|
|
243
|
+
*/
|
|
244
|
+
export type AnyFileTreeDirectoryItem<TCT extends string = string> = IFileTreeDirectoryItem<TCT> | IMutableFileTreeDirectoryItem<TCT>;
|
|
180
245
|
/**
|
|
181
246
|
* Common abstraction layer interface for a tree of files
|
|
182
247
|
* (e.g. a file system or a zip file).
|
|
@@ -236,6 +301,8 @@ export interface IFileTreeAccessors<TCT extends string = string> {
|
|
|
236
301
|
}
|
|
237
302
|
/**
|
|
238
303
|
* Extended accessors interface that supports mutation operations.
|
|
304
|
+
* All mutation methods are required — use {@link FileTree.isMutableAccessors | isMutableAccessors}
|
|
305
|
+
* type guard to check if an accessor supports mutation.
|
|
239
306
|
* @public
|
|
240
307
|
*/
|
|
241
308
|
export interface IMutableFileTreeAccessors<TCT extends string = string> extends IFileTreeAccessors<TCT> {
|
|
@@ -253,12 +320,25 @@ export interface IMutableFileTreeAccessors<TCT extends string = string> extends
|
|
|
253
320
|
* @returns `Success` if the file was saved, or `Failure` with an error message.
|
|
254
321
|
*/
|
|
255
322
|
saveFileContents(path: string, contents: string): Result<string>;
|
|
323
|
+
/**
|
|
324
|
+
* Deletes a file at the given path.
|
|
325
|
+
* @param path - The path of the file to delete.
|
|
326
|
+
* @returns `Success` with `true` if the file was deleted, or `Failure` with an error message.
|
|
327
|
+
*/
|
|
328
|
+
deleteFile(path: string): Result<boolean>;
|
|
256
329
|
/**
|
|
257
330
|
* Creates a directory at the given path, including any missing parent directories.
|
|
258
331
|
* @param path - The path of the directory to create.
|
|
259
332
|
* @returns `Success` with the absolute path if created, or `Failure` with an error message.
|
|
260
333
|
*/
|
|
261
|
-
createDirectory
|
|
334
|
+
createDirectory(path: string): Result<string>;
|
|
335
|
+
/**
|
|
336
|
+
* Deletes a directory at the given path.
|
|
337
|
+
* The directory must be empty or the operation will fail.
|
|
338
|
+
* @param path - The path of the directory to delete.
|
|
339
|
+
* @returns `Success` with `true` if the directory was deleted, or `Failure` with an error message.
|
|
340
|
+
*/
|
|
341
|
+
deleteDirectory(path: string): Result<boolean>;
|
|
262
342
|
}
|
|
263
343
|
/**
|
|
264
344
|
* Extended accessors interface that supports persistence operations.
|
|
@@ -295,4 +375,18 @@ export declare function isMutableAccessors<TCT extends string = string>(accessor
|
|
|
295
375
|
* @public
|
|
296
376
|
*/
|
|
297
377
|
export declare function isPersistentAccessors<TCT extends string = string>(accessors: IFileTreeAccessors<TCT>): accessors is IPersistentFileTreeAccessors<TCT>;
|
|
378
|
+
/**
|
|
379
|
+
* Type guard to check if a file item supports mutation.
|
|
380
|
+
* @param item - The file item to check.
|
|
381
|
+
* @returns `true` if the item implements {@link FileTree.IMutableFileTreeFileItem}.
|
|
382
|
+
* @public
|
|
383
|
+
*/
|
|
384
|
+
export declare function isMutableFileItem<TCT extends string = string>(item: AnyFileTreeFileItem<TCT> | FileTreeItem<TCT>): item is IMutableFileTreeFileItem<TCT>;
|
|
385
|
+
/**
|
|
386
|
+
* Type guard to check if a directory item supports mutation.
|
|
387
|
+
* @param item - The directory item to check.
|
|
388
|
+
* @returns `true` if the item implements {@link FileTree.IMutableFileTreeDirectoryItem}.
|
|
389
|
+
* @public
|
|
390
|
+
*/
|
|
391
|
+
export declare function isMutableDirectoryItem<TCT extends string = string>(item: AnyFileTreeDirectoryItem<TCT> | FileTreeItem<TCT>): item is IMutableFileTreeDirectoryItem<TCT>;
|
|
298
392
|
//# sourceMappingURL=fileTreeAccessors.d.ts.map
|
|
@@ -23,6 +23,11 @@
|
|
|
23
23
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
24
24
|
exports.isMutableAccessors = isMutableAccessors;
|
|
25
25
|
exports.isPersistentAccessors = isPersistentAccessors;
|
|
26
|
+
exports.isMutableFileItem = isMutableFileItem;
|
|
27
|
+
exports.isMutableDirectoryItem = isMutableDirectoryItem;
|
|
28
|
+
// ============================================================================
|
|
29
|
+
// Type Guards
|
|
30
|
+
// ============================================================================
|
|
26
31
|
/**
|
|
27
32
|
* Type guard to check if accessors support mutation.
|
|
28
33
|
* @param accessors - The accessors to check.
|
|
@@ -31,7 +36,11 @@ exports.isPersistentAccessors = isPersistentAccessors;
|
|
|
31
36
|
*/
|
|
32
37
|
function isMutableAccessors(accessors) {
|
|
33
38
|
const mutable = accessors;
|
|
34
|
-
return typeof mutable.fileIsMutable === 'function' &&
|
|
39
|
+
return (typeof mutable.fileIsMutable === 'function' &&
|
|
40
|
+
typeof mutable.saveFileContents === 'function' &&
|
|
41
|
+
typeof mutable.deleteFile === 'function' &&
|
|
42
|
+
typeof mutable.createDirectory === 'function' &&
|
|
43
|
+
typeof mutable.deleteDirectory === 'function');
|
|
35
44
|
}
|
|
36
45
|
/**
|
|
37
46
|
* Type guard to check if accessors support persistence.
|
|
@@ -47,4 +56,32 @@ function isPersistentAccessors(accessors) {
|
|
|
47
56
|
typeof persistent.isDirty === 'function' &&
|
|
48
57
|
typeof persistent.getDirtyPaths === 'function');
|
|
49
58
|
}
|
|
59
|
+
/**
|
|
60
|
+
* Type guard to check if a file item supports mutation.
|
|
61
|
+
* @param item - The file item to check.
|
|
62
|
+
* @returns `true` if the item implements {@link FileTree.IMutableFileTreeFileItem}.
|
|
63
|
+
* @public
|
|
64
|
+
*/
|
|
65
|
+
function isMutableFileItem(item) {
|
|
66
|
+
const mutable = item;
|
|
67
|
+
return (mutable.type === 'file' &&
|
|
68
|
+
typeof mutable.getIsMutable === 'function' &&
|
|
69
|
+
typeof mutable.setContents === 'function' &&
|
|
70
|
+
typeof mutable.setRawContents === 'function' &&
|
|
71
|
+
typeof mutable.delete === 'function');
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Type guard to check if a directory item supports mutation.
|
|
75
|
+
* @param item - The directory item to check.
|
|
76
|
+
* @returns `true` if the item implements {@link FileTree.IMutableFileTreeDirectoryItem}.
|
|
77
|
+
* @public
|
|
78
|
+
*/
|
|
79
|
+
function isMutableDirectoryItem(item) {
|
|
80
|
+
const mutable = item;
|
|
81
|
+
return (mutable.type === 'directory' &&
|
|
82
|
+
typeof mutable.createChildFile === 'function' &&
|
|
83
|
+
typeof mutable.createChildDirectory === 'function' &&
|
|
84
|
+
typeof mutable.deleteChild === 'function' &&
|
|
85
|
+
typeof mutable.delete === 'function');
|
|
86
|
+
}
|
|
50
87
|
//# sourceMappingURL=fileTreeAccessors.js.map
|
|
@@ -65,9 +65,17 @@ export declare class FsFileTreeAccessors<TCT extends string = string> implements
|
|
|
65
65
|
* {@inheritDoc FileTree.IMutableFileTreeAccessors.saveFileContents}
|
|
66
66
|
*/
|
|
67
67
|
saveFileContents(path: string, contents: string): Result<string>;
|
|
68
|
+
/**
|
|
69
|
+
* {@inheritDoc FileTree.IMutableFileTreeAccessors.deleteFile}
|
|
70
|
+
*/
|
|
71
|
+
deleteFile(path: string): Result<boolean>;
|
|
68
72
|
/**
|
|
69
73
|
* {@inheritDoc FileTree.IMutableFileTreeAccessors.createDirectory}
|
|
70
74
|
*/
|
|
71
75
|
createDirectory(dirPath: string): Result<string>;
|
|
76
|
+
/**
|
|
77
|
+
* {@inheritDoc FileTree.IMutableFileTreeAccessors.deleteDirectory}
|
|
78
|
+
*/
|
|
79
|
+
deleteDirectory(dirPath: string): Result<boolean>;
|
|
72
80
|
}
|
|
73
81
|
//# sourceMappingURL=fsTree.d.ts.map
|
|
@@ -154,6 +154,7 @@ class FsFileTreeAccessors {
|
|
|
154
154
|
}
|
|
155
155
|
}
|
|
156
156
|
return (0, ts_utils_1.succeedWithDetail)(true, 'persistent');
|
|
157
|
+
/* c8 ignore next 3 - unreachable when running as root (CI), tested in mutableFsTree.test.ts */
|
|
157
158
|
}
|
|
158
159
|
catch (_a) {
|
|
159
160
|
return (0, ts_utils_1.failWithDetail)(`${absolutePath}: permission denied`, 'permission-denied');
|
|
@@ -171,6 +172,22 @@ class FsFileTreeAccessors {
|
|
|
171
172
|
});
|
|
172
173
|
});
|
|
173
174
|
}
|
|
175
|
+
/**
|
|
176
|
+
* {@inheritDoc FileTree.IMutableFileTreeAccessors.deleteFile}
|
|
177
|
+
*/
|
|
178
|
+
deleteFile(path) {
|
|
179
|
+
return this.fileIsMutable(path).asResult.onSuccess(() => {
|
|
180
|
+
const absolutePath = this.resolveAbsolutePath(path);
|
|
181
|
+
return (0, ts_utils_1.captureResult)(() => {
|
|
182
|
+
const stat = fs_1.default.statSync(absolutePath);
|
|
183
|
+
if (!stat.isFile()) {
|
|
184
|
+
throw new Error(`${absolutePath}: not a file`);
|
|
185
|
+
}
|
|
186
|
+
fs_1.default.unlinkSync(absolutePath);
|
|
187
|
+
return true;
|
|
188
|
+
});
|
|
189
|
+
});
|
|
190
|
+
}
|
|
174
191
|
/**
|
|
175
192
|
* {@inheritDoc FileTree.IMutableFileTreeAccessors.createDirectory}
|
|
176
193
|
*/
|
|
@@ -185,6 +202,23 @@ class FsFileTreeAccessors {
|
|
|
185
202
|
return absolutePath;
|
|
186
203
|
});
|
|
187
204
|
}
|
|
205
|
+
/**
|
|
206
|
+
* {@inheritDoc FileTree.IMutableFileTreeAccessors.deleteDirectory}
|
|
207
|
+
*/
|
|
208
|
+
deleteDirectory(dirPath) {
|
|
209
|
+
return this.fileIsMutable(dirPath).asResult.onSuccess(() => {
|
|
210
|
+
const absolutePath = this.resolveAbsolutePath(dirPath);
|
|
211
|
+
return (0, ts_utils_1.captureResult)(() => {
|
|
212
|
+
const stat = fs_1.default.statSync(absolutePath);
|
|
213
|
+
if (!stat.isDirectory()) {
|
|
214
|
+
throw new Error(`${absolutePath}: not a directory`);
|
|
215
|
+
}
|
|
216
|
+
// fs.rmdirSync fails if directory is non-empty (desired behavior)
|
|
217
|
+
fs_1.default.rmdirSync(absolutePath);
|
|
218
|
+
return true;
|
|
219
|
+
});
|
|
220
|
+
});
|
|
221
|
+
}
|
|
188
222
|
}
|
|
189
223
|
exports.FsFileTreeAccessors = FsFileTreeAccessors;
|
|
190
224
|
//# sourceMappingURL=fsTree.js.map
|
|
@@ -91,6 +91,14 @@ export declare class InMemoryTreeAccessors<TCT extends string = string> implemen
|
|
|
91
91
|
* {@inheritDoc FileTree.IMutableFileTreeAccessors.fileIsMutable}
|
|
92
92
|
*/
|
|
93
93
|
fileIsMutable(path: string): DetailedResult<boolean, SaveDetail>;
|
|
94
|
+
/**
|
|
95
|
+
* {@inheritDoc FileTree.IMutableFileTreeAccessors.deleteFile}
|
|
96
|
+
*/
|
|
97
|
+
deleteFile(path: string): Result<boolean>;
|
|
98
|
+
/**
|
|
99
|
+
* {@inheritDoc FileTree.IMutableFileTreeAccessors.deleteDirectory}
|
|
100
|
+
*/
|
|
101
|
+
deleteDirectory(path: string): Result<boolean>;
|
|
94
102
|
/**
|
|
95
103
|
* {@inheritDoc FileTree.IMutableFileTreeAccessors.saveFileContents}
|
|
96
104
|
*/
|
|
@@ -95,6 +95,9 @@ class MutableInMemoryDirectory {
|
|
|
95
95
|
}
|
|
96
96
|
return this.addFile(name, contents, contentType);
|
|
97
97
|
}
|
|
98
|
+
removeChild(name) {
|
|
99
|
+
return this._children.delete(name);
|
|
100
|
+
}
|
|
98
101
|
}
|
|
99
102
|
/**
|
|
100
103
|
* Implementation of {@link FileTree.IMutableFileTreeAccessors} that uses an in-memory
|
|
@@ -323,6 +326,78 @@ class InMemoryTreeAccessors {
|
|
|
323
326
|
}
|
|
324
327
|
return (0, ts_utils_1.succeedWithDetail)(true, 'transient');
|
|
325
328
|
}
|
|
329
|
+
/**
|
|
330
|
+
* {@inheritDoc FileTree.IMutableFileTreeAccessors.deleteFile}
|
|
331
|
+
*/
|
|
332
|
+
deleteFile(path) {
|
|
333
|
+
const absolutePath = this.resolveAbsolutePath(path);
|
|
334
|
+
const parts = absolutePath.split('/').filter((p) => p.length > 0);
|
|
335
|
+
if (parts.length === 0) {
|
|
336
|
+
return (0, ts_utils_1.fail)(`${absolutePath}: invalid file path`);
|
|
337
|
+
}
|
|
338
|
+
const fileName = parts.pop();
|
|
339
|
+
// Navigate to parent directory
|
|
340
|
+
let dir = this._mutableRoot;
|
|
341
|
+
for (const part of parts) {
|
|
342
|
+
const child = dir.children.get(part);
|
|
343
|
+
if (!child || !(child instanceof MutableInMemoryDirectory)) {
|
|
344
|
+
return (0, ts_utils_1.fail)(`${absolutePath}: parent directory not found`);
|
|
345
|
+
}
|
|
346
|
+
dir = child;
|
|
347
|
+
}
|
|
348
|
+
if (!dir.removeChild(fileName)) {
|
|
349
|
+
return (0, ts_utils_1.fail)(`${absolutePath}: file not found`);
|
|
350
|
+
}
|
|
351
|
+
// Also remove from the read layer's directory children and path index
|
|
352
|
+
const parentPath = parts.length === 0 ? '/' : '/' + parts.join('/');
|
|
353
|
+
const readParent = this._tree.byAbsolutePath.get(parentPath);
|
|
354
|
+
if (readParent instanceof treeBuilder_1.InMemoryDirectory) {
|
|
355
|
+
readParent.removeChild(fileName);
|
|
356
|
+
}
|
|
357
|
+
this._tree.byAbsolutePath.delete(absolutePath);
|
|
358
|
+
this._mutableByPath.delete(absolutePath);
|
|
359
|
+
return (0, ts_utils_1.succeed)(true);
|
|
360
|
+
}
|
|
361
|
+
/**
|
|
362
|
+
* {@inheritDoc FileTree.IMutableFileTreeAccessors.deleteDirectory}
|
|
363
|
+
*/
|
|
364
|
+
deleteDirectory(path) {
|
|
365
|
+
const absolutePath = this.resolveAbsolutePath(path);
|
|
366
|
+
const parts = absolutePath.split('/').filter((p) => p.length > 0);
|
|
367
|
+
if (parts.length === 0) {
|
|
368
|
+
return (0, ts_utils_1.fail)(`${absolutePath}: invalid directory path`);
|
|
369
|
+
}
|
|
370
|
+
const dirName = parts.pop();
|
|
371
|
+
// Navigate to parent directory
|
|
372
|
+
let parentDir = this._mutableRoot;
|
|
373
|
+
for (const part of parts) {
|
|
374
|
+
const child = parentDir.children.get(part);
|
|
375
|
+
if (!child || !(child instanceof MutableInMemoryDirectory)) {
|
|
376
|
+
return (0, ts_utils_1.fail)(`${absolutePath}: parent directory not found`);
|
|
377
|
+
}
|
|
378
|
+
parentDir = child;
|
|
379
|
+
}
|
|
380
|
+
// Verify target is a directory
|
|
381
|
+
const target = parentDir.children.get(dirName);
|
|
382
|
+
if (!target || !(target instanceof MutableInMemoryDirectory)) {
|
|
383
|
+
return (0, ts_utils_1.fail)(`${absolutePath}: not a directory`);
|
|
384
|
+
}
|
|
385
|
+
// Check non-empty
|
|
386
|
+
if (target.children.size > 0) {
|
|
387
|
+
return (0, ts_utils_1.fail)(`${absolutePath}: directory is not empty`);
|
|
388
|
+
}
|
|
389
|
+
parentDir.removeChild(dirName);
|
|
390
|
+
// Also remove from the read layer
|
|
391
|
+
/* c8 ignore next 1 - defensive: branch for top-level directory deletion */
|
|
392
|
+
const readParentPath = parts.length === 0 ? '/' : '/' + parts.join('/');
|
|
393
|
+
const readParent = this._tree.byAbsolutePath.get(readParentPath);
|
|
394
|
+
if (readParent instanceof treeBuilder_1.InMemoryDirectory) {
|
|
395
|
+
readParent.removeChild(dirName);
|
|
396
|
+
}
|
|
397
|
+
this._tree.byAbsolutePath.delete(absolutePath);
|
|
398
|
+
this._mutableByPath.delete(absolutePath);
|
|
399
|
+
return (0, ts_utils_1.succeed)(true);
|
|
400
|
+
}
|
|
326
401
|
/**
|
|
327
402
|
* {@inheritDoc FileTree.IMutableFileTreeAccessors.saveFileContents}
|
|
328
403
|
*/
|
|
@@ -59,6 +59,12 @@ export declare class InMemoryDirectory<TCT extends string = string> {
|
|
|
59
59
|
* `Failure` with an error message otherwise.
|
|
60
60
|
*/
|
|
61
61
|
addFile(name: string, contents: unknown, contentType?: TCT): Result<InMemoryFile<TCT>>;
|
|
62
|
+
/**
|
|
63
|
+
* Removes a child from the directory.
|
|
64
|
+
* @param name - The name of the child to remove.
|
|
65
|
+
* @returns `true` if the child was found and removed, `false` otherwise.
|
|
66
|
+
*/
|
|
67
|
+
removeChild(name: string): boolean;
|
|
62
68
|
/**
|
|
63
69
|
* Gets the absolute path for a child of this directory with the supplied
|
|
64
70
|
* name.
|
|
@@ -94,6 +94,14 @@ class InMemoryDirectory {
|
|
|
94
94
|
this._children.set(name, child);
|
|
95
95
|
return (0, ts_utils_1.succeed)(child);
|
|
96
96
|
}
|
|
97
|
+
/**
|
|
98
|
+
* Removes a child from the directory.
|
|
99
|
+
* @param name - The name of the child to remove.
|
|
100
|
+
* @returns `true` if the child was found and removed, `false` otherwise.
|
|
101
|
+
*/
|
|
102
|
+
removeChild(name) {
|
|
103
|
+
return this._children.delete(name);
|
|
104
|
+
}
|
|
97
105
|
/**
|
|
98
106
|
* Gets the absolute path for a child of this directory with the supplied
|
|
99
107
|
* name.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fgv/ts-json-base",
|
|
3
|
-
"version": "5.1.0-
|
|
3
|
+
"version": "5.1.0-10",
|
|
4
4
|
"description": "Typescript types and basic functions for working with json",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"types": "dist/ts-json-base.d.ts",
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"ts-node": "^10.9.2",
|
|
45
45
|
"typescript": "5.9.3",
|
|
46
46
|
"eslint-plugin-n": "^17.23.1",
|
|
47
|
-
"@rushstack/heft": "1.2.
|
|
47
|
+
"@rushstack/heft": "1.2.7",
|
|
48
48
|
"@rushstack/heft-jest-plugin": "1.2.6",
|
|
49
49
|
"@types/heft-jest": "1.0.6",
|
|
50
50
|
"@microsoft/api-documenter": "^7.28.2",
|
|
@@ -52,14 +52,16 @@
|
|
|
52
52
|
"@rushstack/eslint-config": "4.6.4",
|
|
53
53
|
"eslint-plugin-tsdoc": "~0.5.2",
|
|
54
54
|
"@types/luxon": "^3.7.1",
|
|
55
|
-
"@rushstack/heft-node-rig": "2.11.
|
|
55
|
+
"@rushstack/heft-node-rig": "2.11.27",
|
|
56
56
|
"@microsoft/api-extractor": "^7.55.2",
|
|
57
|
-
"
|
|
58
|
-
"@fgv/ts-utils
|
|
59
|
-
"@fgv/
|
|
57
|
+
"typedoc": "~0.28.16",
|
|
58
|
+
"@fgv/ts-utils": "5.1.0-10",
|
|
59
|
+
"@fgv/ts-utils-jest": "5.1.0-10",
|
|
60
|
+
"@fgv/heft-dual-rig": "5.1.0-10",
|
|
61
|
+
"@fgv/typedoc-compact-theme": "5.1.0-10"
|
|
60
62
|
},
|
|
61
63
|
"peerDependencies": {
|
|
62
|
-
"@fgv/ts-utils": "5.1.0-
|
|
64
|
+
"@fgv/ts-utils": "5.1.0-10"
|
|
63
65
|
},
|
|
64
66
|
"dependencies": {
|
|
65
67
|
"luxon": "^3.7.2"
|
|
@@ -76,7 +78,6 @@
|
|
|
76
78
|
"build-all": "rushx build; rushx build-docs",
|
|
77
79
|
"test-handles": "jest --runInBand --detectOpenHandles",
|
|
78
80
|
"clean-jest": "jest --clear-cache",
|
|
79
|
-
"coverage": "jest --coverage --no-cache",
|
|
80
81
|
"lint": "eslint src --ext .ts",
|
|
81
82
|
"fixlint": "eslint src --ext .ts --fix"
|
|
82
83
|
}
|