@fgv/ts-json-base 5.0.0-9 → 5.0.1-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 (65) hide show
  1. package/CHANGELOG.json +9 -6
  2. package/README.md +150 -0
  3. package/dist/ts-json-base.d.ts +674 -9
  4. package/dist/tsdoc-metadata.json +1 -1
  5. package/eslint.config.js +16 -0
  6. package/lib/index.browser.d.ts +7 -0
  7. package/lib/index.browser.js +72 -0
  8. package/lib/index.d.ts +2 -1
  9. package/lib/index.js +3 -1
  10. package/lib/packlets/file-tree/directoryItem.d.ts +47 -0
  11. package/lib/packlets/file-tree/directoryItem.js +71 -0
  12. package/lib/packlets/file-tree/fileItem.d.ts +97 -0
  13. package/lib/packlets/file-tree/fileItem.js +130 -0
  14. package/lib/packlets/file-tree/fileTree.d.ts +49 -0
  15. package/lib/packlets/file-tree/fileTree.js +89 -0
  16. package/lib/packlets/file-tree/fileTreeAccessors.d.ts +158 -0
  17. package/lib/packlets/file-tree/fileTreeAccessors.js +24 -0
  18. package/lib/packlets/file-tree/fileTreeHelpers.d.ts +43 -0
  19. package/lib/packlets/file-tree/fileTreeHelpers.js +38 -0
  20. package/lib/packlets/file-tree/fsTree.d.ts +57 -0
  21. package/lib/packlets/file-tree/fsTree.js +129 -0
  22. package/lib/packlets/file-tree/in-memory/inMemoryTree.d.ts +83 -0
  23. package/lib/packlets/file-tree/in-memory/inMemoryTree.js +181 -0
  24. package/lib/packlets/file-tree/in-memory/index.d.ts +2 -0
  25. package/lib/packlets/file-tree/in-memory/index.js +39 -0
  26. package/lib/packlets/file-tree/in-memory/treeBuilder.d.ts +113 -0
  27. package/lib/packlets/file-tree/in-memory/treeBuilder.js +179 -0
  28. package/lib/packlets/file-tree/index.browser.d.ts +6 -0
  29. package/lib/packlets/file-tree/index.browser.js +49 -0
  30. package/lib/packlets/file-tree/index.d.ts +8 -0
  31. package/lib/packlets/file-tree/index.js +50 -0
  32. package/lib/packlets/json/common.d.ts +56 -2
  33. package/lib/packlets/json/common.js +7 -3
  34. package/lib/packlets/json-file/index.browser.d.ts +4 -0
  35. package/lib/packlets/json-file/index.browser.js +46 -0
  36. package/lib/packlets/json-file/index.d.ts +2 -1
  37. package/lib/packlets/json-file/index.js +6 -1
  38. package/lib/packlets/json-file/jsonFsHelper.js +14 -44
  39. package/lib/packlets/json-file/jsonTreeHelper.d.ts +65 -0
  40. package/lib/packlets/json-file/jsonTreeHelper.js +120 -0
  41. package/lib/packlets/validators/validators.js +4 -4
  42. package/package.json +35 -19
  43. package/CHANGELOG.md +0 -100
  44. package/lib/index.d.ts.map +0 -1
  45. package/lib/index.js.map +0 -1
  46. package/lib/packlets/converters/converters.d.ts.map +0 -1
  47. package/lib/packlets/converters/converters.js.map +0 -1
  48. package/lib/packlets/converters/index.d.ts.map +0 -1
  49. package/lib/packlets/converters/index.js.map +0 -1
  50. package/lib/packlets/json/common.d.ts.map +0 -1
  51. package/lib/packlets/json/common.js.map +0 -1
  52. package/lib/packlets/json/index.d.ts.map +0 -1
  53. package/lib/packlets/json/index.js.map +0 -1
  54. package/lib/packlets/json-file/file.d.ts.map +0 -1
  55. package/lib/packlets/json-file/file.js.map +0 -1
  56. package/lib/packlets/json-file/index.d.ts.map +0 -1
  57. package/lib/packlets/json-file/index.js.map +0 -1
  58. package/lib/packlets/json-file/jsonFsHelper.d.ts.map +0 -1
  59. package/lib/packlets/json-file/jsonFsHelper.js.map +0 -1
  60. package/lib/packlets/json-file/jsonLike.d.ts.map +0 -1
  61. package/lib/packlets/json-file/jsonLike.js.map +0 -1
  62. package/lib/packlets/validators/index.d.ts.map +0 -1
  63. package/lib/packlets/validators/index.js.map +0 -1
  64. package/lib/packlets/validators/validators.d.ts.map +0 -1
  65. package/lib/packlets/validators/validators.js.map +0 -1
