@fgv/ts-res-ui-components 5.0.0-10

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 (231) hide show
  1. package/.rush/temp/03c8b056281d9db0a97d8a6e25eea798a160d393.tar.log +271 -0
  2. package/.rush/temp/chunked-rush-logs/ts-res-ui-components.build.chunks.jsonl +9 -0
  3. package/.rush/temp/operation/build/all.log +9 -0
  4. package/.rush/temp/operation/build/log-chunks.jsonl +9 -0
  5. package/.rush/temp/operation/build/state.json +3 -0
  6. package/.rush/temp/shrinkwrap-deps.json +1111 -0
  7. package/README.md +18 -0
  8. package/REFACTORING_PLAN.md +171 -0
  9. package/config/jest.config.json +16 -0
  10. package/config/jest.setup.js +64 -0
  11. package/config/rig.json +16 -0
  12. package/lib/components/common/QualifierContextControl.d.ts +14 -0
  13. package/lib/components/common/QualifierContextControl.d.ts.map +1 -0
  14. package/lib/components/common/QualifierContextControl.js +78 -0
  15. package/lib/components/common/QualifierContextControl.js.map +1 -0
  16. package/lib/components/common/ResourceListView.d.ts +11 -0
  17. package/lib/components/common/ResourceListView.d.ts.map +1 -0
  18. package/lib/components/common/ResourceListView.js +20 -0
  19. package/lib/components/common/ResourceListView.js.map +1 -0
  20. package/lib/components/common/ResourceTreeView.d.ts +12 -0
  21. package/lib/components/common/ResourceTreeView.d.ts.map +1 -0
  22. package/lib/components/common/ResourceTreeView.js +162 -0
  23. package/lib/components/common/ResourceTreeView.js.map +1 -0
  24. package/lib/components/forms/HierarchyEditor.d.ts +10 -0
  25. package/lib/components/forms/HierarchyEditor.d.ts.map +1 -0
  26. package/lib/components/forms/HierarchyEditor.js +106 -0
  27. package/lib/components/forms/HierarchyEditor.js.map +1 -0
  28. package/lib/components/forms/QualifierEditForm.d.ts +11 -0
  29. package/lib/components/forms/QualifierEditForm.d.ts.map +1 -0
  30. package/lib/components/forms/QualifierEditForm.js +181 -0
  31. package/lib/components/forms/QualifierEditForm.js.map +1 -0
  32. package/lib/components/forms/QualifierTypeEditForm.d.ts +10 -0
  33. package/lib/components/forms/QualifierTypeEditForm.d.ts.map +1 -0
  34. package/lib/components/forms/QualifierTypeEditForm.js +172 -0
  35. package/lib/components/forms/QualifierTypeEditForm.js.map +1 -0
  36. package/lib/components/forms/ResourceTypeEditForm.d.ts +10 -0
  37. package/lib/components/forms/ResourceTypeEditForm.d.ts.map +1 -0
  38. package/lib/components/forms/ResourceTypeEditForm.js +188 -0
  39. package/lib/components/forms/ResourceTypeEditForm.js.map +1 -0
  40. package/lib/components/forms/index.d.ts +9 -0
  41. package/lib/components/forms/index.d.ts.map +1 -0
  42. package/lib/components/forms/index.js +5 -0
  43. package/lib/components/forms/index.js.map +1 -0
  44. package/lib/components/orchestrator/ResourceOrchestrator.d.ts +14 -0
  45. package/lib/components/orchestrator/ResourceOrchestrator.d.ts.map +1 -0
  46. package/lib/components/orchestrator/ResourceOrchestrator.js +278 -0
  47. package/lib/components/orchestrator/ResourceOrchestrator.js.map +1 -0
  48. package/lib/components/views/CompiledView/index.d.ts +5 -0
  49. package/lib/components/views/CompiledView/index.d.ts.map +1 -0
  50. package/lib/components/views/CompiledView/index.js +595 -0
  51. package/lib/components/views/CompiledView/index.js.map +1 -0
  52. package/lib/components/views/ConfigurationView/index.d.ts +5 -0
  53. package/lib/components/views/ConfigurationView/index.d.ts.map +1 -0
  54. package/lib/components/views/ConfigurationView/index.js +363 -0
  55. package/lib/components/views/ConfigurationView/index.js.map +1 -0
  56. package/lib/components/views/FilterView/index.d.ts +5 -0
  57. package/lib/components/views/FilterView/index.d.ts.map +1 -0
  58. package/lib/components/views/FilterView/index.js +463 -0
  59. package/lib/components/views/FilterView/index.js.map +1 -0
  60. package/lib/components/views/ImportView/index.d.ts +5 -0
  61. package/lib/components/views/ImportView/index.d.ts.map +1 -0
  62. package/lib/components/views/ImportView/index.js +514 -0
  63. package/lib/components/views/ImportView/index.js.map +1 -0
  64. package/lib/components/views/ResolutionView/EditableJsonView.d.ts +21 -0
  65. package/lib/components/views/ResolutionView/EditableJsonView.d.ts.map +1 -0
  66. package/lib/components/views/ResolutionView/EditableJsonView.js +109 -0
  67. package/lib/components/views/ResolutionView/EditableJsonView.js.map +1 -0
  68. package/lib/components/views/ResolutionView/ResolutionEditControls.d.ts +19 -0
  69. package/lib/components/views/ResolutionView/ResolutionEditControls.d.ts.map +1 -0
  70. package/lib/components/views/ResolutionView/ResolutionEditControls.js +82 -0
  71. package/lib/components/views/ResolutionView/ResolutionEditControls.js.map +1 -0
  72. package/lib/components/views/ResolutionView/index.d.ts +5 -0
  73. package/lib/components/views/ResolutionView/index.d.ts.map +1 -0
  74. package/lib/components/views/ResolutionView/index.js +255 -0
  75. package/lib/components/views/ResolutionView/index.js.map +1 -0
  76. package/lib/components/views/SourceView/index.d.ts +5 -0
  77. package/lib/components/views/SourceView/index.d.ts.map +1 -0
  78. package/lib/components/views/SourceView/index.js +316 -0
  79. package/lib/components/views/SourceView/index.js.map +1 -0
  80. package/lib/components/views/ZipLoaderView/index.d.ts +5 -0
  81. package/lib/components/views/ZipLoaderView/index.d.ts.map +1 -0
  82. package/lib/components/views/ZipLoaderView/index.js +313 -0
  83. package/lib/components/views/ZipLoaderView/index.js.map +1 -0
  84. package/lib/hooks/useConfigurationState.d.ts +46 -0
  85. package/lib/hooks/useConfigurationState.d.ts.map +1 -0
  86. package/lib/hooks/useConfigurationState.js +239 -0
  87. package/lib/hooks/useConfigurationState.js.map +1 -0
  88. package/lib/hooks/useFilterState.d.ts +7 -0
  89. package/lib/hooks/useFilterState.d.ts.map +1 -0
  90. package/lib/hooks/useFilterState.js +80 -0
  91. package/lib/hooks/useFilterState.js.map +1 -0
  92. package/lib/hooks/useResolutionState.d.ts +8 -0
  93. package/lib/hooks/useResolutionState.d.ts.map +1 -0
  94. package/lib/hooks/useResolutionState.js +253 -0
  95. package/lib/hooks/useResolutionState.js.map +1 -0
  96. package/lib/hooks/useResourceData.d.ts +19 -0
  97. package/lib/hooks/useResourceData.d.ts.map +1 -0
  98. package/lib/hooks/useResourceData.js +368 -0
  99. package/lib/hooks/useResourceData.js.map +1 -0
  100. package/lib/hooks/useViewState.d.ts +10 -0
  101. package/lib/hooks/useViewState.d.ts.map +1 -0
  102. package/lib/hooks/useViewState.js +29 -0
  103. package/lib/hooks/useViewState.js.map +1 -0
  104. package/lib/index.d.ts +27 -0
  105. package/lib/index.d.ts.map +1 -0
  106. package/lib/index.js +34 -0
  107. package/lib/index.js.map +1 -0
  108. package/lib/test/helpers/testDataLoader.d.ts +37 -0
  109. package/lib/test/helpers/testDataLoader.d.ts.map +1 -0
  110. package/lib/test/helpers/testDataLoader.js +171 -0
  111. package/lib/test/helpers/testDataLoader.js.map +1 -0
  112. package/lib/test/unit/utils/configurationUtils.test.d.ts +2 -0
  113. package/lib/test/unit/utils/configurationUtils.test.d.ts.map +1 -0
  114. package/lib/test/unit/utils/configurationUtils.test.js +497 -0
  115. package/lib/test/unit/utils/configurationUtils.test.js.map +1 -0
  116. package/lib/test/unit/utils/fileProcessing.test.d.ts +2 -0
  117. package/lib/test/unit/utils/fileProcessing.test.d.ts.map +1 -0
  118. package/lib/test/unit/utils/fileProcessing.test.js +321 -0
  119. package/lib/test/unit/utils/fileProcessing.test.js.map +1 -0
  120. package/lib/test/unit/utils/filterResources.test.d.ts +2 -0
  121. package/lib/test/unit/utils/filterResources.test.d.ts.map +1 -0
  122. package/lib/test/unit/utils/filterResources.test.js +403 -0
  123. package/lib/test/unit/utils/filterResources.test.js.map +1 -0
  124. package/lib/test/unit/utils/resolutionEditing.test.d.ts +2 -0
  125. package/lib/test/unit/utils/resolutionEditing.test.d.ts.map +1 -0
  126. package/lib/test/unit/utils/resolutionEditing.test.js +439 -0
  127. package/lib/test/unit/utils/resolutionEditing.test.js.map +1 -0
  128. package/lib/test/unit/utils/resolutionUtils.test.d.ts +2 -0
  129. package/lib/test/unit/utils/resolutionUtils.test.d.ts.map +1 -0
  130. package/lib/test/unit/utils/resolutionUtils.test.js +397 -0
  131. package/lib/test/unit/utils/resolutionUtils.test.js.map +1 -0
  132. package/lib/test/unit/utils/tsResIntegration.test.d.ts +2 -0
  133. package/lib/test/unit/utils/tsResIntegration.test.d.ts.map +1 -0
  134. package/lib/test/unit/utils/tsResIntegration.test.js +376 -0
  135. package/lib/test/unit/utils/tsResIntegration.test.js.map +1 -0
  136. package/lib/types/index.d.ts +251 -0
  137. package/lib/types/index.d.ts.map +1 -0
  138. package/lib/types/index.js +2 -0
  139. package/lib/types/index.js.map +1 -0
  140. package/lib/utils/configurationUtils.d.ts +74 -0
  141. package/lib/utils/configurationUtils.d.ts.map +1 -0
  142. package/lib/utils/configurationUtils.js +359 -0
  143. package/lib/utils/configurationUtils.js.map +1 -0
  144. package/lib/utils/fileProcessing.d.ts +18 -0
  145. package/lib/utils/fileProcessing.d.ts.map +1 -0
  146. package/lib/utils/fileProcessing.js +142 -0
  147. package/lib/utils/fileProcessing.js.map +1 -0
  148. package/lib/utils/filterResources.d.ts +38 -0
  149. package/lib/utils/filterResources.d.ts.map +1 -0
  150. package/lib/utils/filterResources.js +153 -0
  151. package/lib/utils/filterResources.js.map +1 -0
  152. package/lib/utils/resolutionEditing.d.ts +58 -0
  153. package/lib/utils/resolutionEditing.d.ts.map +1 -0
  154. package/lib/utils/resolutionEditing.js +246 -0
  155. package/lib/utils/resolutionEditing.js.map +1 -0
  156. package/lib/utils/resolutionUtils.d.ts +28 -0
  157. package/lib/utils/resolutionUtils.d.ts.map +1 -0
  158. package/lib/utils/resolutionUtils.js +216 -0
  159. package/lib/utils/resolutionUtils.js.map +1 -0
  160. package/lib/utils/tsResIntegration.d.ts +71 -0
  161. package/lib/utils/tsResIntegration.d.ts.map +1 -0
  162. package/lib/utils/tsResIntegration.js +294 -0
  163. package/lib/utils/tsResIntegration.js.map +1 -0
  164. package/lib/utils/zipLoader/browserZipLoader.d.ts +48 -0
  165. package/lib/utils/zipLoader/browserZipLoader.d.ts.map +1 -0
  166. package/lib/utils/zipLoader/browserZipLoader.js +247 -0
  167. package/lib/utils/zipLoader/browserZipLoader.js.map +1 -0
  168. package/lib/utils/zipLoader/index.d.ts +8 -0
  169. package/lib/utils/zipLoader/index.d.ts.map +1 -0
  170. package/lib/utils/zipLoader/index.js +13 -0
  171. package/lib/utils/zipLoader/index.js.map +1 -0
  172. package/lib/utils/zipLoader/nodeZipBuilder.d.ts +55 -0
  173. package/lib/utils/zipLoader/nodeZipBuilder.d.ts.map +1 -0
  174. package/lib/utils/zipLoader/nodeZipBuilder.js +98 -0
  175. package/lib/utils/zipLoader/nodeZipBuilder.js.map +1 -0
  176. package/lib/utils/zipLoader/types.d.ts +139 -0
  177. package/lib/utils/zipLoader/types.d.ts.map +1 -0
  178. package/lib/utils/zipLoader/types.js +2 -0
  179. package/lib/utils/zipLoader/types.js.map +1 -0
  180. package/lib/utils/zipLoader/zipUtils.d.ts +53 -0
  181. package/lib/utils/zipLoader/zipUtils.d.ts.map +1 -0
  182. package/lib/utils/zipLoader/zipUtils.js +229 -0
  183. package/lib/utils/zipLoader/zipUtils.js.map +1 -0
  184. package/package.json +69 -0
  185. package/rush-logs/ts-res-ui-components.build.cache.log +3 -0
  186. package/rush-logs/ts-res-ui-components.build.log +9 -0
  187. package/src/components/common/QualifierContextControl.tsx +151 -0
  188. package/src/components/common/ResourceListView.tsx +63 -0
  189. package/src/components/common/ResourceTreeView.tsx +271 -0
  190. package/src/components/forms/HierarchyEditor.tsx +204 -0
  191. package/src/components/forms/QualifierEditForm.tsx +355 -0
  192. package/src/components/forms/QualifierTypeEditForm.tsx +347 -0
  193. package/src/components/forms/ResourceTypeEditForm.tsx +331 -0
  194. package/src/components/forms/index.ts +11 -0
  195. package/src/components/orchestrator/ResourceOrchestrator.tsx +372 -0
  196. package/src/components/views/CompiledView/index.tsx +922 -0
  197. package/src/components/views/ConfigurationView/index.tsx +800 -0
  198. package/src/components/views/FilterView/index.tsx +825 -0
  199. package/src/components/views/ImportView/index.tsx +717 -0
  200. package/src/components/views/ResolutionView/EditableJsonView.tsx +214 -0
  201. package/src/components/views/ResolutionView/ResolutionEditControls.tsx +170 -0
  202. package/src/components/views/ResolutionView/index.tsx +591 -0
  203. package/src/components/views/SourceView/index.tsx +536 -0
  204. package/src/components/views/ZipLoaderView/index.tsx +485 -0
  205. package/src/hooks/useConfigurationState.ts +374 -0
  206. package/src/hooks/useFilterState.ts +97 -0
  207. package/src/hooks/useResolutionState.ts +355 -0
  208. package/src/hooks/useResourceData.ts +467 -0
  209. package/src/hooks/useViewState.ts +44 -0
  210. package/src/index.ts +45 -0
  211. package/src/test/helpers/testDataLoader.ts +195 -0
  212. package/src/test/unit/utils/configurationUtils.test.ts +630 -0
  213. package/src/test/unit/utils/fileProcessing.test.ts +391 -0
  214. package/src/test/unit/utils/filterResources.test.ts +574 -0
  215. package/src/test/unit/utils/resolutionEditing.test.ts +556 -0
  216. package/src/test/unit/utils/resolutionUtils.test.ts +521 -0
  217. package/src/test/unit/utils/tsResIntegration.test.ts +433 -0
  218. package/src/types/index.ts +322 -0
  219. package/src/utils/configurationUtils.ts +424 -0
  220. package/src/utils/fileProcessing.ts +160 -0
  221. package/src/utils/filterResources.ts +206 -0
  222. package/src/utils/resolutionEditing.ts +319 -0
  223. package/src/utils/resolutionUtils.ts +289 -0
  224. package/src/utils/tsResIntegration.ts +440 -0
  225. package/src/utils/zipLoader/browserZipLoader.ts +319 -0
  226. package/src/utils/zipLoader/index.ts +26 -0
  227. package/src/utils/zipLoader/nodeZipBuilder.ts +153 -0
  228. package/src/utils/zipLoader/types.ts +175 -0
  229. package/src/utils/zipLoader/zipUtils.ts +266 -0
  230. package/temp/build/typescript/ts_gZid87Hu.json +1 -0
  231. package/tsconfig.json +15 -0
