@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.
Files changed (43) hide show
  1. package/dist/packlets/converters/converters.js +36 -14
  2. package/dist/packlets/file-tree/directoryItem.js +99 -4
  3. package/dist/packlets/file-tree/fileItem.js +47 -9
  4. package/dist/packlets/file-tree/fileTreeAccessors.js +59 -1
  5. package/dist/packlets/file-tree/filterSpec.js +74 -0
  6. package/dist/packlets/file-tree/fsTree.js +107 -12
  7. package/dist/packlets/file-tree/in-memory/inMemoryTree.js +279 -21
  8. package/dist/packlets/file-tree/in-memory/treeBuilder.js +31 -0
  9. package/dist/packlets/file-tree/index.browser.js +1 -0
  10. package/dist/packlets/file-tree/index.js +1 -0
  11. package/dist/packlets/json-file/file.js +1 -1
  12. package/dist/packlets/json-file/jsonFsHelper.js +1 -1
  13. package/dist/packlets/validators/validators.js +8 -8
  14. package/dist/ts-json-base.d.ts +439 -65
  15. package/dist/tsdoc-metadata.json +1 -1
  16. package/lib/packlets/converters/converters.d.ts +20 -13
  17. package/lib/packlets/converters/converters.js +36 -13
  18. package/lib/packlets/file-tree/directoryItem.d.ts +29 -6
  19. package/lib/packlets/file-tree/directoryItem.js +98 -3
  20. package/lib/packlets/file-tree/fileItem.d.ts +31 -14
  21. package/lib/packlets/file-tree/fileItem.js +46 -8
  22. package/lib/packlets/file-tree/fileTreeAccessors.d.ts +237 -3
  23. package/lib/packlets/file-tree/fileTreeAccessors.js +63 -0
  24. package/lib/packlets/file-tree/filterSpec.d.ts +10 -0
  25. package/lib/packlets/file-tree/filterSpec.js +77 -0
  26. package/lib/packlets/file-tree/fsTree.d.ts +37 -13
  27. package/lib/packlets/file-tree/fsTree.js +106 -11
  28. package/lib/packlets/file-tree/in-memory/inMemoryTree.d.ts +37 -13
  29. package/lib/packlets/file-tree/in-memory/inMemoryTree.js +278 -20
  30. package/lib/packlets/file-tree/in-memory/treeBuilder.d.ts +15 -0
  31. package/lib/packlets/file-tree/in-memory/treeBuilder.js +31 -0
  32. package/lib/packlets/file-tree/index.browser.d.ts +1 -0
  33. package/lib/packlets/file-tree/index.browser.js +1 -0
  34. package/lib/packlets/file-tree/index.d.ts +1 -0
  35. package/lib/packlets/file-tree/index.js +1 -0
  36. package/lib/packlets/json-file/file.d.ts +1 -1
  37. package/lib/packlets/json-file/file.js +1 -1
  38. package/lib/packlets/json-file/jsonFsHelper.d.ts +1 -1
  39. package/lib/packlets/json-file/jsonFsHelper.js +1 -1
  40. package/lib/packlets/validators/validators.d.ts +9 -9
  41. package/lib/packlets/validators/validators.js +8 -8
  42. package/package.json +29 -30
  43. 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
- * {@link Converters.IJsonConverterContext | context} at runtime.
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
- * {@link Converters.IJsonConverterContext | context} at runtime.
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
- * {@link Converters.IJsonConverterContext | context} at runtime.
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 {@link Converter | Converter} which converts `unknown` to a `string`.
136
- * Accepts {@link Converters.IJsonConverterContext | IJsonConverterContext} but ignores it.
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 {@link Converter | Converter} which converts `unknown` to a `number`.
142
- * Accepts {@link Converters.IJsonConverterContext | IJsonConverterContext} but ignores it.
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 {@link Converter | Converter} which converts `unknown` to a `boolean`.
149
- * Accepts {@link Converters.IJsonConverterContext | IJsonConverterContext} but ignores it.
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 {@link Converters.IJsonConverterContext | IJsonConverterContext} but ignores it.
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 {@link Converter | Converter} which converts `unknown` to one of a set of
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 {@link Converters.IJsonConverterContext | IJsonConverterContext} OR
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 {@link Converter | Converter} returning `<T>`.
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
- * {@inheritdoc FileTree.IFileTreeDirectoryItem.name}
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
- * {@inheritdoc FileTree.IFileTreeDirectoryItem."type"}
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
- * {@inheritdoc FileTree.IFileTreeDirectoryItem.getChildren}
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
- * {@inheritdoc FileTree.IFileTreeFileItem.name}
30
+ * {@inheritDoc FileTree.IFileTreeFileItem.name}
30
31
  */
31
32
  get name() {
32
33
  return this._hal.getBaseName(this.absolutePath);
33
34
  }
34
35
  /**
35
- * {@inheritdoc FileTree.IFileTreeFileItem.baseName}
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
- * {@inheritdoc FileTree.IFileTreeFileItem.extension}
42
+ * {@inheritDoc FileTree.IFileTreeFileItem.extension}
42
43
  */
43
44
  get extension() {
44
45
  return this._hal.getExtension(this.absolutePath);
45
46
  }
46
47
  /**
47
- * {@inheritdoc FileTree.IFileTreeFileItem.contentType}
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
- * {@inheritdoc FileTree.IFileTreeFileItem."type"}
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
- * {@inheritdoc FileTree.IFileTreeFileItem.getRawContents}
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(__filePath, __provided) {
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(__filePath, provided) {
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
- export {};
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