@fgv/ts-json-base 5.0.2 → 5.1.0-1
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 +99 -4
- package/dist/packlets/file-tree/fileItem.js +47 -9
- package/dist/packlets/file-tree/fileTreeAccessors.js +59 -1
- package/dist/packlets/file-tree/filterSpec.js +74 -0
- package/dist/packlets/file-tree/fsTree.js +107 -12
- package/dist/packlets/file-tree/in-memory/inMemoryTree.js +279 -21
- package/dist/packlets/file-tree/in-memory/treeBuilder.js +31 -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 +439 -65
- 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 +29 -6
- package/lib/packlets/file-tree/directoryItem.js +98 -3
- package/lib/packlets/file-tree/fileItem.d.ts +31 -14
- package/lib/packlets/file-tree/fileItem.js +46 -8
- package/lib/packlets/file-tree/fileTreeAccessors.d.ts +237 -3
- package/lib/packlets/file-tree/fileTreeAccessors.js +63 -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 +37 -13
- package/lib/packlets/file-tree/fsTree.js +106 -11
- package/lib/packlets/file-tree/in-memory/inMemoryTree.d.ts +37 -13
- package/lib/packlets/file-tree/in-memory/inMemoryTree.js +278 -20
- package/lib/packlets/file-tree/in-memory/treeBuilder.d.ts +15 -0
- package/lib/packlets/file-tree/in-memory/treeBuilder.js +31 -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 +29 -30
- package/dist/test/fixtures/file-tree/docs/api/reference.json +0 -1
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
20
20
|
* SOFTWARE.
|
|
21
21
|
*/
|
|
22
|
-
import { Conversion, Converters as BaseConverters, StringConverter, fail, succeed } from '@fgv/ts-utils';
|
|
22
|
+
import { Conversion, Converters as BaseConverters, StringConverter, captureResult, fail, succeed } from '@fgv/ts-utils';
|
|
23
23
|
import { isJsonArray, isJsonObject } from '../json';
|
|
24
24
|
/**
|
|
25
25
|
* An converter which converts a supplied `unknown` value to a valid {@link JsonPrimitive | JsonPrimitive}.
|
|
@@ -45,7 +45,7 @@ export const jsonPrimitive = new Conversion.BaseConverter((from, __self, ctx) =>
|
|
|
45
45
|
* An copying converter which converts a supplied `unknown` value into
|
|
46
46
|
* a valid {@link JsonObject | JsonObject}. Fails by default if any properties or array elements
|
|
47
47
|
* are `undefined` - this default behavior can be overridden by supplying an appropriate
|
|
48
|
-
*
|
|
48
|
+
* `IJsonConverterContext` at runtime.
|
|
49
49
|
*
|
|
50
50
|
* Guaranteed to return a new object.
|
|
51
51
|
* @public
|
|
@@ -81,7 +81,7 @@ export const jsonObject = new Conversion.BaseConverter((from, __self, ctx) => {
|
|
|
81
81
|
* An copying converter which converts a supplied `unknown` value to
|
|
82
82
|
* a valid {@link JsonArray | JsonArray}. Fails by default if any properties or array elements
|
|
83
83
|
* are `undefined` - this default behavior can be overridden by supplying an appropriate
|
|
84
|
-
*
|
|
84
|
+
* `IJsonConverterContext` at runtime.
|
|
85
85
|
*
|
|
86
86
|
* Guaranteed to return a new array.
|
|
87
87
|
* @public
|
|
@@ -119,7 +119,7 @@ export const jsonArray = new Conversion.BaseConverter((from, __self, ctx) => {
|
|
|
119
119
|
* An copying converter which converts a supplied `unknown` value to a
|
|
120
120
|
* valid {@link JsonValue | JsonValue}. Fails by default if any properties or array elements
|
|
121
121
|
* are `undefined` - this default behavior can be overridden by supplying an appropriate
|
|
122
|
-
*
|
|
122
|
+
* `IJsonConverterContext` at runtime.
|
|
123
123
|
* @public
|
|
124
124
|
*/
|
|
125
125
|
export const jsonValue = new Conversion.BaseConverter((from, __self, ctx) => {
|
|
@@ -132,28 +132,28 @@ export const jsonValue = new Conversion.BaseConverter((from, __self, ctx) => {
|
|
|
132
132
|
return jsonPrimitive.convert(from, ctx);
|
|
133
133
|
});
|
|
134
134
|
/**
|
|
135
|
-
* A
|
|
136
|
-
* Accepts
|
|
135
|
+
* A `StringConverter` which converts `unknown` to a `string`.
|
|
136
|
+
* Accepts `IJsonConverterContext` but ignores it.
|
|
137
137
|
* @public
|
|
138
138
|
*/
|
|
139
139
|
export const string = new StringConverter();
|
|
140
140
|
/**
|
|
141
|
-
* A
|
|
142
|
-
* Accepts
|
|
141
|
+
* A `Converter` which converts `unknown` to a `number`.
|
|
142
|
+
* Accepts `IJsonConverterContext` but ignores it.
|
|
143
143
|
* Mirrors the behavior of `@fgv/ts-utils`.
|
|
144
144
|
* @public
|
|
145
145
|
*/
|
|
146
146
|
export const number = new Conversion.BaseConverter((from) => BaseConverters.number.convert(from));
|
|
147
147
|
/**
|
|
148
|
-
* A
|
|
149
|
-
* Accepts
|
|
148
|
+
* A `Converter` which converts `unknown` to a `boolean`.
|
|
149
|
+
* Accepts `IJsonConverterContext` but ignores it.
|
|
150
150
|
* Mirrors the behavior of `@fgv/ts-utils`.
|
|
151
151
|
* @public
|
|
152
152
|
*/
|
|
153
153
|
export const boolean = new Conversion.BaseConverter((from) => BaseConverters.boolean.convert(from));
|
|
154
154
|
/**
|
|
155
155
|
* Helper to create a converter for a literal value.
|
|
156
|
-
* Accepts
|
|
156
|
+
* Accepts `IJsonConverterContext` but ignores it.
|
|
157
157
|
* Mirrors the behavior of `@fgv/ts-utils`.
|
|
158
158
|
* @public
|
|
159
159
|
*/
|
|
@@ -161,17 +161,17 @@ export function literal(value) {
|
|
|
161
161
|
return BaseConverters.literal(value);
|
|
162
162
|
}
|
|
163
163
|
/**
|
|
164
|
-
* Helper function to create a
|
|
164
|
+
* Helper function to create a `Converter` which converts `unknown` to one of a set of
|
|
165
165
|
* supplied enumerated values. Anything else fails.
|
|
166
166
|
*
|
|
167
167
|
* @remarks
|
|
168
|
-
* This JSON variant accepts an
|
|
168
|
+
* This JSON variant accepts an `IJsonConverterContext` OR
|
|
169
169
|
* a `ReadonlyArray<T>` as its conversion context. If the context is an array, it is used to override the
|
|
170
170
|
* allowed values for that conversion; otherwise, the original `values` supplied at creation time are used.
|
|
171
171
|
*
|
|
172
172
|
* @param values - Array of allowed values.
|
|
173
173
|
* @param message - Optional custom failure message.
|
|
174
|
-
* @returns A new
|
|
174
|
+
* @returns A new `Converter` returning `<T>`.
|
|
175
175
|
* @public
|
|
176
176
|
*/
|
|
177
177
|
export function enumeratedValue(values, message) {
|
|
@@ -184,4 +184,26 @@ export function enumeratedValue(values, message) {
|
|
|
184
184
|
return fail(message !== null && message !== void 0 ? message : `Invalid enumerated value ${JSON.stringify(from)}`);
|
|
185
185
|
});
|
|
186
186
|
}
|
|
187
|
+
/**
|
|
188
|
+
* Creates a converter that parses JSON string content and then applies the supplied converter.
|
|
189
|
+
* @param converter - Converter to apply to the parsed JSON
|
|
190
|
+
* @returns Converter that parses JSON then validates
|
|
191
|
+
* @public
|
|
192
|
+
*/
|
|
193
|
+
export function jsonConverter(converter) {
|
|
194
|
+
return new Conversion.BaseConverter((from) => {
|
|
195
|
+
if (typeof from !== 'string') {
|
|
196
|
+
return fail('Input must be a string');
|
|
197
|
+
}
|
|
198
|
+
const parseResult = captureResult(() => JSON.parse(from));
|
|
199
|
+
if (parseResult.isFailure()) {
|
|
200
|
+
return fail(`Failed to parse JSON: ${parseResult.message}`);
|
|
201
|
+
}
|
|
202
|
+
const parsed = parseResult.value;
|
|
203
|
+
if (typeof parsed !== 'object' || parsed === null) {
|
|
204
|
+
return fail('Failed to parse JSON: JSON content must be an object');
|
|
205
|
+
}
|
|
206
|
+
return converter.convert(parsed);
|
|
207
|
+
});
|
|
208
|
+
}
|
|
187
209
|
//# sourceMappingURL=converters.js.map
|
|
@@ -19,14 +19,15 @@
|
|
|
19
19
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
20
20
|
* SOFTWARE.
|
|
21
21
|
*/
|
|
22
|
-
import { captureResult } from '@fgv/ts-utils';
|
|
22
|
+
import { captureResult, fail, succeed } from '@fgv/ts-utils';
|
|
23
|
+
import { isMutableAccessors, isMutableFileItem } from './fileTreeAccessors';
|
|
23
24
|
/**
|
|
24
25
|
* Class representing a directory in a file tree.
|
|
25
26
|
* @public
|
|
26
27
|
*/
|
|
27
28
|
export class DirectoryItem {
|
|
28
29
|
/**
|
|
29
|
-
* {@
|
|
30
|
+
* {@inheritDoc FileTree.IFileTreeDirectoryItem.name}
|
|
30
31
|
*/
|
|
31
32
|
get name() {
|
|
32
33
|
return this._hal.getBaseName(this.absolutePath);
|
|
@@ -40,7 +41,7 @@ export class DirectoryItem {
|
|
|
40
41
|
*/
|
|
41
42
|
constructor(path, hal) {
|
|
42
43
|
/**
|
|
43
|
-
* {@
|
|
44
|
+
* {@inheritDoc FileTree.IFileTreeDirectoryItem."type"}
|
|
44
45
|
*/
|
|
45
46
|
this.type = 'directory';
|
|
46
47
|
this._hal = hal;
|
|
@@ -58,10 +59,104 @@ export class DirectoryItem {
|
|
|
58
59
|
return captureResult(() => new DirectoryItem(path, hal));
|
|
59
60
|
}
|
|
60
61
|
/**
|
|
61
|
-
* {@
|
|
62
|
+
* {@inheritDoc FileTree.IFileTreeDirectoryItem.getChildren}
|
|
62
63
|
*/
|
|
63
64
|
getChildren() {
|
|
64
65
|
return this._hal.getChildren(this.absolutePath);
|
|
65
66
|
}
|
|
67
|
+
/**
|
|
68
|
+
* {@inheritDoc FileTree.IMutableFileTreeDirectoryItem.createChildFile}
|
|
69
|
+
*/
|
|
70
|
+
createChildFile(name, contents) {
|
|
71
|
+
const hal = this._hal;
|
|
72
|
+
if (!isMutableAccessors(hal)) {
|
|
73
|
+
/* c8 ignore next 2 - defensive: all current accessor implementations support mutation interface */
|
|
74
|
+
return fail(`${this.absolutePath}: mutation not supported`);
|
|
75
|
+
}
|
|
76
|
+
const filePath = hal.joinPaths(this.absolutePath, name);
|
|
77
|
+
return hal.saveFileContents(filePath, contents).onSuccess(() => hal.getItem(filePath).onSuccess((item) => {
|
|
78
|
+
/* c8 ignore next 3 - defensive: verifies accessor returned correct item type after save */
|
|
79
|
+
if (!isMutableFileItem(item)) {
|
|
80
|
+
return fail(`${filePath}: expected mutable file but got ${item.type}`);
|
|
81
|
+
}
|
|
82
|
+
return succeed(item);
|
|
83
|
+
}));
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* {@inheritDoc FileTree.IMutableFileTreeDirectoryItem.createChildDirectory}
|
|
87
|
+
*/
|
|
88
|
+
createChildDirectory(name) {
|
|
89
|
+
const hal = this._hal;
|
|
90
|
+
if (!isMutableAccessors(hal)) {
|
|
91
|
+
/* c8 ignore next 2 - defensive: all current accessor implementations support mutation interface */
|
|
92
|
+
return fail(`${this.absolutePath}: mutation not supported`);
|
|
93
|
+
}
|
|
94
|
+
const dirPath = hal.joinPaths(this.absolutePath, name);
|
|
95
|
+
return hal.createDirectory(dirPath).onSuccess(() => DirectoryItem.create(dirPath, hal));
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* {@inheritDoc FileTree.IMutableFileTreeDirectoryItem.deleteChild}
|
|
99
|
+
*/
|
|
100
|
+
deleteChild(name, options) {
|
|
101
|
+
const hal = this._hal;
|
|
102
|
+
if (!isMutableAccessors(hal)) {
|
|
103
|
+
/* c8 ignore next 2 - defensive: all current accessor implementations support mutation interface */
|
|
104
|
+
return fail(`${this.absolutePath}: mutation not supported`);
|
|
105
|
+
}
|
|
106
|
+
const childPath = hal.joinPaths(this.absolutePath, name);
|
|
107
|
+
return hal.getItem(childPath).onSuccess((item) => {
|
|
108
|
+
if (item.type === 'file') {
|
|
109
|
+
return hal.deleteFile(childPath);
|
|
110
|
+
}
|
|
111
|
+
// Directory child
|
|
112
|
+
if (options === null || options === void 0 ? void 0 : options.recursive) {
|
|
113
|
+
return this._deleteRecursive(childPath);
|
|
114
|
+
}
|
|
115
|
+
return hal.deleteDirectory(childPath);
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* {@inheritDoc FileTree.IMutableFileTreeDirectoryItem.delete}
|
|
120
|
+
*/
|
|
121
|
+
delete() {
|
|
122
|
+
const hal = this._hal;
|
|
123
|
+
if (!isMutableAccessors(hal)) {
|
|
124
|
+
/* c8 ignore next 2 - defensive: all current accessor implementations support mutation interface */
|
|
125
|
+
return fail(`${this.absolutePath}: mutation not supported`);
|
|
126
|
+
}
|
|
127
|
+
return hal.deleteDirectory(this.absolutePath);
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Recursively deletes all children of a directory and then the directory itself.
|
|
131
|
+
* @param dirPath - The absolute path of the directory to delete.
|
|
132
|
+
* @returns `Success` with `true` if the directory was deleted, or `Failure` with an error message.
|
|
133
|
+
* @internal
|
|
134
|
+
*/
|
|
135
|
+
_deleteRecursive(dirPath) {
|
|
136
|
+
const hal = this._hal;
|
|
137
|
+
/* c8 ignore next 3 - defensive: caller already verified mutable */
|
|
138
|
+
if (!isMutableAccessors(hal)) {
|
|
139
|
+
return fail(`${dirPath}: mutation not supported`);
|
|
140
|
+
}
|
|
141
|
+
return hal.getChildren(dirPath).onSuccess((children) => {
|
|
142
|
+
for (const child of children) {
|
|
143
|
+
if (child.type === 'file') {
|
|
144
|
+
const result = hal.deleteFile(child.absolutePath);
|
|
145
|
+
/* c8 ignore next 3 - defensive: error propagation during recursive delete */
|
|
146
|
+
if (result.isFailure()) {
|
|
147
|
+
return result;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
const result = this._deleteRecursive(child.absolutePath);
|
|
152
|
+
/* c8 ignore next 3 - defensive: error propagation during recursive delete */
|
|
153
|
+
if (result.isFailure()) {
|
|
154
|
+
return result;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return hal.deleteDirectory(dirPath);
|
|
159
|
+
});
|
|
160
|
+
}
|
|
66
161
|
}
|
|
67
162
|
//# sourceMappingURL=directoryItem.js.map
|
|
@@ -19,32 +19,33 @@
|
|
|
19
19
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
20
20
|
* SOFTWARE.
|
|
21
21
|
*/
|
|
22
|
-
import { captureResult, succeed } from '@fgv/ts-utils';
|
|
22
|
+
import { captureResult, fail, failWithDetail, succeed, Success } from '@fgv/ts-utils';
|
|
23
|
+
import { isMutableAccessors } from './fileTreeAccessors';
|
|
23
24
|
/**
|
|
24
25
|
* Class representing a file in a file tree.
|
|
25
26
|
* @public
|
|
26
27
|
*/
|
|
27
28
|
export class FileItem {
|
|
28
29
|
/**
|
|
29
|
-
* {@
|
|
30
|
+
* {@inheritDoc FileTree.IFileTreeFileItem.name}
|
|
30
31
|
*/
|
|
31
32
|
get name() {
|
|
32
33
|
return this._hal.getBaseName(this.absolutePath);
|
|
33
34
|
}
|
|
34
35
|
/**
|
|
35
|
-
* {@
|
|
36
|
+
* {@inheritDoc FileTree.IFileTreeFileItem.baseName}
|
|
36
37
|
*/
|
|
37
38
|
get baseName() {
|
|
38
39
|
return this._hal.getBaseName(this.absolutePath, this.extension);
|
|
39
40
|
}
|
|
40
41
|
/**
|
|
41
|
-
* {@
|
|
42
|
+
* {@inheritDoc FileTree.IFileTreeFileItem.extension}
|
|
42
43
|
*/
|
|
43
44
|
get extension() {
|
|
44
45
|
return this._hal.getExtension(this.absolutePath);
|
|
45
46
|
}
|
|
46
47
|
/**
|
|
47
|
-
* {@
|
|
48
|
+
* {@inheritDoc FileTree.IFileTreeFileItem.contentType}
|
|
48
49
|
*/
|
|
49
50
|
get contentType() {
|
|
50
51
|
return this._contentType;
|
|
@@ -58,7 +59,7 @@ export class FileItem {
|
|
|
58
59
|
*/
|
|
59
60
|
constructor(path, hal) {
|
|
60
61
|
/**
|
|
61
|
-
* {@
|
|
62
|
+
* {@inheritDoc FileTree.IFileTreeFileItem."type"}
|
|
62
63
|
*/
|
|
63
64
|
this.type = 'file';
|
|
64
65
|
this._hal = hal;
|
|
@@ -75,6 +76,16 @@ export class FileItem {
|
|
|
75
76
|
static create(path, hal) {
|
|
76
77
|
return captureResult(() => new FileItem(path, hal));
|
|
77
78
|
}
|
|
79
|
+
/**
|
|
80
|
+
* {@inheritDoc FileTree.IFileTreeFileItem.getIsMutable}
|
|
81
|
+
*/
|
|
82
|
+
getIsMutable() {
|
|
83
|
+
if (isMutableAccessors(this._hal)) {
|
|
84
|
+
return this._hal.fileIsMutable(this.absolutePath);
|
|
85
|
+
}
|
|
86
|
+
/* c8 ignore next 2 - defensive: all current accessor implementations support mutation interface */
|
|
87
|
+
return failWithDetail(`${this.absolutePath}: mutation not supported`, 'not-supported');
|
|
88
|
+
}
|
|
78
89
|
getContents(converter) {
|
|
79
90
|
return this._hal
|
|
80
91
|
.getFileContents(this.absolutePath)
|
|
@@ -87,7 +98,7 @@ export class FileItem {
|
|
|
87
98
|
});
|
|
88
99
|
}
|
|
89
100
|
/**
|
|
90
|
-
* {@
|
|
101
|
+
* {@inheritDoc FileTree.IFileTreeFileItem.getRawContents}
|
|
91
102
|
*/
|
|
92
103
|
getRawContents() {
|
|
93
104
|
return this._hal.getFileContents(this.absolutePath);
|
|
@@ -99,15 +110,42 @@ export class FileItem {
|
|
|
99
110
|
setContentType(contentType) {
|
|
100
111
|
this._contentType = contentType;
|
|
101
112
|
}
|
|
113
|
+
/**
|
|
114
|
+
* {@inheritDoc FileTree.IFileTreeFileItem.setContents}
|
|
115
|
+
*/
|
|
116
|
+
setContents(json) {
|
|
117
|
+
return captureResult(() => JSON.stringify(json, null, 2)).onSuccess((contents) => this.setRawContents(contents).onSuccess(() => Success.with(json)));
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* {@inheritDoc FileTree.IFileTreeFileItem.setRawContents}
|
|
121
|
+
*/
|
|
122
|
+
setRawContents(contents) {
|
|
123
|
+
if (isMutableAccessors(this._hal)) {
|
|
124
|
+
return this._hal.saveFileContents(this.absolutePath, contents);
|
|
125
|
+
}
|
|
126
|
+
/* c8 ignore next 2 - defensive: all current accessor implementations support mutation interface */
|
|
127
|
+
return fail(`${this.absolutePath}: mutation not supported`);
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* {@inheritDoc FileTree.IFileTreeFileItem.delete}
|
|
131
|
+
*/
|
|
132
|
+
delete() {
|
|
133
|
+
if (!isMutableAccessors(this._hal)) {
|
|
134
|
+
/* c8 ignore next 2 - defensive: all current accessor implementations support mutation interface */
|
|
135
|
+
return fail(`${this.absolutePath}: mutation not supported`);
|
|
136
|
+
}
|
|
137
|
+
return this._hal.deleteFile(this.absolutePath);
|
|
138
|
+
}
|
|
102
139
|
/**
|
|
103
140
|
* Default function to infer the content type of a file.
|
|
104
141
|
* @param filePath - The path of the file.
|
|
142
|
+
* @param provided - Optional supplied content type.
|
|
105
143
|
* @returns `Success` with the content type of the file if successful, or
|
|
106
144
|
* `Failure` with an error message otherwise.
|
|
107
145
|
* @remarks This default implementation always returns `Success` with `undefined`.
|
|
108
146
|
* @public
|
|
109
147
|
*/
|
|
110
|
-
static defaultInferContentType(
|
|
148
|
+
static defaultInferContentType(filePath, provided) {
|
|
111
149
|
return succeed(undefined);
|
|
112
150
|
}
|
|
113
151
|
/**
|
|
@@ -119,7 +157,7 @@ export class FileItem {
|
|
|
119
157
|
* @remarks This default implementation always returns `Success` with `undefined`.
|
|
120
158
|
* @public
|
|
121
159
|
*/
|
|
122
|
-
static defaultAcceptContentType(
|
|
160
|
+
static defaultAcceptContentType(filePath, provided) {
|
|
123
161
|
return succeed(provided);
|
|
124
162
|
}
|
|
125
163
|
}
|
|
@@ -19,5 +19,63 @@
|
|
|
19
19
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
20
20
|
* SOFTWARE.
|
|
21
21
|
*/
|
|
22
|
-
|
|
22
|
+
// ============================================================================
|
|
23
|
+
// Type Guards
|
|
24
|
+
// ============================================================================
|
|
25
|
+
/**
|
|
26
|
+
* Type guard to check if accessors support mutation.
|
|
27
|
+
* @param accessors - The accessors to check.
|
|
28
|
+
* @returns `true` if the accessors implement {@link FileTree.IMutableFileTreeAccessors}.
|
|
29
|
+
* @public
|
|
30
|
+
*/
|
|
31
|
+
export function isMutableAccessors(accessors) {
|
|
32
|
+
const mutable = accessors;
|
|
33
|
+
return (typeof mutable.fileIsMutable === 'function' &&
|
|
34
|
+
typeof mutable.saveFileContents === 'function' &&
|
|
35
|
+
typeof mutable.deleteFile === 'function' &&
|
|
36
|
+
typeof mutable.createDirectory === 'function' &&
|
|
37
|
+
typeof mutable.deleteDirectory === 'function');
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Type guard to check if accessors support persistence.
|
|
41
|
+
* @param accessors - The accessors to check.
|
|
42
|
+
* @returns `true` if the accessors implement {@link FileTree.IPersistentFileTreeAccessors}.
|
|
43
|
+
* @public
|
|
44
|
+
*/
|
|
45
|
+
export function isPersistentAccessors(accessors) {
|
|
46
|
+
const persistent = accessors;
|
|
47
|
+
/* c8 ignore next 6 - no current accessor implements IPersistentFileTreeAccessors */
|
|
48
|
+
return (isMutableAccessors(accessors) &&
|
|
49
|
+
typeof persistent.syncToDisk === 'function' &&
|
|
50
|
+
typeof persistent.isDirty === 'function' &&
|
|
51
|
+
typeof persistent.getDirtyPaths === 'function');
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Type guard to check if a file item supports mutation.
|
|
55
|
+
* @param item - The file item to check.
|
|
56
|
+
* @returns `true` if the item implements {@link FileTree.IMutableFileTreeFileItem}.
|
|
57
|
+
* @public
|
|
58
|
+
*/
|
|
59
|
+
export function isMutableFileItem(item) {
|
|
60
|
+
const mutable = item;
|
|
61
|
+
return (mutable.type === 'file' &&
|
|
62
|
+
typeof mutable.getIsMutable === 'function' &&
|
|
63
|
+
typeof mutable.setContents === 'function' &&
|
|
64
|
+
typeof mutable.setRawContents === 'function' &&
|
|
65
|
+
typeof mutable.delete === 'function');
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Type guard to check if a directory item supports mutation.
|
|
69
|
+
* @param item - The directory item to check.
|
|
70
|
+
* @returns `true` if the item implements {@link FileTree.IMutableFileTreeDirectoryItem}.
|
|
71
|
+
* @public
|
|
72
|
+
*/
|
|
73
|
+
export function isMutableDirectoryItem(item) {
|
|
74
|
+
const mutable = item;
|
|
75
|
+
return (mutable.type === 'directory' &&
|
|
76
|
+
typeof mutable.createChildFile === 'function' &&
|
|
77
|
+
typeof mutable.createChildDirectory === 'function' &&
|
|
78
|
+
typeof mutable.deleteChild === 'function' &&
|
|
79
|
+
typeof mutable.delete === 'function');
|
|
80
|
+
}
|
|
23
81
|
//# sourceMappingURL=fileTreeAccessors.js.map
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2025 Erik Fortune
|
|
3
|
+
*
|
|
4
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
5
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
6
|
+
* in the Software without restriction, including without limitation the rights
|
|
7
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
8
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
9
|
+
* furnished to do so, subject to the following conditions:
|
|
10
|
+
*
|
|
11
|
+
* The above copyright notice and this permission notice shall be included in all
|
|
12
|
+
* copies or substantial portions of the Software.
|
|
13
|
+
*
|
|
14
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
15
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
16
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
17
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
18
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
19
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
20
|
+
* SOFTWARE.
|
|
21
|
+
*/
|
|
22
|
+
/**
|
|
23
|
+
* Checks if a path matches a single pattern (string or RegExp).
|
|
24
|
+
* @param path - The path to check.
|
|
25
|
+
* @param pattern - The pattern to match against.
|
|
26
|
+
* @returns `true` if the path matches the pattern.
|
|
27
|
+
* @internal
|
|
28
|
+
*/
|
|
29
|
+
function matchesPattern(path, pattern) {
|
|
30
|
+
if (typeof pattern === 'string') {
|
|
31
|
+
return path === pattern || path.startsWith(pattern + '/') || path.includes(pattern);
|
|
32
|
+
}
|
|
33
|
+
return pattern.test(path);
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Checks if a path matches any pattern in an array.
|
|
37
|
+
* @param path - The path to check.
|
|
38
|
+
* @param patterns - The patterns to match against.
|
|
39
|
+
* @returns `true` if the path matches any pattern.
|
|
40
|
+
* @internal
|
|
41
|
+
*/
|
|
42
|
+
function matchesAny(path, patterns) {
|
|
43
|
+
if (!patterns || patterns.length === 0) {
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
return patterns.some((pattern) => matchesPattern(path, pattern));
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Checks if a path is allowed by a mutability configuration.
|
|
50
|
+
* @param path - The path to check.
|
|
51
|
+
* @param mutable - The mutability configuration.
|
|
52
|
+
* @returns `true` if the path is mutable according to the configuration.
|
|
53
|
+
* @public
|
|
54
|
+
*/
|
|
55
|
+
export function isPathMutable(path, mutable) {
|
|
56
|
+
if (mutable === undefined || mutable === false) {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
if (mutable === true) {
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
const { include, exclude } = mutable;
|
|
63
|
+
// If exclude patterns are specified and path matches, it's not mutable
|
|
64
|
+
if (matchesAny(path, exclude)) {
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
// If include patterns are specified, path must match at least one
|
|
68
|
+
if (include && include.length > 0) {
|
|
69
|
+
return matchesAny(path, include);
|
|
70
|
+
}
|
|
71
|
+
// No include patterns means all paths (not excluded) are mutable
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=filterSpec.js.map
|