@@ -0,0 +1,403 @@
1
+ /*
2
+ * Copyright (c) 2025 Erik Fortune
3
+ *
4
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ * of this software and associated documentation files (the "Software"), to deal
6
+ * in the Software without restriction, including without limitation the rights
7
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ * copies of the Software, and to permit persons to whom the Software is
9
+ * furnished to do so, subject to the following conditions:
10
+ *
11
+ * The above copyright notice and this permission notice shall be included in all
12
+ * copies or substantial portions of the Software.
13
+ *
14
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
+ * SOFTWARE.
21
+ */
22
+ import '@fgv/ts-utils-jest';
23
+ import { succeed, fail } from '@fgv/ts-utils';
24
+ import { hasFilterValues, getFilterSummary, createFilteredResourceManagerSimple, analyzeFilteredResources } from '../../../utils/filterResources';
25
+ // Mock the tsResIntegration module
26
+ jest.mock('../../../utils/tsResIntegration', () => ({
27
+ createCompiledResourceCollectionManager: jest.fn().mockReturnValue(succeed({}))
28
+ }));
29
+ describe('filterResources utilities', () => {
30
+ describe('hasFilterValues', () => {
31
+ test('returns false for empty object', () => {
32
+ expect(hasFilterValues({})).toBe(false);
33
+ });
34
+ test('returns false for object with all undefined values', () => {
35
+ expect(hasFilterValues({
36
+ key1: undefined,
37
+ key2: undefined
38
+ })).toBe(false);
39
+ });
40
+ test('returns false for object with all empty string values', () => {
41
+ expect(hasFilterValues({
42
+ key1: '',
43
+ key2: ''
44
+ })).toBe(false);
45
+ });
46
+ test('returns false for object with mixed undefined and empty string values', () => {
47
+ expect(hasFilterValues({
48
+ key1: undefined,
49
+ key2: '',
50
+ key3: undefined
51
+ })).toBe(false);
52
+ });
53
+ test('returns true for object with at least one meaningful value', () => {
54
+ expect(hasFilterValues({
55
+ key1: undefined,
56
+ key2: '',
57
+ key3: 'value'
58
+ })).toBe(true);
59
+ });
60
+ test('returns true for object with multiple meaningful values', () => {
61
+ expect(hasFilterValues({
62
+ key1: 'value1',
63
+ key2: 'value2'
64
+ })).toBe(true);
65
+ });
66
+ test('returns true for object with meaningful value containing spaces', () => {
67
+ expect(hasFilterValues({
68
+ key1: ' value with spaces '
69
+ })).toBe(true);
70
+ });
71
+ test('returns true for object with zero as string value', () => {
72
+ expect(hasFilterValues({
73
+ key1: '0'
74
+ })).toBe(true);
75
+ });
76
+ test('returns true for object with boolean string values', () => {
77
+ expect(hasFilterValues({
78
+ key1: 'false'
79
+ })).toBe(true);
80
+ });
81
+ });
82
+ describe('getFilterSummary', () => {
83
+ test('returns "No filters" for empty object', () => {
84
+ expect(getFilterSummary({})).toBe('No filters');
85
+ });
86
+ test('returns "No filters" for object with all undefined values', () => {
87
+ expect(getFilterSummary({
88
+ key1: undefined,
89
+ key2: undefined
90
+ })).toBe('No filters');
91
+ });
92
+ test('returns "No filters" for object with all empty string values', () => {
93
+ expect(getFilterSummary({
94
+ key1: '',
95
+ key2: ''
96
+ })).toBe('No filters');
97
+ });
98
+ test('returns summary for single active filter', () => {
99
+ expect(getFilterSummary({
100
+ language: 'en',
101
+ territory: undefined
102
+ })).toBe('language=en');
103
+ });
104
+ test('returns summary for multiple active filters', () => {
105
+ const result = getFilterSummary({
106
+ language: 'en',
107
+ territory: 'US',
108
+ platform: undefined
109
+ });
110
+ // Check that it contains both filters (order may vary)
111
+ expect(result).toMatch(/language=en/);
112
+ expect(result).toMatch(/territory=US/);
113
+ expect(result).toMatch(/,/); // Should contain comma separator
114
+ });
115
+ test('returns summary ignoring empty and undefined values', () => {
116
+ expect(getFilterSummary({
117
+ empty: '',
118
+ undefined: undefined,
119
+ language: 'fr',
120
+ nullish: undefined,
121
+ territory: 'CA'
122
+ })).toMatch(/language=fr.*territory=CA|territory=CA.*language=fr/);
123
+ });
124
+ test('handles special characters in values', () => {
125
+ expect(getFilterSummary({
126
+ language: 'en-US',
127
+ territory: 'US/CA'
128
+ })).toMatch(/language=en-US.*territory=US\/CA|territory=US\/CA.*language=en-US/);
129
+ });
130
+ test('handles numeric string values', () => {
131
+ expect(getFilterSummary({
132
+ version: '1.0',
133
+ level: '0'
134
+ })).toMatch(/version=1\.0.*level=0|level=0.*version=1\.0/);
135
+ });
136
+ });
137
+ describe('createFilteredResourceManagerSimple', () => {
138
+ let mockResourceManager;
139
+ let mockSystem;
140
+ beforeEach(() => {
141
+ mockResourceManager = {
142
+ getCompiledResourceCollection: jest.fn(),
143
+ validateContext: jest.fn(),
144
+ clone: jest.fn(),
145
+ resources: new Map([
146
+ ['resource1', {}],
147
+ ['resource2', {}]
148
+ ])
149
+ };
150
+ mockSystem = {
151
+ resourceManager: mockResourceManager,
152
+ qualifiers: {},
153
+ qualifierTypes: {
154
+ values: jest.fn().mockReturnValue([])
155
+ },
156
+ resourceTypes: {
157
+ values: jest.fn().mockReturnValue([])
158
+ },
159
+ importManager: {},
160
+ contextQualifierProvider: {
161
+ create: jest.fn()
162
+ }
163
+ };
164
+ });
165
+ test('returns error when original system is undefined', async () => {
166
+ const result = await createFilteredResourceManagerSimple(undefined, {}, { partialContextMatch: true });
167
+ expect(result).toFail();
168
+ expect(result.message).toBe('Original system or resourceManager is undefined');
169
+ });
170
+ test('returns error when resourceManager is undefined', async () => {
171
+ const result = await createFilteredResourceManagerSimple({ ...mockSystem, resourceManager: undefined }, {}, { partialContextMatch: true });
172
+ expect(result).toFail();
173
+ expect(result.message).toBe('Original system or resourceManager is undefined');
174
+ });
175
+ test('skips bundle resources and tries filtering', async () => {
176
+ // Make getCompiledResourceCollection fail to force the filtering path
177
+ mockResourceManager.getCompiledResourceCollection.mockReturnValue(fail('No bundle available'));
178
+ // Mock the validation and clone steps to fail gracefully
179
+ mockResourceManager.validateContext.mockReturnValue(fail('Context validation failed'));
180
+ const result = await createFilteredResourceManagerSimple(mockSystem, { language: 'en' }, { partialContextMatch: true });
181
+ expect(result).toFail();
182
+ expect(result.message).toContain('Failed to validate context or clone');
183
+ });
184
+ test('filters context values before processing', async () => {
185
+ mockResourceManager.getCompiledResourceCollection.mockReturnValue(fail('No bundle'));
186
+ mockResourceManager.validateContext.mockReturnValue(succeed({}));
187
+ mockResourceManager.clone.mockReturnValue(fail('Clone failed'));
188
+ const partialContext = {
189
+ language: 'en',
190
+ territory: undefined,
191
+ platform: 'web'
192
+ };
193
+ await createFilteredResourceManagerSimple(mockSystem, partialContext);
194
+ expect(mockResourceManager.validateContext).toHaveBeenCalledWith({
195
+ language: 'en',
196
+ platform: 'web'
197
+ });
198
+ });
199
+ test('handles validation context error', async () => {
200
+ mockResourceManager.getCompiledResourceCollection.mockReturnValue(fail('No bundle'));
201
+ mockResourceManager.validateContext.mockReturnValue(fail('Invalid context'));
202
+ const result = await createFilteredResourceManagerSimple(mockSystem, { language: 'invalid' });
203
+ expect(result).toFail();
204
+ expect(result.message).toContain('Failed to validate context or clone');
205
+ });
206
+ test('handles clone error', async () => {
207
+ mockResourceManager.getCompiledResourceCollection.mockReturnValue(fail('No bundle'));
208
+ mockResourceManager.validateContext.mockReturnValue(succeed({}));
209
+ mockResourceManager.clone.mockReturnValue(fail('Clone failed'));
210
+ const result = await createFilteredResourceManagerSimple(mockSystem, { language: 'en' });
211
+ expect(result).toFail();
212
+ expect(result.message).toContain('Failed to validate context or clone');
213
+ });
214
+ test('passes options to clone correctly', async () => {
215
+ mockResourceManager.getCompiledResourceCollection.mockReturnValue(fail('No bundle'));
216
+ mockResourceManager.validateContext.mockReturnValue(succeed({ language: 'en' }));
217
+ mockResourceManager.clone.mockReturnValue(fail('Clone failed for test'));
218
+ const options = {
219
+ partialContextMatch: false,
220
+ enableDebugLogging: true,
221
+ reduceQualifiers: true
222
+ };
223
+ await createFilteredResourceManagerSimple(mockSystem, { language: 'en' }, options);
224
+ expect(mockResourceManager.clone).toHaveBeenCalledWith({
225
+ filterForContext: { language: 'en' },
226
+ reduceQualifiers: true
227
+ });
228
+ });
229
+ test('handles debug logging option', async () => {
230
+ const consoleSpy = jest.spyOn(console, 'log').mockImplementation(() => { });
231
+ mockResourceManager.getCompiledResourceCollection.mockReturnValue(fail('No bundle'));
232
+ mockResourceManager.validateContext.mockReturnValue(succeed({}));
233
+ mockResourceManager.clone.mockReturnValue(fail('Clone failed'));
234
+ await createFilteredResourceManagerSimple(mockSystem, { language: 'en' }, { enableDebugLogging: true });
235
+ expect(consoleSpy).toHaveBeenCalledWith('=== SIMPLE FILTER CREATION ===');
236
+ expect(consoleSpy).toHaveBeenCalledWith('Original system:', mockSystem);
237
+ consoleSpy.mockRestore();
238
+ });
239
+ test('does not log when debug logging is disabled', async () => {
240
+ const consoleSpy = jest.spyOn(console, 'log').mockImplementation(() => { });
241
+ mockResourceManager.getCompiledResourceCollection.mockReturnValue(fail('No bundle'));
242
+ mockResourceManager.validateContext.mockReturnValue(succeed({}));
243
+ mockResourceManager.clone.mockReturnValue(fail('Clone failed'));
244
+ await createFilteredResourceManagerSimple(mockSystem, { language: 'en' }, { enableDebugLogging: false });
245
+ expect(consoleSpy).not.toHaveBeenCalled();
246
+ consoleSpy.mockRestore();
247
+ });
248
+ });
249
+ describe('analyzeFilteredResources', () => {
250
+ let mockOriginalProcessedResources;
251
+ let mockFilteredProcessedResources;
252
+ beforeEach(() => {
253
+ mockOriginalProcessedResources = {
254
+ system: {
255
+ resourceManager: {
256
+ getBuiltResource: jest.fn()
257
+ },
258
+ qualifiers: {}, // TODO: Fix mock types after refactoring
259
+ qualifierTypes: {},
260
+ resourceTypes: {},
261
+ importManager: {},
262
+ contextQualifierProvider: {}
263
+ },
264
+ compiledCollection: {},
265
+ resolver: {},
266
+ resourceCount: 2,
267
+ summary: {
268
+ totalResources: 2,
269
+ resourceIds: [],
270
+ errorCount: 0,
271
+ warnings: []
272
+ }
273
+ };
274
+ mockFilteredProcessedResources = {
275
+ system: {
276
+ resourceManager: {
277
+ getBuiltResource: jest.fn()
278
+ },
279
+ qualifiers: {}, // TODO: Fix mock types after refactoring
280
+ qualifierTypes: {},
281
+ resourceTypes: {},
282
+ importManager: {},
283
+ contextQualifierProvider: {}
284
+ },
285
+ compiledCollection: {},
286
+ resolver: {},
287
+ resourceCount: 1,
288
+ summary: {
289
+ totalResources: 1,
290
+ resourceIds: [],
291
+ errorCount: 0,
292
+ warnings: []
293
+ }
294
+ };
295
+ });
296
+ test('analyzes resources with successful filtering', () => {
297
+ const originalGetBuiltResource = mockOriginalProcessedResources.system.resourceManager
298
+ .getBuiltResource;
299
+ const filteredGetBuiltResource = mockFilteredProcessedResources.system.resourceManager
300
+ .getBuiltResource;
301
+ originalGetBuiltResource
302
+ .mockReturnValueOnce(succeed({ candidates: ['c1', 'c2'] }))
303
+ .mockReturnValueOnce(succeed({ candidates: ['c3'] }));
304
+ filteredGetBuiltResource
305
+ .mockReturnValueOnce(succeed({ candidates: ['c1'] }))
306
+ .mockReturnValueOnce(succeed({ candidates: ['c3'] }));
307
+ const result = analyzeFilteredResources(['resource1', 'resource2'], mockFilteredProcessedResources, mockOriginalProcessedResources);
308
+ expect(result.success).toBe(true);
309
+ expect(result.filteredResources).toHaveLength(2);
310
+ const resource1 = result.filteredResources[0];
311
+ expect(resource1.id).toBe('resource1');
312
+ expect(resource1.originalCandidateCount).toBe(2);
313
+ expect(resource1.filteredCandidateCount).toBe(1);
314
+ expect(resource1.hasWarning).toBe(false);
315
+ const resource2 = result.filteredResources[1];
316
+ expect(resource2.id).toBe('resource2');
317
+ expect(resource2.originalCandidateCount).toBe(1);
318
+ expect(resource2.filteredCandidateCount).toBe(1);
319
+ expect(resource2.hasWarning).toBe(false);
320
+ expect(result.warnings).toEqual([]);
321
+ expect(result.processedResources).toBe(mockFilteredProcessedResources);
322
+ });
323
+ test('detects resources filtered out completely', () => {
324
+ const originalGetBuiltResource = mockOriginalProcessedResources.system.resourceManager
325
+ .getBuiltResource;
326
+ const filteredGetBuiltResource = mockFilteredProcessedResources.system.resourceManager
327
+ .getBuiltResource;
328
+ originalGetBuiltResource.mockReturnValueOnce(succeed({ candidates: ['c1', 'c2'] }));
329
+ filteredGetBuiltResource.mockReturnValueOnce(succeed({ candidates: [] }));
330
+ const result = analyzeFilteredResources(['resource1'], mockFilteredProcessedResources, mockOriginalProcessedResources);
331
+ expect(result.success).toBe(true);
332
+ expect(result.filteredResources).toHaveLength(1);
333
+ const resource1 = result.filteredResources[0];
334
+ expect(resource1.id).toBe('resource1');
335
+ expect(resource1.originalCandidateCount).toBe(2);
336
+ expect(resource1.filteredCandidateCount).toBe(0);
337
+ expect(resource1.hasWarning).toBe(true);
338
+ expect(result.warnings).toEqual(['Resource resource1 has no matching candidates after filtering']);
339
+ });
340
+ test('handles resources that failed to load originally', () => {
341
+ const originalGetBuiltResource = mockOriginalProcessedResources.system.resourceManager
342
+ .getBuiltResource;
343
+ const filteredGetBuiltResource = mockFilteredProcessedResources.system.resourceManager
344
+ .getBuiltResource;
345
+ originalGetBuiltResource.mockReturnValueOnce(fail('Resource not found'));
346
+ filteredGetBuiltResource.mockReturnValueOnce(fail('Resource not found'));
347
+ const result = analyzeFilteredResources(['resource1'], mockFilteredProcessedResources, mockOriginalProcessedResources);
348
+ expect(result.success).toBe(true);
349
+ expect(result.filteredResources).toHaveLength(1);
350
+ const resource1 = result.filteredResources[0];
351
+ expect(resource1.id).toBe('resource1');
352
+ expect(resource1.originalCandidateCount).toBe(0);
353
+ expect(resource1.filteredCandidateCount).toBe(0);
354
+ expect(resource1.hasWarning).toBe(false);
355
+ expect(result.warnings).toEqual([]);
356
+ });
357
+ test('handles resources that failed to load after filtering', () => {
358
+ const originalGetBuiltResource = mockOriginalProcessedResources.system.resourceManager
359
+ .getBuiltResource;
360
+ const filteredGetBuiltResource = mockFilteredProcessedResources.system.resourceManager
361
+ .getBuiltResource;
362
+ originalGetBuiltResource.mockReturnValueOnce(succeed({ candidates: ['c1'] }));
363
+ filteredGetBuiltResource.mockReturnValueOnce(fail('Resource filtered out'));
364
+ const result = analyzeFilteredResources(['resource1'], mockFilteredProcessedResources, mockOriginalProcessedResources);
365
+ expect(result.success).toBe(true);
366
+ expect(result.filteredResources).toHaveLength(1);
367
+ const resource1 = result.filteredResources[0];
368
+ expect(resource1.id).toBe('resource1');
369
+ expect(resource1.originalCandidateCount).toBe(1);
370
+ expect(resource1.filteredCandidateCount).toBe(0);
371
+ expect(resource1.hasWarning).toBe(true);
372
+ expect(result.warnings).toContain('Resource resource1 has no matching candidates after filtering');
373
+ });
374
+ test('handles empty resource list', () => {
375
+ const result = analyzeFilteredResources([], mockFilteredProcessedResources, mockOriginalProcessedResources);
376
+ expect(result.success).toBe(true);
377
+ expect(result.filteredResources).toEqual([]);
378
+ expect(result.warnings).toEqual([]);
379
+ });
380
+ test('handles mixed success and failure scenarios', () => {
381
+ const originalGetBuiltResource = mockOriginalProcessedResources.system.resourceManager
382
+ .getBuiltResource;
383
+ const filteredGetBuiltResource = mockFilteredProcessedResources.system.resourceManager
384
+ .getBuiltResource;
385
+ originalGetBuiltResource
386
+ .mockReturnValueOnce(succeed({ candidates: ['c1', 'c2'] }))
387
+ .mockReturnValueOnce(fail('Original failed'))
388
+ .mockReturnValueOnce(succeed({ candidates: ['c3'] }));
389
+ filteredGetBuiltResource
390
+ .mockReturnValueOnce(succeed({ candidates: [] }))
391
+ .mockReturnValueOnce(succeed({ candidates: ['c2'] }))
392
+ .mockReturnValueOnce(succeed({ candidates: ['c3'] }));
393
+ const result = analyzeFilteredResources(['resource1', 'resource2', 'resource3'], mockFilteredProcessedResources, mockOriginalProcessedResources);
394
+ expect(result.success).toBe(true);
395
+ expect(result.filteredResources).toHaveLength(3);
396
+ expect(result.filteredResources[0].hasWarning).toBe(true); // Had candidates, now none
397
+ expect(result.filteredResources[1].hasWarning).toBe(false); // Originally failed, now has candidates
398
+ expect(result.filteredResources[2].hasWarning).toBe(false); // Same count
399
+ expect(result.warnings).toEqual(['Resource resource1 has no matching candidates after filtering']);
400
+ });
401
+ });
402
+ });
403
+ //# sourceMappingURL=filterResources.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"filterResources.test.js","sourceRoot":"","sources":["../../../../src/test/unit/utils/filterResources.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,oBAAoB,CAAC;AAC5B,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EACL,eAAe,EACf,gBAAgB,EAChB,mCAAmC,EACnC,wBAAwB,EAGzB,MAAM,gCAAgC,CAAC;AAGxC,mCAAmC;AACnC,IAAI,CAAC,IAAI,CAAC,iCAAiC,EAAE,GAAG,EAAE,CAAC,CAAC;IAClD,uCAAuC,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;CAChF,CAAC,CAAC,CAAC;AAEJ,QAAQ,CAAC,2BAA2B,EAAE,GAAG,EAAE;IACzC,QAAQ,CAAC,iBAAiB,EAAE,GAAG,EAAE;QAC/B,IAAI,CAAC,gCAAgC,EAAE,GAAG,EAAE;YAC1C,MAAM,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC1C,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,oDAAoD,EAAE,GAAG,EAAE;YAC9D,MAAM,CACJ,eAAe,CAAC;gBACd,IAAI,EAAE,SAAS;gBACf,IAAI,EAAE,SAAS;aAChB,CAAC,CACH,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAChB,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,uDAAuD,EAAE,GAAG,EAAE;YACjE,MAAM,CACJ,eAAe,CAAC;gBACd,IAAI,EAAE,EAAE;gBACR,IAAI,EAAE,EAAE;aACT,CAAC,CACH,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAChB,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,uEAAuE,EAAE,GAAG,EAAE;YACjF,MAAM,CACJ,eAAe,CAAC;gBACd,IAAI,EAAE,SAAS;gBACf,IAAI,EAAE,EAAE;gBACR,IAAI,EAAE,SAAS;aAChB,CAAC,CACH,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAChB,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,4DAA4D,EAAE,GAAG,EAAE;YACtE,MAAM,CACJ,eAAe,CAAC;gBACd,IAAI,EAAE,SAAS;gBACf,IAAI,EAAE,EAAE;gBACR,IAAI,EAAE,OAAO;aACd,CAAC,CACH,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACf,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,yDAAyD,EAAE,GAAG,EAAE;YACnE,MAAM,CACJ,eAAe,CAAC;gBACd,IAAI,EAAE,QAAQ;gBACd,IAAI,EAAE,QAAQ;aACf,CAAC,CACH,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACf,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,iEAAiE,EAAE,GAAG,EAAE;YAC3E,MAAM,CACJ,eAAe,CAAC;gBACd,IAAI,EAAE,uBAAuB;aAC9B,CAAC,CACH,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACf,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,mDAAmD,EAAE,GAAG,EAAE;YAC7D,MAAM,CACJ,eAAe,CAAC;gBACd,IAAI,EAAE,GAAG;aACV,CAAC,CACH,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACf,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,oDAAoD,EAAE,GAAG,EAAE;YAC9D,MAAM,CACJ,eAAe,CAAC;gBACd,IAAI,EAAE,OAAO;aACd,CAAC,CACH,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACf,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,kBAAkB,EAAE,GAAG,EAAE;QAChC,IAAI,CAAC,uCAAuC,EAAE,GAAG,EAAE;YACjD,MAAM,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAClD,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,2DAA2D,EAAE,GAAG,EAAE;YACrE,MAAM,CACJ,gBAAgB,CAAC;gBACf,IAAI,EAAE,SAAS;gBACf,IAAI,EAAE,SAAS;aAChB,CAAC,CACH,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QACvB,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,8DAA8D,EAAE,GAAG,EAAE;YACxE,MAAM,CACJ,gBAAgB,CAAC;gBACf,IAAI,EAAE,EAAE;gBACR,IAAI,EAAE,EAAE;aACT,CAAC,CACH,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QACvB,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,0CAA0C,EAAE,GAAG,EAAE;YACpD,MAAM,CACJ,gBAAgB,CAAC;gBACf,QAAQ,EAAE,IAAI;gBACd,SAAS,EAAE,SAAS;aACrB,CAAC,CACH,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QACxB,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,6CAA6C,EAAE,GAAG,EAAE;YACvD,MAAM,MAAM,GAAG,gBAAgB,CAAC;gBAC9B,QAAQ,EAAE,IAAI;gBACd,SAAS,EAAE,IAAI;gBACf,QAAQ,EAAE,SAAS;aACpB,CAAC,CAAC;YAEH,uDAAuD;YACvD,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;YACtC,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;YACvC,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,iCAAiC;QAChE,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,qDAAqD,EAAE,GAAG,EAAE;YAC/D,MAAM,CACJ,gBAAgB,CAAC;gBACf,KAAK,EAAE,EAAE;gBACT,SAAS,EAAE,SAAS;gBACpB,QAAQ,EAAE,IAAI;gBACd,OAAO,EAAE,SAAS;gBAClB,SAAS,EAAE,IAAI;aAChB,CAAC,CACH,CAAC,OAAO,CAAC,qDAAqD,CAAC,CAAC;QACnE,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,sCAAsC,EAAE,GAAG,EAAE;YAChD,MAAM,CACJ,gBAAgB,CAAC;gBACf,QAAQ,EAAE,OAAO;gBACjB,SAAS,EAAE,OAAO;aACnB,CAAC,CACH,CAAC,OAAO,CAAC,mEAAmE,CAAC,CAAC;QACjF,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,+BAA+B,EAAE,GAAG,EAAE;YACzC,MAAM,CACJ,gBAAgB,CAAC;gBACf,OAAO,EAAE,KAAK;gBACd,KAAK,EAAE,GAAG;aACX,CAAC,CACH,CAAC,OAAO,CAAC,6CAA6C,CAAC,CAAC;QAC3D,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,qCAAqC,EAAE,GAAG,EAAE;QACnD,IAAI,mBAAwB,CAAC;QAC7B,IAAI,UAAe,CAAC;QAEpB,UAAU,CAAC,GAAG,EAAE;YACd,mBAAmB,GAAG;gBACpB,6BAA6B,EAAE,IAAI,CAAC,EAAE,EAAE;gBACxC,eAAe,EAAE,IAAI,CAAC,EAAE,EAAE;gBAC1B,KAAK,EAAE,IAAI,CAAC,EAAE,EAAE;gBAChB,SAAS,EAAE,IAAI,GAAG,CAAC;oBACjB,CAAC,WAAW,EAAE,EAAE,CAAC;oBACjB,CAAC,WAAW,EAAE,EAAE,CAAC;iBAClB,CAAC;aACH,CAAC;YAEF,UAAU,GAAG;gBACX,eAAe,EAAE,mBAAmB;gBACpC,UAAU,EAAE,EAAE;gBACd,cAAc,EAAE;oBACd,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,EAAE,CAAC;iBACtC;gBACD,aAAa,EAAE;oBACb,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,EAAE,CAAC;iBACtC;gBACD,aAAa,EAAE,EAAE;gBACjB,wBAAwB,EAAE;oBACxB,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE;iBAClB;aACF,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,iDAAiD,EAAE,KAAK,IAAI,EAAE;YACjE,MAAM,MAAM,GAAG,MAAM,mCAAmC,CACtD,SAAgB,EAChB,EAAE,EACF,EAAE,mBAAmB,EAAE,IAAI,EAAE,CAC9B,CAAC;YAEF,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,CAAC;YACxB,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,iDAAiD,CAAC,CAAC;QACjF,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,iDAAiD,EAAE,KAAK,IAAI,EAAE;YACjE,MAAM,MAAM,GAAG,MAAM,mCAAmC,CACtD,EAAE,GAAG,UAAU,EAAE,eAAe,EAAE,SAAS,EAAE,EAC7C,EAAE,EACF,EAAE,mBAAmB,EAAE,IAAI,EAAE,CAC9B,CAAC;YAEF,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,CAAC;YACxB,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,iDAAiD,CAAC,CAAC;QACjF,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,4CAA4C,EAAE,KAAK,IAAI,EAAE;YAC5D,sEAAsE;YACtE,mBAAmB,CAAC,6BAA6B,CAAC,eAAe,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC,CAAC;YAE/F,yDAAyD;YACzD,mBAAmB,CAAC,eAAe,CAAC,eAAe,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC,CAAC;YAEvF,MAAM,MAAM,GAAG,MAAM,mCAAmC,CACtD,UAAU,EACV,EAAE,QAAQ,EAAE,IAAI,EAAE,EAClB,EAAE,mBAAmB,EAAE,IAAI,EAAE,CAC9B,CAAC;YAEF,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,CAAC;YACxB,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,qCAAqC,CAAC,CAAC;QAC1E,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,0CAA0C,EAAE,KAAK,IAAI,EAAE;YAC1D,mBAAmB,CAAC,6BAA6B,CAAC,eAAe,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC;YACrF,mBAAmB,CAAC,eAAe,CAAC,eAAe,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC;YACjE,mBAAmB,CAAC,KAAK,CAAC,eAAe,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC;YAEhE,MAAM,cAAc,GAAG;gBACrB,QAAQ,EAAE,IAAI;gBACd,SAAS,EAAE,SAAS;gBACpB,QAAQ,EAAE,KAAK;aAChB,CAAC;YAEF,MAAM,mCAAmC,CAAC,UAAU,EAAE,cAAc,CAAC,CAAC;YAEtE,MAAM,CAAC,mBAAmB,CAAC,eAAe,CAAC,CAAC,oBAAoB,CAAC;gBAC/D,QAAQ,EAAE,IAAI;gBACd,QAAQ,EAAE,KAAK;aAChB,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,kCAAkC,EAAE,KAAK,IAAI,EAAE;YAClD,mBAAmB,CAAC,6BAA6B,CAAC,eAAe,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC;YACrF,mBAAmB,CAAC,eAAe,CAAC,eAAe,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,CAAC;YAE7E,MAAM,MAAM,GAAG,MAAM,mCAAmC,CAAC,UAAU,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,CAAC;YAE9F,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,CAAC;YACxB,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,qCAAqC,CAAC,CAAC;QAC1E,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,qBAAqB,EAAE,KAAK,IAAI,EAAE;YACrC,mBAAmB,CAAC,6BAA6B,CAAC,eAAe,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC;YACrF,mBAAmB,CAAC,eAAe,CAAC,eAAe,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC;YACjE,mBAAmB,CAAC,KAAK,CAAC,eAAe,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC;YAEhE,MAAM,MAAM,GAAG,MAAM,mCAAmC,CAAC,UAAU,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;YAEzF,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,CAAC;YACxB,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,qCAAqC,CAAC,CAAC;QAC1E,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,mCAAmC,EAAE,KAAK,IAAI,EAAE;YACnD,mBAAmB,CAAC,6BAA6B,CAAC,eAAe,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC;YACrF,mBAAmB,CAAC,eAAe,CAAC,eAAe,CAAC,OAAO,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;YACjF,mBAAmB,CAAC,KAAK,CAAC,eAAe,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC,CAAC;YAEzE,MAAM,OAAO,GAAkB;gBAC7B,mBAAmB,EAAE,KAAK;gBAC1B,kBAAkB,EAAE,IAAI;gBACxB,gBAAgB,EAAE,IAAI;aACvB,CAAC;YAEF,MAAM,mCAAmC,CAAC,UAAU,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,OAAO,CAAC,CAAC;YAEnF,MAAM,CAAC,mBAAmB,CAAC,KAAK,CAAC,CAAC,oBAAoB,CAAC;gBACrD,gBAAgB,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE;gBACpC,gBAAgB,EAAE,IAAI;aACvB,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,8BAA8B,EAAE,KAAK,IAAI,EAAE;YAC9C,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,kBAAkB,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;YAE3E,mBAAmB,CAAC,6BAA6B,CAAC,eAAe,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC;YACrF,mBAAmB,CAAC,eAAe,CAAC,eAAe,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC;YACjE,mBAAmB,CAAC,KAAK,CAAC,eAAe,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC;YAEhE,MAAM,mCAAmC,CAAC,UAAU,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,EAAE,kBAAkB,EAAE,IAAI,EAAE,CAAC,CAAC;YAExG,MAAM,CAAC,UAAU,CAAC,CAAC,oBAAoB,CAAC,gCAAgC,CAAC,CAAC;YAC1E,MAAM,CAAC,UAAU,CAAC,CAAC,oBAAoB,CAAC,kBAAkB,EAAE,UAAU,CAAC,CAAC;YAExE,UAAU,CAAC,WAAW,EAAE,CAAC;QAC3B,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,6CAA6C,EAAE,KAAK,IAAI,EAAE;YAC7D,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,kBAAkB,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;YAE3E,mBAAmB,CAAC,6BAA6B,CAAC,eAAe,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC;YACrF,mBAAmB,CAAC,eAAe,CAAC,eAAe,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC;YACjE,mBAAmB,CAAC,KAAK,CAAC,eAAe,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC;YAEhE,MAAM,mCAAmC,CACvC,UAAU,EACV,EAAE,QAAQ,EAAE,IAAI,EAAE,EAClB,EAAE,kBAAkB,EAAE,KAAK,EAAE,CAC9B,CAAC;YAEF,MAAM,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;YAE1C,UAAU,CAAC,WAAW,EAAE,CAAC;QAC3B,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,0BAA0B,EAAE,GAAG,EAAE;QACxC,IAAI,8BAAkD,CAAC;QACvD,IAAI,8BAAkD,CAAC;QAEvD,UAAU,CAAC,GAAG,EAAE;YACd,8BAA8B,GAAG;gBAC/B,MAAM,EAAE;oBACN,eAAe,EAAE;wBACf,gBAAgB,EAAE,IAAI,CAAC,EAAE,EAAE;qBACrB;oBACR,UAAU,EAAE,EAAS,EAAE,yCAAyC;oBAChE,cAAc,EAAE,EAAS;oBACzB,aAAa,EAAE,EAAS;oBACxB,aAAa,EAAE,EAAS;oBACxB,wBAAwB,EAAE,EAAS;iBACpC;gBACD,kBAAkB,EAAE,EAAS;gBAC7B,QAAQ,EAAE,EAAS;gBACnB,aAAa,EAAE,CAAC;gBAChB,OAAO,EAAE;oBACP,cAAc,EAAE,CAAC;oBACjB,WAAW,EAAE,EAAE;oBACf,UAAU,EAAE,CAAC;oBACb,QAAQ,EAAE,EAAE;iBACb;aACF,CAAC;YAEF,8BAA8B,GAAG;gBAC/B,MAAM,EAAE;oBACN,eAAe,EAAE;wBACf,gBAAgB,EAAE,IAAI,CAAC,EAAE,EAAE;qBACrB;oBACR,UAAU,EAAE,EAAS,EAAE,yCAAyC;oBAChE,cAAc,EAAE,EAAS;oBACzB,aAAa,EAAE,EAAS;oBACxB,aAAa,EAAE,EAAS;oBACxB,wBAAwB,EAAE,EAAS;iBACpC;gBACD,kBAAkB,EAAE,EAAS;gBAC7B,QAAQ,EAAE,EAAS;gBACnB,aAAa,EAAE,CAAC;gBAChB,OAAO,EAAE;oBACP,cAAc,EAAE,CAAC;oBACjB,WAAW,EAAE,EAAE;oBACf,UAAU,EAAE,CAAC;oBACb,QAAQ,EAAE,EAAE;iBACb;aACF,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,8CAA8C,EAAE,GAAG,EAAE;YACxD,MAAM,wBAAwB,GAAG,8BAA8B,CAAC,MAAM,CAAC,eAAe;iBACnF,gBAA6B,CAAC;YACjC,MAAM,wBAAwB,GAAG,8BAA8B,CAAC,MAAM,CAAC,eAAe;iBACnF,gBAA6B,CAAC;YAEjC,wBAAwB;iBACrB,mBAAmB,CAAC,OAAO,CAAC,EAAE,UAAU,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC;iBAC1D,mBAAmB,CAAC,OAAO,CAAC,EAAE,UAAU,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;YAExD,wBAAwB;iBACrB,mBAAmB,CAAC,OAAO,CAAC,EAAE,UAAU,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;iBACpD,mBAAmB,CAAC,OAAO,CAAC,EAAE,UAAU,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;YAExD,MAAM,MAAM,GAAG,wBAAwB,CACrC,CAAC,WAAW,EAAE,WAAW,CAAC,EAC1B,8BAA8B,EAC9B,8BAA8B,CAC/B,CAAC;YAEF,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAClC,MAAM,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;YAEjD,MAAM,SAAS,GAAG,MAAM,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC;YAC9C,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;YACvC,MAAM,CAAC,SAAS,CAAC,sBAAsB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACjD,MAAM,CAAC,SAAS,CAAC,sBAAsB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACjD,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAEzC,MAAM,SAAS,GAAG,MAAM,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC;YAC9C,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;YACvC,MAAM,CAAC,SAAS,CAAC,sBAAsB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACjD,MAAM,CAAC,SAAS,CAAC,sBAAsB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACjD,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAEzC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;YACpC,MAAM,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAAC,IAAI,CAAC,8BAA8B,CAAC,CAAC;QACzE,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,2CAA2C,EAAE,GAAG,EAAE;YACrD,MAAM,wBAAwB,GAAG,8BAA8B,CAAC,MAAM,CAAC,eAAe;iBACnF,gBAA6B,CAAC;YACjC,MAAM,wBAAwB,GAAG,8BAA8B,CAAC,MAAM,CAAC,eAAe;iBACnF,gBAA6B,CAAC;YAEjC,wBAAwB,CAAC,mBAAmB,CAAC,OAAO,CAAC,EAAE,UAAU,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;YAEpF,wBAAwB,CAAC,mBAAmB,CAAC,OAAO,CAAC,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;YAE1E,MAAM,MAAM,GAAG,wBAAwB,CACrC,CAAC,WAAW,CAAC,EACb,8BAA8B,EAC9B,8BAA8B,CAC/B,CAAC;YAEF,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAClC,MAAM,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;YAEjD,MAAM,SAAS,GAAG,MAAM,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC;YAC9C,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;YACvC,MAAM,CAAC,SAAS,CAAC,sBAAsB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACjD,MAAM,CAAC,SAAS,CAAC,sBAAsB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACjD,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAExC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,+DAA+D,CAAC,CAAC,CAAC;QACrG,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,kDAAkD,EAAE,GAAG,EAAE;YAC5D,MAAM,wBAAwB,GAAG,8BAA8B,CAAC,MAAM,CAAC,eAAe;iBACnF,gBAA6B,CAAC;YACjC,MAAM,wBAAwB,GAAG,8BAA8B,CAAC,MAAM,CAAC,eAAe;iBACnF,gBAA6B,CAAC;YAEjC,wBAAwB,CAAC,mBAAmB,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC,CAAC;YAEzE,wBAAwB,CAAC,mBAAmB,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC,CAAC;YAEzE,MAAM,MAAM,GAAG,wBAAwB,CACrC,CAAC,WAAW,CAAC,EACb,8BAA8B,EAC9B,8BAA8B,CAC/B,CAAC;YAEF,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAClC,MAAM,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;YAEjD,MAAM,SAAS,GAAG,MAAM,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC;YAC9C,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;YACvC,MAAM,CAAC,SAAS,CAAC,sBAAsB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACjD,MAAM,CAAC,SAAS,CAAC,sBAAsB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACjD,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAEzC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QACtC,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,uDAAuD,EAAE,GAAG,EAAE;YACjE,MAAM,wBAAwB,GAAG,8BAA8B,CAAC,MAAM,CAAC,eAAe;iBACnF,gBAA6B,CAAC;YACjC,MAAM,wBAAwB,GAAG,8BAA8B,CAAC,MAAM,CAAC,eAAe;iBACnF,gBAA6B,CAAC;YAEjC,wBAAwB,CAAC,mBAAmB,CAAC,OAAO,CAAC,EAAE,UAAU,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;YAE9E,wBAAwB,CAAC,mBAAmB,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC,CAAC;YAE5E,MAAM,MAAM,GAAG,wBAAwB,CACrC,CAAC,WAAW,CAAC,EACb,8BAA8B,EAC9B,8BAA8B,CAC/B,CAAC;YAEF,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAClC,MAAM,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;YAEjD,MAAM,SAAS,GAAG,MAAM,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC;YAC9C,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;YACvC,MAAM,CAAC,SAAS,CAAC,sBAAsB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACjD,MAAM,CAAC,SAAS,CAAC,sBAAsB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACjD,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAExC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,+DAA+D,CAAC,CAAC;QACrG,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,6BAA6B,EAAE,GAAG,EAAE;YACvC,MAAM,MAAM,GAAG,wBAAwB,CACrC,EAAE,EACF,8BAA8B,EAC9B,8BAA8B,CAC/B,CAAC;YAEF,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAClC,MAAM,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;YAC7C,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QACtC,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,6CAA6C,EAAE,GAAG,EAAE;YACvD,MAAM,wBAAwB,GAAG,8BAA8B,CAAC,MAAM,CAAC,eAAe;iBACnF,gBAA6B,CAAC;YACjC,MAAM,wBAAwB,GAAG,8BAA8B,CAAC,MAAM,CAAC,eAAe;iBACnF,gBAA6B,CAAC;YAEjC,wBAAwB;iBACrB,mBAAmB,CAAC,OAAO,CAAC,EAAE,UAAU,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC;iBAC1D,mBAAmB,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;iBAC5C,mBAAmB,CAAC,OAAO,CAAC,EAAE,UAAU,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;YAExD,wBAAwB;iBACrB,mBAAmB,CAAC,OAAO,CAAC,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC,CAAC;iBAChD,mBAAmB,CAAC,OAAO,CAAC,EAAE,UAAU,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;iBACpD,mBAAmB,CAAC,OAAO,CAAC,EAAE,UAAU,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;YAExD,MAAM,MAAM,GAAG,wBAAwB,CACrC,CAAC,WAAW,EAAE,WAAW,EAAE,WAAW,CAAC,EACvC,8BAA8B,EAC9B,8BAA8B,CAC/B,CAAC;YAEF,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAClC,MAAM,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;YAEjD,MAAM,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,2BAA2B;YACtF,MAAM,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,wCAAwC;YACpG,MAAM,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,aAAa;YAEzE,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,+DAA+D,CAAC,CAAC,CAAC;QACrG,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC","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 '@fgv/ts-utils-jest';\nimport { succeed, fail } from '@fgv/ts-utils';\nimport {\n hasFilterValues,\n getFilterSummary,\n createFilteredResourceManagerSimple,\n analyzeFilteredResources,\n type FilterOptions,\n type FilteredResource\n} from '../../../utils/filterResources';\nimport { ProcessedResources } from '../../../types';\n\n// Mock the tsResIntegration module\njest.mock('../../../utils/tsResIntegration', () => ({\n createCompiledResourceCollectionManager: jest.fn().mockReturnValue(succeed({}))\n}));\n\ndescribe('filterResources utilities', () => {\n describe('hasFilterValues', () => {\n test('returns false for empty object', () => {\n expect(hasFilterValues({})).toBe(false);\n });\n\n test('returns false for object with all undefined values', () => {\n expect(\n hasFilterValues({\n key1: undefined,\n key2: undefined\n })\n ).toBe(false);\n });\n\n test('returns false for object with all empty string values', () => {\n expect(\n hasFilterValues({\n key1: '',\n key2: ''\n })\n ).toBe(false);\n });\n\n test('returns false for object with mixed undefined and empty string values', () => {\n expect(\n hasFilterValues({\n key1: undefined,\n key2: '',\n key3: undefined\n })\n ).toBe(false);\n });\n\n test('returns true for object with at least one meaningful value', () => {\n expect(\n hasFilterValues({\n key1: undefined,\n key2: '',\n key3: 'value'\n })\n ).toBe(true);\n });\n\n test('returns true for object with multiple meaningful values', () => {\n expect(\n hasFilterValues({\n key1: 'value1',\n key2: 'value2'\n })\n ).toBe(true);\n });\n\n test('returns true for object with meaningful value containing spaces', () => {\n expect(\n hasFilterValues({\n key1: ' value with spaces '\n })\n ).toBe(true);\n });\n\n test('returns true for object with zero as string value', () => {\n expect(\n hasFilterValues({\n key1: '0'\n })\n ).toBe(true);\n });\n\n test('returns true for object with boolean string values', () => {\n expect(\n hasFilterValues({\n key1: 'false'\n })\n ).toBe(true);\n });\n });\n\n describe('getFilterSummary', () => {\n test('returns \"No filters\" for empty object', () => {\n expect(getFilterSummary({})).toBe('No filters');\n });\n\n test('returns \"No filters\" for object with all undefined values', () => {\n expect(\n getFilterSummary({\n key1: undefined,\n key2: undefined\n })\n ).toBe('No filters');\n });\n\n test('returns \"No filters\" for object with all empty string values', () => {\n expect(\n getFilterSummary({\n key1: '',\n key2: ''\n })\n ).toBe('No filters');\n });\n\n test('returns summary for single active filter', () => {\n expect(\n getFilterSummary({\n language: 'en',\n territory: undefined\n })\n ).toBe('language=en');\n });\n\n test('returns summary for multiple active filters', () => {\n const result = getFilterSummary({\n language: 'en',\n territory: 'US',\n platform: undefined\n });\n\n // Check that it contains both filters (order may vary)\n expect(result).toMatch(/language=en/);\n expect(result).toMatch(/territory=US/);\n expect(result).toMatch(/,/); // Should contain comma separator\n });\n\n test('returns summary ignoring empty and undefined values', () => {\n expect(\n getFilterSummary({\n empty: '',\n undefined: undefined,\n language: 'fr',\n nullish: undefined,\n territory: 'CA'\n })\n ).toMatch(/language=fr.*territory=CA|territory=CA.*language=fr/);\n });\n\n test('handles special characters in values', () => {\n expect(\n getFilterSummary({\n language: 'en-US',\n territory: 'US/CA'\n })\n ).toMatch(/language=en-US.*territory=US\\/CA|territory=US\\/CA.*language=en-US/);\n });\n\n test('handles numeric string values', () => {\n expect(\n getFilterSummary({\n version: '1.0',\n level: '0'\n })\n ).toMatch(/version=1\\.0.*level=0|level=0.*version=1\\.0/);\n });\n });\n\n describe('createFilteredResourceManagerSimple', () => {\n let mockResourceManager: any;\n let mockSystem: any;\n\n beforeEach(() => {\n mockResourceManager = {\n getCompiledResourceCollection: jest.fn(),\n validateContext: jest.fn(),\n clone: jest.fn(),\n resources: new Map([\n ['resource1', {}],\n ['resource2', {}]\n ])\n };\n\n mockSystem = {\n resourceManager: mockResourceManager,\n qualifiers: {},\n qualifierTypes: {\n values: jest.fn().mockReturnValue([])\n },\n resourceTypes: {\n values: jest.fn().mockReturnValue([])\n },\n importManager: {},\n contextQualifierProvider: {\n create: jest.fn()\n }\n };\n });\n\n test('returns error when original system is undefined', async () => {\n const result = await createFilteredResourceManagerSimple(\n undefined as any,\n {},\n { partialContextMatch: true }\n );\n\n expect(result).toFail();\n expect(result.message).toBe('Original system or resourceManager is undefined');\n });\n\n test('returns error when resourceManager is undefined', async () => {\n const result = await createFilteredResourceManagerSimple(\n { ...mockSystem, resourceManager: undefined },\n {},\n { partialContextMatch: true }\n );\n\n expect(result).toFail();\n expect(result.message).toBe('Original system or resourceManager is undefined');\n });\n\n test('skips bundle resources and tries filtering', async () => {\n // Make getCompiledResourceCollection fail to force the filtering path\n mockResourceManager.getCompiledResourceCollection.mockReturnValue(fail('No bundle available'));\n\n // Mock the validation and clone steps to fail gracefully\n mockResourceManager.validateContext.mockReturnValue(fail('Context validation failed'));\n\n const result = await createFilteredResourceManagerSimple(\n mockSystem,\n { language: 'en' },\n { partialContextMatch: true }\n );\n\n expect(result).toFail();\n expect(result.message).toContain('Failed to validate context or clone');\n });\n\n test('filters context values before processing', async () => {\n mockResourceManager.getCompiledResourceCollection.mockReturnValue(fail('No bundle'));\n mockResourceManager.validateContext.mockReturnValue(succeed({}));\n mockResourceManager.clone.mockReturnValue(fail('Clone failed'));\n\n const partialContext = {\n language: 'en',\n territory: undefined,\n platform: 'web'\n };\n\n await createFilteredResourceManagerSimple(mockSystem, partialContext);\n\n expect(mockResourceManager.validateContext).toHaveBeenCalledWith({\n language: 'en',\n platform: 'web'\n });\n });\n\n test('handles validation context error', async () => {\n mockResourceManager.getCompiledResourceCollection.mockReturnValue(fail('No bundle'));\n mockResourceManager.validateContext.mockReturnValue(fail('Invalid context'));\n\n const result = await createFilteredResourceManagerSimple(mockSystem, { language: 'invalid' });\n\n expect(result).toFail();\n expect(result.message).toContain('Failed to validate context or clone');\n });\n\n test('handles clone error', async () => {\n mockResourceManager.getCompiledResourceCollection.mockReturnValue(fail('No bundle'));\n mockResourceManager.validateContext.mockReturnValue(succeed({}));\n mockResourceManager.clone.mockReturnValue(fail('Clone failed'));\n\n const result = await createFilteredResourceManagerSimple(mockSystem, { language: 'en' });\n\n expect(result).toFail();\n expect(result.message).toContain('Failed to validate context or clone');\n });\n\n test('passes options to clone correctly', async () => {\n mockResourceManager.getCompiledResourceCollection.mockReturnValue(fail('No bundle'));\n mockResourceManager.validateContext.mockReturnValue(succeed({ language: 'en' }));\n mockResourceManager.clone.mockReturnValue(fail('Clone failed for test'));\n\n const options: FilterOptions = {\n partialContextMatch: false,\n enableDebugLogging: true,\n reduceQualifiers: true\n };\n\n await createFilteredResourceManagerSimple(mockSystem, { language: 'en' }, options);\n\n expect(mockResourceManager.clone).toHaveBeenCalledWith({\n filterForContext: { language: 'en' },\n reduceQualifiers: true\n });\n });\n\n test('handles debug logging option', async () => {\n const consoleSpy = jest.spyOn(console, 'log').mockImplementation(() => {});\n\n mockResourceManager.getCompiledResourceCollection.mockReturnValue(fail('No bundle'));\n mockResourceManager.validateContext.mockReturnValue(succeed({}));\n mockResourceManager.clone.mockReturnValue(fail('Clone failed'));\n\n await createFilteredResourceManagerSimple(mockSystem, { language: 'en' }, { enableDebugLogging: true });\n\n expect(consoleSpy).toHaveBeenCalledWith('=== SIMPLE FILTER CREATION ===');\n expect(consoleSpy).toHaveBeenCalledWith('Original system:', mockSystem);\n\n consoleSpy.mockRestore();\n });\n\n test('does not log when debug logging is disabled', async () => {\n const consoleSpy = jest.spyOn(console, 'log').mockImplementation(() => {});\n\n mockResourceManager.getCompiledResourceCollection.mockReturnValue(fail('No bundle'));\n mockResourceManager.validateContext.mockReturnValue(succeed({}));\n mockResourceManager.clone.mockReturnValue(fail('Clone failed'));\n\n await createFilteredResourceManagerSimple(\n mockSystem,\n { language: 'en' },\n { enableDebugLogging: false }\n );\n\n expect(consoleSpy).not.toHaveBeenCalled();\n\n consoleSpy.mockRestore();\n });\n });\n\n describe('analyzeFilteredResources', () => {\n let mockOriginalProcessedResources: ProcessedResources;\n let mockFilteredProcessedResources: ProcessedResources;\n\n beforeEach(() => {\n mockOriginalProcessedResources = {\n system: {\n resourceManager: {\n getBuiltResource: jest.fn()\n } as any,\n qualifiers: {} as any, // TODO: Fix mock types after refactoring\n qualifierTypes: {} as any,\n resourceTypes: {} as any,\n importManager: {} as any,\n contextQualifierProvider: {} as any\n },\n compiledCollection: {} as any,\n resolver: {} as any,\n resourceCount: 2,\n summary: {\n totalResources: 2,\n resourceIds: [],\n errorCount: 0,\n warnings: []\n }\n };\n\n mockFilteredProcessedResources = {\n system: {\n resourceManager: {\n getBuiltResource: jest.fn()\n } as any,\n qualifiers: {} as any, // TODO: Fix mock types after refactoring\n qualifierTypes: {} as any,\n resourceTypes: {} as any,\n importManager: {} as any,\n contextQualifierProvider: {} as any\n },\n compiledCollection: {} as any,\n resolver: {} as any,\n resourceCount: 1,\n summary: {\n totalResources: 1,\n resourceIds: [],\n errorCount: 0,\n warnings: []\n }\n };\n });\n\n test('analyzes resources with successful filtering', () => {\n const originalGetBuiltResource = mockOriginalProcessedResources.system.resourceManager\n .getBuiltResource as jest.Mock;\n const filteredGetBuiltResource = mockFilteredProcessedResources.system.resourceManager\n .getBuiltResource as jest.Mock;\n\n originalGetBuiltResource\n .mockReturnValueOnce(succeed({ candidates: ['c1', 'c2'] }))\n .mockReturnValueOnce(succeed({ candidates: ['c3'] }));\n\n filteredGetBuiltResource\n .mockReturnValueOnce(succeed({ candidates: ['c1'] }))\n .mockReturnValueOnce(succeed({ candidates: ['c3'] }));\n\n const result = analyzeFilteredResources(\n ['resource1', 'resource2'],\n mockFilteredProcessedResources,\n mockOriginalProcessedResources\n );\n\n expect(result.success).toBe(true);\n expect(result.filteredResources).toHaveLength(2);\n\n const resource1 = result.filteredResources[0];\n expect(resource1.id).toBe('resource1');\n expect(resource1.originalCandidateCount).toBe(2);\n expect(resource1.filteredCandidateCount).toBe(1);\n expect(resource1.hasWarning).toBe(false);\n\n const resource2 = result.filteredResources[1];\n expect(resource2.id).toBe('resource2');\n expect(resource2.originalCandidateCount).toBe(1);\n expect(resource2.filteredCandidateCount).toBe(1);\n expect(resource2.hasWarning).toBe(false);\n\n expect(result.warnings).toEqual([]);\n expect(result.processedResources).toBe(mockFilteredProcessedResources);\n });\n\n test('detects resources filtered out completely', () => {\n const originalGetBuiltResource = mockOriginalProcessedResources.system.resourceManager\n .getBuiltResource as jest.Mock;\n const filteredGetBuiltResource = mockFilteredProcessedResources.system.resourceManager\n .getBuiltResource as jest.Mock;\n\n originalGetBuiltResource.mockReturnValueOnce(succeed({ candidates: ['c1', 'c2'] }));\n\n filteredGetBuiltResource.mockReturnValueOnce(succeed({ candidates: [] }));\n\n const result = analyzeFilteredResources(\n ['resource1'],\n mockFilteredProcessedResources,\n mockOriginalProcessedResources\n );\n\n expect(result.success).toBe(true);\n expect(result.filteredResources).toHaveLength(1);\n\n const resource1 = result.filteredResources[0];\n expect(resource1.id).toBe('resource1');\n expect(resource1.originalCandidateCount).toBe(2);\n expect(resource1.filteredCandidateCount).toBe(0);\n expect(resource1.hasWarning).toBe(true);\n\n expect(result.warnings).toEqual(['Resource resource1 has no matching candidates after filtering']);\n });\n\n test('handles resources that failed to load originally', () => {\n const originalGetBuiltResource = mockOriginalProcessedResources.system.resourceManager\n .getBuiltResource as jest.Mock;\n const filteredGetBuiltResource = mockFilteredProcessedResources.system.resourceManager\n .getBuiltResource as jest.Mock;\n\n originalGetBuiltResource.mockReturnValueOnce(fail('Resource not found'));\n\n filteredGetBuiltResource.mockReturnValueOnce(fail('Resource not found'));\n\n const result = analyzeFilteredResources(\n ['resource1'],\n mockFilteredProcessedResources,\n mockOriginalProcessedResources\n );\n\n expect(result.success).toBe(true);\n expect(result.filteredResources).toHaveLength(1);\n\n const resource1 = result.filteredResources[0];\n expect(resource1.id).toBe('resource1');\n expect(resource1.originalCandidateCount).toBe(0);\n expect(resource1.filteredCandidateCount).toBe(0);\n expect(resource1.hasWarning).toBe(false);\n\n expect(result.warnings).toEqual([]);\n });\n\n test('handles resources that failed to load after filtering', () => {\n const originalGetBuiltResource = mockOriginalProcessedResources.system.resourceManager\n .getBuiltResource as jest.Mock;\n const filteredGetBuiltResource = mockFilteredProcessedResources.system.resourceManager\n .getBuiltResource as jest.Mock;\n\n originalGetBuiltResource.mockReturnValueOnce(succeed({ candidates: ['c1'] }));\n\n filteredGetBuiltResource.mockReturnValueOnce(fail('Resource filtered out'));\n\n const result = analyzeFilteredResources(\n ['resource1'],\n mockFilteredProcessedResources,\n mockOriginalProcessedResources\n );\n\n expect(result.success).toBe(true);\n expect(result.filteredResources).toHaveLength(1);\n\n const resource1 = result.filteredResources[0];\n expect(resource1.id).toBe('resource1');\n expect(resource1.originalCandidateCount).toBe(1);\n expect(resource1.filteredCandidateCount).toBe(0);\n expect(resource1.hasWarning).toBe(true);\n\n expect(result.warnings).toContain('Resource resource1 has no matching candidates after filtering');\n });\n\n test('handles empty resource list', () => {\n const result = analyzeFilteredResources(\n [],\n mockFilteredProcessedResources,\n mockOriginalProcessedResources\n );\n\n expect(result.success).toBe(true);\n expect(result.filteredResources).toEqual([]);\n expect(result.warnings).toEqual([]);\n });\n\n test('handles mixed success and failure scenarios', () => {\n const originalGetBuiltResource = mockOriginalProcessedResources.system.resourceManager\n .getBuiltResource as jest.Mock;\n const filteredGetBuiltResource = mockFilteredProcessedResources.system.resourceManager\n .getBuiltResource as jest.Mock;\n\n originalGetBuiltResource\n .mockReturnValueOnce(succeed({ candidates: ['c1', 'c2'] }))\n .mockReturnValueOnce(fail('Original failed'))\n .mockReturnValueOnce(succeed({ candidates: ['c3'] }));\n\n filteredGetBuiltResource\n .mockReturnValueOnce(succeed({ candidates: [] }))\n .mockReturnValueOnce(succeed({ candidates: ['c2'] }))\n .mockReturnValueOnce(succeed({ candidates: ['c3'] }));\n\n const result = analyzeFilteredResources(\n ['resource1', 'resource2', 'resource3'],\n mockFilteredProcessedResources,\n mockOriginalProcessedResources\n );\n\n expect(result.success).toBe(true);\n expect(result.filteredResources).toHaveLength(3);\n\n expect(result.filteredResources[0].hasWarning).toBe(true); // Had candidates, now none\n expect(result.filteredResources[1].hasWarning).toBe(false); // Originally failed, now has candidates\n expect(result.filteredResources[2].hasWarning).toBe(false); // Same count\n\n expect(result.warnings).toEqual(['Resource resource1 has no matching candidates after filtering']);\n });\n });\n});\n"]}
@@ -0,0 +1,2 @@
1
+ import '@fgv/ts-utils-jest';
2
+ //# sourceMappingURL=resolutionEditing.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolutionEditing.test.d.ts","sourceRoot":"","sources":["../../../../src/test/unit/utils/resolutionEditing.test.ts"],"names":[],"mappings":"AAsBA,OAAO,oBAAoB,CAAC"}