@fgv/ts-res 5.0.0-23 → 5.0.0-24

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 (110) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/lib/packlets/runtime/index.d.ts +1 -0
  3. package/lib/packlets/runtime/index.js +1 -0
  4. package/lib/packlets/runtime/resourceTreeResolver.d.ts +152 -0
  5. package/lib/packlets/runtime/resourceTreeResolver.js +222 -0
  6. package/package.json +12 -12
  7. package/.vscode/4.json +0 -3
  8. package/.vscode/launch.json +0 -16
  9. package/.vscode/settings.json +0 -3
  10. package/dist/ts-res.d.ts +0 -10115
  11. package/dist/tsdoc-metadata.json +0 -11
  12. package/lib/test/data/sample.json +0 -32
  13. package/lib/test/unit/bundle/bundleBuilder.test.d.ts +0 -2
  14. package/lib/test/unit/bundle/bundleLoader.test.d.ts +0 -2
  15. package/lib/test/unit/bundle/bundleUtils.test.d.ts +0 -2
  16. package/lib/test/unit/bundle/convert.test.d.ts +0 -2
  17. package/lib/test/unit/bundle/integration.test.d.ts +0 -2
  18. package/lib/test/unit/bundle/model.test.d.ts +0 -2
  19. package/lib/test/unit/bundle/normalization.test.d.ts +0 -2
  20. package/lib/test/unit/common/conditions.test.d.ts +0 -2
  21. package/lib/test/unit/common/helpers/conditions.test.d.ts +0 -2
  22. package/lib/test/unit/common/helpers/contexts.test.d.ts +0 -2
  23. package/lib/test/unit/common/helpers/qualifierDefaultValues.test.d.ts +0 -2
  24. package/lib/test/unit/common/resources.test.d.ts +0 -2
  25. package/lib/test/unit/conditions/condition.test.d.ts +0 -2
  26. package/lib/test/unit/conditions/conditionCollector.test.d.ts +0 -2
  27. package/lib/test/unit/conditions/conditionScoreAsDefault.test.d.ts +0 -2
  28. package/lib/test/unit/conditions/conditionSet.test.d.ts +0 -2
  29. package/lib/test/unit/conditions/conditionSetCollector.test.d.ts +0 -2
  30. package/lib/test/unit/conditions/conditionToken.test.d.ts +0 -2
  31. package/lib/test/unit/conditions/convert.test.d.ts +0 -2
  32. package/lib/test/unit/config/common.test.d.ts +0 -2
  33. package/lib/test/unit/config/convert.test.d.ts +0 -2
  34. package/lib/test/unit/config/predefined/default.test.d.ts +0 -2
  35. package/lib/test/unit/config/predefined/extended.test.d.ts +0 -2
  36. package/lib/test/unit/config/systemConfiguration.test.d.ts +0 -2
  37. package/lib/test/unit/config/systemConfigurationInitParams.test.d.ts +0 -2
  38. package/lib/test/unit/context/contextToken.test.d.ts +0 -2
  39. package/lib/test/unit/context/convert.test.d.ts +0 -2
  40. package/lib/test/unit/decisions/abstractDecision.test.d.ts +0 -2
  41. package/lib/test/unit/decisions/abstractDecisionCollector.test.d.ts +0 -2
  42. package/lib/test/unit/decisions/candidate.test.d.ts +0 -2
  43. package/lib/test/unit/decisions/concreteDecision.test.d.ts +0 -2
  44. package/lib/test/unit/decisions/decision.test.d.ts +0 -2
  45. package/lib/test/unit/import/collectionImporter.test.d.ts +0 -2
  46. package/lib/test/unit/import/fsItem.test.d.ts +0 -2
  47. package/lib/test/unit/import/fsItemImporter.test.d.ts +0 -2
  48. package/lib/test/unit/import/importContext.test.d.ts +0 -2
  49. package/lib/test/unit/import/importManager.test.d.ts +0 -2
  50. package/lib/test/unit/import/jsonImporter.test.d.ts +0 -2
  51. package/lib/test/unit/import/pathImporter.test.d.ts +0 -2
  52. package/lib/test/unit/qualifier-types/convert.test.d.ts +0 -2
  53. package/lib/test/unit/qualifier-types/helpers.test.d.ts +0 -2
  54. package/lib/test/unit/qualifier-types/languageQualifierType.test.d.ts +0 -2
  55. package/lib/test/unit/qualifier-types/literalQualifierType.test.d.ts +0 -2
  56. package/lib/test/unit/qualifier-types/literalValueHierarchy.test.d.ts +0 -2
  57. package/lib/test/unit/qualifier-types/qualifierType.test.d.ts +0 -2
  58. package/lib/test/unit/qualifier-types/qualifierTypeCollector.test.d.ts +0 -2
  59. package/lib/test/unit/qualifier-types/territoryQualifierType.test.d.ts +0 -2
  60. package/lib/test/unit/qualifier-types/testQualifierType.d.ts +0 -19
  61. package/lib/test/unit/qualifier-types/testQualifierType.js +0 -113
  62. package/lib/test/unit/qualifiers/convert.test.d.ts +0 -2
  63. package/lib/test/unit/qualifiers/qualifierCollector.test.d.ts +0 -2
  64. package/lib/test/unit/qualifiers/qualifierDefaultValue.test.d.ts +0 -2
  65. package/lib/test/unit/qualifiers/qualifierDefaultValueToken.test.d.ts +0 -2
  66. package/lib/test/unit/resource-json/convert.test.d.ts +0 -2
  67. package/lib/test/unit/resource-json/nameInheritance.test.d.ts +0 -2
  68. package/lib/test/unit/resource-json/resourceDeclCollection.test.d.ts +0 -2
  69. package/lib/test/unit/resource-json/resourceDeclTree.test.d.ts +0 -2
  70. package/lib/test/unit/resource-types/derivedResourceType.test.d.ts +0 -2
  71. package/lib/test/unit/resource-types/jsonResourceType.test.d.ts +0 -2
  72. package/lib/test/unit/resource-types/resourceTypeCollector.test.d.ts +0 -2
  73. package/lib/test/unit/resource-types/testDerivedResourceType.d.ts +0 -79
  74. package/lib/test/unit/resource-types/testDerivedResourceType.js +0 -113
  75. package/lib/test/unit/resources/candidateReducer.integration.test.d.ts +0 -2
  76. package/lib/test/unit/resources/candidateReducer.test.d.ts +0 -2
  77. package/lib/test/unit/resources/candidateValue.test.d.ts +0 -2
  78. package/lib/test/unit/resources/candidateValueCollector.test.d.ts +0 -2
  79. package/lib/test/unit/resources/reduceCandidates.test.d.ts +0 -2
  80. package/lib/test/unit/resources/reduceQualifiers.comprehensive.test.d.ts +0 -2
  81. package/lib/test/unit/resources/reduceQualifiers.test.d.ts +0 -2
  82. package/lib/test/unit/resources/resource.test.d.ts +0 -2
  83. package/lib/test/unit/resources/resourceBuilder.test.d.ts +0 -2
  84. package/lib/test/unit/resources/resourceCandidate.test.d.ts +0 -2
  85. package/lib/test/unit/resources/resourceManagerBuilder.clone.test.d.ts +0 -2
  86. package/lib/test/unit/resources/resourceManagerBuilder.getBuiltResourceTree.test.d.ts +0 -2
  87. package/lib/test/unit/resources/resourceManagerBuilder.test.d.ts +0 -2
  88. package/lib/test/unit/runtime/cacheListener.test.d.ts +0 -2
  89. package/lib/test/unit/runtime/cacheMetrics.test.d.ts +0 -2
  90. package/lib/test/unit/runtime/compiledResourceCollection.test.d.ts +0 -2
  91. package/lib/test/unit/runtime/conditionSetResolutionResult.comprehensive.test.d.ts +0 -2
  92. package/lib/test/unit/runtime/conditionSetResolutionResult.test.d.ts +0 -2
  93. package/lib/test/unit/runtime/context/contextQualifierProvider.test.d.ts +0 -2
  94. package/lib/test/unit/runtime/context/contextQualifierProviderValidator.test.d.ts +0 -2
  95. package/lib/test/unit/runtime/context/simpleContextQualifierProvider.test.d.ts +0 -2
  96. package/lib/test/unit/runtime/context/validatingSimpleContextQualifierProvider.test.d.ts +0 -2
  97. package/lib/test/unit/runtime/resource-tree/readOnlyResourceTree.test.d.ts +0 -2
  98. package/lib/test/unit/runtime/resource-tree/resourceTreeChildren.test.d.ts +0 -2
  99. package/lib/test/unit/runtime/resource-tree/resourceTreeChildrenValidator.test.d.ts +0 -2
  100. package/lib/test/unit/runtime/resourceResolver.coverage.test.d.ts +0 -2
  101. package/lib/test/unit/runtime/resourceResolver.defaultResolution.test.d.ts +0 -2
  102. package/lib/test/unit/runtime/resourceResolver.newFeatures.test.d.ts +0 -2
  103. package/lib/test/unit/runtime/resourceResolver.test.d.ts +0 -2
  104. package/lib/test/unit/runtime/validate.test.d.ts +0 -2
  105. package/lib/test/unit/zip-archive/convert.test.d.ts +0 -2
  106. package/lib/test/unit/zip-archive/json.test.d.ts +0 -2
  107. package/lib/test/unit/zip-archive/zipArchiveCreator.test.d.ts +0 -2
  108. package/lib/test/unit/zip-archive/zipArchiveFormat.test.d.ts +0 -2
  109. package/lib/test/unit/zip-archive/zipArchiveIdempotency.test.d.ts +0 -2
  110. package/lib/test/unit/zip-archive/zipArchiveLoader.test.d.ts +0 -2
