@fgv/ts-res-browser 5.0.0-2 → 5.0.0-21
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/cli.js +132 -21
- package/dist/bundle.js +1 -1
- package/dist/bundle.js.LICENSE.txt +11 -1
- package/package.json +42 -36
- package/.rush/temp/587277bfc395406ad444e989b6c309b9698f534c.tar.log +0 -15
- package/.rush/temp/chunked-rush-logs/ts-res-browser.build.chunks.jsonl +0 -35
- package/.rush/temp/operation/build/all.log +0 -35
- package/.rush/temp/operation/build/log-chunks.jsonl +0 -35
- package/.rush/temp/operation/build/state.json +0 -3
- package/.rush/temp/shrinkwrap-deps.json +0 -1225
- package/TS_RES_BROWSER_PLAN.md +0 -689
- package/babel.config.js +0 -17
- package/config/jest.config.json +0 -13
- package/config/rig.json +0 -16
- package/postcss.config.js +0 -3
- package/public/index.html +0 -15
- package/rush-logs/ts-res-browser.build.cache.log +0 -3
- package/rush-logs/ts-res-browser.build.log +0 -35
- package/src/App.tsx +0 -274
- package/src/cli.ts +0 -44
- package/src/components/common/FileImporter.tsx +0 -143
- package/src/components/common/NavigationWarningModal.tsx +0 -62
- package/src/components/layout/AppLayout.tsx +0 -46
- package/src/components/layout/Header.tsx +0 -22
- package/src/components/layout/MessagesWindow.tsx +0 -108
- package/src/components/layout/Sidebar.tsx +0 -99
- package/src/components/tools/CompiledBrowser.tsx +0 -949
- package/src/components/tools/ConfigurationTool.tsx +0 -1405
- package/src/components/tools/FilterTool.tsx +0 -1114
- package/src/components/tools/ImportTool.tsx +0 -249
- package/src/components/tools/ResolutionViewer.tsx +0 -1672
- package/src/components/tools/SourceBrowser.tsx +0 -496
- package/src/components/tools/ZipLoader.tsx +0 -302
- package/src/hooks/useAppState.ts +0 -111
- package/src/hooks/useFileImport.ts +0 -86
- package/src/hooks/useNavigationWarning.ts +0 -67
- package/src/hooks/useResourceManager.ts +0 -295
- package/src/hooks/useUrlParams.ts +0 -56
- package/src/index.css +0 -38
- package/src/main.tsx +0 -16
- package/src/types/app.ts +0 -70
- package/src/types/fileSystemAccess.d.ts +0 -94
- package/src/utils/browserFileTreeAccessors.ts +0 -245
- package/src/utils/fileImport.ts +0 -336
- package/src/utils/fileTreeConverter.ts +0 -160
- package/src/utils/filterResources.ts +0 -677
- package/src/utils/tsResIntegration.ts +0 -467
- package/src/utils/urlParams.ts +0 -238
- package/src/utils/zip/browserZipFileTreeAccessors.ts +0 -385
- package/tailwind.config.js +0 -21
- package/test-data/README.md +0 -184
- package/test-data/config-variations/README.md +0 -64
- package/test-data/config-variations/composition-terminology.json +0 -112
- package/test-data/config-variations/enterprise-complex.json +0 -129
- package/test-data/config-variations/gaming-app.json +0 -87
- package/test-data/config-variations/high-priority-language.json +0 -65
- package/test-data/config-variations/minimal-basic.json +0 -37
- package/test-data/config-variations/qualifier-default-values.json +0 -71
- package/test-data/config-variations/territory-first.json +0 -68
- package/test-data/config-variations/territory-hierarchy-test.json +0 -31
- package/test-data/config-variations/territory-hierarchy-unconstrained.json +0 -32
- package/test-data/default-matching-test/greeting.res.json +0 -83
- package/test-data/default-matching-test/only-defaults.res.json +0 -48
- package/test-data/sample-project/package.json +0 -27
- package/test-data/sample-project/src/resources/app-config.json +0 -27
- package/test-data/sample-project/src/resources/app.json +0 -177
- package/test-data/sample-project/src/resources/config/app.env=development.json +0 -21
- package/test-data/sample-project/src/resources/config/app.json +0 -21
- package/test-data/sample-project/src/resources/config/app.platform=mobile.json +0 -23
- package/test-data/sample-project/src/resources/feature-flags.json +0 -23
- package/test-data/sample-project/src/resources/home=CA/common.json +0 -16
- package/test-data/sample-project/src/resources/images/density=hdpi.json +0 -29
- package/test-data/sample-project/src/resources/images/home.json +0 -29
- package/test-data/sample-project/src/resources/images/logout.json +0 -14
- package/test-data/sample-project/src/resources/images/settings.json +0 -14
- package/test-data/sample-project/src/resources/images/ui-icons.json +0 -29
- package/test-data/sample-project/src/resources/images/user.density=hdpi.json +0 -14
- package/test-data/sample-project/src/resources/images/user.json +0 -14
- package/test-data/sample-project/src/resources/lang=en-US/common.json +0 -15
- package/test-data/sample-project/src/resources/language=en-CA/ui-terms.json +0 -19
- package/test-data/sample-project/src/resources/language=en-GB/ui-terms.json +0 -30
- package/test-data/sample-project/src/resources/language=fr-CA/ui-terms.json +0 -25
- package/test-data/sample-project/src/resources/language=nl-BE/ui-terms.json +0 -17
- package/test-data/sample-project/src/resources/region=europe/feature-flags.json +0 -17
- package/test-data/sample-project/src/resources/region=north-america/feature-flags.json +0 -18
- package/test-data/sample-project/src/resources/strings/dashboard.home=CA,language=fr.json +0 -20
- package/test-data/sample-project/src/resources/strings/dashboard.json +0 -18
- package/test-data/sample-project/src/resources/strings/dashboard.role=admin.json +0 -23
- package/test-data/sample-project/src/resources/strings/dashboard.role=user.json +0 -21
- package/test-data/sample-project/src/resources/strings/language=en-US.json +0 -16
- package/test-data/sample-project/src/resources/strings.json +0 -78
- package/test-data/sample-project/src/resources/territory=BE/app-config.json +0 -19
- package/test-data/sample-project/src/resources/territory=CA/app-config.json +0 -21
- package/test-data/sample-project/src/resources/territory=GB/app-config.json +0 -25
- package/test-data/sample-project/src/resources/territory=NL/app-config.json +0 -25
- package/test-data/sample-project/src/resources/ui-terms.json +0 -96
- package/test-data/sample-project/src/resources-config.json +0 -111
- package/tsconfig.json +0 -27
- package/webpack.config.js +0 -60
|
@@ -1,677 +0,0 @@
|
|
|
1
|
-
import { Result, succeed, fail } from '@fgv/ts-utils';
|
|
2
|
-
import { Context, Runtime, Import, Resources } from '@fgv/ts-res';
|
|
3
|
-
import { ProcessedResources, TsResSystem, createTsResSystemFromConfig } from './tsResIntegration';
|
|
4
|
-
|
|
5
|
-
export interface FilterOptions {
|
|
6
|
-
partialContextMatch?: boolean;
|
|
7
|
-
enableDebugLogging?: boolean;
|
|
8
|
-
reduceQualifiers?: boolean;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export interface FilteredResource {
|
|
12
|
-
id: string;
|
|
13
|
-
originalCandidateCount: number;
|
|
14
|
-
filteredCandidateCount: number;
|
|
15
|
-
hasWarning: boolean;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export interface FilterResult {
|
|
19
|
-
success: boolean;
|
|
20
|
-
filteredResources: FilteredResource[];
|
|
21
|
-
processedResources?: ProcessedResources;
|
|
22
|
-
error?: string;
|
|
23
|
-
warnings: string[];
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Creates a filtered resource manager based on partial context matching
|
|
28
|
-
*/
|
|
29
|
-
// Helper function for conditional debug logging
|
|
30
|
-
const debugLog = (enableDebug: boolean, ...args: any[]) => {
|
|
31
|
-
if (enableDebug) {
|
|
32
|
-
console.log(...args);
|
|
33
|
-
}
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Creates a filtered resource manager using the new base library filtering functionality.
|
|
38
|
-
* This is a much simpler implementation that leverages the ResourceManagerBuilder.clone() method.
|
|
39
|
-
*/
|
|
40
|
-
export const createFilteredResourceManagerSimple = async (
|
|
41
|
-
originalSystem: TsResSystem,
|
|
42
|
-
partialContext: Record<string, string>,
|
|
43
|
-
options: FilterOptions = { partialContextMatch: true }
|
|
44
|
-
): Promise<Result<ProcessedResources>> => {
|
|
45
|
-
try {
|
|
46
|
-
const enableDebug = options.enableDebugLogging === true;
|
|
47
|
-
|
|
48
|
-
debugLog(enableDebug, '=== SIMPLE FILTER CREATION ===');
|
|
49
|
-
debugLog(enableDebug, 'Original system:', originalSystem);
|
|
50
|
-
debugLog(enableDebug, 'Partial context:', partialContext);
|
|
51
|
-
|
|
52
|
-
// Validate the original system
|
|
53
|
-
if (!originalSystem?.resourceManager) {
|
|
54
|
-
return fail('Original system or resourceManager is undefined');
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// Use Result pattern chaining as recommended
|
|
58
|
-
debugLog(enableDebug, 'Validating context and cloning manager:', partialContext);
|
|
59
|
-
const cloneResult = originalSystem.resourceManager
|
|
60
|
-
.validateContext(partialContext)
|
|
61
|
-
.onSuccess((validatedContext) => {
|
|
62
|
-
debugLog(enableDebug, 'Context validated, creating clone with context:', validatedContext);
|
|
63
|
-
return originalSystem.resourceManager.clone({
|
|
64
|
-
filterForContext: validatedContext,
|
|
65
|
-
reduceQualifiers: options.reduceQualifiers
|
|
66
|
-
});
|
|
67
|
-
})
|
|
68
|
-
.onFailure((error) => {
|
|
69
|
-
debugLog(enableDebug, 'Failed to validate context or clone:', error);
|
|
70
|
-
return fail(error);
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
if (cloneResult.isFailure()) {
|
|
74
|
-
return fail(`Failed to create filtered resource manager: ${cloneResult.message}`);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
const filteredManager = cloneResult.value;
|
|
78
|
-
debugLog(enableDebug, 'Filtered manager created:', filteredManager);
|
|
79
|
-
|
|
80
|
-
// Create new ImportManager for the filtered system
|
|
81
|
-
const newImportManagerResult = Import.ImportManager.create({
|
|
82
|
-
resources: filteredManager
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
if (newImportManagerResult.isFailure()) {
|
|
86
|
-
return fail(`Failed to create filtered import manager: ${newImportManagerResult.message}`);
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
// Create new ContextQualifierProvider for the filtered system
|
|
90
|
-
const newContextQualifierProviderResult = Runtime.ValidatingSimpleContextQualifierProvider.create({
|
|
91
|
-
qualifiers: originalSystem.qualifiers
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
if (newContextQualifierProviderResult.isFailure()) {
|
|
95
|
-
return fail(`Failed to create filtered context provider: ${newContextQualifierProviderResult.message}`);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
// Create TsResSystem for the filtered manager
|
|
99
|
-
const filteredSystem: TsResSystem = {
|
|
100
|
-
qualifierTypes: originalSystem.qualifierTypes,
|
|
101
|
-
qualifiers: originalSystem.qualifiers,
|
|
102
|
-
resourceTypes: originalSystem.resourceTypes,
|
|
103
|
-
resourceManager: filteredManager,
|
|
104
|
-
importManager: newImportManagerResult.value,
|
|
105
|
-
contextQualifierProvider: newContextQualifierProviderResult.value
|
|
106
|
-
};
|
|
107
|
-
|
|
108
|
-
// Process the filtered system into ProcessedResources
|
|
109
|
-
const compiledResult = filteredSystem.resourceManager.getCompiledResourceCollection({
|
|
110
|
-
includeMetadata: true
|
|
111
|
-
});
|
|
112
|
-
if (compiledResult.isFailure()) {
|
|
113
|
-
return fail(`Failed to compile filtered resources: ${compiledResult.message}`);
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
const resolverResult = Runtime.ResourceResolver.create({
|
|
117
|
-
resourceManager: filteredSystem.resourceManager,
|
|
118
|
-
qualifierTypes: filteredSystem.qualifierTypes,
|
|
119
|
-
contextQualifierProvider: filteredSystem.contextQualifierProvider
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
if (resolverResult.isFailure()) {
|
|
123
|
-
return fail(`Failed to create filtered resolver: ${resolverResult.message}`);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
// Create resource summary
|
|
127
|
-
const resourceIds = Array.from(filteredSystem.resourceManager.resources.keys());
|
|
128
|
-
const summary = {
|
|
129
|
-
totalResources: resourceIds.length,
|
|
130
|
-
resourceIds,
|
|
131
|
-
errorCount: 0,
|
|
132
|
-
warnings: []
|
|
133
|
-
};
|
|
134
|
-
|
|
135
|
-
const processedResources: ProcessedResources = {
|
|
136
|
-
system: filteredSystem,
|
|
137
|
-
compiledCollection: compiledResult.value,
|
|
138
|
-
resolver: resolverResult.value,
|
|
139
|
-
resourceCount: resourceIds.length,
|
|
140
|
-
summary
|
|
141
|
-
};
|
|
142
|
-
|
|
143
|
-
debugLog(enableDebug, 'Simple filtering completed successfully');
|
|
144
|
-
return succeed(processedResources);
|
|
145
|
-
} catch (error) {
|
|
146
|
-
return fail(
|
|
147
|
-
`Unexpected error during simple filtering: ${error instanceof Error ? error.message : String(error)}`
|
|
148
|
-
);
|
|
149
|
-
}
|
|
150
|
-
};
|
|
151
|
-
|
|
152
|
-
export const createFilteredResourceManager = async (
|
|
153
|
-
originalSystem: TsResSystem,
|
|
154
|
-
partialContext: Record<string, string>,
|
|
155
|
-
options: FilterOptions = { partialContextMatch: true }
|
|
156
|
-
): Promise<Result<ProcessedResources>> => {
|
|
157
|
-
try {
|
|
158
|
-
const enableDebug = options.enableDebugLogging === true;
|
|
159
|
-
|
|
160
|
-
debugLog(enableDebug, '=== FILTER CREATION DEBUG ===');
|
|
161
|
-
debugLog(enableDebug, 'Original system:', originalSystem);
|
|
162
|
-
debugLog(enableDebug, 'Partial context:', partialContext);
|
|
163
|
-
debugLog(enableDebug, 'Options:', options);
|
|
164
|
-
|
|
165
|
-
// Validate the original system has required components
|
|
166
|
-
if (!originalSystem) {
|
|
167
|
-
return fail('Original system is undefined - ensure resources are loaded before filtering');
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
debugLog(enableDebug, 'System validation - qualifiers:', originalSystem.qualifiers);
|
|
171
|
-
debugLog(enableDebug, 'System validation - resourceTypes:', originalSystem.resourceTypes);
|
|
172
|
-
debugLog(enableDebug, 'System validation - resourceManager:', originalSystem.resourceManager);
|
|
173
|
-
|
|
174
|
-
if (!originalSystem.qualifiers) {
|
|
175
|
-
return fail('Original system qualifiers are undefined - system may not be properly initialized');
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
if (!originalSystem.resourceTypes) {
|
|
179
|
-
return fail('Original system resourceTypes are undefined - system may not be properly initialized');
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
if (!originalSystem.resourceManager) {
|
|
183
|
-
return fail('Original system resourceManager is undefined - system may not be properly initialized');
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
// Additional validation for the objects themselves
|
|
187
|
-
if (typeof originalSystem.qualifiers !== 'object') {
|
|
188
|
-
return fail(`Original system qualifiers has invalid type: ${typeof originalSystem.qualifiers}`);
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
if (typeof originalSystem.resourceTypes !== 'object') {
|
|
192
|
-
return fail(`Original system resourceTypes has invalid type: ${typeof originalSystem.resourceTypes}`);
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
// Create validated context from user input
|
|
196
|
-
debugLog(enableDebug, 'Creating validated context...');
|
|
197
|
-
debugLog(enableDebug, 'Partial context (raw):', partialContext);
|
|
198
|
-
|
|
199
|
-
// Filter out empty string values - only include qualifiers with actual values
|
|
200
|
-
const cleanedContext = Object.fromEntries(
|
|
201
|
-
Object.entries(partialContext).filter(([, value]) => value.trim() !== '')
|
|
202
|
-
);
|
|
203
|
-
|
|
204
|
-
debugLog(enableDebug, 'Cleaned context (empty strings removed):', cleanedContext);
|
|
205
|
-
debugLog(enableDebug, 'Available qualifiers:', originalSystem.qualifiers);
|
|
206
|
-
|
|
207
|
-
const contextResult = Context.Convert.validatedContextDecl.convert(cleanedContext, {
|
|
208
|
-
qualifiers: originalSystem.qualifiers
|
|
209
|
-
});
|
|
210
|
-
|
|
211
|
-
if (contextResult.isFailure()) {
|
|
212
|
-
debugLog(enableDebug, 'Context creation failed:', contextResult.message);
|
|
213
|
-
return fail(`Failed to create context: ${contextResult.message}`);
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
const validatedContext = contextResult.value;
|
|
217
|
-
debugLog(enableDebug, 'Validated context created:', validatedContext);
|
|
218
|
-
|
|
219
|
-
// Get filtered resource builders that match the context
|
|
220
|
-
debugLog(enableDebug, 'Getting resources for context...');
|
|
221
|
-
debugLog(enableDebug, 'Validated context:', validatedContext);
|
|
222
|
-
debugLog(enableDebug, 'Filter options:', options);
|
|
223
|
-
|
|
224
|
-
const filteredResourceBuilders = originalSystem.resourceManager.getResourcesForContext(
|
|
225
|
-
validatedContext,
|
|
226
|
-
options
|
|
227
|
-
);
|
|
228
|
-
|
|
229
|
-
debugLog(enableDebug, 'Filtered resource builders count:', filteredResourceBuilders.length);
|
|
230
|
-
debugLog(enableDebug, 'Filtered resource builders:', filteredResourceBuilders);
|
|
231
|
-
|
|
232
|
-
// Debug: Show detailed condition evaluation for each resource
|
|
233
|
-
if (enableDebug) {
|
|
234
|
-
debugLog(enableDebug, '=== DETAILED CANDIDATE FILTERING DEBUG ===');
|
|
235
|
-
const allResourceBuilders = originalSystem.resourceManager.getAllResources();
|
|
236
|
-
for (const resourceBuilder of allResourceBuilders) {
|
|
237
|
-
const builtResult = resourceBuilder.build();
|
|
238
|
-
if (builtResult.isSuccess()) {
|
|
239
|
-
const resource = builtResult.value;
|
|
240
|
-
debugLog(enableDebug, `\n--- Resource: ${resource.id} ---`);
|
|
241
|
-
debugLog(enableDebug, `Candidates: ${resource.candidates.length}`);
|
|
242
|
-
|
|
243
|
-
resource.candidates.forEach((candidate, index) => {
|
|
244
|
-
debugLog(enableDebug, ` Candidate ${index}:`);
|
|
245
|
-
if (candidate.conditions && candidate.conditions.conditions) {
|
|
246
|
-
candidate.conditions.conditions.forEach((condition, condIndex) => {
|
|
247
|
-
const canMatch = condition.canMatchPartialContext(validatedContext, options);
|
|
248
|
-
const contextMatch = condition.getContextMatch(validatedContext, options);
|
|
249
|
-
debugLog(
|
|
250
|
-
enableDebug,
|
|
251
|
-
` Condition ${condIndex}: ${condition.qualifier.name}=${condition.value} (operator: ${condition.operator})`
|
|
252
|
-
);
|
|
253
|
-
debugLog(enableDebug, ` canMatchPartialContext: ${canMatch}`);
|
|
254
|
-
debugLog(enableDebug, ` contextMatch: ${contextMatch}`);
|
|
255
|
-
debugLog(
|
|
256
|
-
enableDebug,
|
|
257
|
-
` qualifier in context: ${condition.qualifier.name in validatedContext}`
|
|
258
|
-
);
|
|
259
|
-
if (condition.qualifier.name in validatedContext) {
|
|
260
|
-
debugLog(enableDebug, ` context value: ${validatedContext[condition.qualifier.name]}`);
|
|
261
|
-
}
|
|
262
|
-
});
|
|
263
|
-
} else {
|
|
264
|
-
debugLog(enableDebug, ` No conditions (default candidate)`);
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
const candidateCanMatch = candidate.canMatchPartialContext(validatedContext, options);
|
|
268
|
-
debugLog(enableDebug, ` -> Candidate ${index} canMatchPartialContext: ${candidateCanMatch}`);
|
|
269
|
-
});
|
|
270
|
-
|
|
271
|
-
const resourceCandidatesForContext = resourceBuilder.getCandidatesForContext(
|
|
272
|
-
validatedContext,
|
|
273
|
-
options
|
|
274
|
-
);
|
|
275
|
-
debugLog(
|
|
276
|
-
enableDebug,
|
|
277
|
-
` -> Resource has ${resourceCandidatesForContext.length} matching candidates`
|
|
278
|
-
);
|
|
279
|
-
debugLog(
|
|
280
|
-
enableDebug,
|
|
281
|
-
` -> Resource included in filter: ${filteredResourceBuilders.includes(resourceBuilder)}`
|
|
282
|
-
);
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
// Convert filtered resources to declarations with only matching candidates
|
|
288
|
-
const resourceDeclarations: ResourceJson.Json.ILooseResourceDecl[] = [];
|
|
289
|
-
|
|
290
|
-
debugLog(enableDebug, '=== CONVERTING FILTERED RESOURCES TO DECLARATIONS ===');
|
|
291
|
-
for (const resourceBuilder of filteredResourceBuilders) {
|
|
292
|
-
const builtResourceResult = resourceBuilder.build();
|
|
293
|
-
if (builtResourceResult.isFailure()) {
|
|
294
|
-
debugLog(enableDebug, `Failed to build resource: ${builtResourceResult.message}`);
|
|
295
|
-
continue;
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
const builtResource = builtResourceResult.value;
|
|
299
|
-
debugLog(enableDebug, `\n--- Converting Resource: ${builtResource.id} ---`);
|
|
300
|
-
debugLog(enableDebug, `Original candidates: ${builtResource.candidates.length}`);
|
|
301
|
-
|
|
302
|
-
// Filter candidates to only include those that match the context
|
|
303
|
-
const matchingCandidates = builtResource.candidates.filter((candidate) => {
|
|
304
|
-
const canMatch = candidate.canMatchPartialContext(validatedContext, options);
|
|
305
|
-
debugLog(
|
|
306
|
-
enableDebug,
|
|
307
|
-
` Candidate with conditions ${
|
|
308
|
-
candidate.conditions?.conditions.map((c) => `${c.qualifier.name}=${c.value}`).join(', ') || 'none'
|
|
309
|
-
}: canMatch = ${canMatch}`
|
|
310
|
-
);
|
|
311
|
-
return canMatch;
|
|
312
|
-
});
|
|
313
|
-
|
|
314
|
-
debugLog(enableDebug, `Filtered to ${matchingCandidates.length} matching candidates`);
|
|
315
|
-
|
|
316
|
-
// Create a new resource declaration with only the matching candidates
|
|
317
|
-
const originalDeclaration = builtResource.toLooseResourceDecl();
|
|
318
|
-
const filteredDeclaration: ResourceJson.Json.ILooseResourceDecl = {
|
|
319
|
-
...originalDeclaration,
|
|
320
|
-
candidates: matchingCandidates.map((candidate) => candidate.toLooseResourceCandidateDecl())
|
|
321
|
-
};
|
|
322
|
-
|
|
323
|
-
debugLog(enableDebug, `Final declaration candidates: ${filteredDeclaration.candidates?.length || 0}`);
|
|
324
|
-
|
|
325
|
-
// Debug: Check what candidates are in the final declaration
|
|
326
|
-
if (enableDebug) {
|
|
327
|
-
filteredDeclaration.candidates?.forEach((candidate, index) => {
|
|
328
|
-
debugLog(enableDebug, ` Final Declaration Candidate ${index}:`);
|
|
329
|
-
if (candidate.conditions) {
|
|
330
|
-
Object.entries(candidate.conditions).forEach(([qualifier, value]) => {
|
|
331
|
-
debugLog(enableDebug, ` Condition: ${qualifier}=${value}`);
|
|
332
|
-
});
|
|
333
|
-
} else {
|
|
334
|
-
debugLog(enableDebug, ` No conditions (default candidate)`);
|
|
335
|
-
}
|
|
336
|
-
});
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
resourceDeclarations.push(filteredDeclaration);
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
// Validate system components before creating new manager
|
|
343
|
-
if (!originalSystem.qualifiers) {
|
|
344
|
-
return fail('Original system qualifiers is undefined');
|
|
345
|
-
}
|
|
346
|
-
if (!originalSystem.resourceTypes) {
|
|
347
|
-
return fail('Original system resourceTypes is undefined');
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
// Create new ResourceManagerBuilder with same configuration
|
|
351
|
-
debugLog(enableDebug, 'Creating new resource manager...');
|
|
352
|
-
debugLog(enableDebug, 'Qualifiers for new manager:', originalSystem.qualifiers);
|
|
353
|
-
debugLog(enableDebug, 'ResourceTypes for new manager:', originalSystem.resourceTypes);
|
|
354
|
-
|
|
355
|
-
const newManagerResult = Resources.ResourceManagerBuilder.create({
|
|
356
|
-
qualifiers: originalSystem.qualifiers,
|
|
357
|
-
resourceTypes: originalSystem.resourceTypes
|
|
358
|
-
});
|
|
359
|
-
|
|
360
|
-
if (newManagerResult.isFailure()) {
|
|
361
|
-
debugLog(enableDebug, 'New manager creation failed:', newManagerResult.message, newManagerResult);
|
|
362
|
-
return fail(`Failed to create new manager: ${newManagerResult.message}`);
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
const newManager = newManagerResult.value;
|
|
366
|
-
debugLog(enableDebug, 'New manager created successfully:', newManager);
|
|
367
|
-
|
|
368
|
-
// Add each filtered resource to the new manager
|
|
369
|
-
debugLog(enableDebug, '=== ADDING RESOURCES TO NEW FILTERED MANAGER ===');
|
|
370
|
-
for (const declaration of resourceDeclarations) {
|
|
371
|
-
debugLog(
|
|
372
|
-
enableDebug,
|
|
373
|
-
`Adding resource: ${declaration.id} with ${declaration.candidates?.length || 0} candidates`
|
|
374
|
-
);
|
|
375
|
-
const addResult = newManager.addResource(declaration);
|
|
376
|
-
if (addResult.isFailure()) {
|
|
377
|
-
debugLog(enableDebug, `Failed to add resource ${declaration.id}: ${addResult.message}`);
|
|
378
|
-
} else if (enableDebug) {
|
|
379
|
-
// Verify what actually got added to the manager
|
|
380
|
-
const retrievedResult = newManager.getBuiltResource(declaration.id);
|
|
381
|
-
if (retrievedResult.isSuccess()) {
|
|
382
|
-
const retrievedResource = retrievedResult.value;
|
|
383
|
-
debugLog(
|
|
384
|
-
enableDebug,
|
|
385
|
-
` -> Resource added successfully with ${retrievedResource.candidates.length} candidates:`
|
|
386
|
-
);
|
|
387
|
-
retrievedResource.candidates.forEach((candidate, index) => {
|
|
388
|
-
debugLog(enableDebug, ` Final Candidate ${index}:`);
|
|
389
|
-
if (candidate.conditions && candidate.conditions.conditions) {
|
|
390
|
-
candidate.conditions.conditions.forEach((condition, condIndex) => {
|
|
391
|
-
debugLog(
|
|
392
|
-
enableDebug,
|
|
393
|
-
` Condition ${condIndex}: ${condition.qualifier.name}=${condition.value}`
|
|
394
|
-
);
|
|
395
|
-
});
|
|
396
|
-
} else {
|
|
397
|
-
debugLog(enableDebug, ` No conditions (default candidate)`);
|
|
398
|
-
}
|
|
399
|
-
});
|
|
400
|
-
}
|
|
401
|
-
}
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
// Create new ImportManager for the filtered system
|
|
405
|
-
const newImportManagerResult = Import.ImportManager.create({
|
|
406
|
-
resources: newManager
|
|
407
|
-
});
|
|
408
|
-
|
|
409
|
-
if (newImportManagerResult.isFailure()) {
|
|
410
|
-
return fail(`Failed to create filtered import manager: ${newImportManagerResult.message}`);
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
// Create new ContextQualifierProvider for the filtered system
|
|
414
|
-
// Validate qualifiers again before using them
|
|
415
|
-
if (!originalSystem.qualifiers) {
|
|
416
|
-
return fail('Original system qualifiers became undefined during processing');
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
const newContextQualifierProviderResult = Runtime.ValidatingSimpleContextQualifierProvider.create({
|
|
420
|
-
qualifiers: originalSystem.qualifiers
|
|
421
|
-
});
|
|
422
|
-
|
|
423
|
-
if (newContextQualifierProviderResult.isFailure()) {
|
|
424
|
-
return fail(`Failed to create filtered context provider: ${newContextQualifierProviderResult.message}`);
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
// Create TsResSystem for the filtered manager
|
|
428
|
-
const filteredSystem: TsResSystem = {
|
|
429
|
-
qualifierTypes: originalSystem.qualifierTypes,
|
|
430
|
-
qualifiers: originalSystem.qualifiers,
|
|
431
|
-
resourceTypes: originalSystem.resourceTypes,
|
|
432
|
-
resourceManager: newManager,
|
|
433
|
-
importManager: newImportManagerResult.value,
|
|
434
|
-
contextQualifierProvider: newContextQualifierProviderResult.value
|
|
435
|
-
};
|
|
436
|
-
|
|
437
|
-
// Process the filtered system into ProcessedResources
|
|
438
|
-
const compiledResult = filteredSystem.resourceManager.getCompiledResourceCollection({
|
|
439
|
-
includeMetadata: true
|
|
440
|
-
});
|
|
441
|
-
if (compiledResult.isFailure()) {
|
|
442
|
-
return fail(`Failed to compile filtered resources: ${compiledResult.message}`);
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
const resolverResult = Runtime.ResourceResolver.create({
|
|
446
|
-
resourceManager: filteredSystem.resourceManager,
|
|
447
|
-
qualifierTypes: filteredSystem.qualifierTypes,
|
|
448
|
-
contextQualifierProvider: filteredSystem.contextQualifierProvider
|
|
449
|
-
});
|
|
450
|
-
|
|
451
|
-
if (resolverResult.isFailure()) {
|
|
452
|
-
return fail(`Failed to create filtered resolver: ${resolverResult.message}`);
|
|
453
|
-
}
|
|
454
|
-
|
|
455
|
-
// Create resource summary
|
|
456
|
-
const resourceIds = Array.from(filteredSystem.resourceManager.resources.keys());
|
|
457
|
-
const summary = {
|
|
458
|
-
totalResources: resourceIds.length,
|
|
459
|
-
resourceIds,
|
|
460
|
-
errorCount: 0,
|
|
461
|
-
warnings: []
|
|
462
|
-
};
|
|
463
|
-
|
|
464
|
-
const processedResources: ProcessedResources = {
|
|
465
|
-
system: filteredSystem,
|
|
466
|
-
compiledCollection: compiledResult.value,
|
|
467
|
-
resolver: resolverResult.value,
|
|
468
|
-
resourceCount: resourceIds.length,
|
|
469
|
-
summary
|
|
470
|
-
};
|
|
471
|
-
|
|
472
|
-
return succeed(processedResources);
|
|
473
|
-
} catch (error) {
|
|
474
|
-
return fail(
|
|
475
|
-
`Unexpected error during filtering: ${error instanceof Error ? error.message : String(error)}`
|
|
476
|
-
);
|
|
477
|
-
}
|
|
478
|
-
};
|
|
479
|
-
|
|
480
|
-
/**
|
|
481
|
-
* Analyzes resources to create filter result with validation
|
|
482
|
-
*/
|
|
483
|
-
export const analyzeFilteredResources = (
|
|
484
|
-
originalResources: string[],
|
|
485
|
-
filteredProcessedResources: ProcessedResources | null,
|
|
486
|
-
originalProcessedResources: ProcessedResources
|
|
487
|
-
): FilterResult => {
|
|
488
|
-
const warnings: string[] = [];
|
|
489
|
-
const filteredResources: FilteredResource[] = [];
|
|
490
|
-
|
|
491
|
-
if (!filteredProcessedResources) {
|
|
492
|
-
return {
|
|
493
|
-
success: false,
|
|
494
|
-
filteredResources: [],
|
|
495
|
-
error: 'Failed to create filtered resources',
|
|
496
|
-
warnings: []
|
|
497
|
-
};
|
|
498
|
-
}
|
|
499
|
-
|
|
500
|
-
const filteredResourceIds = filteredProcessedResources.summary.resourceIds || [];
|
|
501
|
-
|
|
502
|
-
// Analyze each original resource
|
|
503
|
-
for (const resourceId of originalResources) {
|
|
504
|
-
// Get original candidate count
|
|
505
|
-
const originalResourceResult =
|
|
506
|
-
originalProcessedResources.system.resourceManager.getBuiltResource(resourceId);
|
|
507
|
-
const originalCandidateCount = originalResourceResult.isSuccess()
|
|
508
|
-
? originalResourceResult.value.candidates.length
|
|
509
|
-
: 0;
|
|
510
|
-
|
|
511
|
-
// Check if resource exists in filtered set
|
|
512
|
-
const isInFilteredSet = filteredResourceIds.includes(resourceId);
|
|
513
|
-
let filteredCandidateCount = 0;
|
|
514
|
-
let hasWarning = false;
|
|
515
|
-
|
|
516
|
-
if (isInFilteredSet) {
|
|
517
|
-
// Get filtered candidate count
|
|
518
|
-
const filteredResourceResult =
|
|
519
|
-
filteredProcessedResources.system.resourceManager.getBuiltResource(resourceId);
|
|
520
|
-
if (filteredResourceResult.isSuccess()) {
|
|
521
|
-
filteredCandidateCount = filteredResourceResult.value.candidates.length;
|
|
522
|
-
hasWarning = filteredCandidateCount === 0;
|
|
523
|
-
|
|
524
|
-
if (hasWarning) {
|
|
525
|
-
warnings.push(`Resource "${resourceId}" has no matching candidates`);
|
|
526
|
-
}
|
|
527
|
-
}
|
|
528
|
-
} else {
|
|
529
|
-
// Resource was completely filtered out
|
|
530
|
-
hasWarning = true;
|
|
531
|
-
warnings.push(`Resource "${resourceId}" was completely filtered out`);
|
|
532
|
-
}
|
|
533
|
-
|
|
534
|
-
filteredResources.push({
|
|
535
|
-
id: resourceId,
|
|
536
|
-
originalCandidateCount,
|
|
537
|
-
filteredCandidateCount,
|
|
538
|
-
hasWarning
|
|
539
|
-
});
|
|
540
|
-
}
|
|
541
|
-
|
|
542
|
-
return {
|
|
543
|
-
success: true,
|
|
544
|
-
filteredResources,
|
|
545
|
-
processedResources: filteredProcessedResources,
|
|
546
|
-
warnings
|
|
547
|
-
};
|
|
548
|
-
};
|
|
549
|
-
|
|
550
|
-
/**
|
|
551
|
-
* Helper to check if context has any meaningful values
|
|
552
|
-
*/
|
|
553
|
-
export const hasFilterValues = (context: Record<string, string>): boolean => {
|
|
554
|
-
return Object.values(context).some((value) => value.trim() !== '');
|
|
555
|
-
};
|
|
556
|
-
|
|
557
|
-
/**
|
|
558
|
-
* Helper to create filter display text
|
|
559
|
-
*/
|
|
560
|
-
export const getFilterSummary = (context: Record<string, string>): string => {
|
|
561
|
-
const setValues = Object.entries(context)
|
|
562
|
-
.filter(([, value]) => value.trim() !== '')
|
|
563
|
-
.map(([key, value]) => `${key}=${value}`);
|
|
564
|
-
|
|
565
|
-
if (setValues.length === 0) {
|
|
566
|
-
return 'No filters applied';
|
|
567
|
-
}
|
|
568
|
-
|
|
569
|
-
return `Filtering by: ${setValues.join(', ')}`;
|
|
570
|
-
};
|
|
571
|
-
|
|
572
|
-
/**
|
|
573
|
-
* Alternative approach: Creates a filtered resource manager by recreating the system from scratch
|
|
574
|
-
* This is more robust but potentially slower than the direct approach
|
|
575
|
-
*/
|
|
576
|
-
export const createFilteredResourceManagerAlternative = async (
|
|
577
|
-
originalSystem: TsResSystem,
|
|
578
|
-
partialContext: Record<string, string>,
|
|
579
|
-
options: FilterOptions = { partialContextMatch: true }
|
|
580
|
-
): Promise<Result<ProcessedResources>> => {
|
|
581
|
-
const enableDebug = options.enableDebugLogging === true;
|
|
582
|
-
try {
|
|
583
|
-
// Validate inputs first
|
|
584
|
-
if (!originalSystem?.qualifiers || !originalSystem?.resourceTypes || !originalSystem?.resourceManager) {
|
|
585
|
-
return fail('Original system is missing required components');
|
|
586
|
-
}
|
|
587
|
-
|
|
588
|
-
// Create a fresh system using the original system's configuration
|
|
589
|
-
const freshSystemResult = createTsResSystemFromConfig();
|
|
590
|
-
|
|
591
|
-
if (freshSystemResult.isFailure()) {
|
|
592
|
-
return fail(`Failed to create fresh system: ${freshSystemResult.message}`);
|
|
593
|
-
}
|
|
594
|
-
|
|
595
|
-
const freshSystem = freshSystemResult.value;
|
|
596
|
-
|
|
597
|
-
// Get all resources from the original system that match the context
|
|
598
|
-
// Filter out empty string values - only include qualifiers with actual values
|
|
599
|
-
const cleanedContext = Object.fromEntries(
|
|
600
|
-
Object.entries(partialContext).filter(([, value]) => value.trim() !== '')
|
|
601
|
-
);
|
|
602
|
-
|
|
603
|
-
const contextResult = Context.Convert.validatedContextDecl.convert(cleanedContext, {
|
|
604
|
-
qualifiers: originalSystem.qualifiers
|
|
605
|
-
});
|
|
606
|
-
|
|
607
|
-
if (contextResult.isFailure()) {
|
|
608
|
-
return fail(`Failed to create context: ${contextResult.message}`);
|
|
609
|
-
}
|
|
610
|
-
|
|
611
|
-
const validatedContext = contextResult.value;
|
|
612
|
-
const filteredResourceBuilders = originalSystem.resourceManager.getResourcesForContext(
|
|
613
|
-
validatedContext,
|
|
614
|
-
options
|
|
615
|
-
);
|
|
616
|
-
|
|
617
|
-
// Add each filtered resource to the fresh system
|
|
618
|
-
for (const resourceBuilder of filteredResourceBuilders) {
|
|
619
|
-
const builtResourceResult = resourceBuilder.build();
|
|
620
|
-
if (builtResourceResult.isFailure()) {
|
|
621
|
-
debugLog(enableDebug, `Failed to build resource: ${builtResourceResult.message}`);
|
|
622
|
-
continue;
|
|
623
|
-
}
|
|
624
|
-
|
|
625
|
-
const builtResource = builtResourceResult.value;
|
|
626
|
-
const declaration = builtResource.toLooseResourceDecl();
|
|
627
|
-
|
|
628
|
-
const addResult = freshSystem.resourceManager.addResource(declaration);
|
|
629
|
-
if (addResult.isFailure()) {
|
|
630
|
-
debugLog(enableDebug, `Failed to add resource ${declaration.id}: ${addResult.message}`);
|
|
631
|
-
}
|
|
632
|
-
}
|
|
633
|
-
|
|
634
|
-
// Finalize the fresh system similar to how it's done in tsResIntegration
|
|
635
|
-
const compiledResult = freshSystem.resourceManager.getCompiledResourceCollection({
|
|
636
|
-
includeMetadata: true
|
|
637
|
-
});
|
|
638
|
-
if (compiledResult.isFailure()) {
|
|
639
|
-
return fail(`Failed to compile filtered resources: ${compiledResult.message}`);
|
|
640
|
-
}
|
|
641
|
-
|
|
642
|
-
const resolverResult = Runtime.ResourceResolver.create({
|
|
643
|
-
resourceManager: freshSystem.resourceManager,
|
|
644
|
-
qualifierTypes: freshSystem.qualifierTypes,
|
|
645
|
-
contextQualifierProvider: freshSystem.contextQualifierProvider
|
|
646
|
-
});
|
|
647
|
-
|
|
648
|
-
if (resolverResult.isFailure()) {
|
|
649
|
-
return fail(`Failed to create filtered resolver: ${resolverResult.message}`);
|
|
650
|
-
}
|
|
651
|
-
|
|
652
|
-
// Create resource summary
|
|
653
|
-
const resourceIds = Array.from(freshSystem.resourceManager.resources.keys());
|
|
654
|
-
const summary = {
|
|
655
|
-
totalResources: resourceIds.length,
|
|
656
|
-
resourceIds,
|
|
657
|
-
errorCount: 0,
|
|
658
|
-
warnings: []
|
|
659
|
-
};
|
|
660
|
-
|
|
661
|
-
const processedResources: ProcessedResources = {
|
|
662
|
-
system: freshSystem,
|
|
663
|
-
compiledCollection: compiledResult.value,
|
|
664
|
-
resolver: resolverResult.value,
|
|
665
|
-
resourceCount: resourceIds.length,
|
|
666
|
-
summary
|
|
667
|
-
};
|
|
668
|
-
|
|
669
|
-
return succeed(processedResources);
|
|
670
|
-
} catch (error) {
|
|
671
|
-
return fail(
|
|
672
|
-
`Unexpected error during alternative filtering: ${
|
|
673
|
-
error instanceof Error ? error.message : String(error)
|
|
674
|
-
}`
|
|
675
|
-
);
|
|
676
|
-
}
|
|
677
|
-
};
|