@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.
- package/CHANGELOG.json +9 -6
- package/README.md +150 -0
- package/dist/ts-json-base.d.ts +674 -9
- package/dist/tsdoc-metadata.json +1 -1
- package/eslint.config.js +16 -0
- package/lib/index.browser.d.ts +7 -0
- package/lib/index.browser.js +72 -0
- package/lib/index.d.ts +2 -1
- package/lib/index.js +3 -1
- package/lib/packlets/file-tree/directoryItem.d.ts +47 -0
- package/lib/packlets/file-tree/directoryItem.js +71 -0
- package/lib/packlets/file-tree/fileItem.d.ts +97 -0
- package/lib/packlets/file-tree/fileItem.js +130 -0
- package/lib/packlets/file-tree/fileTree.d.ts +49 -0
- package/lib/packlets/file-tree/fileTree.js +89 -0
- package/lib/packlets/file-tree/fileTreeAccessors.d.ts +158 -0
- package/lib/packlets/file-tree/fileTreeAccessors.js +24 -0
- package/lib/packlets/file-tree/fileTreeHelpers.d.ts +43 -0
- package/lib/packlets/file-tree/fileTreeHelpers.js +38 -0
- package/lib/packlets/file-tree/fsTree.d.ts +57 -0
- package/lib/packlets/file-tree/fsTree.js +129 -0
- package/lib/packlets/file-tree/in-memory/inMemoryTree.d.ts +83 -0
- package/lib/packlets/file-tree/in-memory/inMemoryTree.js +181 -0
- package/lib/packlets/file-tree/in-memory/index.d.ts +2 -0
- package/lib/packlets/file-tree/in-memory/index.js +39 -0
- package/lib/packlets/file-tree/in-memory/treeBuilder.d.ts +113 -0
- package/lib/packlets/file-tree/in-memory/treeBuilder.js +179 -0
- package/lib/packlets/file-tree/index.browser.d.ts +6 -0
- package/lib/packlets/file-tree/index.browser.js +49 -0
- package/lib/packlets/file-tree/index.d.ts +8 -0
- package/lib/packlets/file-tree/index.js +50 -0
- package/lib/packlets/json/common.d.ts +56 -2
- package/lib/packlets/json/common.js +7 -3
- package/lib/packlets/json-file/index.browser.d.ts +4 -0
- package/lib/packlets/json-file/index.browser.js +46 -0
- package/lib/packlets/json-file/index.d.ts +2 -1
- package/lib/packlets/json-file/index.js +6 -1
- package/lib/packlets/json-file/jsonFsHelper.js +14 -44
- package/lib/packlets/json-file/jsonTreeHelper.d.ts +65 -0
- package/lib/packlets/json-file/jsonTreeHelper.js +120 -0
- package/lib/packlets/validators/validators.js +4 -4
- package/package.json +35 -19
- package/CHANGELOG.md +0 -100
- package/lib/index.d.ts.map +0 -1
- package/lib/index.js.map +0 -1
- package/lib/packlets/converters/converters.d.ts.map +0 -1
- package/lib/packlets/converters/converters.js.map +0 -1
- package/lib/packlets/converters/index.d.ts.map +0 -1
- package/lib/packlets/converters/index.js.map +0 -1
- package/lib/packlets/json/common.d.ts.map +0 -1
- package/lib/packlets/json/common.js.map +0 -1
- package/lib/packlets/json/index.d.ts.map +0 -1
- package/lib/packlets/json/index.js.map +0 -1
- package/lib/packlets/json-file/file.d.ts.map +0 -1
- package/lib/packlets/json-file/file.js.map +0 -1
- package/lib/packlets/json-file/index.d.ts.map +0 -1
- package/lib/packlets/json-file/index.js.map +0 -1
- package/lib/packlets/json-file/jsonFsHelper.d.ts.map +0 -1
- package/lib/packlets/json-file/jsonFsHelper.js.map +0 -1
- package/lib/packlets/json-file/jsonLike.d.ts.map +0 -1
- package/lib/packlets/json-file/jsonLike.js.map +0 -1
- package/lib/packlets/validators/index.d.ts.map +0 -1
- package/lib/packlets/validators/index.js.map +0 -1
- package/lib/packlets/validators/validators.d.ts.map +0 -1
- 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,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
|
|
@@ -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
|
|
24
|
-
|
|
25
|
-
|
|
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
|
|
60
|
-
const
|
|
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 =
|
|
102
|
-
const body =
|
|
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 =
|
|
127
|
-
if (!
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
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.
|
|
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": "^
|
|
22
|
-
"@typescript-eslint/parser": "^
|
|
23
|
-
"eslint": "^
|
|
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": "^
|
|
39
|
+
"eslint-plugin-promise": "^7.2.1",
|
|
27
40
|
"jest": "^29.7.0",
|
|
28
41
|
"jest-extended": "^4.0.2",
|
|
29
|
-
"rimraf": "^
|
|
30
|
-
"ts-jest": "^29.4.
|
|
42
|
+
"rimraf": "^6.0.1",
|
|
43
|
+
"ts-jest": "^29.4.1",
|
|
31
44
|
"ts-node": "^10.9.2",
|
|
32
|
-
"typescript": "
|
|
33
|
-
"eslint-plugin-n": "^
|
|
34
|
-
"@rushstack/heft-node-rig": "
|
|
35
|
-
"@rushstack/heft": "
|
|
36
|
-
"heft-jest": "
|
|
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.
|
|
51
|
+
"@microsoft/api-documenter": "^7.26.31",
|
|
39
52
|
"@rushstack/eslint-patch": "~1.12.0",
|
|
40
|
-
"@rushstack/eslint-config": "
|
|
53
|
+
"@rushstack/eslint-config": "4.4.0",
|
|
41
54
|
"eslint-plugin-tsdoc": "~0.4.0",
|
|
42
|
-
"@
|
|
43
|
-
"@fgv/ts-
|
|
44
|
-
"@fgv/ts-utils-jest": "5.0.
|
|
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.
|
|
60
|
+
"@fgv/ts-utils": "5.0.1-1"
|
|
61
|
+
},
|
|
62
|
+
"dependencies": {
|
|
63
|
+
"luxon": "^3.7.2"
|
|
48
64
|
},
|
|
49
65
|
"scripts": {
|
|
50
|
-
"build": "heft
|
|
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",
|