@@ -29,6 +29,59 @@ export interface JsonArray extends Array<JsonValue> {
29
29
  * @public
30
30
  */
31
31
  export type JsonValueType = 'primitive' | 'object' | 'array';
32
+ /**
33
+ * Helper type to detect if T is exactly unknown.
34
+ */
35
+ type IsUnknown<T> = unknown extends T ? ([T] extends [unknown] ? true : false) : false;
36
+ /**
37
+ * A constrained type that is compatible with JSON serialization.
38
+ *
39
+ * This type transforms input types to ensure they can be safely serialized to JSON:
40
+ * - JSON primitives (string, number, boolean, null) are preserved as-is
41
+ * - `undefined` is allowed for TypeScript compatibility with optional properties
42
+ * - Objects are recursively transformed with all properties made JSON-compatible
43
+ * - Arrays are transformed to contain only JSON-compatible elements
44
+ * - Functions are transformed to error types
45
+ * - Other non-JSON types are transformed to error types
46
+ *
47
+ * Note: While `undefined` is technically not JSON-serializable, it's allowed here
48
+ * to support TypeScript's optional property patterns. Use `sanitizeJsonObject`
49
+ * to remove undefined properties before actual JSON serialization.
50
+ *
51
+ * @param T - The type to be constrained
52
+ * @returns A constrained type that is compatible with JSON serialization.
53
+ *
54
+ * @example
55
+ * ```typescript
56
+ * interface IUser {
57
+ * name: string;
58
+ * email?: string; // Optional property can be undefined
59
+ * }
60
+ *
61
+ * type UserCompatible = JsonCompatible<IUser>; // Allows undefined for email
62
+ *
63
+ * const user: UserCompatible = {
64
+ * name: "John",
65
+ * email: undefined // This works
66
+ * };
67
+ *
68
+ * // Before JSON serialization, sanitize to remove undefined:
69
+ * const sanitized = sanitizeJsonObject(user); // Removes undefined properties
70
+ * JSON.stringify(sanitized.value); // Safe to serialize
71
+ * ```
72
+ *
73
+ * @public
74
+ */
75
+ export type JsonCompatible<T> = IsUnknown<T> extends true ? JsonValue : T extends JsonPrimitive | undefined ? T : T extends Array<unknown> ? JsonCompatibleArray<T[number]> : T extends Function ? ['Error: Function is not JSON-compatible'] : T extends object ? {
76
+ [K in keyof T]: JsonCompatible<T[K]>;
77
+ } : ['Error: Non-JSON type'];
78
+ /**
79
+ * A type that represents an array of JSON-compatible values.
80
+ * @param T - The type to be constrained
81
+ * @returns A constrained type that is compatible with JSON serialization.
82
+ * @public
83
+ */
84
+ export type JsonCompatibleArray<T> = Array<JsonCompatible<T>>;
32
85
  /**
33
86
  * Test if an `unknown` is a {@link JsonValue | JsonValue}.
34
87
  * @param from - The `unknown` to be tested
@@ -40,8 +93,8 @@ export declare function isJsonPrimitive(from: unknown): from is JsonPrimitive;
40
93
  /**
41
94
  * Test if an `unknown` is potentially a {@link JsonObject | JsonObject}.
42
95
  * @param from - The `unknown` to be tested.
43
- * @returns `true` if the supplied parameter is a non-array, non-special object,
44
- * `false` otherwise.
96
+ * @returns `true` if the supplied parameter is a non-array, non-special object
97
+ * with no symbol keys, `false` otherwise.
45
98
  * @public
46
99
  */
47
100
  export declare function isJsonObject(from: unknown): from is JsonObject;
@@ -101,4 +154,5 @@ export declare function sanitizeJson(from: unknown): Result<JsonValue>;
101
154
  * @public
102
155
  */
103
156
  export declare function sanitizeJsonObject<T>(from: T): Result<T>;
157
+ export {};
104
158
  //# sourceMappingURL=common.d.ts.map
@@ -43,8 +43,8 @@ function isJsonPrimitive(from) {
43
43
  /**
44
44
  * Test if an `unknown` is potentially a {@link JsonObject | JsonObject}.
45
45
  * @param from - The `unknown` to be tested.
46
- * @returns `true` if the supplied parameter is a non-array, non-special object,
47
- * `false` otherwise.
46
+ * @returns `true` if the supplied parameter is a non-array, non-special object
47
+ * with no symbol keys, `false` otherwise.
48
48
  * @public
49
49
  */
50
50
  function isJsonObject(from) {
@@ -52,7 +52,11 @@ function isJsonObject(from) {
52
52
  from !== null &&
53
53
  !Array.isArray(from) &&
54
54
  !(from instanceof RegExp) &&
55
- !(from instanceof Date));
55
+ !(from instanceof Date) &&
56
+ !(from instanceof Map) &&
57
+ !(from instanceof Set) &&
58
+ !(from instanceof Error) &&
59
+ Object.getOwnPropertySymbols(from).length === 0);
56
60
  }
57
61
  /**
58
62
  * Test if an `unknown` is potentially a {@link JsonArray | JsonArray}.
@@ -0,0 +1,4 @@
1
+ export * from './file';
2
+ export * from './jsonLike';
3
+ export * from './jsonTreeHelper';
4
+ //# sourceMappingURL=index.browser.d.ts.map
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ /*
3
+ * Copyright (c) 2020 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
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
24
+ if (k2 === undefined) k2 = k;
25
+ var desc = Object.getOwnPropertyDescriptor(m, k);
26
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
27
+ desc = { enumerable: true, get: function() { return m[k]; } };
28
+ }
29
+ Object.defineProperty(o, k2, desc);
30
+ }) : (function(o, m, k, k2) {
31
+ if (k2 === undefined) k2 = k;
32
+ o[k2] = m[k];
33
+ }));
34
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
35
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
36
+ };
37
+ Object.defineProperty(exports, "__esModule", { value: true });
38
+ // Browser-safe JSON file exports - excludes Node.js filesystem dependencies
39
+ // Export core JSON functionality (no filesystem deps)
40
+ __exportStar(require("./file"), exports);
41
+ __exportStar(require("./jsonLike"), exports);
42
+ // Export FileTree-based helper (web-compatible)
43
+ __exportStar(require("./jsonTreeHelper"), exports);
44
+ // Exclude:
45
+ // - jsonFsHelper (requires Node.js fs/path)
46
+ //# sourceMappingURL=index.browser.js.map
@@ -1,4 +1,5 @@
1
1
  export * from './file';
2
- export * from './jsonFsHelper';
3
2
  export * from './jsonLike';
3
+ export * from './jsonTreeHelper';
4
+ export * from './jsonFsHelper';
4
5
  //# sourceMappingURL=index.d.ts.map
@@ -35,7 +35,12 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
35
35
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
36
36
  };
37
37
  Object.defineProperty(exports, "__esModule", { value: true });
38
+ // Export core JSON functionality (no filesystem deps)
38
39
  __exportStar(require("./file"), exports);
39
- __exportStar(require("./jsonFsHelper"), exports);
40
40
  __exportStar(require("./jsonLike"), exports);
41
+ // Export FileTree-based helper (web-compatible)
42
+ __exportStar(require("./jsonTreeHelper"), exports);
43
+ // Export filesystem helpers separately for tree-shaking
44
+ // Web apps that don't import JsonFsHelper won't bundle fs/path
45
+ __exportStar(require("./jsonFsHelper"), exports);
41
46
  //# sourceMappingURL=index.js.map
@@ -20,44 +20,14 @@
20
20
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
21
  * SOFTWARE.
22
22
  */
23
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
24
- if (k2 === undefined) k2 = k;
25
- var desc = Object.getOwnPropertyDescriptor(m, k);
26
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
27
- desc = { enumerable: true, get: function() { return m[k]; } };
28
- }
29
- Object.defineProperty(o, k2, desc);
30
- }) : (function(o, m, k, k2) {
31
- if (k2 === undefined) k2 = k;
32
- o[k2] = m[k];
33
- }));
34
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
35
- Object.defineProperty(o, "default", { enumerable: true, value: v });
36
- }) : function(o, v) {
37
- o["default"] = v;
38
- });
39
- var __importStar = (this && this.__importStar) || (function () {
40
- var ownKeys = function(o) {
41
- ownKeys = Object.getOwnPropertyNames || function (o) {
42
- var ar = [];
43
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
44
- return ar;
45
- };
46
- return ownKeys(o);
47
- };
48
- return function (mod) {
49
- if (mod && mod.__esModule) return mod;
50
- var result = {};
51
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
52
- __setModuleDefault(result, mod);
53
- return result;
54
- };
55
- })();
23
+ var __importDefault = (this && this.__importDefault) || function (mod) {
24
+ return (mod && mod.__esModule) ? mod : { "default": mod };
25
+ };
56
26
  Object.defineProperty(exports, "__esModule", { value: true });
