@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,266 @@
|
|
|
1
|
+
import { Result, succeed, fail } from '@fgv/ts-utils';
|
|
2
|
+
import { Config } from '@fgv/ts-res';
|
|
3
|
+
import { ZipManifest, ZipFileItem, ZipFileTree } from './types';
|
|
4
|
+
import { ImportedDirectory, ImportedFile } from '../../types';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Generate a timestamp-based filename for ZIP archives
|
|
8
|
+
*/
|
|
9
|
+
export function generateZipFilename(customName?: string): string {
|
|
10
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, '-').replace('T', '_').slice(0, -5);
|
|
11
|
+
return customName ? `${customName}-${timestamp}.zip` : `ts-res-bundle-${timestamp}.zip`;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Create a ZIP manifest object
|
|
16
|
+
*/
|
|
17
|
+
export function createManifest(
|
|
18
|
+
inputType: 'file' | 'directory',
|
|
19
|
+
originalPath: string,
|
|
20
|
+
archivePath: string,
|
|
21
|
+
configPath?: string
|
|
22
|
+
): ZipManifest {
|
|
23
|
+
const manifest: ZipManifest = {
|
|
24
|
+
timestamp: new Date().toISOString(),
|
|
25
|
+
input: {
|
|
26
|
+
type: inputType,
|
|
27
|
+
originalPath,
|
|
28
|
+
archivePath
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
if (configPath) {
|
|
33
|
+
manifest.config = {
|
|
34
|
+
type: 'file',
|
|
35
|
+
originalPath: configPath,
|
|
36
|
+
archivePath: 'config.json'
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return manifest;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Parse and validate a ZIP manifest
|
|
45
|
+
*/
|
|
46
|
+
export function parseManifest(manifestData: string): Result<ZipManifest> {
|
|
47
|
+
try {
|
|
48
|
+
const parsed = JSON.parse(manifestData);
|
|
49
|
+
|
|
50
|
+
// Basic validation
|
|
51
|
+
if (!parsed.timestamp || typeof parsed.timestamp !== 'string') {
|
|
52
|
+
return fail('Invalid manifest: missing or invalid timestamp');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Validate input section if present
|
|
56
|
+
if (parsed.input) {
|
|
57
|
+
if (!parsed.input.type || !['file', 'directory'].includes(parsed.input.type)) {
|
|
58
|
+
return fail('Invalid manifest: invalid input type');
|
|
59
|
+
}
|
|
60
|
+
if (!parsed.input.originalPath || !parsed.input.archivePath) {
|
|
61
|
+
return fail('Invalid manifest: missing input paths');
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Validate config section if present
|
|
66
|
+
if (parsed.config) {
|
|
67
|
+
if (parsed.config.type !== 'file') {
|
|
68
|
+
return fail('Invalid manifest: invalid config type');
|
|
69
|
+
}
|
|
70
|
+
if (!parsed.config.originalPath || !parsed.config.archivePath) {
|
|
71
|
+
return fail('Invalid manifest: missing config paths');
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return succeed(parsed as ZipManifest);
|
|
76
|
+
} catch (error) {
|
|
77
|
+
return fail(`Failed to parse manifest: ${error instanceof Error ? error.message : String(error)}`);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Parse and validate configuration JSON
|
|
83
|
+
*/
|
|
84
|
+
export function parseConfiguration(configData: string): Result<Config.Model.ISystemConfiguration> {
|
|
85
|
+
try {
|
|
86
|
+
const parsed = JSON.parse(configData);
|
|
87
|
+
|
|
88
|
+
// Basic validation - check for expected properties
|
|
89
|
+
if (typeof parsed !== 'object' || parsed === null) {
|
|
90
|
+
return fail('Invalid configuration: not an object');
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// More detailed validation could be added here using ts-res validators
|
|
94
|
+
return succeed(parsed as Config.Model.ISystemConfiguration);
|
|
95
|
+
} catch (error) {
|
|
96
|
+
return fail(`Failed to parse configuration: ${error instanceof Error ? error.message : String(error)}`);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Convert ZIP file tree to ImportedFiles array
|
|
102
|
+
*/
|
|
103
|
+
export function zipTreeToFiles(tree: ZipFileTree): ImportedFile[] {
|
|
104
|
+
const files: ImportedFile[] = [];
|
|
105
|
+
|
|
106
|
+
for (const [path, item] of Array.from(tree.files.entries())) {
|
|
107
|
+
if (!item.isDirectory && item.content && typeof item.content === 'string') {
|
|
108
|
+
files.push({
|
|
109
|
+
name: item.name,
|
|
110
|
+
path: path,
|
|
111
|
+
content: item.content,
|
|
112
|
+
type: getFileType(item.name)
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return files;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Convert ZIP file tree to ImportedDirectory structure
|
|
122
|
+
*/
|
|
123
|
+
export function zipTreeToDirectory(tree: ZipFileTree): ImportedDirectory | null {
|
|
124
|
+
if (tree.files.size === 0) {
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Build directory structure
|
|
129
|
+
const directories = new Map<string, ImportedDirectory>();
|
|
130
|
+
const rootDir: ImportedDirectory = {
|
|
131
|
+
name: tree.root || 'root',
|
|
132
|
+
files: [],
|
|
133
|
+
subdirectories: []
|
|
134
|
+
};
|
|
135
|
+
directories.set('', rootDir);
|
|
136
|
+
|
|
137
|
+
// Process all paths to build directory structure
|
|
138
|
+
for (const [path, item] of Array.from(tree.files.entries())) {
|
|
139
|
+
const pathParts = path.split('/').filter((part: string) => part.length > 0);
|
|
140
|
+
|
|
141
|
+
if (pathParts.length === 0) continue;
|
|
142
|
+
|
|
143
|
+
// Ensure all parent directories exist
|
|
144
|
+
let currentPath = '';
|
|
145
|
+
for (let i = 0; i < pathParts.length - 1; i++) {
|
|
146
|
+
const parentPath = currentPath;
|
|
147
|
+
currentPath = currentPath ? `${currentPath}/${pathParts[i]}` : pathParts[i];
|
|
148
|
+
|
|
149
|
+
if (!directories.has(currentPath)) {
|
|
150
|
+
const newDir: ImportedDirectory = {
|
|
151
|
+
name: pathParts[i],
|
|
152
|
+
files: [],
|
|
153
|
+
subdirectories: []
|
|
154
|
+
};
|
|
155
|
+
directories.set(currentPath, newDir);
|
|
156
|
+
|
|
157
|
+
// Add to parent directory
|
|
158
|
+
const parentDir = directories.get(parentPath);
|
|
159
|
+
if (parentDir) {
|
|
160
|
+
parentDir.subdirectories = parentDir.subdirectories || [];
|
|
161
|
+
parentDir.subdirectories.push(newDir);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Add file to its parent directory
|
|
167
|
+
if (!item.isDirectory && item.content && typeof item.content === 'string') {
|
|
168
|
+
const fileName = pathParts[pathParts.length - 1];
|
|
169
|
+
const parentPath = pathParts.length > 1 ? pathParts.slice(0, -1).join('/') : '';
|
|
170
|
+
const parentDir = directories.get(parentPath);
|
|
171
|
+
|
|
172
|
+
if (parentDir) {
|
|
173
|
+
parentDir.files.push({
|
|
174
|
+
name: fileName,
|
|
175
|
+
path: path,
|
|
176
|
+
content: item.content,
|
|
177
|
+
type: getFileType(fileName)
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
return rootDir;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Get file type based on extension
|
|
188
|
+
*/
|
|
189
|
+
function getFileType(filename: string): string {
|
|
190
|
+
const ext = filename.toLowerCase().split('.').pop();
|
|
191
|
+
switch (ext) {
|
|
192
|
+
case 'json':
|
|
193
|
+
return 'application/json';
|
|
194
|
+
case 'yaml':
|
|
195
|
+
case 'yml':
|
|
196
|
+
return 'application/yaml';
|
|
197
|
+
case 'xml':
|
|
198
|
+
return 'application/xml';
|
|
199
|
+
case 'txt':
|
|
200
|
+
return 'text/plain';
|
|
201
|
+
case 'md':
|
|
202
|
+
return 'text/markdown';
|
|
203
|
+
case 'js':
|
|
204
|
+
return 'application/javascript';
|
|
205
|
+
case 'ts':
|
|
206
|
+
return 'application/typescript';
|
|
207
|
+
default:
|
|
208
|
+
return 'application/octet-stream';
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Normalize path separators for cross-platform compatibility
|
|
214
|
+
*/
|
|
215
|
+
export function normalizePath(path: string): string {
|
|
216
|
+
return path.replace(/\\/g, '/').replace(/\/+/g, '/');
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Extract directory name from a file path
|
|
221
|
+
*/
|
|
222
|
+
export function getDirectoryName(path: string): string {
|
|
223
|
+
const normalized = normalizePath(path);
|
|
224
|
+
const parts = normalized.split('/');
|
|
225
|
+
return parts[parts.length - 1] || 'archive';
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Create a safe filename by removing invalid characters
|
|
230
|
+
*/
|
|
231
|
+
export function sanitizeFilename(filename: string): string {
|
|
232
|
+
return filename
|
|
233
|
+
.replace(/[<>:"/\\|?*]/g, '_')
|
|
234
|
+
.replace(/\s+/g, '_')
|
|
235
|
+
.replace(/_+/g, '_')
|
|
236
|
+
.trim();
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Format file size in human readable format
|
|
241
|
+
*/
|
|
242
|
+
export function formatFileSize(bytes: number): string {
|
|
243
|
+
if (bytes === 0) return '0 B';
|
|
244
|
+
|
|
245
|
+
const sizes = ['B', 'KB', 'MB', 'GB'];
|
|
246
|
+
const i = Math.floor(Math.log(bytes) / Math.log(1024));
|
|
247
|
+
const size = bytes / Math.pow(1024, i);
|
|
248
|
+
|
|
249
|
+
return `${size.toFixed(i === 0 ? 0 : 1)} ${sizes[i]}`;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Validate ZIP file extension
|
|
254
|
+
*/
|
|
255
|
+
export function isZipFile(filename: string): boolean {
|
|
256
|
+
return filename.toLowerCase().endsWith('.zip');
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Extract base name from filename (without extension)
|
|
261
|
+
*/
|
|
262
|
+
export function getBaseName(filename: string): string {
|
|
263
|
+
const name = filename.split('/').pop() || filename;
|
|
264
|
+
const dotIndex = name.lastIndexOf('.');
|
|
265
|
+
return dotIndex > 0 ? name.substring(0, dotIndex) : name;
|
|
266
|
+
}
|