@fgv/ts-res 5.0.0-5 → 5.0.0-7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ts-res.d.ts +136 -42
- package/lib/index.d.ts +8 -2
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +18 -2
- package/lib/index.js.map +1 -1
- package/lib/packlets/common/resources.d.ts +8 -0
- package/lib/packlets/common/resources.d.ts.map +1 -1
- package/lib/packlets/common/resources.js.map +1 -1
- package/lib/packlets/resource-types/jsonResourceType.d.ts +4 -4
- package/lib/packlets/resource-types/jsonResourceType.d.ts.map +1 -1
- package/lib/packlets/resource-types/jsonResourceType.js +1 -1
- package/lib/packlets/resource-types/jsonResourceType.js.map +1 -1
- package/lib/packlets/resource-types/resourceType.d.ts +16 -7
- package/lib/packlets/resource-types/resourceType.d.ts.map +1 -1
- package/lib/packlets/resource-types/resourceType.js.map +1 -1
- package/lib/packlets/resources/common.d.ts +12 -0
- package/lib/packlets/resources/common.d.ts.map +1 -1
- package/lib/packlets/resources/common.js.map +1 -1
- package/lib/packlets/resources/resourceManagerBuilder.d.ts +50 -3
- package/lib/packlets/resources/resourceManagerBuilder.d.ts.map +1 -1
- package/lib/packlets/resources/resourceManagerBuilder.js +203 -8
- package/lib/packlets/resources/resourceManagerBuilder.js.map +1 -1
- package/lib/packlets/runtime/cacheListener.d.ts +9 -0
- package/lib/packlets/runtime/cacheListener.d.ts.map +1 -1
- package/lib/packlets/runtime/cacheListener.js +6 -0
- package/lib/packlets/runtime/cacheListener.js.map +1 -1
- package/lib/packlets/runtime/cacheMetrics.d.ts +6 -0
- package/lib/packlets/runtime/cacheMetrics.d.ts.map +1 -1
- package/lib/packlets/runtime/cacheMetrics.js +11 -0
- package/lib/packlets/runtime/cacheMetrics.js.map +1 -1
- package/lib/packlets/runtime/resourceResolver.js +15 -11
- package/lib/packlets/runtime/resourceResolver.js.map +1 -1
- package/package.json +12 -12
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { JsonValue } from '@fgv/ts-json-base';
|
|
2
2
|
import { ICollectible, Result } from '@fgv/ts-utils';
|
|
3
|
-
import { ResourceTypeIndex, ResourceTypeName, ResourceValueMergeMethod, ResourceId } from '../common';
|
|
3
|
+
import { CandidateCompleteness, ResourceTypeIndex, ResourceTypeName, ResourceValueMergeMethod, ResourceId } from '../common';
|
|
4
4
|
/**
|
|
5
5
|
* Parameters used to validate a {@link ResourceJson.Json.ILooseResourceCandidateDecl | resource candidate declaration}.
|
|
6
6
|
* @public
|
|
@@ -56,30 +56,39 @@ export declare abstract class ResourceType<T = unknown> implements ICollectible<
|
|
|
56
56
|
/**
|
|
57
57
|
* Validates a JSON value for use as a partial resource instance value.
|
|
58
58
|
* @param json - The JSON value to validate.
|
|
59
|
-
* @param
|
|
59
|
+
* @param completeness - Describes {@link CandidateCompleteness | how complete} the candidate value is.
|
|
60
60
|
* @returns `Success` with the strongly-typed partial resource value if the JSON is valid,
|
|
61
61
|
* `Failure` with an error message otherwise.
|
|
62
62
|
* @public
|
|
63
63
|
*/
|
|
64
|
-
abstract validate(json: JsonValue,
|
|
64
|
+
abstract validate(json: JsonValue, completeness: CandidateCompleteness): Result<Partial<T>>;
|
|
65
65
|
/**
|
|
66
66
|
* Validates a JSON value for use as a complete resource instance value.
|
|
67
67
|
* @param json - The JSON value to validate.
|
|
68
|
-
* @param
|
|
68
|
+
* @param completeness - Describes {@link CandidateCompleteness | how complete} the candidate value is.
|
|
69
69
|
* @returns `Success` with the strongly-typed resource value if the JSON is valid,
|
|
70
70
|
* `Failure` with an error message otherwise.
|
|
71
71
|
* @public
|
|
72
72
|
*/
|
|
73
|
-
abstract validate(json: JsonValue,
|
|
73
|
+
abstract validate(json: JsonValue, completeness: 'full'): Result<T>;
|
|
74
|
+
/**
|
|
75
|
+
* Validates a JSON value for use as a partial resource instance value.
|
|
76
|
+
* @param json - The JSON value to validate.
|
|
77
|
+
* @param completeness - Describes {@link CandidateCompleteness | how complete} the candidate value is.
|
|
78
|
+
* @returns `Success` with the strongly-typed partial resource value if the JSON is valid,
|
|
79
|
+
* `Failure` with an error message otherwise.
|
|
80
|
+
* @public
|
|
81
|
+
*/
|
|
82
|
+
abstract validate(json: JsonValue, completeness: 'partial'): Result<Partial<T>>;
|
|
74
83
|
/**
|
|
75
84
|
* Validates a JSON value for use as a full or partial resource instance value.
|
|
76
85
|
* @param json - The JSON value to validate.
|
|
77
|
-
* @param
|
|
86
|
+
* @param completeness - Describes {@link CandidateCompleteness | how complete} the candidate value is.
|
|
78
87
|
* @returns `Success` with the strongly-typed full or partial resource value if
|
|
79
88
|
* the JSON is valid, `Failure` with an error message otherwise.
|
|
80
89
|
* @public
|
|
81
90
|
*/
|
|
82
|
-
abstract validate(json: JsonValue,
|
|
91
|
+
abstract validate(json: JsonValue, completeness?: CandidateCompleteness): Result<T | Partial<T>>;
|
|
83
92
|
/**
|
|
84
93
|
* Sets the index for this resource type. Once set, the index cannot be changed.
|
|
85
94
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resourceType.d.ts","sourceRoot":"","sources":["../../../src/packlets/resource-types/resourceType.ts"],"names":[],"mappings":"AAsBA,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAC9C,OAAO,EAAe,YAAY,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAClE,OAAO,
|
|
1
|
+
{"version":3,"file":"resourceType.d.ts","sourceRoot":"","sources":["../../../src/packlets/resource-types/resourceType.ts"],"names":[],"mappings":"AAsBA,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAC9C,OAAO,EAAe,YAAY,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAClE,OAAO,EACL,qBAAqB,EAGrB,iBAAiB,EACjB,gBAAgB,EAChB,wBAAwB,EACxB,UAAU,EACX,MAAM,WAAW,CAAC;AAEnB;;;GAGG;AACH,MAAM,WAAW,sCAAsC;IACrD;;;OAGG;IACH,EAAE,EAAE,UAAU,CAAC;IAEf;;;OAGG;IACH,SAAS,EAAE,OAAO,CAAC;IAEnB;;;OAGG;IACH,IAAI,EAAE,SAAS,CAAC;IAEhB;;;OAGG;IACH,WAAW,EAAE,wBAAwB,CAAC;CACvC;AAED;;;;;GAKG;AACH,8BAAsB,YAAY,CAAC,CAAC,GAAG,OAAO,CAAE,YAAW,YAAY,CAAC,gBAAgB,EAAE,iBAAiB,CAAC;IAC1G,OAAO,CAAC,YAAY,CAA+D;IACnF;;OAEG;IACH,IAAW,GAAG,IAAI,gBAAgB,CAEjC;IAED;;OAEG;IACH,IAAW,KAAK,IAAI,iBAAiB,GAAG,SAAS,CAEhD;IAED,SAAS,aAAa,GAAG,EAAE,gBAAgB,EAAE,KAAK,CAAC,EAAE,MAAM;IAS3D;;;;;;;OAOG;aACa,mBAAmB,CAAC,KAAK,EAAE,sCAAsC,GAAG,MAAM,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IAE1G;;;;;;;OAOG;aACa,QAAQ,CAAC,IAAI,EAAE,SAAS,EAAE,YAAY,EAAE,qBAAqB,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IAElG;;;;;;;OAOG;aACa,QAAQ,CAAC,IAAI,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC;IAE1E;;;;;;;OAOG;aACa,QAAQ,CAAC,IAAI,EAAE,SAAS,EAAE,YAAY,EAAE,SAAS,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IAEtF;;;;;;;OAOG;aACa,QAAQ,CAAC,IAAI,EAAE,SAAS,EAAE,YAAY,CAAC,EAAE,qBAAqB,GAAG,MAAM,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IAEvG;;OAEG;IACI,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC,iBAAiB,CAAC;CAG1D"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resourceType.js","sourceRoot":"","sources":["../../../src/packlets/resource-types/resourceType.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;;;AAGH,4CAAkE;AAClE,
|
|
1
|
+
{"version":3,"file":"resourceType.js","sourceRoot":"","sources":["../../../src/packlets/resource-types/resourceType.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;;;AAGH,4CAAkE;AAClE,sCAQmB;AAgCnB;;;;;GAKG;AACH,MAAsB,YAAY;IAEhC;;OAEG;IACH,IAAW,GAAG;QACZ,OAAO,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC;IAC/B,CAAC;IAED;;OAEG;IACH,IAAW,KAAK;QACd,OAAO,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC;IACjC,CAAC;IAED,YAAsB,GAAqB,EAAE,KAAc;QACzD,IAAI,CAAC,YAAY,GAAG,IAAI,sBAAW,CAAC,WAAW,CAAsC;YACnF,GAAG;YACH,qDAAqD;YACrD,KAAK,EAAE,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,iBAAQ,CAAC,mBAAmB,CAAC,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,SAAS;YACtF,cAAc,EAAE,gBAAa,CAAC,iBAAiB;SAChD,CAAC,CAAC;IACL,CAAC;IAoDD;;OAEG;IACI,QAAQ,CAAC,KAAa;QAC3B,OAAO,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC3C,CAAC;CACF;AAjFD,oCAiFC","sourcesContent":["/*\n * Copyright (c) 2025 Erik Fortune\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\nimport { JsonValue } from '@fgv/ts-json-base';\nimport { Collections, ICollectible, Result } from '@fgv/ts-utils';\nimport {\n CandidateCompleteness,\n Convert as CommonConvert,\n Validate,\n ResourceTypeIndex,\n ResourceTypeName,\n ResourceValueMergeMethod,\n ResourceId\n} from '../common';\n\n/**\n * Parameters used to validate a {@link ResourceJson.Json.ILooseResourceCandidateDecl | resource candidate declaration}.\n * @public\n */\nexport interface IResourceCandidateValidationProperties {\n /**\n * {@inheritdoc ResourceJson.Json.ILooseResourceCandidateDecl.id}\n * @public\n */\n id: ResourceId;\n\n /**\n * {@inheritdoc ResourceJson.Json.ILooseResourceCandidateDecl.isPartial}\n * @public\n */\n isPartial: boolean;\n\n /**\n * {@inheritdoc ResourceJson.Json.ILooseResourceCandidateDecl.json}\n * @public\n */\n json: JsonValue;\n\n /**\n * {@inheritdoc ResourceJson.Json.ILooseResourceCandidateDecl.mergeMethod}\n * @public\n */\n mergeMethod: ResourceValueMergeMethod;\n}\n\n/**\n * Abstract base class for resource types which are responsible for\n * validating and converting JSON values into the appropriate strongly-typed\n * resource value.\n * @public\n */\nexport abstract class ResourceType<T = unknown> implements ICollectible<ResourceTypeName, ResourceTypeIndex> {\n private _collectible: Collections.Collectible<ResourceTypeName, ResourceTypeIndex>;\n /**\n * The key for this resource type.\n */\n public get key(): ResourceTypeName {\n return this._collectible.key;\n }\n\n /**\n * The index for this resource type.\n */\n public get index(): ResourceTypeIndex | undefined {\n return this._collectible.index;\n }\n\n protected constructor(key: ResourceTypeName, index?: number) {\n this._collectible = new Collections.Collectible<ResourceTypeName, ResourceTypeIndex>({\n key,\n /* c8 ignore next 1 - coverage having a rough time */\n index: index !== undefined ? Validate.toResourceTypeIndex(index).orThrow() : undefined,\n indexConverter: CommonConvert.resourceTypeIndex\n });\n }\n\n /**\n * Validates properties of a {@link ResourceJson.Json.ILooseResourceCandidateDecl | resource candidate declaration} for\n * a resource instance value.\n * @param props - The {@link ResourceTypes.IResourceCandidateValidationProperties | properties } to validate.\n * @returns `Success` with the strongly-typed resource value if the JSON and merge method\n * are valid, `Failure` with an error message otherwise.\n * @public\n */\n public abstract validateDeclaration(props: IResourceCandidateValidationProperties): Result<T | Partial<T>>;\n\n /**\n * Validates a JSON value for use as a partial resource instance value.\n * @param json - The JSON value to validate.\n * @param completeness - Describes {@link CandidateCompleteness | how complete} the candidate value is.\n * @returns `Success` with the strongly-typed partial resource value if the JSON is valid,\n * `Failure` with an error message otherwise.\n * @public\n */\n public abstract validate(json: JsonValue, completeness: CandidateCompleteness): Result<Partial<T>>;\n\n /**\n * Validates a JSON value for use as a complete resource instance value.\n * @param json - The JSON value to validate.\n * @param completeness - Describes {@link CandidateCompleteness | how complete} the candidate value is.\n * @returns `Success` with the strongly-typed resource value if the JSON is valid,\n * `Failure` with an error message otherwise.\n * @public\n */\n public abstract validate(json: JsonValue, completeness: 'full'): Result<T>;\n\n /**\n * Validates a JSON value for use as a partial resource instance value.\n * @param json - The JSON value to validate.\n * @param completeness - Describes {@link CandidateCompleteness | how complete} the candidate value is.\n * @returns `Success` with the strongly-typed partial resource value if the JSON is valid,\n * `Failure` with an error message otherwise.\n * @public\n */\n public abstract validate(json: JsonValue, completeness: 'partial'): Result<Partial<T>>;\n\n /**\n * Validates a JSON value for use as a full or partial resource instance value.\n * @param json - The JSON value to validate.\n * @param completeness - Describes {@link CandidateCompleteness | how complete} the candidate value is.\n * @returns `Success` with the strongly-typed full or partial resource value if\n * the JSON is valid, `Failure` with an error message otherwise.\n * @public\n */\n public abstract validate(json: JsonValue, completeness?: CandidateCompleteness): Result<T | Partial<T>>;\n\n /**\n * Sets the index for this resource type. Once set, the index cannot be changed.\n */\n public setIndex(index: number): Result<ResourceTypeIndex> {\n return this._collectible.setIndex(index);\n }\n}\n"]}
|
|
@@ -57,4 +57,16 @@ export interface ICompiledResourceOptionsWithFilter extends ResourceJson.Compile
|
|
|
57
57
|
*/
|
|
58
58
|
filterForContext?: IValidatedContextDecl;
|
|
59
59
|
}
|
|
60
|
+
/**
|
|
61
|
+
* Options for ResourceManagerBuilder clone operations.
|
|
62
|
+
* Extends IDeclarationOptions to include support for applying edits when cloning.
|
|
63
|
+
* @public
|
|
64
|
+
*/
|
|
65
|
+
export interface IResourceManagerCloneOptions extends IResourceDeclarationOptions {
|
|
66
|
+
/**
|
|
67
|
+
* Optional array of loose condition declarations to be applied as edits during the clone operation.
|
|
68
|
+
* These conditions can modify or extend the resource candidates in the cloned manager.
|
|
69
|
+
*/
|
|
70
|
+
readonly candidates?: ReadonlyArray<ResourceJson.Json.ILooseResourceCandidateDecl>;
|
|
71
|
+
}
|
|
60
72
|
//# sourceMappingURL=common.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"common.d.ts","sourceRoot":"","sources":["../../../src/packlets/resources/common.ts"],"names":[],"mappings":"AAsBA,OAAO,KAAK,YAAY,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAEnD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,WAAW,2BAA4B,SAAQ,YAAY,CAAC,OAAO,CAAC,mBAAmB;IAC3F;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,qBAAqB,CAAC;IAEzC;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAE3B;;;;;OAKG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED;;;;;GAKG;AACH,MAAM,WAAW,kCAAmC,SAAQ,YAAY,CAAC,QAAQ,CAAC,wBAAwB;IACxG;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,qBAAqB,CAAC;CAC1C"}
|
|
1
|
+
{"version":3,"file":"common.d.ts","sourceRoot":"","sources":["../../../src/packlets/resources/common.ts"],"names":[],"mappings":"AAsBA,OAAO,KAAK,YAAY,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAEnD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,WAAW,2BAA4B,SAAQ,YAAY,CAAC,OAAO,CAAC,mBAAmB;IAC3F;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,qBAAqB,CAAC;IAEzC;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAE3B;;;;;OAKG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED;;;;;GAKG;AACH,MAAM,WAAW,kCAAmC,SAAQ,YAAY,CAAC,QAAQ,CAAC,wBAAwB;IACxG;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,qBAAqB,CAAC;CAC1C;AAED;;;;GAIG;AACH,MAAM,WAAW,4BAA6B,SAAQ,2BAA2B;IAC/E;;;OAGG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,aAAa,CAAC,YAAY,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC;CACpF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"common.js","sourceRoot":"","sources":["../../../src/packlets/resources/common.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;GAoBG","sourcesContent":["/*\n * Copyright (c) 2025 Erik Fortune\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\nimport * as ResourceJson from '../resource-json';\nimport { IValidatedContextDecl } from '../context';\n\n/**\n * Options for resource declaration operations with strongly-typed context filtering.\n * Extends the base IDeclarationOptions with proper type safety for context filtering.\n *\n * @example\n * ```typescript\n * // Preferred Result pattern with onSuccess chaining\n * resourceManager.validateContext({ language: 'en' })\n * .onSuccess((validatedContext) => {\n * return resourceManager.clone({ filterForContext: validatedContext });\n * })\n * .onSuccess((clonedManager) => {\n * return clonedManager.getResourceCollectionDecl();\n * })\n * .onFailure((error) => {\n * console.error('Failed to create filtered clone:', error);\n * });\n * ```\n * @public\n */\nexport interface IResourceDeclarationOptions extends ResourceJson.Helpers.IDeclarationOptions {\n /**\n * If provided, filters resource candidates to only include those that can match the\n * specified validated context. This provides strongly-typed context filtering.\n *\n * Use resourceManager.validateContext() to create a validated context from an IContextDecl.\n */\n filterForContext?: IValidatedContextDecl;\n\n /**\n * If true, reduces the qualifiers of the resource candidates by removing qualifiers that are made\n * irrelevant by the filterForContext.\n * @defaultValue false\n */\n reduceQualifiers?: boolean;\n\n /**\n * Whether to include metadata in compiled outputs.\n * Metadata includes human-readable information like semantic keys\n * that can be useful for debugging or tooling.\n * @defaultValue false\n */\n includeMetadata?: boolean;\n}\n\n/**\n * Extended compiled resource options that includes context filtering capabilities.\n * This interface combines the standard compilation options with strongly-typed\n * context filtering for resource candidates.\n * @public\n */\nexport interface ICompiledResourceOptionsWithFilter extends ResourceJson.Compiled.ICompiledResourceOptions {\n /**\n * If provided, filters resource candidates to only include those that can match the\n * specified validated context. This provides strongly-typed context filtering.\n *\n * Use resourceManager.validateContext() to create a validated context from an IContextDecl.\n */\n filterForContext?: IValidatedContextDecl;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"common.js","sourceRoot":"","sources":["../../../src/packlets/resources/common.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;GAoBG","sourcesContent":["/*\n * Copyright (c) 2025 Erik Fortune\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\nimport * as ResourceJson from '../resource-json';\nimport { IValidatedContextDecl } from '../context';\n\n/**\n * Options for resource declaration operations with strongly-typed context filtering.\n * Extends the base IDeclarationOptions with proper type safety for context filtering.\n *\n * @example\n * ```typescript\n * // Preferred Result pattern with onSuccess chaining\n * resourceManager.validateContext({ language: 'en' })\n * .onSuccess((validatedContext) => {\n * return resourceManager.clone({ filterForContext: validatedContext });\n * })\n * .onSuccess((clonedManager) => {\n * return clonedManager.getResourceCollectionDecl();\n * })\n * .onFailure((error) => {\n * console.error('Failed to create filtered clone:', error);\n * });\n * ```\n * @public\n */\nexport interface IResourceDeclarationOptions extends ResourceJson.Helpers.IDeclarationOptions {\n /**\n * If provided, filters resource candidates to only include those that can match the\n * specified validated context. This provides strongly-typed context filtering.\n *\n * Use resourceManager.validateContext() to create a validated context from an IContextDecl.\n */\n filterForContext?: IValidatedContextDecl;\n\n /**\n * If true, reduces the qualifiers of the resource candidates by removing qualifiers that are made\n * irrelevant by the filterForContext.\n * @defaultValue false\n */\n reduceQualifiers?: boolean;\n\n /**\n * Whether to include metadata in compiled outputs.\n * Metadata includes human-readable information like semantic keys\n * that can be useful for debugging or tooling.\n * @defaultValue false\n */\n includeMetadata?: boolean;\n}\n\n/**\n * Extended compiled resource options that includes context filtering capabilities.\n * This interface combines the standard compilation options with strongly-typed\n * context filtering for resource candidates.\n * @public\n */\nexport interface ICompiledResourceOptionsWithFilter extends ResourceJson.Compiled.ICompiledResourceOptions {\n /**\n * If provided, filters resource candidates to only include those that can match the\n * specified validated context. This provides strongly-typed context filtering.\n *\n * Use resourceManager.validateContext() to create a validated context from an IContextDecl.\n */\n filterForContext?: IValidatedContextDecl;\n}\n\n/**\n * Options for ResourceManagerBuilder clone operations.\n * Extends IDeclarationOptions to include support for applying edits when cloning.\n * @public\n */\nexport interface IResourceManagerCloneOptions extends IResourceDeclarationOptions {\n /**\n * Optional array of loose condition declarations to be applied as edits during the clone operation.\n * These conditions can modify or extend the resource candidates in the cloned manager.\n */\n readonly candidates?: ReadonlyArray<ResourceJson.Json.ILooseResourceCandidateDecl>;\n}\n"]}
|
|
@@ -8,9 +8,10 @@ import { IResourceManager } from '../runtime';
|
|
|
8
8
|
import { ResourceBuilder, ResourceBuilderResultDetail } from './resourceBuilder';
|
|
9
9
|
import { Resource } from './resource';
|
|
10
10
|
import { ResourceCandidate } from './resourceCandidate';
|
|
11
|
-
import { IResourceDeclarationOptions } from './common';
|
|
11
|
+
import { IResourceDeclarationOptions, IResourceManagerCloneOptions } from './common';
|
|
12
12
|
import * as ResourceJson from '../resource-json';
|
|
13
13
|
import * as Context from '../context';
|
|
14
|
+
import * as Config from '../config';
|
|
14
15
|
/**
|
|
15
16
|
* Interface for parameters to the {@link Resources.ResourceManagerBuilder.create | ResourceManagerBuilder create method}.
|
|
16
17
|
* @public
|
|
@@ -96,6 +97,15 @@ export declare class ResourceManagerBuilder implements IResourceManager {
|
|
|
96
97
|
* @public
|
|
97
98
|
*/
|
|
98
99
|
static create(params: IResourceManagerBuilderCreateParams): Result<ResourceManagerBuilder>;
|
|
100
|
+
/**
|
|
101
|
+
* Creates a new {@link Resources.ResourceManagerBuilder | ResourceManagerBuilder} object from a predefined system configuration.
|
|
102
|
+
* @param name - The name of the predefined system configuration to use.
|
|
103
|
+
* @param qualifierDefaultValues - Optional default values for qualifiers.
|
|
104
|
+
* @returns `Success` with the new {@link Resources.ResourceManagerBuilder | ResourceManagerBuilder} object if successful,
|
|
105
|
+
* or `Failure` with an error message if not.
|
|
106
|
+
* @public
|
|
107
|
+
*/
|
|
108
|
+
static createPredefined(name: Config.PredefinedSystemConfiguration, qualifierDefaultValues?: Config.ISystemConfigurationInitParams['qualifierDefaultValues']): Result<ResourceManagerBuilder>;
|
|
99
109
|
/**
|
|
100
110
|
* Given a {@link ResourceJson.Json.ILooseResourceCandidateDecl | resource candidate declaration}, builds and adds
|
|
101
111
|
* a {@link Resources.ResourceCandidate | candidate} to the manager.
|
|
@@ -211,10 +221,47 @@ export declare class ResourceManagerBuilder implements IResourceManager {
|
|
|
211
221
|
* Creates a filtered clone of this ResourceManagerBuilder using the specified context.
|
|
212
222
|
* This is a convenience method that creates a new ResourceManagerBuilder with the same
|
|
213
223
|
* configuration but filtered to include only candidates that match the provided context.
|
|
214
|
-
*
|
|
224
|
+
* If candidates are provided for editing, they will be applied with collision detection.
|
|
225
|
+
* @param options - Options for the cloning operation, including the strongly-typed filterForContext property and optional candidates for edits.
|
|
215
226
|
* @returns A Result containing the new filtered ResourceManagerBuilder.
|
|
216
227
|
* @public
|
|
217
228
|
*/
|
|
218
|
-
clone(options?:
|
|
229
|
+
clone(options?: IResourceManagerCloneOptions): Result<ResourceManagerBuilder>;
|
|
230
|
+
/**
|
|
231
|
+
* Creates a resource ID keyed map from an array of loose resource candidate declarations.
|
|
232
|
+
* This enables efficient detection of edit collisions by grouping candidates by their target resource.
|
|
233
|
+
* @param candidates - Array of loose resource candidate declarations to organize
|
|
234
|
+
* @returns A Result containing a Map where keys are validated ResourceIds and values are arrays of candidates for that resource
|
|
235
|
+
* @internal
|
|
236
|
+
*/
|
|
237
|
+
private static _createCandidatesByResourceMap;
|
|
238
|
+
/**
|
|
239
|
+
* Generates a proper ConditionSet token for collision detection using the existing ConditionSet.getKeyForDecl method.
|
|
240
|
+
* @param conditionSet - The condition set to generate a token for
|
|
241
|
+
* @param conditionCollector - The condition collector needed for validation context
|
|
242
|
+
* @returns A Result containing the ConditionSet token if successful, or failure if validation fails
|
|
243
|
+
* @internal
|
|
244
|
+
*/
|
|
245
|
+
private static _getConditionSetToken;
|
|
246
|
+
/**
|
|
247
|
+
* Applies candidate edits to a resource declaration, handling collisions using condition set tokens.
|
|
248
|
+
* If there's no collision, adds the candidate. If there's a collision, replaces the original candidate with the edit.
|
|
249
|
+
* @param resourceDecl - The original resource declaration to potentially modify
|
|
250
|
+
* @param candidatesByResource - Map of resource IDs to arrays of candidate edits
|
|
251
|
+
* @param conditionCollector - The condition collector needed for generating condition tokens
|
|
252
|
+
* @returns A Result containing the resource declaration to use (original or modified)
|
|
253
|
+
* @internal
|
|
254
|
+
*/
|
|
255
|
+
private static _applyEditsToResourceDeclaration;
|
|
256
|
+
/**
|
|
257
|
+
* Creates a new resource declaration from an array of candidate declarations.
|
|
258
|
+
* This is used when cloning to create new resources that don't exist in the original manager.
|
|
259
|
+
* @param resourceId - The validated resource ID for the new resource
|
|
260
|
+
* @param candidates - Array of loose candidate declarations for the new resource
|
|
261
|
+
* @param conditionCollector - The condition collector for validation context
|
|
262
|
+
* @returns A Result containing the new resource declaration if successful, or failure if validation fails
|
|
263
|
+
* @internal
|
|
264
|
+
*/
|
|
265
|
+
private static _createResourceDeclFromCandidates;
|
|
219
266
|
}
|
|
220
267
|
//# sourceMappingURL=resourceManagerBuilder.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resourceManagerBuilder.d.ts","sourceRoot":"","sources":["../../../src/packlets/resources/resourceManagerBuilder.ts"],"names":[],"mappings":"AAsBA,OAAO,EAEL,WAAW,EACX,cAAc,EAMd,MAAM,EAGN,mBAAmB,EACpB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,kBAAkB,
|
|
1
|
+
{"version":3,"file":"resourceManagerBuilder.d.ts","sourceRoot":"","sources":["../../../src/packlets/resources/resourceManagerBuilder.ts"],"names":[],"mappings":"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"}
|
|
@@ -63,6 +63,7 @@ const resourceBuilder_1 = require("./resourceBuilder");
|
|
|
63
63
|
const resource_1 = require("./resource");
|
|
64
64
|
const ResourceJson = __importStar(require("../resource-json"));
|
|
65
65
|
const Context = __importStar(require("../context"));
|
|
66
|
+
const Config = __importStar(require("../config"));
|
|
66
67
|
/**
|
|
67
68
|
* Builder for a collection of {@link Resources.Resource | resources}. Collects
|
|
68
69
|
* {@link Resources.ResourceCandidate | candidates} for each resource into a
|
|
@@ -165,6 +166,22 @@ class ResourceManagerBuilder {
|
|
|
165
166
|
static create(params) {
|
|
166
167
|
return (0, ts_utils_1.captureResult)(() => new ResourceManagerBuilder(params));
|
|
167
168
|
}
|
|
169
|
+
/**
|
|
170
|
+
* Creates a new {@link Resources.ResourceManagerBuilder | ResourceManagerBuilder} object from a predefined system configuration.
|
|
171
|
+
* @param name - The name of the predefined system configuration to use.
|
|
172
|
+
* @param qualifierDefaultValues - Optional default values for qualifiers.
|
|
173
|
+
* @returns `Success` with the new {@link Resources.ResourceManagerBuilder | ResourceManagerBuilder} object if successful,
|
|
174
|
+
* or `Failure` with an error message if not.
|
|
175
|
+
* @public
|
|
176
|
+
*/
|
|
177
|
+
static createPredefined(name, qualifierDefaultValues) {
|
|
178
|
+
return Config.getPredefinedSystemConfiguration(name, qualifierDefaultValues ? { qualifierDefaultValues } : undefined).onSuccess((systemConfig) => {
|
|
179
|
+
return ResourceManagerBuilder.create({
|
|
180
|
+
qualifiers: systemConfig.qualifiers,
|
|
181
|
+
resourceTypes: systemConfig.resourceTypes
|
|
182
|
+
});
|
|
183
|
+
});
|
|
184
|
+
}
|
|
168
185
|
/**
|
|
169
186
|
* Given a {@link ResourceJson.Json.ILooseResourceCandidateDecl | resource candidate declaration}, builds and adds
|
|
170
187
|
* a {@link Resources.ResourceCandidate | candidate} to the manager.
|
|
@@ -422,7 +439,8 @@ class ResourceManagerBuilder {
|
|
|
422
439
|
* Creates a filtered clone of this ResourceManagerBuilder using the specified context.
|
|
423
440
|
* This is a convenience method that creates a new ResourceManagerBuilder with the same
|
|
424
441
|
* configuration but filtered to include only candidates that match the provided context.
|
|
425
|
-
*
|
|
442
|
+
* If candidates are provided for editing, they will be applied with collision detection.
|
|
443
|
+
* @param options - Options for the cloning operation, including the strongly-typed filterForContext property and optional candidates for edits.
|
|
426
444
|
* @returns A Result containing the new filtered ResourceManagerBuilder.
|
|
427
445
|
* @public
|
|
428
446
|
*/
|
|
@@ -433,19 +451,196 @@ class ResourceManagerBuilder {
|
|
|
433
451
|
qualifiers: this.qualifiers,
|
|
434
452
|
resourceTypes: this.resourceTypes
|
|
435
453
|
}).onSuccess((newManager) => {
|
|
436
|
-
//
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
454
|
+
// Check if we have candidates to apply as edits
|
|
455
|
+
const editCandidates = (options === null || options === void 0 ? void 0 : options.candidates) || [];
|
|
456
|
+
const candidatesByResourceResult = editCandidates.length > 0
|
|
457
|
+
? ResourceManagerBuilder._createCandidatesByResourceMap(editCandidates)
|
|
458
|
+
: (0, ts_utils_1.succeed)(new Map());
|
|
459
|
+
return candidatesByResourceResult.onSuccess((candidatesByResource) => {
|
|
460
|
+
// Track which resource IDs have been processed from the original collection
|
|
461
|
+
const processedResourceIds = new Set();
|
|
462
|
+
// Add each resource from the filtered collection to the new manager
|
|
463
|
+
if (collection.resources) {
|
|
464
|
+
for (const resourceDecl of collection.resources) {
|
|
465
|
+
processedResourceIds.add(resourceDecl.id);
|
|
466
|
+
// Apply edits if there are candidates for this resource
|
|
467
|
+
const editedDeclResult = ResourceManagerBuilder._applyEditsToResourceDeclaration(resourceDecl, candidatesByResource, this._conditions);
|
|
468
|
+
if (editedDeclResult.isFailure()) {
|
|
469
|
+
return (0, ts_utils_1.fail)(`${resourceDecl.id}: Failed to apply edits: ${editedDeclResult.message}`);
|
|
470
|
+
}
|
|
471
|
+
const addResult = newManager.addResource(editedDeclResult.value);
|
|
472
|
+
if (addResult.isFailure()) {
|
|
473
|
+
return (0, ts_utils_1.fail)(`${resourceDecl.id}: Failed to add resource to cloned manager: ${addResult.message}`);
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
// Handle any remaining candidates that target new resources not in the original collection
|
|
478
|
+
const errors = new ts_utils_1.MessageAggregator();
|
|
479
|
+
for (const [resourceId, candidates] of candidatesByResource) {
|
|
480
|
+
if (!processedResourceIds.has(resourceId)) {
|
|
481
|
+
// Create a new resource declaration for candidates targeting a new resource ID
|
|
482
|
+
ResourceManagerBuilder._createResourceDeclFromCandidates(resourceId, candidates, this._conditions)
|
|
483
|
+
.withErrorFormat((e) => `${resourceId}: Failed to create new resource from candidates: ${e}`)
|
|
484
|
+
.onSuccess((newResourceDecl) => {
|
|
485
|
+
return newManager
|
|
486
|
+
.addResource(newResourceDecl)
|
|
487
|
+
.withErrorFormat((e) => `${resourceId}: Failed to add new resource to cloned manager: ${e}`);
|
|
488
|
+
})
|
|
489
|
+
.aggregateError(errors);
|
|
442
490
|
}
|
|
443
491
|
}
|
|
492
|
+
return errors.returnOrReport((0, ts_utils_1.succeed)(newManager));
|
|
493
|
+
});
|
|
494
|
+
});
|
|
495
|
+
});
|
|
496
|
+
}
|
|
497
|
+
/**
|
|
498
|
+
* Creates a resource ID keyed map from an array of loose resource candidate declarations.
|
|
499
|
+
* This enables efficient detection of edit collisions by grouping candidates by their target resource.
|
|
500
|
+
* @param candidates - Array of loose resource candidate declarations to organize
|
|
501
|
+
* @returns A Result containing a Map where keys are validated ResourceIds and values are arrays of candidates for that resource
|
|
502
|
+
* @internal
|
|
503
|
+
*/
|
|
504
|
+
static _createCandidatesByResourceMap(candidates) {
|
|
505
|
+
const candidatesByResource = new Map();
|
|
506
|
+
for (const candidate of candidates) {
|
|
507
|
+
const { value: resourceId, message } = common_1.Validate.toResourceId(candidate.id);
|
|
508
|
+
if (message !== undefined) {
|
|
509
|
+
return (0, ts_utils_1.fail)(`Invalid resource ID "${candidate.id}": ${message}`);
|
|
510
|
+
}
|
|
511
|
+
const existingCandidates = candidatesByResource.get(resourceId);
|
|
512
|
+
if (existingCandidates) {
|
|
513
|
+
existingCandidates.push(candidate);
|
|
514
|
+
}
|
|
515
|
+
else {
|
|
516
|
+
candidatesByResource.set(resourceId, [candidate]);
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
return (0, ts_utils_1.succeed)(candidatesByResource);
|
|
520
|
+
}
|
|
521
|
+
/**
|
|
522
|
+
* Generates a proper ConditionSet token for collision detection using the existing ConditionSet.getKeyForDecl method.
|
|
523
|
+
* @param conditionSet - The condition set to generate a token for
|
|
524
|
+
* @param conditionCollector - The condition collector needed for validation context
|
|
525
|
+
* @returns A Result containing the ConditionSet token if successful, or failure if validation fails
|
|
526
|
+
* @internal
|
|
527
|
+
*/
|
|
528
|
+
static _getConditionSetToken(conditionSet, conditionCollector) {
|
|
529
|
+
if (!conditionSet) {
|
|
530
|
+
return (0, ts_utils_1.succeed)(conditions_1.ConditionSet.UnconditionalKey);
|
|
531
|
+
}
|
|
532
|
+
// Convert ConditionSetDecl to IConditionSetDecl format
|
|
533
|
+
let conditionSetDecl;
|
|
534
|
+
if (Array.isArray(conditionSet)) {
|
|
535
|
+
// ConditionSetDeclAsArray: array of ILooseConditionDecl
|
|
536
|
+
conditionSetDecl = { conditions: conditionSet };
|
|
537
|
+
}
|
|
538
|
+
else {
|
|
539
|
+
// ConditionSetDeclAsRecord: Record<string, string | IChildConditionDecl>
|
|
540
|
+
const conditions = Object.entries(conditionSet).map(([qualifierName, value]) => {
|
|
541
|
+
if (typeof value === 'string') {
|
|
542
|
+
return { qualifierName, value };
|
|
543
|
+
}
|
|
544
|
+
else {
|
|
545
|
+
return Object.assign({ qualifierName }, value);
|
|
444
546
|
}
|
|
445
|
-
return (0, ts_utils_1.succeed)(newManager);
|
|
446
547
|
});
|
|
548
|
+
conditionSetDecl = { conditions };
|
|
549
|
+
}
|
|
550
|
+
// Validate and convert to IValidatedConditionSetDecl
|
|
551
|
+
return conditions_1.Convert.validatedConditionSetDecl
|
|
552
|
+
.convert(conditionSetDecl, { conditions: conditionCollector })
|
|
553
|
+
.onSuccess((validatedDecl) => {
|
|
554
|
+
// Use proper ConditionSet.getKeyForDecl method to generate the token
|
|
555
|
+
return conditions_1.ConditionSet.getKeyForDecl(validatedDecl);
|
|
447
556
|
});
|
|
448
557
|
}
|
|
558
|
+
/**
|
|
559
|
+
* Applies candidate edits to a resource declaration, handling collisions using condition set tokens.
|
|
560
|
+
* If there's no collision, adds the candidate. If there's a collision, replaces the original candidate with the edit.
|
|
561
|
+
* @param resourceDecl - The original resource declaration to potentially modify
|
|
562
|
+
* @param candidatesByResource - Map of resource IDs to arrays of candidate edits
|
|
563
|
+
* @param conditionCollector - The condition collector needed for generating condition tokens
|
|
564
|
+
* @returns A Result containing the resource declaration to use (original or modified)
|
|
565
|
+
* @internal
|
|
566
|
+
*/
|
|
567
|
+
static _applyEditsToResourceDeclaration(resourceDecl, candidatesByResource, conditionCollector) {
|
|
568
|
+
const { value: resourceId, message } = common_1.Validate.toResourceId(resourceDecl.id);
|
|
569
|
+
if (message !== undefined) {
|
|
570
|
+
return (0, ts_utils_1.fail)(`Invalid resource ID "${resourceDecl.id}": ${message}`);
|
|
571
|
+
}
|
|
572
|
+
const editCandidates = candidatesByResource.get(resourceId);
|
|
573
|
+
if (!editCandidates || editCandidates.length === 0) {
|
|
574
|
+
return (0, ts_utils_1.succeed)(resourceDecl);
|
|
575
|
+
}
|
|
576
|
+
// Use Map approach: apply original candidates first, then replace with edits on collision
|
|
577
|
+
const candidatesByConditionKey = new Map();
|
|
578
|
+
// First, add all original candidates keyed by their condition set token
|
|
579
|
+
for (const candidate of resourceDecl.candidates || []) {
|
|
580
|
+
const conditionTokenResult = ResourceManagerBuilder._getConditionSetToken(candidate.conditions, conditionCollector);
|
|
581
|
+
if (conditionTokenResult.isFailure()) {
|
|
582
|
+
return (0, ts_utils_1.fail)(`Failed to generate condition token for original candidate: ${conditionTokenResult.message}`);
|
|
583
|
+
}
|
|
584
|
+
candidatesByConditionKey.set(conditionTokenResult.value, candidate);
|
|
585
|
+
}
|
|
586
|
+
// Then, apply edits (this replaces any colliding original candidates)
|
|
587
|
+
// Convert edit candidates (which have ids) to child candidates (without ids) for merging
|
|
588
|
+
for (const editCandidate of editCandidates) {
|
|
589
|
+
const conditionTokenResult = ResourceManagerBuilder._getConditionSetToken(editCandidate.conditions, conditionCollector);
|
|
590
|
+
if (conditionTokenResult.isFailure()) {
|
|
591
|
+
return (0, ts_utils_1.fail)(`Failed to generate condition token for edit candidate: ${conditionTokenResult.message}`);
|
|
592
|
+
}
|
|
593
|
+
const childCandidate = {
|
|
594
|
+
json: editCandidate.json,
|
|
595
|
+
conditions: editCandidate.conditions,
|
|
596
|
+
isPartial: editCandidate.isPartial,
|
|
597
|
+
mergeMethod: editCandidate.mergeMethod
|
|
598
|
+
};
|
|
599
|
+
candidatesByConditionKey.set(conditionTokenResult.value, childCandidate);
|
|
600
|
+
}
|
|
601
|
+
// Extract the final merged candidate list
|
|
602
|
+
const mergedCandidates = Array.from(candidatesByConditionKey.values());
|
|
603
|
+
const modifiedDecl = Object.assign(Object.assign({}, resourceDecl), { candidates: mergedCandidates });
|
|
604
|
+
return (0, ts_utils_1.succeed)(modifiedDecl);
|
|
605
|
+
}
|
|
606
|
+
/**
|
|
607
|
+
* Creates a new resource declaration from an array of candidate declarations.
|
|
608
|
+
* This is used when cloning to create new resources that don't exist in the original manager.
|
|
609
|
+
* @param resourceId - The validated resource ID for the new resource
|
|
610
|
+
* @param candidates - Array of loose candidate declarations for the new resource
|
|
611
|
+
* @param conditionCollector - The condition collector for validation context
|
|
612
|
+
* @returns A Result containing the new resource declaration if successful, or failure if validation fails
|
|
613
|
+
* @internal
|
|
614
|
+
*/
|
|
615
|
+
static _createResourceDeclFromCandidates(resourceId, candidates, conditionCollector) {
|
|
616
|
+
// Convert candidate declarations to child candidate declarations
|
|
617
|
+
const childCandidates = [];
|
|
618
|
+
// Ensure we have candidates
|
|
619
|
+
if (candidates.length === 0) {
|
|
620
|
+
return (0, ts_utils_1.fail)('Cannot create resource declaration from empty candidates array');
|
|
621
|
+
}
|
|
622
|
+
// Extract resourceTypeName from the first candidate (all candidates for the same resource should have the same type)
|
|
623
|
+
const resourceTypeName = candidates[0].resourceTypeName;
|
|
624
|
+
if (!resourceTypeName) {
|
|
625
|
+
return (0, ts_utils_1.fail)('resourceTypeName is required for new resource candidates');
|
|
626
|
+
}
|
|
627
|
+
for (const candidate of candidates) {
|
|
628
|
+
const childCandidate = {
|
|
629
|
+
json: candidate.json,
|
|
630
|
+
conditions: candidate.conditions,
|
|
631
|
+
isPartial: candidate.isPartial,
|
|
632
|
+
mergeMethod: candidate.mergeMethod
|
|
633
|
+
};
|
|
634
|
+
childCandidates.push(childCandidate);
|
|
635
|
+
}
|
|
636
|
+
// Create the new resource declaration
|
|
637
|
+
const newResourceDecl = {
|
|
638
|
+
id: resourceId,
|
|
639
|
+
candidates: childCandidates,
|
|
640
|
+
resourceTypeName
|
|
641
|
+
};
|
|
642
|
+
return (0, ts_utils_1.succeed)(newResourceDecl);
|
|
643
|
+
}
|
|
449
644
|
}
|
|
450
645
|
exports.ResourceManagerBuilder = ResourceManagerBuilder;
|
|
451
646
|
//# sourceMappingURL=resourceManagerBuilder.js.map
|