package/CHANGELOG.md ADDED
@@ -0,0 +1,14 @@
1
+ # Change Log - @fgv/ts-res
2
+
3
+ This log was last generated on Thu, 17 Jul 2025 00:13:24 GMT and should not be manually modified.
4
+
5
+ ## 5.0.0
6
+ Thu, 17 Jul 2025 00:13:24 GMT
7
+
8
+ ### Updates
9
+
10
+ - add decl generators
11
+ - fix merge errors
12
+ - flesh out tests
13
+ - initial checkin
14
+
@@ -3,6 +3,7 @@ export * from './iResourceManager';
3
3
  export * from './context/simpleContextQualifierProvider';
4
4
  export * from './context/validatingSimpleContextQualifierProvider';
5
5
  export * from './resourceResolver';
6
+ export * from './resourceTreeResolver';
6
7
  export * from './conditionSetResolutionResult';
7
8
  export * from './cacheListener';
8
9
  export * from './cacheMetrics';
@@ -63,6 +63,7 @@ __exportStar(require("./iResourceManager"), exports);
63
63
  __exportStar(require("./context/simpleContextQualifierProvider"), exports);
64
64
  __exportStar(require("./context/validatingSimpleContextQualifierProvider"), exports);
65
65
  __exportStar(require("./resourceResolver"), exports);
