@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.
- package/.rush/temp/03c8b056281d9db0a97d8a6e25eea798a160d393.tar.log +271 -0
- package/.rush/temp/chunked-rush-logs/ts-res-ui-components.build.chunks.jsonl +9 -0
- package/.rush/temp/operation/build/all.log +9 -0
- package/.rush/temp/operation/build/log-chunks.jsonl +9 -0
- package/.rush/temp/operation/build/state.json +3 -0
- package/.rush/temp/shrinkwrap-deps.json +1111 -0
- package/README.md +18 -0
- package/REFACTORING_PLAN.md +171 -0
- package/config/jest.config.json +16 -0
- package/config/jest.setup.js +64 -0
- package/config/rig.json +16 -0
- package/lib/components/common/QualifierContextControl.d.ts +14 -0
- package/lib/components/common/QualifierContextControl.d.ts.map +1 -0
- package/lib/components/common/QualifierContextControl.js +78 -0
- package/lib/components/common/QualifierContextControl.js.map +1 -0
- package/lib/components/common/ResourceListView.d.ts +11 -0
- package/lib/components/common/ResourceListView.d.ts.map +1 -0
- package/lib/components/common/ResourceListView.js +20 -0
- package/lib/components/common/ResourceListView.js.map +1 -0
- package/lib/components/common/ResourceTreeView.d.ts +12 -0
- package/lib/components/common/ResourceTreeView.d.ts.map +1 -0
- package/lib/components/common/ResourceTreeView.js +162 -0
- package/lib/components/common/ResourceTreeView.js.map +1 -0
- package/lib/components/forms/HierarchyEditor.d.ts +10 -0
- package/lib/components/forms/HierarchyEditor.d.ts.map +1 -0
- package/lib/components/forms/HierarchyEditor.js +106 -0
- package/lib/components/forms/HierarchyEditor.js.map +1 -0
- package/lib/components/forms/QualifierEditForm.d.ts +11 -0
- package/lib/components/forms/QualifierEditForm.d.ts.map +1 -0
- package/lib/components/forms/QualifierEditForm.js +181 -0
- package/lib/components/forms/QualifierEditForm.js.map +1 -0
- package/lib/components/forms/QualifierTypeEditForm.d.ts +10 -0
- package/lib/components/forms/QualifierTypeEditForm.d.ts.map +1 -0
- package/lib/components/forms/QualifierTypeEditForm.js +172 -0
- package/lib/components/forms/QualifierTypeEditForm.js.map +1 -0
- package/lib/components/forms/ResourceTypeEditForm.d.ts +10 -0
- package/lib/components/forms/ResourceTypeEditForm.d.ts.map +1 -0
- package/lib/components/forms/ResourceTypeEditForm.js +188 -0
- package/lib/components/forms/ResourceTypeEditForm.js.map +1 -0
- package/lib/components/forms/index.d.ts +9 -0
- package/lib/components/forms/index.d.ts.map +1 -0
- package/lib/components/forms/index.js +5 -0
- package/lib/components/forms/index.js.map +1 -0
- package/lib/components/orchestrator/ResourceOrchestrator.d.ts +14 -0
- package/lib/components/orchestrator/ResourceOrchestrator.d.ts.map +1 -0
- package/lib/components/orchestrator/ResourceOrchestrator.js +278 -0
- package/lib/components/orchestrator/ResourceOrchestrator.js.map +1 -0
- package/lib/components/views/CompiledView/index.d.ts +5 -0
- package/lib/components/views/CompiledView/index.d.ts.map +1 -0
- package/lib/components/views/CompiledView/index.js +595 -0
- package/lib/components/views/CompiledView/index.js.map +1 -0
- package/lib/components/views/ConfigurationView/index.d.ts +5 -0
- package/lib/components/views/ConfigurationView/index.d.ts.map +1 -0
- package/lib/components/views/ConfigurationView/index.js +363 -0
- package/lib/components/views/ConfigurationView/index.js.map +1 -0
- package/lib/components/views/FilterView/index.d.ts +5 -0
- package/lib/components/views/FilterView/index.d.ts.map +1 -0
- package/lib/components/views/FilterView/index.js +463 -0
- package/lib/components/views/FilterView/index.js.map +1 -0
- package/lib/components/views/ImportView/index.d.ts +5 -0
- package/lib/components/views/ImportView/index.d.ts.map +1 -0
- package/lib/components/views/ImportView/index.js +514 -0
- package/lib/components/views/ImportView/index.js.map +1 -0
- package/lib/components/views/ResolutionView/EditableJsonView.d.ts +21 -0
- package/lib/components/views/ResolutionView/EditableJsonView.d.ts.map +1 -0
- package/lib/components/views/ResolutionView/EditableJsonView.js +109 -0
- package/lib/components/views/ResolutionView/EditableJsonView.js.map +1 -0
- package/lib/components/views/ResolutionView/ResolutionEditControls.d.ts +19 -0
- package/lib/components/views/ResolutionView/ResolutionEditControls.d.ts.map +1 -0
- package/lib/components/views/ResolutionView/ResolutionEditControls.js +82 -0
- package/lib/components/views/ResolutionView/ResolutionEditControls.js.map +1 -0
- package/lib/components/views/ResolutionView/index.d.ts +5 -0
- package/lib/components/views/ResolutionView/index.d.ts.map +1 -0
- package/lib/components/views/ResolutionView/index.js +255 -0
- package/lib/components/views/ResolutionView/index.js.map +1 -0
- package/lib/components/views/SourceView/index.d.ts +5 -0
- package/lib/components/views/SourceView/index.d.ts.map +1 -0
- package/lib/components/views/SourceView/index.js +316 -0
- package/lib/components/views/SourceView/index.js.map +1 -0
- package/lib/components/views/ZipLoaderView/index.d.ts +5 -0
- package/lib/components/views/ZipLoaderView/index.d.ts.map +1 -0
- package/lib/components/views/ZipLoaderView/index.js +313 -0
- package/lib/components/views/ZipLoaderView/index.js.map +1 -0
- package/lib/hooks/useConfigurationState.d.ts +46 -0
- package/lib/hooks/useConfigurationState.d.ts.map +1 -0
- package/lib/hooks/useConfigurationState.js +239 -0
- package/lib/hooks/useConfigurationState.js.map +1 -0
- package/lib/hooks/useFilterState.d.ts +7 -0
- package/lib/hooks/useFilterState.d.ts.map +1 -0
- package/lib/hooks/useFilterState.js +80 -0
- package/lib/hooks/useFilterState.js.map +1 -0
- package/lib/hooks/useResolutionState.d.ts +8 -0
- package/lib/hooks/useResolutionState.d.ts.map +1 -0
- package/lib/hooks/useResolutionState.js +253 -0
- package/lib/hooks/useResolutionState.js.map +1 -0
- package/lib/hooks/useResourceData.d.ts +19 -0
- package/lib/hooks/useResourceData.d.ts.map +1 -0
- package/lib/hooks/useResourceData.js +368 -0
- package/lib/hooks/useResourceData.js.map +1 -0
- package/lib/hooks/useViewState.d.ts +10 -0
- package/lib/hooks/useViewState.d.ts.map +1 -0
- package/lib/hooks/useViewState.js +29 -0
- package/lib/hooks/useViewState.js.map +1 -0
- package/lib/index.d.ts +27 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +34 -0
- package/lib/index.js.map +1 -0
- package/lib/test/helpers/testDataLoader.d.ts +37 -0
- package/lib/test/helpers/testDataLoader.d.ts.map +1 -0
- package/lib/test/helpers/testDataLoader.js +171 -0
- package/lib/test/helpers/testDataLoader.js.map +1 -0
- package/lib/test/unit/utils/configurationUtils.test.d.ts +2 -0
- package/lib/test/unit/utils/configurationUtils.test.d.ts.map +1 -0
- package/lib/test/unit/utils/configurationUtils.test.js +497 -0
- package/lib/test/unit/utils/configurationUtils.test.js.map +1 -0
- package/lib/test/unit/utils/fileProcessing.test.d.ts +2 -0
- package/lib/test/unit/utils/fileProcessing.test.d.ts.map +1 -0
- package/lib/test/unit/utils/fileProcessing.test.js +321 -0
- package/lib/test/unit/utils/fileProcessing.test.js.map +1 -0
- package/lib/test/unit/utils/filterResources.test.d.ts +2 -0
- package/lib/test/unit/utils/filterResources.test.d.ts.map +1 -0
- package/lib/test/unit/utils/filterResources.test.js +403 -0
- package/lib/test/unit/utils/filterResources.test.js.map +1 -0
- package/lib/test/unit/utils/resolutionEditing.test.d.ts +2 -0
- package/lib/test/unit/utils/resolutionEditing.test.d.ts.map +1 -0
- package/lib/test/unit/utils/resolutionEditing.test.js +439 -0
- package/lib/test/unit/utils/resolutionEditing.test.js.map +1 -0
- package/lib/test/unit/utils/resolutionUtils.test.d.ts +2 -0
- package/lib/test/unit/utils/resolutionUtils.test.d.ts.map +1 -0
- package/lib/test/unit/utils/resolutionUtils.test.js +397 -0
- package/lib/test/unit/utils/resolutionUtils.test.js.map +1 -0
- package/lib/test/unit/utils/tsResIntegration.test.d.ts +2 -0
- package/lib/test/unit/utils/tsResIntegration.test.d.ts.map +1 -0
- package/lib/test/unit/utils/tsResIntegration.test.js +376 -0
- package/lib/test/unit/utils/tsResIntegration.test.js.map +1 -0
- package/lib/types/index.d.ts +251 -0
- package/lib/types/index.d.ts.map +1 -0
- package/lib/types/index.js +2 -0
- package/lib/types/index.js.map +1 -0
- package/lib/utils/configurationUtils.d.ts +74 -0
- package/lib/utils/configurationUtils.d.ts.map +1 -0
- package/lib/utils/configurationUtils.js +359 -0
- package/lib/utils/configurationUtils.js.map +1 -0
- package/lib/utils/fileProcessing.d.ts +18 -0
- package/lib/utils/fileProcessing.d.ts.map +1 -0
- package/lib/utils/fileProcessing.js +142 -0
- package/lib/utils/fileProcessing.js.map +1 -0
- package/lib/utils/filterResources.d.ts +38 -0
- package/lib/utils/filterResources.d.ts.map +1 -0
- package/lib/utils/filterResources.js +153 -0
- package/lib/utils/filterResources.js.map +1 -0
- package/lib/utils/resolutionEditing.d.ts +58 -0
- package/lib/utils/resolutionEditing.d.ts.map +1 -0
- package/lib/utils/resolutionEditing.js +246 -0
- package/lib/utils/resolutionEditing.js.map +1 -0
- package/lib/utils/resolutionUtils.d.ts +28 -0
- package/lib/utils/resolutionUtils.d.ts.map +1 -0
- package/lib/utils/resolutionUtils.js +216 -0
- package/lib/utils/resolutionUtils.js.map +1 -0
- package/lib/utils/tsResIntegration.d.ts +71 -0
- package/lib/utils/tsResIntegration.d.ts.map +1 -0
- package/lib/utils/tsResIntegration.js +294 -0
- package/lib/utils/tsResIntegration.js.map +1 -0
- package/lib/utils/zipLoader/browserZipLoader.d.ts +48 -0
- package/lib/utils/zipLoader/browserZipLoader.d.ts.map +1 -0
- package/lib/utils/zipLoader/browserZipLoader.js +247 -0
- package/lib/utils/zipLoader/browserZipLoader.js.map +1 -0
- package/lib/utils/zipLoader/index.d.ts +8 -0
- package/lib/utils/zipLoader/index.d.ts.map +1 -0
- package/lib/utils/zipLoader/index.js +13 -0
- package/lib/utils/zipLoader/index.js.map +1 -0
- package/lib/utils/zipLoader/nodeZipBuilder.d.ts +55 -0
- package/lib/utils/zipLoader/nodeZipBuilder.d.ts.map +1 -0
- package/lib/utils/zipLoader/nodeZipBuilder.js +98 -0
- package/lib/utils/zipLoader/nodeZipBuilder.js.map +1 -0
- package/lib/utils/zipLoader/types.d.ts +139 -0
- package/lib/utils/zipLoader/types.d.ts.map +1 -0
- package/lib/utils/zipLoader/types.js +2 -0
- package/lib/utils/zipLoader/types.js.map +1 -0
- package/lib/utils/zipLoader/zipUtils.d.ts +53 -0
- package/lib/utils/zipLoader/zipUtils.d.ts.map +1 -0
- package/lib/utils/zipLoader/zipUtils.js +229 -0
- package/lib/utils/zipLoader/zipUtils.js.map +1 -0
- package/package.json +69 -0
- package/rush-logs/ts-res-ui-components.build.cache.log +3 -0
- package/rush-logs/ts-res-ui-components.build.log +9 -0
- package/src/components/common/QualifierContextControl.tsx +151 -0
- package/src/components/common/ResourceListView.tsx +63 -0
- package/src/components/common/ResourceTreeView.tsx +271 -0
- package/src/components/forms/HierarchyEditor.tsx +204 -0
- package/src/components/forms/QualifierEditForm.tsx +355 -0
- package/src/components/forms/QualifierTypeEditForm.tsx +347 -0
- package/src/components/forms/ResourceTypeEditForm.tsx +331 -0
- package/src/components/forms/index.ts +11 -0
- package/src/components/orchestrator/ResourceOrchestrator.tsx +372 -0
- package/src/components/views/CompiledView/index.tsx +922 -0
- package/src/components/views/ConfigurationView/index.tsx +800 -0
- package/src/components/views/FilterView/index.tsx +825 -0
- package/src/components/views/ImportView/index.tsx +717 -0
- package/src/components/views/ResolutionView/EditableJsonView.tsx +214 -0
- package/src/components/views/ResolutionView/ResolutionEditControls.tsx +170 -0
- package/src/components/views/ResolutionView/index.tsx +591 -0
- package/src/components/views/SourceView/index.tsx +536 -0
- package/src/components/views/ZipLoaderView/index.tsx +485 -0
- package/src/hooks/useConfigurationState.ts +374 -0
- package/src/hooks/useFilterState.ts +97 -0
- package/src/hooks/useResolutionState.ts +355 -0
- package/src/hooks/useResourceData.ts +467 -0
- package/src/hooks/useViewState.ts +44 -0
- package/src/index.ts +45 -0
- package/src/test/helpers/testDataLoader.ts +195 -0
- package/src/test/unit/utils/configurationUtils.test.ts +630 -0
- package/src/test/unit/utils/fileProcessing.test.ts +391 -0
- package/src/test/unit/utils/filterResources.test.ts +574 -0
- package/src/test/unit/utils/resolutionEditing.test.ts +556 -0
- package/src/test/unit/utils/resolutionUtils.test.ts +521 -0
- package/src/test/unit/utils/tsResIntegration.test.ts +433 -0
- package/src/types/index.ts +322 -0
- package/src/utils/configurationUtils.ts +424 -0
- package/src/utils/fileProcessing.ts +160 -0
- package/src/utils/filterResources.ts +206 -0
- package/src/utils/resolutionEditing.ts +319 -0
- package/src/utils/resolutionUtils.ts +289 -0
- package/src/utils/tsResIntegration.ts +440 -0
- package/src/utils/zipLoader/browserZipLoader.ts +319 -0
- package/src/utils/zipLoader/index.ts +26 -0
- package/src/utils/zipLoader/nodeZipBuilder.ts +153 -0
- package/src/utils/zipLoader/types.ts +175 -0
- package/src/utils/zipLoader/zipUtils.ts +266 -0
- package/temp/build/typescript/ts_gZid87Hu.json +1 -0
- package/tsconfig.json +15 -0
|
@@ -0,0 +1,497 @@
|
|
|
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 { getDefaultConfiguration, validateConfiguration, cloneConfiguration, compareConfigurations, trackConfigurationChanges, exportConfiguration, importConfiguration, getConfigurationTemplates, generateConfigurationFilename } from '../../../utils/configurationUtils';
|
|
24
|
+
describe('configurationUtils', () => {
|
|
25
|
+
let defaultConfig;
|
|
26
|
+
beforeEach(() => {
|
|
27
|
+
defaultConfig = getDefaultConfiguration();
|
|
28
|
+
});
|
|
29
|
+
describe('getDefaultConfiguration', () => {
|
|
30
|
+
test('returns valid default configuration', () => {
|
|
31
|
+
const config = getDefaultConfiguration();
|
|
32
|
+
expect(config.qualifierTypes).toHaveLength(2);
|
|
33
|
+
expect(config.qualifierTypes[0]).toEqual({
|
|
34
|
+
name: 'language',
|
|
35
|
+
systemType: 'language'
|
|
36
|
+
});
|
|
37
|
+
expect(config.qualifierTypes[1]).toEqual({
|
|
38
|
+
name: 'territory',
|
|
39
|
+
systemType: 'territory'
|
|
40
|
+
});
|
|
41
|
+
expect(config.qualifiers).toHaveLength(2);
|
|
42
|
+
expect(config.qualifiers[0]).toEqual({
|
|
43
|
+
name: 'language',
|
|
44
|
+
typeName: 'language',
|
|
45
|
+
defaultPriority: 100,
|
|
46
|
+
token: 'lang'
|
|
47
|
+
});
|
|
48
|
+
expect(config.qualifiers[1]).toEqual({
|
|
49
|
+
name: 'territory',
|
|
50
|
+
typeName: 'territory',
|
|
51
|
+
defaultPriority: 90,
|
|
52
|
+
token: 'territory'
|
|
53
|
+
});
|
|
54
|
+
expect(config.resourceTypes).toHaveLength(2);
|
|
55
|
+
expect(config.resourceTypes[0]).toEqual({
|
|
56
|
+
name: 'string',
|
|
57
|
+
typeName: 'string'
|
|
58
|
+
});
|
|
59
|
+
expect(config.resourceTypes[1]).toEqual({
|
|
60
|
+
name: 'object',
|
|
61
|
+
typeName: 'object'
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
test('returns different instances on multiple calls', () => {
|
|
65
|
+
const config1 = getDefaultConfiguration();
|
|
66
|
+
const config2 = getDefaultConfiguration();
|
|
67
|
+
expect(config1).not.toBe(config2);
|
|
68
|
+
expect(config1).toEqual(config2);
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
describe('validateConfiguration', () => {
|
|
72
|
+
test('validates valid configuration successfully', () => {
|
|
73
|
+
const result = validateConfiguration(defaultConfig);
|
|
74
|
+
expect(result.isValid).toBe(true);
|
|
75
|
+
expect(result.errors).toEqual([]);
|
|
76
|
+
expect(result.warnings).toEqual([]);
|
|
77
|
+
});
|
|
78
|
+
test('reports error for missing qualifierTypes', () => {
|
|
79
|
+
const config = { ...defaultConfig, qualifierTypes: [] };
|
|
80
|
+
const result = validateConfiguration(config);
|
|
81
|
+
expect(result.isValid).toBe(false);
|
|
82
|
+
expect(result.errors).toContain('Configuration must have at least one qualifier type');
|
|
83
|
+
});
|
|
84
|
+
test('reports error for undefined qualifierTypes', () => {
|
|
85
|
+
const config = { ...defaultConfig };
|
|
86
|
+
delete config.qualifierTypes;
|
|
87
|
+
const result = validateConfiguration(config);
|
|
88
|
+
expect(result.isValid).toBe(false);
|
|
89
|
+
expect(result.errors).toContain('Configuration must have at least one qualifier type');
|
|
90
|
+
});
|
|
91
|
+
test('reports error for qualifier type without name', () => {
|
|
92
|
+
const config = {
|
|
93
|
+
...defaultConfig,
|
|
94
|
+
qualifierTypes: [{ systemType: 'language' }]
|
|
95
|
+
};
|
|
96
|
+
const result = validateConfiguration(config);
|
|
97
|
+
expect(result.isValid).toBe(false);
|
|
98
|
+
expect(result.errors).toContain('Qualifier type at index 0 is missing a name');
|
|
99
|
+
});
|
|
100
|
+
test('reports error for qualifier type without systemType', () => {
|
|
101
|
+
const config = {
|
|
102
|
+
...defaultConfig,
|
|
103
|
+
qualifierTypes: [{ name: 'language' }]
|
|
104
|
+
};
|
|
105
|
+
const result = validateConfiguration(config);
|
|
106
|
+
expect(result.isValid).toBe(false);
|
|
107
|
+
expect(result.errors).toContain("Qualifier type 'language' is missing systemType");
|
|
108
|
+
});
|
|
109
|
+
test('reports error for duplicate qualifier type names', () => {
|
|
110
|
+
const config = {
|
|
111
|
+
...defaultConfig,
|
|
112
|
+
qualifierTypes: [
|
|
113
|
+
{ name: 'language', systemType: 'language' },
|
|
114
|
+
{ name: 'language', systemType: 'territory' }
|
|
115
|
+
]
|
|
116
|
+
};
|
|
117
|
+
const result = validateConfiguration(config);
|
|
118
|
+
expect(result.isValid).toBe(false);
|
|
119
|
+
expect(result.errors).toContain('Duplicate qualifier type name: language');
|
|
120
|
+
});
|
|
121
|
+
test('reports warning for empty qualifiers', () => {
|
|
122
|
+
const config = { ...defaultConfig, qualifiers: [] };
|
|
123
|
+
const result = validateConfiguration(config);
|
|
124
|
+
expect(result.isValid).toBe(true);
|
|
125
|
+
expect(result.warnings).toContain('Configuration has no qualifiers defined');
|
|
126
|
+
});
|
|
127
|
+
test('reports error for qualifier without name', () => {
|
|
128
|
+
const config = {
|
|
129
|
+
...defaultConfig,
|
|
130
|
+
qualifiers: [{ typeName: 'language', defaultPriority: 100 }]
|
|
131
|
+
};
|
|
132
|
+
const result = validateConfiguration(config);
|
|
133
|
+
expect(result.isValid).toBe(false);
|
|
134
|
+
expect(result.errors).toContain('Qualifier at index 0 is missing a name');
|
|
135
|
+
});
|
|
136
|
+
test('reports error for qualifier without typeName', () => {
|
|
137
|
+
const config = {
|
|
138
|
+
...defaultConfig,
|
|
139
|
+
qualifiers: [{ name: 'language', defaultPriority: 100 }]
|
|
140
|
+
};
|
|
141
|
+
const result = validateConfiguration(config);
|
|
142
|
+
expect(result.isValid).toBe(false);
|
|
143
|
+
expect(result.errors).toContain("Qualifier 'language' is missing typeName");
|
|
144
|
+
});
|
|
145
|
+
test('reports error for qualifier with unknown typeName', () => {
|
|
146
|
+
const config = {
|
|
147
|
+
...defaultConfig,
|
|
148
|
+
qualifiers: [{ name: 'unknown', typeName: 'unknownType', defaultPriority: 100 }]
|
|
149
|
+
};
|
|
150
|
+
const result = validateConfiguration(config);
|
|
151
|
+
expect(result.isValid).toBe(false);
|
|
152
|
+
expect(result.errors).toContain("Qualifier 'unknown' references unknown qualifier type: unknownType");
|
|
153
|
+
});
|
|
154
|
+
test('reports error for duplicate qualifier names', () => {
|
|
155
|
+
const config = {
|
|
156
|
+
...defaultConfig,
|
|
157
|
+
qualifiers: [
|
|
158
|
+
{ name: 'language', typeName: 'language', defaultPriority: 100 },
|
|
159
|
+
{ name: 'language', typeName: 'territory', defaultPriority: 90 }
|
|
160
|
+
]
|
|
161
|
+
};
|
|
162
|
+
const result = validateConfiguration(config);
|
|
163
|
+
expect(result.isValid).toBe(false);
|
|
164
|
+
expect(result.errors).toContain('Duplicate qualifier name: language');
|
|
165
|
+
});
|
|
166
|
+
test('reports error for qualifier with invalid defaultPriority', () => {
|
|
167
|
+
const config = {
|
|
168
|
+
...defaultConfig,
|
|
169
|
+
qualifiers: [
|
|
170
|
+
{ name: 'language', typeName: 'language', defaultPriority: -1 },
|
|
171
|
+
{ name: 'territory', typeName: 'territory' } // Missing defaultPriority
|
|
172
|
+
]
|
|
173
|
+
};
|
|
174
|
+
const result = validateConfiguration(config);
|
|
175
|
+
expect(result.isValid).toBe(false);
|
|
176
|
+
expect(result.errors).toContain("Qualifier 'language' has invalid defaultPriority");
|
|
177
|
+
expect(result.errors).toContain("Qualifier 'territory' has invalid defaultPriority");
|
|
178
|
+
});
|
|
179
|
+
test('reports error for missing resourceTypes', () => {
|
|
180
|
+
const config = { ...defaultConfig, resourceTypes: [] };
|
|
181
|
+
const result = validateConfiguration(config);
|
|
182
|
+
expect(result.isValid).toBe(false);
|
|
183
|
+
expect(result.errors).toContain('Configuration must have at least one resource type');
|
|
184
|
+
});
|
|
185
|
+
test('reports error for resource type without name', () => {
|
|
186
|
+
const config = {
|
|
187
|
+
...defaultConfig,
|
|
188
|
+
resourceTypes: [{ typeName: 'string' }]
|
|
189
|
+
};
|
|
190
|
+
const result = validateConfiguration(config);
|
|
191
|
+
expect(result.isValid).toBe(false);
|
|
192
|
+
expect(result.errors).toContain('Resource type at index 0 is missing a name');
|
|
193
|
+
});
|
|
194
|
+
test('reports error for resource type without typeName', () => {
|
|
195
|
+
const config = {
|
|
196
|
+
...defaultConfig,
|
|
197
|
+
resourceTypes: [{ name: 'string' }]
|
|
198
|
+
};
|
|
199
|
+
const result = validateConfiguration(config);
|
|
200
|
+
expect(result.isValid).toBe(false);
|
|
201
|
+
expect(result.errors).toContain("Resource type 'string' is missing typeName");
|
|
202
|
+
});
|
|
203
|
+
test('reports error for duplicate resource type names', () => {
|
|
204
|
+
const config = {
|
|
205
|
+
...defaultConfig,
|
|
206
|
+
resourceTypes: [
|
|
207
|
+
{ name: 'string', typeName: 'string' },
|
|
208
|
+
{ name: 'string', typeName: 'object' }
|
|
209
|
+
]
|
|
210
|
+
};
|
|
211
|
+
const result = validateConfiguration(config);
|
|
212
|
+
expect(result.isValid).toBe(false);
|
|
213
|
+
expect(result.errors).toContain('Duplicate resource type name: string');
|
|
214
|
+
});
|
|
215
|
+
test('handles complex validation scenario with multiple errors', () => {
|
|
216
|
+
const config = {
|
|
217
|
+
qualifierTypes: [
|
|
218
|
+
{ name: 'language' }, // Missing systemType
|
|
219
|
+
{ systemType: 'territory' } // Missing name
|
|
220
|
+
],
|
|
221
|
+
qualifiers: [
|
|
222
|
+
{ name: 'lang', typeName: 'unknownType', defaultPriority: 100 }, // Unknown type
|
|
223
|
+
{ typeName: 'language', defaultPriority: -1 } // Missing name, invalid priority
|
|
224
|
+
],
|
|
225
|
+
resourceTypes: [
|
|
226
|
+
{ name: 'type1' }, // Missing typeName
|
|
227
|
+
{ typeName: 'string' } // Missing name
|
|
228
|
+
]
|
|
229
|
+
};
|
|
230
|
+
const result = validateConfiguration(config);
|
|
231
|
+
expect(result.isValid).toBe(false);
|
|
232
|
+
expect(result.errors.length).toBeGreaterThan(5);
|
|
233
|
+
expect(result.errors).toContain("Qualifier type 'language' is missing systemType");
|
|
234
|
+
expect(result.errors).toContain("Qualifier 'lang' references unknown qualifier type: unknownType");
|
|
235
|
+
expect(result.errors).toContain("Resource type 'type1' is missing typeName");
|
|
236
|
+
});
|
|
237
|
+
});
|
|
238
|
+
describe('cloneConfiguration', () => {
|
|
239
|
+
test('creates deep copy of configuration', () => {
|
|
240
|
+
const cloned = cloneConfiguration(defaultConfig);
|
|
241
|
+
expect(cloned).not.toBe(defaultConfig);
|
|
242
|
+
expect(cloned).toEqual(defaultConfig);
|
|
243
|
+
expect(cloned.qualifierTypes).not.toBe(defaultConfig.qualifierTypes);
|
|
244
|
+
expect(cloned.qualifiers).not.toBe(defaultConfig.qualifiers);
|
|
245
|
+
expect(cloned.resourceTypes).not.toBe(defaultConfig.resourceTypes);
|
|
246
|
+
});
|
|
247
|
+
test('modifications to clone do not affect original', () => {
|
|
248
|
+
const cloned = cloneConfiguration(defaultConfig);
|
|
249
|
+
cloned.qualifierTypes[0].name = 'modified';
|
|
250
|
+
expect(defaultConfig.qualifierTypes[0].name).toBe('language');
|
|
251
|
+
expect(cloned.qualifierTypes[0].name).toBe('modified');
|
|
252
|
+
});
|
|
253
|
+
test('handles nested object modifications', () => {
|
|
254
|
+
const cloned = cloneConfiguration(defaultConfig);
|
|
255
|
+
cloned.qualifiers[0].customProperty = 'added';
|
|
256
|
+
expect(defaultConfig.qualifiers[0].customProperty).toBeUndefined();
|
|
257
|
+
expect(cloned.qualifiers[0].customProperty).toBe('added');
|
|
258
|
+
});
|
|
259
|
+
});
|
|
260
|
+
describe('compareConfigurations', () => {
|
|
261
|
+
test('returns true for identical configurations', () => {
|
|
262
|
+
const config1 = getDefaultConfiguration();
|
|
263
|
+
const config2 = getDefaultConfiguration();
|
|
264
|
+
expect(compareConfigurations(config1, config2)).toBe(true);
|
|
265
|
+
});
|
|
266
|
+
test('returns false for different configurations', () => {
|
|
267
|
+
const config1 = getDefaultConfiguration();
|
|
268
|
+
const config2 = getDefaultConfiguration();
|
|
269
|
+
config2.qualifierTypes[0].name = 'modified';
|
|
270
|
+
expect(compareConfigurations(config1, config2)).toBe(false);
|
|
271
|
+
});
|
|
272
|
+
test('returns true for same reference', () => {
|
|
273
|
+
expect(compareConfigurations(defaultConfig, defaultConfig)).toBe(true);
|
|
274
|
+
});
|
|
275
|
+
test('returns false for different property order', () => {
|
|
276
|
+
const config1 = { a: 1, b: 2 };
|
|
277
|
+
const config2 = { b: 2, a: 1 };
|
|
278
|
+
expect(compareConfigurations(config1, config2)).toBe(false);
|
|
279
|
+
});
|
|
280
|
+
test('handles null and undefined values', () => {
|
|
281
|
+
const config1 = { ...defaultConfig, description: null };
|
|
282
|
+
const config2 = { ...defaultConfig, description: undefined };
|
|
283
|
+
expect(compareConfigurations(config1, config2)).toBe(false);
|
|
284
|
+
});
|
|
285
|
+
});
|
|
286
|
+
describe('trackConfigurationChanges', () => {
|
|
287
|
+
test('reports no changes for identical configurations', () => {
|
|
288
|
+
const original = getDefaultConfiguration();
|
|
289
|
+
const current = getDefaultConfiguration();
|
|
290
|
+
const changes = trackConfigurationChanges(original, current);
|
|
291
|
+
expect(changes.hasChanges).toBe(false);
|
|
292
|
+
expect(changes.changedSections).toEqual([]);
|
|
293
|
+
expect(changes.timestamp).toBeInstanceOf(Date);
|
|
294
|
+
});
|
|
295
|
+
test('detects qualifierTypes changes', () => {
|
|
296
|
+
const original = getDefaultConfiguration();
|
|
297
|
+
const current = getDefaultConfiguration();
|
|
298
|
+
current.qualifierTypes[0].name = 'modified';
|
|
299
|
+
const changes = trackConfigurationChanges(original, current);
|
|
300
|
+
expect(changes.hasChanges).toBe(true);
|
|
301
|
+
expect(changes.changedSections).toContain('qualifierTypes');
|
|
302
|
+
expect(changes.changedSections).toHaveLength(1);
|
|
303
|
+
});
|
|
304
|
+
test('detects qualifiers changes', () => {
|
|
305
|
+
const original = getDefaultConfiguration();
|
|
306
|
+
const current = getDefaultConfiguration();
|
|
307
|
+
current.qualifiers[0].defaultPriority = 200;
|
|
308
|
+
const changes = trackConfigurationChanges(original, current);
|
|
309
|
+
expect(changes.hasChanges).toBe(true);
|
|
310
|
+
expect(changes.changedSections).toContain('qualifiers');
|
|
311
|
+
expect(changes.changedSections).toHaveLength(1);
|
|
312
|
+
});
|
|
313
|
+
test('detects resourceTypes changes', () => {
|
|
314
|
+
const original = getDefaultConfiguration();
|
|
315
|
+
const current = getDefaultConfiguration();
|
|
316
|
+
current.resourceTypes.push({ name: 'array', typeName: 'array' });
|
|
317
|
+
const changes = trackConfigurationChanges(original, current);
|
|
318
|
+
expect(changes.hasChanges).toBe(true);
|
|
319
|
+
expect(changes.changedSections).toContain('resourceTypes');
|
|
320
|
+
expect(changes.changedSections).toHaveLength(1);
|
|
321
|
+
});
|
|
322
|
+
test('detects multiple changes', () => {
|
|
323
|
+
const original = getDefaultConfiguration();
|
|
324
|
+
const current = getDefaultConfiguration();
|
|
325
|
+
current.qualifierTypes[0].name = 'modified';
|
|
326
|
+
current.qualifiers[0].defaultPriority = 200;
|
|
327
|
+
const changes = trackConfigurationChanges(original, current);
|
|
328
|
+
expect(changes.hasChanges).toBe(true);
|
|
329
|
+
expect(changes.changedSections).toContain('qualifierTypes');
|
|
330
|
+
expect(changes.changedSections).toContain('qualifiers');
|
|
331
|
+
expect(changes.changedSections).toHaveLength(2);
|
|
332
|
+
});
|
|
333
|
+
test('timestamp is recent', () => {
|
|
334
|
+
const before = new Date();
|
|
335
|
+
const changes = trackConfigurationChanges(defaultConfig, defaultConfig);
|
|
336
|
+
const after = new Date();
|
|
337
|
+
expect(changes.timestamp.getTime()).toBeGreaterThanOrEqual(before.getTime());
|
|
338
|
+
expect(changes.timestamp.getTime()).toBeLessThanOrEqual(after.getTime());
|
|
339
|
+
});
|
|
340
|
+
});
|
|
341
|
+
describe('exportConfiguration', () => {
|
|
342
|
+
test('exports configuration as pretty JSON by default', () => {
|
|
343
|
+
const result = exportConfiguration(defaultConfig);
|
|
344
|
+
expect(result).toSucceedAndSatisfy((exported) => {
|
|
345
|
+
expect(JSON.parse(exported)).toEqual(defaultConfig);
|
|
346
|
+
expect(exported).toContain('\n'); // Pretty formatted
|
|
347
|
+
expect(exported).toContain(' '); // Indentation
|
|
348
|
+
});
|
|
349
|
+
});
|
|
350
|
+
test('exports configuration as compact JSON', () => {
|
|
351
|
+
const result = exportConfiguration(defaultConfig, { format: 'json', pretty: false });
|
|
352
|
+
expect(result).toSucceedAndSatisfy((exported) => {
|
|
353
|
+
expect(JSON.parse(exported)).toEqual(defaultConfig);
|
|
354
|
+
expect(exported).not.toContain('\n'); // No formatting
|
|
355
|
+
});
|
|
356
|
+
});
|
|
357
|
+
test('fails for YAML format', () => {
|
|
358
|
+
const result = exportConfiguration(defaultConfig, { format: 'yaml', pretty: true });
|
|
359
|
+
expect(result).toFailWith(/YAML export not implemented yet/i);
|
|
360
|
+
});
|
|
361
|
+
test('handles export errors gracefully', () => {
|
|
362
|
+
const circularConfig = defaultConfig;
|
|
363
|
+
circularConfig.self = circularConfig; // Create circular reference
|
|
364
|
+
const result = exportConfiguration(circularConfig);
|
|
365
|
+
expect(result).toFail();
|
|
366
|
+
expect(result.message).toContain('Failed to export configuration');
|
|
367
|
+
});
|
|
368
|
+
});
|
|
369
|
+
describe('importConfiguration', () => {
|
|
370
|
+
test('imports valid JSON configuration', () => {
|
|
371
|
+
const exported = exportConfiguration(defaultConfig).orThrow();
|
|
372
|
+
const result = importConfiguration(exported);
|
|
373
|
+
expect(result).toSucceedAndSatisfy((imported) => {
|
|
374
|
+
expect(imported).toEqual(defaultConfig);
|
|
375
|
+
});
|
|
376
|
+
});
|
|
377
|
+
test('fails for invalid JSON', () => {
|
|
378
|
+
const result = importConfiguration('invalid json {');
|
|
379
|
+
expect(result).toFailWith(/Failed to parse configuration/i);
|
|
380
|
+
});
|
|
381
|
+
test('fails for non-object data', () => {
|
|
382
|
+
const result = importConfiguration('"string"');
|
|
383
|
+
expect(result).toFailWith(/Invalid configuration: not an object/i);
|
|
384
|
+
});
|
|
385
|
+
test('fails for null data', () => {
|
|
386
|
+
const result = importConfiguration('null');
|
|
387
|
+
expect(result).toFailWith(/Invalid configuration: not an object/i);
|
|
388
|
+
});
|
|
389
|
+
test('fails for invalid configuration structure', () => {
|
|
390
|
+
const invalidConfig = {
|
|
391
|
+
qualifierTypes: [],
|
|
392
|
+
qualifiers: [],
|
|
393
|
+
resourceTypes: []
|
|
394
|
+
};
|
|
395
|
+
const result = importConfiguration(JSON.stringify(invalidConfig));
|
|
396
|
+
expect(result).toFailWith(/Invalid configuration/i);
|
|
397
|
+
});
|
|
398
|
+
test('validates imported configuration', () => {
|
|
399
|
+
const invalidConfig = {
|
|
400
|
+
qualifierTypes: [{ name: 'lang' }], // Missing systemType
|
|
401
|
+
qualifiers: [],
|
|
402
|
+
resourceTypes: [{ name: 'string', typeName: 'string' }]
|
|
403
|
+
};
|
|
404
|
+
const result = importConfiguration(JSON.stringify(invalidConfig));
|
|
405
|
+
expect(result).toFailWith(/Invalid configuration.*missing systemType/i);
|
|
406
|
+
});
|
|
407
|
+
});
|
|
408
|
+
describe('getConfigurationTemplates', () => {
|
|
409
|
+
test('returns array of templates', () => {
|
|
410
|
+
const templates = getConfigurationTemplates();
|
|
411
|
+
expect(templates).toBeInstanceOf(Array);
|
|
412
|
+
expect(templates.length).toBeGreaterThan(0);
|
|
413
|
+
});
|
|
414
|
+
test('includes basic template', () => {
|
|
415
|
+
const templates = getConfigurationTemplates();
|
|
416
|
+
const basicTemplate = templates.find((t) => t.id === 'basic');
|
|
417
|
+
expect(basicTemplate).toBeDefined();
|
|
418
|
+
expect(basicTemplate.name).toBe('Basic Configuration');
|
|
419
|
+
expect(basicTemplate.category).toBe('basic');
|
|
420
|
+
expect(basicTemplate.configuration).toEqual(getDefaultConfiguration());
|
|
421
|
+
});
|
|
422
|
+
test('includes multilingual template', () => {
|
|
423
|
+
const templates = getConfigurationTemplates();
|
|
424
|
+
const multilingualTemplate = templates.find((t) => t.id === 'multilingual');
|
|
425
|
+
expect(multilingualTemplate).toBeDefined();
|
|
426
|
+
expect(multilingualTemplate.name).toBe('Multilingual Application');
|
|
427
|
+
expect(multilingualTemplate.category).toBe('intermediate');
|
|
428
|
+
expect(multilingualTemplate.configuration.qualifierTypes).toHaveLength(3);
|
|
429
|
+
expect(multilingualTemplate.configuration.qualifiers).toHaveLength(3);
|
|
430
|
+
});
|
|
431
|
+
test('includes enterprise template', () => {
|
|
432
|
+
const templates = getConfigurationTemplates();
|
|
433
|
+
const enterpriseTemplate = templates.find((t) => t.id === 'enterprise');
|
|
434
|
+
expect(enterpriseTemplate).toBeDefined();
|
|
435
|
+
expect(enterpriseTemplate.name).toBe('Enterprise Configuration');
|
|
436
|
+
expect(enterpriseTemplate.category).toBe('enterprise');
|
|
437
|
+
expect(enterpriseTemplate.configuration.qualifierTypes).toHaveLength(5);
|
|
438
|
+
expect(enterpriseTemplate.configuration.qualifiers).toHaveLength(5);
|
|
439
|
+
});
|
|
440
|
+
test('all templates have valid configurations', () => {
|
|
441
|
+
const templates = getConfigurationTemplates();
|
|
442
|
+
templates.forEach((template) => {
|
|
443
|
+
const validation = validateConfiguration(template.configuration);
|
|
444
|
+
expect(validation.isValid).toBe(true);
|
|
445
|
+
});
|
|
446
|
+
});
|
|
447
|
+
test('all templates have required properties', () => {
|
|
448
|
+
const templates = getConfigurationTemplates();
|
|
449
|
+
templates.forEach((template) => {
|
|
450
|
+
expect(template.id).toBeTruthy();
|
|
451
|
+
expect(template.name).toBeTruthy();
|
|
452
|
+
expect(template.description).toBeTruthy();
|
|
453
|
+
expect(template.category).toMatch(/^(basic|intermediate|advanced|enterprise)$/);
|
|
454
|
+
expect(template.configuration).toBeDefined();
|
|
455
|
+
});
|
|
456
|
+
});
|
|
457
|
+
});
|
|
458
|
+
describe('generateConfigurationFilename', () => {
|
|
459
|
+
test('generates filename without config name', () => {
|
|
460
|
+
const filename = generateConfigurationFilename();
|
|
461
|
+
expect(filename).toMatch(/^ts-res-config-\d{4}-\d{2}-\d{2}T\d{2}-\d{2}-\d{2}\.json$/);
|
|
462
|
+
});
|
|
463
|
+
test('generates filename with config name', () => {
|
|
464
|
+
const filename = generateConfigurationFilename('myapp');
|
|
465
|
+
expect(filename).toMatch(/^myapp-config-\d{4}-\d{2}-\d{2}T\d{2}-\d{2}-\d{2}\.json$/);
|
|
466
|
+
});
|
|
467
|
+
test('generates YAML filename', () => {
|
|
468
|
+
const filename = generateConfigurationFilename('myapp', 'yaml');
|
|
469
|
+
expect(filename).toMatch(/^myapp-config-\d{4}-\d{2}-\d{2}T\d{2}-\d{2}-\d{2}\.yaml$/);
|
|
470
|
+
});
|
|
471
|
+
test('handles special characters in config name', () => {
|
|
472
|
+
const filename = generateConfigurationFilename('my/app:config');
|
|
473
|
+
expect(filename).toMatch(/^my\/app:config-config-\d{4}-\d{2}-\d{2}T\d{2}-\d{2}-\d{2}\.json$/);
|
|
474
|
+
});
|
|
475
|
+
test('generates unique filenames over time', () => {
|
|
476
|
+
const filename1 = generateConfigurationFilename('test');
|
|
477
|
+
// Small delay to ensure different timestamp
|
|
478
|
+
const filename2 = generateConfigurationFilename('test');
|
|
479
|
+
if (filename1 === filename2) {
|
|
480
|
+
// If same, wait a bit and try again
|
|
481
|
+
setTimeout(() => {
|
|
482
|
+
const filename3 = generateConfigurationFilename('test');
|
|
483
|
+
expect(filename3).not.toBe(filename1);
|
|
484
|
+
}, 1);
|
|
485
|
+
}
|
|
486
|
+
else {
|
|
487
|
+
expect(filename2).not.toBe(filename1);
|
|
488
|
+
}
|
|
489
|
+
});
|
|
490
|
+
test('handles empty string config name', () => {
|
|
491
|
+
const filename = generateConfigurationFilename('');
|
|
492
|
+
// Empty string is falsy, so it uses default base name
|
|
493
|
+
expect(filename).toMatch(/^ts-res-config-\d{4}-\d{2}-\d{2}T\d{2}-\d{2}-\d{2}\.json$/);
|
|
494
|
+
});
|
|
495
|
+
});
|
|
496
|
+
});
|
|
497
|
+
//# sourceMappingURL=configurationUtils.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"configurationUtils.test.js","sourceRoot":"","sources":["../../../../src/test/unit/utils/configurationUtils.test.ts"],"names":[],"mappings":"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","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 { Config } from '@fgv/ts-res';\nimport {\n getDefaultConfiguration,\n validateConfiguration,\n cloneConfiguration,\n compareConfigurations,\n trackConfigurationChanges,\n exportConfiguration,\n importConfiguration,\n getConfigurationTemplates,\n generateConfigurationFilename,\n type ConfigurationValidationResult,\n type ConfigurationChanges,\n type ConfigurationTemplate,\n type ConfigurationExportOptions\n} from '../../../utils/configurationUtils';\n\ndescribe('configurationUtils', () => {\n let defaultConfig: Config.Model.ISystemConfiguration;\n\n beforeEach(() => {\n defaultConfig = getDefaultConfiguration();\n });\n\n describe('getDefaultConfiguration', () => {\n test('returns valid default configuration', () => {\n const config = getDefaultConfiguration();\n\n expect(config.qualifierTypes).toHaveLength(2);\n expect(config.qualifierTypes[0]).toEqual({\n name: 'language',\n systemType: 'language'\n });\n expect(config.qualifierTypes[1]).toEqual({\n name: 'territory',\n systemType: 'territory'\n });\n\n expect(config.qualifiers).toHaveLength(2);\n expect(config.qualifiers[0]).toEqual({\n name: 'language',\n typeName: 'language',\n defaultPriority: 100,\n token: 'lang'\n });\n expect(config.qualifiers[1]).toEqual({\n name: 'territory',\n typeName: 'territory',\n defaultPriority: 90,\n token: 'territory'\n });\n\n expect(config.resourceTypes).toHaveLength(2);\n expect(config.resourceTypes[0]).toEqual({\n name: 'string',\n typeName: 'string'\n });\n expect(config.resourceTypes[1]).toEqual({\n name: 'object',\n typeName: 'object'\n });\n });\n\n test('returns different instances on multiple calls', () => {\n const config1 = getDefaultConfiguration();\n const config2 = getDefaultConfiguration();\n\n expect(config1).not.toBe(config2);\n expect(config1).toEqual(config2);\n });\n });\n\n describe('validateConfiguration', () => {\n test('validates valid configuration successfully', () => {\n const result = validateConfiguration(defaultConfig);\n\n expect(result.isValid).toBe(true);\n expect(result.errors).toEqual([]);\n expect(result.warnings).toEqual([]);\n });\n\n test('reports error for missing qualifierTypes', () => {\n const config = { ...defaultConfig, qualifierTypes: [] };\n const result = validateConfiguration(config);\n\n expect(result.isValid).toBe(false);\n expect(result.errors).toContain('Configuration must have at least one qualifier type');\n });\n\n test('reports error for undefined qualifierTypes', () => {\n const config = { ...defaultConfig };\n delete (config as any).qualifierTypes;\n const result = validateConfiguration(config);\n\n expect(result.isValid).toBe(false);\n expect(result.errors).toContain('Configuration must have at least one qualifier type');\n });\n\n test('reports error for qualifier type without name', () => {\n const config = {\n ...defaultConfig,\n qualifierTypes: [{ systemType: 'language' }]\n } as unknown as Config.Model.ISystemConfiguration;\n const result = validateConfiguration(config);\n\n expect(result.isValid).toBe(false);\n expect(result.errors).toContain('Qualifier type at index 0 is missing a name');\n });\n\n test('reports error for qualifier type without systemType', () => {\n const config = {\n ...defaultConfig,\n qualifierTypes: [{ name: 'language' }]\n } as unknown as Config.Model.ISystemConfiguration;\n const result = validateConfiguration(config);\n\n expect(result.isValid).toBe(false);\n expect(result.errors).toContain(\"Qualifier type 'language' is missing systemType\");\n });\n\n test('reports error for duplicate qualifier type names', () => {\n const config = {\n ...defaultConfig,\n qualifierTypes: [\n { name: 'language', systemType: 'language' },\n { name: 'language', systemType: 'territory' }\n ]\n } as unknown as Config.Model.ISystemConfiguration;\n const result = validateConfiguration(config);\n\n expect(result.isValid).toBe(false);\n expect(result.errors).toContain('Duplicate qualifier type name: language');\n });\n\n test('reports warning for empty qualifiers', () => {\n const config = { ...defaultConfig, qualifiers: [] };\n const result = validateConfiguration(config);\n\n expect(result.isValid).toBe(true);\n expect(result.warnings).toContain('Configuration has no qualifiers defined');\n });\n\n test('reports error for qualifier without name', () => {\n const config = {\n ...defaultConfig,\n qualifiers: [{ typeName: 'language', defaultPriority: 100 }]\n } as unknown as Config.Model.ISystemConfiguration;\n const result = validateConfiguration(config);\n\n expect(result.isValid).toBe(false);\n expect(result.errors).toContain('Qualifier at index 0 is missing a name');\n });\n\n test('reports error for qualifier without typeName', () => {\n const config = {\n ...defaultConfig,\n qualifiers: [{ name: 'language', defaultPriority: 100 }]\n } as unknown as Config.Model.ISystemConfiguration;\n const result = validateConfiguration(config);\n\n expect(result.isValid).toBe(false);\n expect(result.errors).toContain(\"Qualifier 'language' is missing typeName\");\n });\n\n test('reports error for qualifier with unknown typeName', () => {\n const config = {\n ...defaultConfig,\n qualifiers: [{ name: 'unknown', typeName: 'unknownType', defaultPriority: 100 }]\n };\n const result = validateConfiguration(config);\n\n expect(result.isValid).toBe(false);\n expect(result.errors).toContain(\"Qualifier 'unknown' references unknown qualifier type: unknownType\");\n });\n\n test('reports error for duplicate qualifier names', () => {\n const config = {\n ...defaultConfig,\n qualifiers: [\n { name: 'language', typeName: 'language', defaultPriority: 100 },\n { name: 'language', typeName: 'territory', defaultPriority: 90 }\n ]\n };\n const result = validateConfiguration(config);\n\n expect(result.isValid).toBe(false);\n expect(result.errors).toContain('Duplicate qualifier name: language');\n });\n\n test('reports error for qualifier with invalid defaultPriority', () => {\n const config = {\n ...defaultConfig,\n qualifiers: [\n { name: 'language', typeName: 'language', defaultPriority: -1 },\n { name: 'territory', typeName: 'territory' } // Missing defaultPriority\n ]\n } as unknown as Config.Model.ISystemConfiguration;\n const result = validateConfiguration(config);\n\n expect(result.isValid).toBe(false);\n expect(result.errors).toContain(\"Qualifier 'language' has invalid defaultPriority\");\n expect(result.errors).toContain(\"Qualifier 'territory' has invalid defaultPriority\");\n });\n\n test('reports error for missing resourceTypes', () => {\n const config = { ...defaultConfig, resourceTypes: [] };\n const result = validateConfiguration(config);\n\n expect(result.isValid).toBe(false);\n expect(result.errors).toContain('Configuration must have at least one resource type');\n });\n\n test('reports error for resource type without name', () => {\n const config = {\n ...defaultConfig,\n resourceTypes: [{ typeName: 'string' }]\n } as unknown as Config.Model.ISystemConfiguration;\n const result = validateConfiguration(config);\n\n expect(result.isValid).toBe(false);\n expect(result.errors).toContain('Resource type at index 0 is missing a name');\n });\n\n test('reports error for resource type without typeName', () => {\n const config = {\n ...defaultConfig,\n resourceTypes: [{ name: 'string' }]\n } as unknown as Config.Model.ISystemConfiguration;\n const result = validateConfiguration(config);\n\n expect(result.isValid).toBe(false);\n expect(result.errors).toContain(\"Resource type 'string' is missing typeName\");\n });\n\n test('reports error for duplicate resource type names', () => {\n const config = {\n ...defaultConfig,\n resourceTypes: [\n { name: 'string', typeName: 'string' },\n { name: 'string', typeName: 'object' }\n ]\n };\n const result = validateConfiguration(config);\n\n expect(result.isValid).toBe(false);\n expect(result.errors).toContain('Duplicate resource type name: string');\n });\n\n test('handles complex validation scenario with multiple errors', () => {\n const config = {\n qualifierTypes: [\n { name: 'language' }, // Missing systemType\n { systemType: 'territory' } // Missing name\n ],\n qualifiers: [\n { name: 'lang', typeName: 'unknownType', defaultPriority: 100 }, // Unknown type\n { typeName: 'language', defaultPriority: -1 } // Missing name, invalid priority\n ],\n resourceTypes: [\n { name: 'type1' }, // Missing typeName\n { typeName: 'string' } // Missing name\n ]\n } as unknown as Config.Model.ISystemConfiguration;\n const result = validateConfiguration(config);\n\n expect(result.isValid).toBe(false);\n expect(result.errors.length).toBeGreaterThan(5);\n expect(result.errors).toContain(\"Qualifier type 'language' is missing systemType\");\n expect(result.errors).toContain(\"Qualifier 'lang' references unknown qualifier type: unknownType\");\n expect(result.errors).toContain(\"Resource type 'type1' is missing typeName\");\n });\n });\n\n describe('cloneConfiguration', () => {\n test('creates deep copy of configuration', () => {\n const cloned = cloneConfiguration(defaultConfig);\n\n expect(cloned).not.toBe(defaultConfig);\n expect(cloned).toEqual(defaultConfig);\n expect(cloned.qualifierTypes).not.toBe(defaultConfig.qualifierTypes);\n expect(cloned.qualifiers).not.toBe(defaultConfig.qualifiers);\n expect(cloned.resourceTypes).not.toBe(defaultConfig.resourceTypes);\n });\n\n test('modifications to clone do not affect original', () => {\n const cloned = cloneConfiguration(defaultConfig);\n cloned.qualifierTypes[0].name = 'modified';\n\n expect(defaultConfig.qualifierTypes[0].name).toBe('language');\n expect(cloned.qualifierTypes[0].name).toBe('modified');\n });\n\n test('handles nested object modifications', () => {\n const cloned = cloneConfiguration(defaultConfig);\n (cloned.qualifiers[0] as any).customProperty = 'added';\n\n expect((defaultConfig.qualifiers[0] as any).customProperty).toBeUndefined();\n expect((cloned.qualifiers[0] as any).customProperty).toBe('added');\n });\n });\n\n describe('compareConfigurations', () => {\n test('returns true for identical configurations', () => {\n const config1 = getDefaultConfiguration();\n const config2 = getDefaultConfiguration();\n\n expect(compareConfigurations(config1, config2)).toBe(true);\n });\n\n test('returns false for different configurations', () => {\n const config1 = getDefaultConfiguration();\n const config2 = getDefaultConfiguration();\n config2.qualifierTypes[0].name = 'modified';\n\n expect(compareConfigurations(config1, config2)).toBe(false);\n });\n\n test('returns true for same reference', () => {\n expect(compareConfigurations(defaultConfig, defaultConfig)).toBe(true);\n });\n\n test('returns false for different property order', () => {\n const config1 = { a: 1, b: 2 } as any;\n const config2 = { b: 2, a: 1 } as any;\n\n expect(compareConfigurations(config1, config2)).toBe(false);\n });\n\n test('handles null and undefined values', () => {\n const config1 = { ...defaultConfig, description: null } as any;\n const config2 = { ...defaultConfig, description: undefined } as any;\n\n expect(compareConfigurations(config1, config2)).toBe(false);\n });\n });\n\n describe('trackConfigurationChanges', () => {\n test('reports no changes for identical configurations', () => {\n const original = getDefaultConfiguration();\n const current = getDefaultConfiguration();\n\n const changes = trackConfigurationChanges(original, current);\n\n expect(changes.hasChanges).toBe(false);\n expect(changes.changedSections).toEqual([]);\n expect(changes.timestamp).toBeInstanceOf(Date);\n });\n\n test('detects qualifierTypes changes', () => {\n const original = getDefaultConfiguration();\n const current = getDefaultConfiguration();\n current.qualifierTypes[0].name = 'modified';\n\n const changes = trackConfigurationChanges(original, current);\n\n expect(changes.hasChanges).toBe(true);\n expect(changes.changedSections).toContain('qualifierTypes');\n expect(changes.changedSections).toHaveLength(1);\n });\n\n test('detects qualifiers changes', () => {\n const original = getDefaultConfiguration();\n const current = getDefaultConfiguration();\n current.qualifiers[0].defaultPriority = 200;\n\n const changes = trackConfigurationChanges(original, current);\n\n expect(changes.hasChanges).toBe(true);\n expect(changes.changedSections).toContain('qualifiers');\n expect(changes.changedSections).toHaveLength(1);\n });\n\n test('detects resourceTypes changes', () => {\n const original = getDefaultConfiguration();\n const current = getDefaultConfiguration();\n current.resourceTypes.push({ name: 'array', typeName: 'array' });\n\n const changes = trackConfigurationChanges(original, current);\n\n expect(changes.hasChanges).toBe(true);\n expect(changes.changedSections).toContain('resourceTypes');\n expect(changes.changedSections).toHaveLength(1);\n });\n\n test('detects multiple changes', () => {\n const original = getDefaultConfiguration();\n const current = getDefaultConfiguration();\n current.qualifierTypes[0].name = 'modified';\n current.qualifiers[0].defaultPriority = 200;\n\n const changes = trackConfigurationChanges(original, current);\n\n expect(changes.hasChanges).toBe(true);\n expect(changes.changedSections).toContain('qualifierTypes');\n expect(changes.changedSections).toContain('qualifiers');\n expect(changes.changedSections).toHaveLength(2);\n });\n\n test('timestamp is recent', () => {\n const before = new Date();\n const changes = trackConfigurationChanges(defaultConfig, defaultConfig);\n const after = new Date();\n\n expect(changes.timestamp.getTime()).toBeGreaterThanOrEqual(before.getTime());\n expect(changes.timestamp.getTime()).toBeLessThanOrEqual(after.getTime());\n });\n });\n\n describe('exportConfiguration', () => {\n test('exports configuration as pretty JSON by default', () => {\n const result = exportConfiguration(defaultConfig);\n\n expect(result).toSucceedAndSatisfy((exported: string) => {\n expect(JSON.parse(exported)).toEqual(defaultConfig);\n expect(exported).toContain('\\n'); // Pretty formatted\n expect(exported).toContain(' '); // Indentation\n });\n });\n\n test('exports configuration as compact JSON', () => {\n const result = exportConfiguration(defaultConfig, { format: 'json', pretty: false });\n\n expect(result).toSucceedAndSatisfy((exported: string) => {\n expect(JSON.parse(exported)).toEqual(defaultConfig);\n expect(exported).not.toContain('\\n'); // No formatting\n });\n });\n\n test('fails for YAML format', () => {\n const result = exportConfiguration(defaultConfig, { format: 'yaml', pretty: true });\n\n expect(result).toFailWith(/YAML export not implemented yet/i);\n });\n\n test('handles export errors gracefully', () => {\n const circularConfig = defaultConfig as any;\n circularConfig.self = circularConfig; // Create circular reference\n\n const result = exportConfiguration(circularConfig);\n\n expect(result).toFail();\n expect(result.message).toContain('Failed to export configuration');\n });\n });\n\n describe('importConfiguration', () => {\n test('imports valid JSON configuration', () => {\n const exported = exportConfiguration(defaultConfig).orThrow();\n const result = importConfiguration(exported);\n\n expect(result).toSucceedAndSatisfy((imported: Config.Model.ISystemConfiguration) => {\n expect(imported).toEqual(defaultConfig);\n });\n });\n\n test('fails for invalid JSON', () => {\n const result = importConfiguration('invalid json {');\n\n expect(result).toFailWith(/Failed to parse configuration/i);\n });\n\n test('fails for non-object data', () => {\n const result = importConfiguration('\"string\"');\n\n expect(result).toFailWith(/Invalid configuration: not an object/i);\n });\n\n test('fails for null data', () => {\n const result = importConfiguration('null');\n\n expect(result).toFailWith(/Invalid configuration: not an object/i);\n });\n\n test('fails for invalid configuration structure', () => {\n const invalidConfig = {\n qualifierTypes: [],\n qualifiers: [],\n resourceTypes: []\n };\n const result = importConfiguration(JSON.stringify(invalidConfig));\n\n expect(result).toFailWith(/Invalid configuration/i);\n });\n\n test('validates imported configuration', () => {\n const invalidConfig = {\n qualifierTypes: [{ name: 'lang' }], // Missing systemType\n qualifiers: [],\n resourceTypes: [{ name: 'string', typeName: 'string' }]\n };\n const result = importConfiguration(JSON.stringify(invalidConfig));\n\n expect(result).toFailWith(/Invalid configuration.*missing systemType/i);\n });\n });\n\n describe('getConfigurationTemplates', () => {\n test('returns array of templates', () => {\n const templates = getConfigurationTemplates();\n\n expect(templates).toBeInstanceOf(Array);\n expect(templates.length).toBeGreaterThan(0);\n });\n\n test('includes basic template', () => {\n const templates = getConfigurationTemplates();\n const basicTemplate = templates.find((t) => t.id === 'basic');\n\n expect(basicTemplate).toBeDefined();\n expect(basicTemplate!.name).toBe('Basic Configuration');\n expect(basicTemplate!.category).toBe('basic');\n expect(basicTemplate!.configuration).toEqual(getDefaultConfiguration());\n });\n\n test('includes multilingual template', () => {\n const templates = getConfigurationTemplates();\n const multilingualTemplate = templates.find((t) => t.id === 'multilingual');\n\n expect(multilingualTemplate).toBeDefined();\n expect(multilingualTemplate!.name).toBe('Multilingual Application');\n expect(multilingualTemplate!.category).toBe('intermediate');\n expect(multilingualTemplate!.configuration.qualifierTypes).toHaveLength(3);\n expect(multilingualTemplate!.configuration.qualifiers).toHaveLength(3);\n });\n\n test('includes enterprise template', () => {\n const templates = getConfigurationTemplates();\n const enterpriseTemplate = templates.find((t) => t.id === 'enterprise');\n\n expect(enterpriseTemplate).toBeDefined();\n expect(enterpriseTemplate!.name).toBe('Enterprise Configuration');\n expect(enterpriseTemplate!.category).toBe('enterprise');\n expect(enterpriseTemplate!.configuration.qualifierTypes).toHaveLength(5);\n expect(enterpriseTemplate!.configuration.qualifiers).toHaveLength(5);\n });\n\n test('all templates have valid configurations', () => {\n const templates = getConfigurationTemplates();\n\n templates.forEach((template) => {\n const validation = validateConfiguration(template.configuration);\n expect(validation.isValid).toBe(true);\n });\n });\n\n test('all templates have required properties', () => {\n const templates = getConfigurationTemplates();\n\n templates.forEach((template) => {\n expect(template.id).toBeTruthy();\n expect(template.name).toBeTruthy();\n expect(template.description).toBeTruthy();\n expect(template.category).toMatch(/^(basic|intermediate|advanced|enterprise)$/);\n expect(template.configuration).toBeDefined();\n });\n });\n });\n\n describe('generateConfigurationFilename', () => {\n test('generates filename without config name', () => {\n const filename = generateConfigurationFilename();\n\n expect(filename).toMatch(/^ts-res-config-\\d{4}-\\d{2}-\\d{2}T\\d{2}-\\d{2}-\\d{2}\\.json$/);\n });\n\n test('generates filename with config name', () => {\n const filename = generateConfigurationFilename('myapp');\n\n expect(filename).toMatch(/^myapp-config-\\d{4}-\\d{2}-\\d{2}T\\d{2}-\\d{2}-\\d{2}\\.json$/);\n });\n\n test('generates YAML filename', () => {\n const filename = generateConfigurationFilename('myapp', 'yaml');\n\n expect(filename).toMatch(/^myapp-config-\\d{4}-\\d{2}-\\d{2}T\\d{2}-\\d{2}-\\d{2}\\.yaml$/);\n });\n\n test('handles special characters in config name', () => {\n const filename = generateConfigurationFilename('my/app:config');\n\n expect(filename).toMatch(/^my\\/app:config-config-\\d{4}-\\d{2}-\\d{2}T\\d{2}-\\d{2}-\\d{2}\\.json$/);\n });\n\n test('generates unique filenames over time', () => {\n const filename1 = generateConfigurationFilename('test');\n // Small delay to ensure different timestamp\n const filename2 = generateConfigurationFilename('test');\n\n if (filename1 === filename2) {\n // If same, wait a bit and try again\n setTimeout(() => {\n const filename3 = generateConfigurationFilename('test');\n expect(filename3).not.toBe(filename1);\n }, 1);\n } else {\n expect(filename2).not.toBe(filename1);\n }\n });\n\n test('handles empty string config name', () => {\n const filename = generateConfigurationFilename('');\n\n // Empty string is falsy, so it uses default base name\n expect(filename).toMatch(/^ts-res-config-\\d{4}-\\d{2}-\\d{2}T\\d{2}-\\d{2}-\\d{2}\\.json$/);\n });\n });\n});\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fileProcessing.test.d.ts","sourceRoot":"","sources":["../../../../src/test/unit/utils/fileProcessing.test.ts"],"names":[],"mappings":"AAsBA,OAAO,oBAAoB,CAAC"}
|