57
27
  exports.DefaultJsonFsHelper = exports.JsonFsHelper = exports.DefaultJsonFsHelperConfig = void 0;
58
28
  const ts_utils_1 = require("@fgv/ts-utils");
59
- const fs = __importStar(require("fs"));
60
- const path = __importStar(require("path"));
29
+ const fs_1 = __importDefault(require("fs"));
30
+ const path_1 = __importDefault(require("path"));
61
31
  const jsonLike_1 = require("./jsonLike");
62
32
  /**
63
33
  * Function to transform the name of some entity, given only a previous name. This
@@ -98,8 +68,8 @@ class JsonFsHelper {
98
68
  */
99
69
  readJsonFileSync(srcPath) {
100
70
  return (0, ts_utils_1.captureResult)(() => {
101
- const fullPath = path.resolve(srcPath);
102
- const body = fs.readFileSync(fullPath, 'utf8').toString();
71
+ const fullPath = path_1.default.resolve(srcPath);
72
+ const body = fs_1.default.readFileSync(fullPath, 'utf8').toString();
103
73
  return this.config.json.parse(body);
104
74
  });
105
75
  }
@@ -123,15 +93,15 @@ class JsonFsHelper {
123
93
  */
124
94
  convertJsonDirectorySync(srcPath, options, context) {
125
95
  return (0, ts_utils_1.captureResult)(() => {
126
- const fullPath = path.resolve(srcPath);
127
- if (!fs.statSync(fullPath).isDirectory()) {
96
+ const fullPath = path_1.default.resolve(srcPath);
97
+ if (!fs_1.default.statSync(fullPath).isDirectory()) {
128
98
  throw new Error(`${fullPath}: Not a directory`);
129
99
  }
130
- const files = fs.readdirSync(fullPath, { withFileTypes: true });
100
+ const files = fs_1.default.readdirSync(fullPath, { withFileTypes: true });
131
101
  const results = files
132
102
  .map((fi) => {
133
103
  if (fi.isFile() && this._pathMatchesOptions(options, fi.name)) {
134
- const filePath = path.resolve(fullPath, fi.name);
104
+ const filePath = path_1.default.resolve(fullPath, fi.name);
135
105
  return this.convertJsonFileSync(filePath, options.converter, context)
136
106
  .onSuccess((payload) => {
137
107
  return (0, ts_utils_1.succeed)({
@@ -162,7 +132,7 @@ class JsonFsHelper {
162
132
  var _a;
163
133
  const transformName = (_a = options.transformName) !== null && _a !== void 0 ? _a : defaultNameTransformer;
164
134
  return (0, ts_utils_1.mapResults)(items.map((item) => {
165
- const basename = path.basename(item.filename, '.json');
135
+ const basename = path_1.default.basename(item.filename, '.json');
166
136
  return transformName(basename, item.item).onSuccess((name) => {
167
137
  return (0, ts_utils_1.succeed)([name, item.item]);
168
138
  });
@@ -178,13 +148,13 @@ class JsonFsHelper {
178
148
  */
179
149
  writeJsonFileSync(srcPath, value) {
180
150
  return (0, ts_utils_1.captureResult)(() => {
181
- const fullPath = path.resolve(srcPath);
151
+ const fullPath = path_1.default.resolve(srcPath);
182
152
  const stringified = this.config.json.stringify(value, undefined, 2);
183
153
  /* c8 ignore next 3 */
184
154
  if (stringified === undefined && this.config.allowUndefinedWrite !== true) {
185
155
  throw new Error(`Could not stringify ${value}`);
186
156
  }
187
- fs.writeFileSync(fullPath, stringified);
157
+ fs_1.default.writeFileSync(fullPath, stringified);
188
158
  return true;
189
159
  });
190
160
  }
@@ -0,0 +1,65 @@
1
+ import { Converter, Result, Validator } from '@fgv/ts-utils';
2
+ import * as FileTree from '../file-tree';
3
+ import { JsonValue } from '../json';
4
+ import { IJsonLike } from './jsonLike';
5
+ import { IReadDirectoryItem } from './jsonFsHelper';
6
+ /**
7
+ * Helper class to work with JSON files using FileTree API (web-compatible).
8
+ * @public
9
+ */
10
+ export declare class JsonTreeHelper {
11
+ /**
12
+ * Configuration for this JsonTreeHelper.
13
+ */
14
+ readonly json: IJsonLike;
15
+ /**
16
+ * Construct a new JsonTreeHelper.
17
+ * @param json - Optional {@link JsonFile.IJsonLike | IJsonLike} used to process strings
18
+ * and JSON values.
19
+ */
20
+ constructor(json?: IJsonLike);
21
+ /**
22
+ * Read type-safe JSON from a file in a FileTree.
23
+ * @param fileTree - The FileTree to read from
24
+ * @param filePath - Path of the file to read within the tree
25
+ * @returns `Success` with a {@link JsonValue | JsonValue} or `Failure`
26
+ * with a message if an error occurs.
27
+ */
28
+ readJsonFromTree(fileTree: FileTree.FileTree, filePath: string): Result<JsonValue>;
29
+ /**
30
+ * Read a JSON file from a FileTree and apply a supplied converter or validator.
31
+ * @param fileTree - The FileTree to read from
32
+ * @param filePath - Path of the file to read within the tree
33
+ * @param cv - Converter or validator used to process the file.
34
+ * @param context - Optional context for the converter/validator
35
+ * @returns `Success` with a result of type `<T>`, or `Failure`
36
+ * with a message if an error occurs.
37
+ */
38
+ convertJsonFromTree<T, TC = unknown>(fileTree: FileTree.FileTree, filePath: string, cv: Converter<T, TC> | Validator<T, TC>, context?: TC): Result<T>;
39
+ /**
40
+ * Reads all JSON files from a directory in a FileTree and applies a converter or validator.
41
+ * @param fileTree - The FileTree to read from
42
+ * @param dirPath - The path of the directory within the tree
43
+ * @param cv - Converter or validator to apply to each JSON file
44
+ * @param filePattern - Optional regex pattern to filter files (defaults to .json files)
45
+ * @param context - Optional context for the converter/validator
46
+ * @returns Array of items with filename and converted content
47
+ */
48
+ convertJsonDirectoryFromTree<T, TC = unknown>(fileTree: FileTree.FileTree, dirPath: string, cv: Converter<T, TC> | Validator<T, TC>, filePattern?: RegExp, context?: TC): Result<IReadDirectoryItem<T>[]>;
49
+ /**
50
+ * Reads and converts all JSON files from a directory in a FileTree,
51
+ * returning a Map indexed by file base name.
52
+ * @param fileTree - The FileTree to read from
53
+ * @param dirPath - The path of the directory within the tree
54
+ * @param cv - Converter or validator to apply to each JSON file
55
+ * @param filePattern - Optional regex pattern to filter files
56
+ * @param context - Optional context for the converter/validator
57
+ * @returns Map of basename to converted content
58
+ */
59
+ convertJsonDirectoryToMapFromTree<T, TC = unknown>(fileTree: FileTree.FileTree, dirPath: string, cv: Converter<T, TC> | Validator<T, TC>, filePattern?: RegExp, context?: TC): Result<Map<string, T>>;
60
+ }
61
+ /**
62
+ * @public
63
+ */
64
+ export declare const DefaultJsonTreeHelper: JsonTreeHelper;
65
+ //# sourceMappingURL=jsonTreeHelper.d.ts.map
@@ -0,0 +1,120 @@
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.DefaultJsonTreeHelper = exports.JsonTreeHelper = void 0;
25
+ const ts_utils_1 = require("@fgv/ts-utils");
26
+ const jsonLike_1 = require("./jsonLike");
27
+ /**
28
+ * Helper class to work with JSON files using FileTree API (web-compatible).
29
+ * @public
30
+ */
31
+ class JsonTreeHelper {
32
+ /**
33
+ * Construct a new JsonTreeHelper.
34
+ * @param json - Optional {@link JsonFile.IJsonLike | IJsonLike} used to process strings
35
+ * and JSON values.
36
+ */
37
+ constructor(json) {
38
+ this.json = json !== null && json !== void 0 ? json : jsonLike_1.DefaultJsonLike;
39
+ }
40
+ /**
41
+ * Read type-safe JSON from a file in a FileTree.
42
+ * @param fileTree - The FileTree to read from
43
+ * @param filePath - Path of the file to read within the tree
44
+ * @returns `Success` with a {@link JsonValue | JsonValue} or `Failure`
45
+ * with a message if an error occurs.
46
+ */
47
+ readJsonFromTree(fileTree, filePath) {
48
+ return fileTree.getFile(filePath).onSuccess((file) => {
49
+ // Now getContents() returns JsonCompatible<unknown> which is assignable to JsonValue!
50
+ return file.getContents();
51
+ });
52
+ }
53
+ /**
54
+ * Read a JSON file from a FileTree and apply a supplied converter or validator.
55
+ * @param fileTree - The FileTree to read from
56
+ * @param filePath - Path of the file to read within the tree
57
+ * @param cv - Converter or validator used to process the file.
58
+ * @param context - Optional context for the converter/validator
59
+ * @returns `Success` with a result of type `<T>`, or `Failure`
60
+ * with a message if an error occurs.
61
+ */
62
+ convertJsonFromTree(fileTree, filePath, cv, context) {
63
+ return this.readJsonFromTree(fileTree, filePath).onSuccess((json) => {
64
+ return cv.convert(json, context);
65
+ });
66
+ }
67
+ /**
68
+ * Reads all JSON files from a directory in a FileTree and applies a converter or validator.
69
+ * @param fileTree - The FileTree to read from
70
+ * @param dirPath - The path of the directory within the tree
71
+ * @param cv - Converter or validator to apply to each JSON file
72
+ * @param filePattern - Optional regex pattern to filter files (defaults to .json files)
73
+ * @param context - Optional context for the converter/validator
74
+ * @returns Array of items with filename and converted content
75
+ */
76
+ convertJsonDirectoryFromTree(fileTree, dirPath, cv, filePattern, context) {
77
+ const pattern = filePattern !== null && filePattern !== void 0 ? filePattern : /\.json$/;
78
+ return fileTree.getDirectory(dirPath).onSuccess((dir) => {
79
+ return dir.getChildren().onSuccess((children) => {
80
+ const results = children
81
+ .filter((child) => child.type === 'file' && pattern.test(child.name))
82
+ .map((file) => {
83
+ return this.convertJsonFromTree(fileTree, file.absolutePath, cv, context).onSuccess((item) => {
84
+ return (0, ts_utils_1.succeed)({
85
+ filename: file.name,
86
+ item
87
+ });
88
+ });
89
+ });
90
+ return (0, ts_utils_1.mapResults)(results);
91
+ });
92
+ });
93
+ }
94
+ /**
95
+ * Reads and converts all JSON files from a directory in a FileTree,
96
+ * returning a Map indexed by file base name.
97
+ * @param fileTree - The FileTree to read from
98
+ * @param dirPath - The path of the directory within the tree
99
+ * @param cv - Converter or validator to apply to each JSON file
100
+ * @param filePattern - Optional regex pattern to filter files
101
+ * @param context - Optional context for the converter/validator
102
+ * @returns Map of basename to converted content
103
+ */
104
+ convertJsonDirectoryToMapFromTree(fileTree, dirPath, cv, filePattern, context) {
105
+ return this.convertJsonDirectoryFromTree(fileTree, dirPath, cv, filePattern, context).onSuccess((items) => {
106
+ const map = new Map();
107
+ for (const item of items) {
108
+ const basename = item.filename.replace(/\.json$/, '');
109
+ map.set(basename, item.item);
110
+ }
111
+ return (0, ts_utils_1.succeed)(map);
112
+ });
113
+ }
114
+ }
115
+ exports.JsonTreeHelper = JsonTreeHelper;
116
+ /**
117
+ * @public
118
+ */
119
+ exports.DefaultJsonTreeHelper = new JsonTreeHelper();
120
+ //# sourceMappingURL=jsonTreeHelper.js.map
@@ -30,7 +30,7 @@ const json_1 = require("../json");
30
30
  * @public
31
31
  */
32
32
  exports.jsonPrimitive = new ts_utils_1.Validation.Base.GenericValidator({
33
- validator: (from, ctx) => {
33
+ validator: (from, ctx, self) => {
34
34
  if (from === null) {
35
35
  return true;
36
36
  }
@@ -58,7 +58,7 @@ exports.jsonPrimitive = new ts_utils_1.Validation.Base.GenericValidator({
58
58
  * @public
59
59
  */
60
60
  exports.jsonObject = new ts_utils_1.Validation.Base.GenericValidator({
61
- validator: (from, ctx) => {
61
+ validator: (from, ctx, self) => {
62
62
  if (!(0, json_1.isJsonObject)(from)) {
63
63
  return (0, ts_utils_1.fail)('not a valid JSON object.');
64
64
  }
@@ -83,7 +83,7 @@ exports.jsonObject = new ts_utils_1.Validation.Base.GenericValidator({
83
83
  * @public
84
84
  */
85
85
  exports.jsonArray = new ts_utils_1.Validation.Base.GenericValidator({
86
- validator: (from, ctx) => {
86
+ validator: (from, ctx, self) => {
87
87
  if (!(0, json_1.isJsonArray)(from)) {
88
88
  return (0, ts_utils_1.fail)('not an array');
89
89
  }
@@ -109,7 +109,7 @@ exports.jsonArray = new ts_utils_1.Validation.Base.GenericValidator({
109
109
  * @public
110
110
  */
111
111
  exports.jsonValue = new ts_utils_1.Validation.Base.GenericValidator({
112
- validator: (from, ctx) => {
112
+ validator: (from, ctx, self) => {
113
113
  if ((0, json_1.isJsonArray)(from)) {
114
114
  const result = exports.jsonArray.validate(from, ctx);
115
115
  return result.success === true ? true : result;
package/package.json CHANGED
@@ -1,9 +1,22 @@
1
1
  {
2
2
  "name": "@fgv/ts-json-base",
3
- "version": "5.0.0-9",
3
+ "version": "5.0.1-1",
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",
7
+ "exports": {
8
+ ".": {
9
+ "node": {
10
+ "import": "./lib/index.js",
11
+ "require": "./lib/index.js"
12
+ },
13
+ "default": {
14
+ "import": "./lib/index.browser.js",
15
+ "require": "./lib/index.browser.js"
16
+ },
17
+ "types": "./dist/ts-json-base.d.ts"
18
+ }
19
+ },
7
20
  "keywords": [
8
21
  "typescript",
9
22
  "json"
@@ -18,36 +31,39 @@
18
31
  "devDependencies": {
19
32
  "@types/jest": "^29.5.14",
20
33
  "@types/node": "^20.14.9",
21
- "@typescript-eslint/eslint-plugin": "^7.14.1",
22
- "@typescript-eslint/parser": "^7.14.1",
23
- "eslint": "^8.57.0",
34
+ "@typescript-eslint/eslint-plugin": "^8.42.0",
35
+ "@typescript-eslint/parser": "^8.42.0",
36
+ "eslint": "^9.35.0",
24
37
  "eslint-plugin-import": "^2.32.0",
25
38
  "eslint-plugin-node": "^11.1.0",
26
- "eslint-plugin-promise": "^6.2.0",
39
+ "eslint-plugin-promise": "^7.2.1",
27
40
  "jest": "^29.7.0",
28
41
  "jest-extended": "^4.0.2",
29
- "rimraf": "^5.0.7",
30
- "ts-jest": "^29.4.0",
42
+ "rimraf": "^6.0.1",
43
+ "ts-jest": "^29.4.1",
31
44
  "ts-node": "^10.9.2",
32
- "typescript": "^5.7.3",
33
- "eslint-plugin-n": "^16.6.2",
34
- "@rushstack/heft-node-rig": "~2.9.0",
35
- "@rushstack/heft": "~0.74.0",
36
- "heft-jest": "~1.0.2",
45
+ "typescript": "5.8.3",
46
+ "eslint-plugin-n": "^17.21.3",
47
+ "@rushstack/heft-node-rig": "2.9.5",
48
+ "@rushstack/heft": "0.74.4",
49
+ "@rushstack/heft-jest-plugin": "0.16.13",
37
50
  "@types/heft-jest": "1.0.6",
38
- "@microsoft/api-documenter": "^7.26.29",
51
+ "@microsoft/api-documenter": "^7.26.31",
39
52
  "@rushstack/eslint-patch": "~1.12.0",
40
- "@rushstack/eslint-config": "~4.4.0",
53
+ "@rushstack/eslint-config": "4.4.0",
41
54
  "eslint-plugin-tsdoc": "~0.4.0",
42
- "@fgv/ts-utils": "5.0.0-9",
43
- "@fgv/ts-extras": "5.0.0-9",
44
- "@fgv/ts-utils-jest": "5.0.0-9"
55
+ "@types/luxon": "^3.7.1",
56
+ "@fgv/ts-utils": "5.0.1-1",
57
+ "@fgv/ts-utils-jest": "5.0.1-1"
45
58
  },
46
59
  "peerDependencies": {
47
- "@fgv/ts-utils": "5.0.0-9"
60
+ "@fgv/ts-utils": "5.0.1-1"
61
+ },
62
+ "dependencies": {
63
+ "luxon": "^3.7.2"
48
64
  },
49
65
  "scripts": {
50
- "build": "heft test --clean",
66
+ "build": "heft build --clean",
51
67
  "clean": "heft clean",
52
68
  "test": "heft test --clean",
53
69
  "build-docs": "api-documenter markdown --input-folder ./temp --output-folder docs",