66
+ __exportStar(require("./resourceTreeResolver"), exports);
66
67
  __exportStar(require("./conditionSetResolutionResult"), exports);
67
68
  __exportStar(require("./cacheListener"), exports);
68
69
  __exportStar(require("./cacheMetrics"), exports);
@@ -0,0 +1,152 @@
1
+ import { Result } from '@fgv/ts-utils';
2
+ import { JsonValue, JsonObject } from '@fgv/ts-json-base';
3
+ import { IResource } from './iResourceManager';
4
+ import { IReadOnlyResourceTreeNode, IReadOnlyResourceTreeRoot } from './resource-tree/common';
5
+ import { ResourceResolver } from './resourceResolver';
6
+ /**
7
+ * Type for handling resource resolution errors during tree traversal.
8
+ * The handler receives the resource that failed to resolve, the error message, and the resolver for recovery attempts.
9
+ * It can return:
10
+ * - Success(undefined) to omit the property from the result
11
+ * - Success(value) to use an alternate value
12
+ * - Failure to propagate the error
13
+ * @public
14
+ */
15
+ export type ResourceErrorHandler = (resource: IResource, message: string, resolver: ResourceResolver) => Result<JsonValue | undefined>;
16
+ /**
17
+ * Type for handling empty branch nodes during tree composition.
18
+ * The handler receives the branch node, names of failed children, and the resolver for recovery attempts.
19
+ * It can return:
20
+ * - Success(undefined) to omit the branch from the result
21
+ * - Success(value) to use an alternate value for the branch
22
+ * - Failure to propagate the error
23
+ * @public
24
+ */
25
+ export type EmptyBranchHandler = (branchNode: IReadOnlyResourceTreeNode<IResource>, failedChildNames: string[], resolver: ResourceResolver) => Result<JsonValue | undefined>;
26
+ /**
27
+ * Options for configuring resource tree resolution.
28
+ * @public
29
+ */
30
+ export interface IResolveResourceTreeOptions {
31
+ /**
32
+ * Controls how errors are handled when resolving individual resources in the tree.
33
+ * - 'fail': Aggregate all errors and fail if any resource fails to resolve
34
+ * - 'ignore': Skip failed resources and omit them from the result
35
+ * - callback: Custom error handler that can provide alternate values or propagate errors
36
+ * @defaultValue 'fail'
37
+ */
38
+ onResourceError?: 'fail' | 'ignore' | ResourceErrorHandler;
39
+ /**
40
+ * Controls how empty branch nodes are handled during tree composition.
41
+ * - 'allow': Include empty branches as empty objects in the result
42
+ * - 'omit': Exclude empty branches from the parent object
43
+ * - callback: Custom handler that can provide alternate values or recovery logic
44
+ * @defaultValue 'allow'
45
+ */
46
+ onEmptyBranch?: 'allow' | 'omit' | EmptyBranchHandler;
47
+ }
48
+ /**
49
+ * Specialized resolver for resource tree operations, providing enhanced APIs for
50
+ * resolving entire resource trees from either resource IDs or pre-built tree nodes.
51
+ *
52
+ * This class provides a clean separation between individual resource resolution
53
+ * (handled by ResourceResolver) and tree-based operations, with support for
54
+ * lazy tree construction and enhanced error handling.
55
+ *
56
+ * @public
57
+ */
58
+ export declare class ResourceTreeResolver {
59
+ /**
60
+ * The {@link Runtime.ResourceResolver | ResourceResolver} to use for individual resource resolution
61
+ */
62
+ readonly resolver: ResourceResolver;
63
+ /**
64
+ * The {@link Runtime.IResourceManager | IResourceManager} to use for lazy tree construction.
65
+ * @internal
66
+ */
67
+ private readonly _resourceManager;
68
+ /**
69
+ * The built resource tree, lazily built on first access.
70
+ * @internal
71
+ */
72
+ private _tree?;
73
+ /**
74
+ * Creates a {@link Runtime.ResourceTreeResolver | ResourceTreeResolver} instance.
75
+ * @param resolver - The ResourceResolver to use for individual resource resolution
76
+ */
77
+ constructor(resolver: ResourceResolver);
78
+ /**
79
+ * Creates a {@link Runtime.ResourceTreeResolver | ResourceTreeResolver} instance.
80
+ * @param resolver - The ResourceResolver to use for individual resource resolution
81
+ */
82
+ static create(resolver: ResourceResolver): Result<ResourceTreeResolver>;
83
+ /**
84
+ * Gets the built resource tree, building it lazily on first access.
85
+ * @returns The resource tree root
86
+ * @throws Error if no resource manager was provided or tree building fails
87
+ * @public
88
+ */
89
+ get tree(): IReadOnlyResourceTreeRoot<IResource>;
90
+ /**
91
+ * Resolves a resource tree from a resource ID, building the tree lazily from the resource manager.
92
+ * @param resourceId - The ID of the root resource to resolve
93
+ * @param options - Optional configuration for error handling during resolution
94
+ * @returns Success with the composed JsonObject or undefined, or Failure with error message
95
+ * @public
96
+ */
97
+ resolveComposedResourceTree(resourceId: string, options?: IResolveResourceTreeOptions): Result<JsonObject | undefined>;
98
+ /**
99
+ * Resolves a pre-built resource tree node.
100
+ * @param node - The resource tree node to resolve
101
+ * @param options - Optional configuration for error handling during resolution
102
+ * @returns Success with the composed JsonObject or undefined, or Failure with error message
103
+ * @public
104
+ */
105
+ resolveComposedResourceTree(node: IReadOnlyResourceTreeNode<IResource>, options?: IResolveResourceTreeOptions): Result<JsonObject | undefined>;
106
+ private _getTree;
107
+ /**
108
+ * Resolves a tree from a resource ID by first building the tree from the resource manager.
109
+ * @internal
110
+ */
111
+ private _resolveFromResourceId;
112
+ /**
113
+ * Resolves a pre-built tree node using the extracted tree resolution logic.
114
+ * @internal
115
+ */
116
+ private _resolveFromTreeNode;
117
+ /**
118
+ * Handles resource resolution errors according to the specified mode.
119
+ * @param resource - The resource that failed to resolve
120
+ * @param message - The error message from the failed resolution
121
+ * @param mode - The error handling mode
122
+ * @param path - The path to the resource in the tree (for error context)
123
+ * @internal
124
+ */
125
+ private _handleResourceError;
126
+ /**
127
+ * Handles empty branch nodes according to the specified mode.
128
+ * @param node - The empty branch node
129
+ * @param failedChildren - Names of children that failed to resolve
130
+ * @param mode - The empty branch handling mode
131
+ * @param path - The path to the branch in the tree (for error context)
132
+ * @internal
133
+ */
134
+ private _handleEmptyBranch;
135
+ /**
136
+ * Processes a leaf node by resolving its resource value.
137
+ * @param node - The leaf node to process (must be a leaf node)
138
+ * @param path - The path to the node in the tree
139
+ * @param resourceErrorMode - How to handle resource resolution errors
140
+ * @internal
141
+ */
142
+ private _processLeafNode;
143
+ /**
144
+ * Processes a branch node by recursively resolving all its children.
145
+ * @param node - The branch node to process (must be a branch node)
146
+ * @param path - The path to the node in the tree
147
+ * @param options - Resolution options
148
+ * @internal
149
+ */
150
+ private _processBranchNode;
151
+ }
152
+ //# sourceMappingURL=resourceTreeResolver.d.ts.map
@@ -0,0 +1,222 @@
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.ResourceTreeResolver = void 0;
25
+ const ts_utils_1 = require("@fgv/ts-utils");
26
+ const ts_json_base_1 = require("@fgv/ts-json-base");
27
+ /**
28
+ * Specialized resolver for resource tree operations, providing enhanced APIs for
29
+ * resolving entire resource trees from either resource IDs or pre-built tree nodes.
30
+ *
31
+ * This class provides a clean separation between individual resource resolution
32
+ * (handled by ResourceResolver) and tree-based operations, with support for
33
+ * lazy tree construction and enhanced error handling.
34
+ *
35
+ * @public
36
+ */
37
+ class ResourceTreeResolver {
38
+ /**
39
+ * Creates a {@link Runtime.ResourceTreeResolver | ResourceTreeResolver} instance.
40
+ * @param resolver - The ResourceResolver to use for individual resource resolution
41
+ */
42
+ constructor(resolver) {
43
+ this.resolver = resolver;
44
+ this._resourceManager = resolver.resourceManager;
45
+ }
46
+ /**
47
+ * Creates a {@link Runtime.ResourceTreeResolver | ResourceTreeResolver} instance.
48
+ * @param resolver - The ResourceResolver to use for individual resource resolution
49
+ */
50
+ static create(resolver) {
51
+ return (0, ts_utils_1.captureResult)(() => new ResourceTreeResolver(resolver));
52
+ }
53
+ /**
54
+ * Gets the built resource tree, building it lazily on first access.
55
+ * @returns The resource tree root
56
+ * @throws Error if no resource manager was provided or tree building fails
57
+ * @public
58
+ */
59
+ get tree() {
60
+ return this._getTree().orThrow();
61
+ }
62
+ /**
63
+ * Implementation for both overloads.
64
+ */
65
+ resolveComposedResourceTree(idOrNode, options) {
66
+ if (typeof idOrNode === 'string') {
67
+ return this._resolveFromResourceId(idOrNode, options);
68
+ }
69
+ return this._resolveFromTreeNode(idOrNode, options);
70
+ }
71
+ _getTree() {
72
+ if (!this._tree) {
73
+ this._tree = this._resourceManager.getBuiltResourceTree();
74
+ }
75
+ return this._tree;
76
+ }
77
+ /**
78
+ * Resolves a tree from a resource ID by first building the tree from the resource manager.
79
+ * @internal
80
+ */
81
+ _resolveFromResourceId(resourceId, options) {
82
+ return this._getTree().onSuccess((tree) => {
83
+ return tree.children.validating
84
+ .getById(resourceId)
85
+ .onFailure((message) => (0, ts_utils_1.fail)(`${resourceId}: Resource not found in resource tree: ${message}`))
86
+ .onSuccess((rootNode) => this._resolveFromTreeNode(rootNode, options));
87
+ });
88
+ }
89
+ /**
90
+ * Resolves a pre-built tree node using the extracted tree resolution logic.
91
+ * @internal
92
+ */
93
+ _resolveFromTreeNode(node, options) {
94
+ var _a, _b;
95
+ const resourceErrorMode = (_a = options === null || options === void 0 ? void 0 : options.onResourceError) !== null && _a !== void 0 ? _a : 'fail';
96
+ const emptyBranchMode = (_b = options === null || options === void 0 ? void 0 : options.onEmptyBranch) !== null && _b !== void 0 ? _b : 'allow';
97
+ // Handle root node with proper Result chaining
98
+ return node.isLeaf
99
+ ? this._processLeafNode(node, '', resourceErrorMode).onSuccess((value) => value !== undefined ? ts_json_base_1.Converters.jsonObject.convert(value) : (0, ts_utils_1.succeed)(undefined))
100
+ : this._processBranchNode(node, '', {
101
+ onResourceError: resourceErrorMode,
102
+ onEmptyBranch: emptyBranchMode
103
+ }).onSuccess((value) => {
104
+ // Only convert undefined to {} if emptyBranchMode is 'allow'
105
+ // For 'omit' mode or custom handlers returning undefined, preserve undefined
106
+ return (0, ts_utils_1.succeed)(value === undefined && emptyBranchMode === 'allow' ? {} : value);
107
+ });
108
+ }
109
+ /**
110
+ * Handles resource resolution errors according to the specified mode.
111
+ * @param resource - The resource that failed to resolve
112
+ * @param message - The error message from the failed resolution
113
+ * @param mode - The error handling mode
114
+ * @param path - The path to the resource in the tree (for error context)
115
+ * @internal
116
+ */
117
+ _handleResourceError(resource, message, mode, path) {
118
+ if (mode === 'ignore') {
119
+ return (0, ts_utils_1.succeed)(undefined);
120
+ }
121
+ if (mode === 'fail') {
122
+ const errorMessage = path ? `${path}: ${message}` : message;
123
+ return (0, ts_utils_1.fail)(errorMessage);
124
+ }
125
+ // Custom handler - pass the resolver for recovery attempts
126
+ return mode(resource, message, this.resolver);
127
+ }
128
+ /**
129
+ * Handles empty branch nodes according to the specified mode.
130
+ * @param node - The empty branch node
131
+ * @param failedChildren - Names of children that failed to resolve
132
+ * @param mode - The empty branch handling mode
133
+ * @param path - The path to the branch in the tree (for error context)
134
+ * @internal
135
+ */
136
+ _handleEmptyBranch(node, failedChildren, mode, path) {
137
+ if (mode === 'omit') {
138
+ return (0, ts_utils_1.succeed)(undefined);
139
+ }
140
+ if (mode === 'allow') {
141
+ return (0, ts_utils_1.succeed)({});
142
+ }
143
+ // Custom handler - pass the resolver for recovery attempts
144
+ return mode(node, failedChildren, this.resolver);
145
+ }
146
+ /**
147
+ * Processes a leaf node by resolving its resource value.
148
+ * @param node - The leaf node to process (must be a leaf node)
149
+ * @param path - The path to the node in the tree
150
+ * @param resourceErrorMode - How to handle resource resolution errors
151
+ * @internal
152
+ */
153
+ _processLeafNode(node, path, resourceErrorMode) {
154
+ /* c8 ignore next 3 - defense in depth */
155
+ if (!node.isLeaf) {
156
+ return (0, ts_utils_1.fail)(`Internal error: processLeafNode called on non-leaf node at ${path}`);
157
+ }
158
+ return this.resolver
159
+ .resolveComposedResourceValue(node.resource)
160
+ .onSuccess((value) => (0, ts_utils_1.succeed)(value))
161
+ .onFailure((message) => this._handleResourceError(node.resource, message, resourceErrorMode, path));
162
+ }
163
+ /**
164
+ * Processes a branch node by recursively resolving all its children.
165
+ * @param node - The branch node to process (must be a branch node)
166
+ * @param path - The path to the node in the tree
167
+ * @param options - Resolution options
168
+ * @internal
169
+ */
170
+ _processBranchNode(node, path, options) {
171
+ var _a, _b;
172
+ /* c8 ignore next 3 - defense in depth */
173
+ if (node.isLeaf) {
174
+ return (0, ts_utils_1.fail)(`Internal error: processBranchNode called on leaf node at ${path}`);
175
+ }
176
+ const resourceErrorMode = (_a = options.onResourceError) !== null && _a !== void 0 ? _a : 'fail';
177
+ const emptyBranchMode = (_b = options.onEmptyBranch) !== null && _b !== void 0 ? _b : 'allow';
178
+ const aggregator = new ts_utils_1.MessageAggregator();
179
+ // Process all children
180
+ const childResults = {};
181
+ const failedChildren = [];
182
+ for (const [childName, childNode] of node.children) {
183
+ const childPath = path ? `${path}.${childName}` : childName;
184
+ const childResult = childNode.isLeaf
185
+ ? this._processLeafNode(childNode, childPath, resourceErrorMode)
186
+ : this._processBranchNode(childNode, childPath, options);
187
+ // Process the child result and update our state
188
+ if (childResult.isSuccess()) {
189
+ const value = childResult.value;
190
+ if (value !== undefined) {
191
+ childResults[childName] = value;
192
+ }
193
+ else {
194
+ failedChildren.push(childName);
195
+ }
196
+ }
197
+ else {
198
+ if (resourceErrorMode === 'fail') {
199
+ aggregator.addMessage(childResult.message);
200
+ }
201
+ failedChildren.push(childName);
202
+ }
203
+ }
204
+ // Check for accumulated errors in 'fail' mode
205
+ if (resourceErrorMode === 'fail' && aggregator.hasMessages) {
206
+ return (0, ts_utils_1.fail)(aggregator.toString('; '));
207
+ }
208
+ // Handle empty branch
209
+ if (Object.keys(childResults).length === 0) {
210
+ return this._handleEmptyBranch(node, failedChildren, emptyBranchMode, path).onSuccess((value) => {
211
+ if (value === undefined) {
212
+ return (0, ts_utils_1.succeed)(undefined);
213
+ }
214
+ // Ensure we return JsonObject or undefined
215
+ return ts_json_base_1.Converters.jsonObject.convert(value);
216
+ });
217
+ }
218
+ return (0, ts_utils_1.succeed)(childResults);
219
+ }
220
+ }
221
+ exports.ResourceTreeResolver = ResourceTreeResolver;
222
+ //# sourceMappingURL=resourceTreeResolver.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fgv/ts-res",
3
- "version": "5.0.0-23",
3
+ "version": "5.0.0-24",
4
4
  "description": "Multi-dimensional Resource Runtime",
5
5
  "main": "lib/index.js",
6
6
  "types": "dist/ts-res.d.ts",
@@ -36,24 +36,24 @@
36
36
  "rimraf": "^5.0.7",
37
37
  "ts-jest": "^29.4.1",
38
38
  "ts-node": "^10.9.2",
39
- "typescript": "^5.8.3",
39
+ "typescript": "5.8.3",
40
40
  "eslint-plugin-n": "^16.6.2",
41
- "@rushstack/eslint-config": "~4.4.0",
42
- "@rushstack/heft": "~0.74.2",
43
- "@rushstack/heft-jest-plugin": "~0.16.11",
44
- "@rushstack/heft-node-rig": "~2.9.3",
41
+ "@rushstack/eslint-config": "4.4.0",
42
+ "@rushstack/heft": "0.74.3",
43
+ "@rushstack/heft-jest-plugin": "0.16.12",
44
+ "@rushstack/heft-node-rig": "2.9.4",
45
45
  "@types/heft-jest": "1.0.6",
46
46
  "eslint-plugin-tsdoc": "~0.4.0",
47
- "@fgv/ts-utils-jest": "5.0.0-23",
48
- "@fgv/ts-extras": "5.0.0-23"
47
+ "@fgv/ts-utils-jest": "5.0.0-24",
48
+ "@fgv/ts-extras": "5.0.0-24"
49
49
  },
50
50
  "dependencies": {
51
51
  "luxon": "^3.7.1",
52
52
  "fflate": "~0.8.2",
53
- "@fgv/ts-utils": "5.0.0-23",
54
- "@fgv/ts-json-base": "5.0.0-23",
55
- "@fgv/ts-json": "5.0.0-23",
56
- "@fgv/ts-bcp47": "5.0.0-23"
53
+ "@fgv/ts-utils": "5.0.0-24",
54
+ "@fgv/ts-json-base": "5.0.0-24",
55
+ "@fgv/ts-json": "5.0.0-24",
56
+ "@fgv/ts-bcp47": "5.0.0-24"
57
57
  },
58
58
  "scripts": {
59
59
  "build": "heft build --clean",
package/.vscode/4.json DELETED
@@ -1,3 +0,0 @@
1
- {
2
- "cSpell.words": ["fixlint", "luxon", "packlets", "rushstack", "rushx", "TINSTANCE", "xyzzy"]
3
- }
@@ -1,16 +0,0 @@
1
- {
2
- // Use IntelliSense to learn about possible attributes.
3
- // Hover to view descriptions of existing attributes.
4
- // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5
- "version": "0.2.0",
6
- "configurations": [
7
- {
8
- "type": "node",
9
- "request": "launch",
10
- "name": "Launch Program",
11
- "skipFiles": ["<node_internals>/**"],
12
- "program": "${workspaceFolder}/lib/index.js",
13
- "outFiles": ["${workspaceFolder}/**/*.js"]
14
- }
15
- ]
16
- }
@@ -1,3 +0,0 @@
1
- {
2
- "cSpell.words": ["importables"]
3
- }