@hamak/smart-data-dico 1.0.4 → 1.1.0
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/backend/dist/server.mjs +82212 -0
- package/bin/cli.js +28 -17
- package/package.json +28 -27
- package/backend/package.json +0 -51
- package/backend/src/__tests__/integration/api.test.ts +0 -149
- package/backend/src/__tests__/setup.ts +0 -24
- package/backend/src/__tests__/utils/testUtils.ts +0 -76
- package/backend/src/adapters/EntityFileAdapter.ts +0 -154
- package/backend/src/adapters/YamlFileInfoEnricher.ts +0 -52
- package/backend/src/controllers/authController.ts +0 -131
- package/backend/src/controllers/diagramController.ts +0 -143
- package/backend/src/controllers/dictionaryController.ts +0 -306
- package/backend/src/controllers/importExportController.ts +0 -64
- package/backend/src/controllers/perspectiveController.ts +0 -90
- package/backend/src/controllers/serviceController.ts +0 -418
- package/backend/src/controllers/stereotypeController.ts +0 -59
- package/backend/src/controllers/versionController.ts +0 -226
- package/backend/src/kernel/config.ts +0 -43
- package/backend/src/middleware/auth.ts +0 -128
- package/backend/src/middleware/jwtAuth.ts +0 -100
- package/backend/src/models/Dictionary.ts +0 -38
- package/backend/src/models/EntitySchema.ts +0 -393
- package/backend/src/models/__tests__/Dictionary.test.ts +0 -92
- package/backend/src/models/__tests__/EntitySchema.test.ts +0 -119
- package/backend/src/routes/index.ts +0 -120
- package/backend/src/scripts/migrate-to-uuid.ts +0 -24
- package/backend/src/server.ts +0 -158
- package/backend/src/services/__mocks__/entityService.ts +0 -38
- package/backend/src/services/__mocks__/serviceService.ts +0 -88
- package/backend/src/services/__mocks__/versionService.ts +0 -38
- package/backend/src/services/__tests__/dictionaryService.test.ts +0 -74
- package/backend/src/services/diagramService.ts +0 -165
- package/backend/src/services/dictionaryService.ts +0 -582
- package/backend/src/services/entityService.ts +0 -102
- package/backend/src/services/exportService.ts +0 -172
- package/backend/src/services/importService.ts +0 -208
- package/backend/src/services/perspectiveService.ts +0 -276
- package/backend/src/services/qualityService.ts +0 -121
- package/backend/src/services/serviceService.ts +0 -763
- package/backend/src/services/stereotypeService.ts +0 -98
- package/backend/src/services/versionService.ts +0 -135
- package/backend/src/setupTests.ts +0 -12
- package/backend/src/utils/__mocks__/fileOperations.ts +0 -116
- package/backend/src/utils/fileOperations.ts +0 -602
- package/backend/src/utils/logger.ts +0 -38
- package/backend/src/utils/migration.ts +0 -254
- package/backend/src/utils/swagger.ts +0 -358
- package/backend/src/utils/uuid.ts +0 -41
- package/backend/tsconfig.json +0 -20
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
import * as fs from 'fs';
|
|
2
|
-
import * as path from 'path';
|
|
3
|
-
import * as YAML from 'yaml';
|
|
4
|
-
import { Stereotype, StereotypeTarget, MetadataEntry } from '../models/EntitySchema.js';
|
|
5
|
-
import { logger } from '../utils/logger.js';
|
|
6
|
-
import { config } from '../kernel/config.js';
|
|
7
|
-
|
|
8
|
-
const DATA_DICTIONARIES_DIR = config.dataDir;
|
|
9
|
-
const STEREOTYPES_FILE = path.join(DATA_DICTIONARIES_DIR, 'stereotypes.yaml');
|
|
10
|
-
|
|
11
|
-
class StereotypeService {
|
|
12
|
-
private readStereotypes(): Stereotype[] {
|
|
13
|
-
if (!fs.existsSync(STEREOTYPES_FILE)) return [];
|
|
14
|
-
const content = fs.readFileSync(STEREOTYPES_FILE, 'utf8');
|
|
15
|
-
return YAML.parse(content) || [];
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
private writeStereotypes(stereotypes: Stereotype[]): void {
|
|
19
|
-
fs.writeFileSync(STEREOTYPES_FILE, YAML.stringify(stereotypes), 'utf8');
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
async getAllStereotypes(appliesTo?: StereotypeTarget): Promise<Stereotype[]> {
|
|
23
|
-
const all = this.readStereotypes();
|
|
24
|
-
if (appliesTo) return all.filter((s) => s.appliesTo === appliesTo);
|
|
25
|
-
return all;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
async getStereotype(id: string): Promise<Stereotype | null> {
|
|
29
|
-
const all = this.readStereotypes();
|
|
30
|
-
return all.find((s) => s.id === id) || null;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
async createStereotype(data: Stereotype): Promise<{ success: boolean; stereotype?: Stereotype; errors?: string[] }> {
|
|
34
|
-
if (!data.id || !data.name || !data.appliesTo) {
|
|
35
|
-
return { success: false, errors: ['id, name, and appliesTo are required'] };
|
|
36
|
-
}
|
|
37
|
-
if (!['package', 'entity', 'attribute'].includes(data.appliesTo)) {
|
|
38
|
-
return { success: false, errors: ['appliesTo must be package, entity, or attribute'] };
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
const all = this.readStereotypes();
|
|
42
|
-
if (all.find((s) => s.id === data.id)) {
|
|
43
|
-
return { success: false, errors: [`Stereotype with id '${data.id}' already exists`] };
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
const stereotype: Stereotype = {
|
|
47
|
-
id: data.id,
|
|
48
|
-
name: data.name,
|
|
49
|
-
description: data.description,
|
|
50
|
-
appliesTo: data.appliesTo,
|
|
51
|
-
metadataDefinitions: data.metadataDefinitions || [],
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
all.push(stereotype);
|
|
55
|
-
this.writeStereotypes(all);
|
|
56
|
-
return { success: true, stereotype };
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
async updateStereotype(id: string, data: Partial<Stereotype>): Promise<{ success: boolean; stereotype?: Stereotype; errors?: string[] }> {
|
|
60
|
-
const all = this.readStereotypes();
|
|
61
|
-
const index = all.findIndex((s) => s.id === id);
|
|
62
|
-
if (index === -1) return { success: false, errors: ['Stereotype not found'] };
|
|
63
|
-
|
|
64
|
-
all[index] = {
|
|
65
|
-
...all[index],
|
|
66
|
-
name: data.name ?? all[index].name,
|
|
67
|
-
description: data.description ?? all[index].description,
|
|
68
|
-
appliesTo: data.appliesTo ?? all[index].appliesTo,
|
|
69
|
-
metadataDefinitions: data.metadataDefinitions ?? all[index].metadataDefinitions,
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
this.writeStereotypes(all);
|
|
73
|
-
return { success: true, stereotype: all[index] };
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
async deleteStereotype(id: string): Promise<{ success: boolean; errors?: string[] }> {
|
|
77
|
-
const all = this.readStereotypes();
|
|
78
|
-
const filtered = all.filter((s) => s.id !== id);
|
|
79
|
-
if (filtered.length === all.length) return { success: false, errors: ['Stereotype not found'] };
|
|
80
|
-
this.writeStereotypes(filtered);
|
|
81
|
-
return { success: true };
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
validateMetadata(stereotype: Stereotype, metadata: MetadataEntry[] = []): string[] {
|
|
85
|
-
const errors: string[] = [];
|
|
86
|
-
for (const def of stereotype.metadataDefinitions) {
|
|
87
|
-
if (def.required) {
|
|
88
|
-
const entry = metadata.find((m) => m.name === def.name);
|
|
89
|
-
if (!entry || entry.value === undefined || entry.value === '') {
|
|
90
|
-
errors.push(`Required metadata '${def.name}' is missing (stereotype: ${stereotype.name})`);
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
return errors;
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
export const stereotypeService = new StereotypeService();
|
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
import { logger } from '../utils/logger.js';
|
|
2
|
-
import { config } from '../kernel/config.js';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Interface for commit information
|
|
6
|
-
*/
|
|
7
|
-
interface CommitInfo {
|
|
8
|
-
hash: string;
|
|
9
|
-
date: string;
|
|
10
|
-
message: string;
|
|
11
|
-
author_name: string;
|
|
12
|
-
author_email: string;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
// Lazy-loaded git service from @hamak/ui-remote-git-fs-backend
|
|
16
|
-
let gitServiceInstance: any = null;
|
|
17
|
-
|
|
18
|
-
async function getGitService() {
|
|
19
|
-
if (gitServiceInstance) return gitServiceInstance;
|
|
20
|
-
try {
|
|
21
|
-
const gitModule = await import('@hamak/ui-remote-git-fs-backend');
|
|
22
|
-
const workspaceRoots = new Map<string, string>([
|
|
23
|
-
['dictionaries', config.dataDir],
|
|
24
|
-
]);
|
|
25
|
-
gitServiceInstance = gitModule.createGitService(workspaceRoots);
|
|
26
|
-
return gitServiceInstance;
|
|
27
|
-
} catch {
|
|
28
|
-
logger.warn('Git service not available');
|
|
29
|
-
return null;
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Service for version control operations using @hamak/ui-remote-git-fs-backend
|
|
35
|
-
*/
|
|
36
|
-
export class VersionService {
|
|
37
|
-
/**
|
|
38
|
-
* Commit all changes to the repository
|
|
39
|
-
*/
|
|
40
|
-
async commitChanges(message: string): Promise<{
|
|
41
|
-
success: boolean;
|
|
42
|
-
errors: string[];
|
|
43
|
-
commitHash?: string;
|
|
44
|
-
timestamp?: Date;
|
|
45
|
-
}> {
|
|
46
|
-
try {
|
|
47
|
-
const gitService = await getGitService();
|
|
48
|
-
if (!gitService) {
|
|
49
|
-
return { success: false, errors: ['Git service not available'] };
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
const status = await gitService.status('dictionaries', '.');
|
|
53
|
-
if (!status.files || status.files.length === 0) {
|
|
54
|
-
return { success: false, errors: ['No changes to commit'] };
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
const result = await gitService.commit('dictionaries', '.', { message });
|
|
58
|
-
|
|
59
|
-
logger.info(`Changes committed: ${result.hash || 'unknown'}`);
|
|
60
|
-
|
|
61
|
-
return {
|
|
62
|
-
success: true,
|
|
63
|
-
errors: [],
|
|
64
|
-
commitHash: result.hash,
|
|
65
|
-
timestamp: new Date(),
|
|
66
|
-
};
|
|
67
|
-
} catch (error) {
|
|
68
|
-
logger.error(`Error committing changes: ${error}`);
|
|
69
|
-
return {
|
|
70
|
-
success: false,
|
|
71
|
-
errors: [`Error committing changes: ${error}`],
|
|
72
|
-
};
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* Get commit history
|
|
78
|
-
*/
|
|
79
|
-
async getCommitHistory(limit: number = 10): Promise<CommitInfo[]> {
|
|
80
|
-
try {
|
|
81
|
-
const gitService = await getGitService();
|
|
82
|
-
if (!gitService) return [];
|
|
83
|
-
|
|
84
|
-
const logResult = await gitService.log('dictionaries', '.', { maxCount: limit });
|
|
85
|
-
|
|
86
|
-
if (!logResult || !Array.isArray(logResult)) return [];
|
|
87
|
-
|
|
88
|
-
return logResult.map((entry: any) => ({
|
|
89
|
-
hash: entry.hash || entry.oid || '',
|
|
90
|
-
date: entry.date || entry.timestamp || '',
|
|
91
|
-
message: entry.message || '',
|
|
92
|
-
author_name: entry.author_name || entry.author?.name || '',
|
|
93
|
-
author_email: entry.author_email || entry.author?.email || '',
|
|
94
|
-
}));
|
|
95
|
-
} catch (error) {
|
|
96
|
-
logger.error(`Error getting commit history: ${error}`);
|
|
97
|
-
return [];
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* Revert to a previous commit
|
|
103
|
-
*/
|
|
104
|
-
async revertToCommit(commitHash: string): Promise<{
|
|
105
|
-
success: boolean;
|
|
106
|
-
errors: string[];
|
|
107
|
-
newCommitHash?: string;
|
|
108
|
-
}> {
|
|
109
|
-
try {
|
|
110
|
-
const gitService = await getGitService();
|
|
111
|
-
if (!gitService) {
|
|
112
|
-
return { success: false, errors: ['Git service not available'] };
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
const result = await gitService.revert('dictionaries', '.', { commit: commitHash });
|
|
116
|
-
|
|
117
|
-
logger.info(`Reverted to commit ${commitHash}`);
|
|
118
|
-
|
|
119
|
-
return {
|
|
120
|
-
success: true,
|
|
121
|
-
errors: [],
|
|
122
|
-
newCommitHash: result?.hash,
|
|
123
|
-
};
|
|
124
|
-
} catch (error) {
|
|
125
|
-
logger.error(`Error reverting to commit: ${error}`);
|
|
126
|
-
return {
|
|
127
|
-
success: false,
|
|
128
|
-
errors: [`Error reverting to commit: ${error}`],
|
|
129
|
-
};
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
// Export a singleton instance
|
|
135
|
-
export const versionService = new VersionService();
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
// This file is automatically loaded by Jest
|
|
2
|
-
// It sets up the testing environment
|
|
3
|
-
|
|
4
|
-
// Global setup
|
|
5
|
-
beforeAll(() => {
|
|
6
|
-
// Any global setup before all tests
|
|
7
|
-
});
|
|
8
|
-
|
|
9
|
-
// Global teardown
|
|
10
|
-
afterAll(() => {
|
|
11
|
-
// Any global cleanup after all tests
|
|
12
|
-
});
|
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
// Mock implementation of file operations for testing
|
|
2
|
-
import { Entity, AttributeType } from '../../models/EntitySchema.js';
|
|
3
|
-
|
|
4
|
-
// Mock data
|
|
5
|
-
const mockMicroservices = ['user-service', 'product-service', 'order-service'];
|
|
6
|
-
|
|
7
|
-
const mockEntities: Record<string, string[]> = {
|
|
8
|
-
'user-service': ['User', 'Profile'],
|
|
9
|
-
'product-service': ['Product'],
|
|
10
|
-
'order-service': ['Order', 'OrderItem']
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
const mockEntityData: Record<string, Entity> = {
|
|
14
|
-
'user-service.User': {
|
|
15
|
-
id: 'User',
|
|
16
|
-
name: 'User',
|
|
17
|
-
description: 'User entity',
|
|
18
|
-
microservice: 'user-service',
|
|
19
|
-
version: '1.0.0',
|
|
20
|
-
attributes: [
|
|
21
|
-
{
|
|
22
|
-
name: 'id',
|
|
23
|
-
description: 'User ID',
|
|
24
|
-
type: AttributeType.STRING,
|
|
25
|
-
required: true
|
|
26
|
-
},
|
|
27
|
-
{
|
|
28
|
-
name: 'email',
|
|
29
|
-
description: 'User email',
|
|
30
|
-
type: AttributeType.STRING,
|
|
31
|
-
format: 'email',
|
|
32
|
-
required: true
|
|
33
|
-
}
|
|
34
|
-
]
|
|
35
|
-
},
|
|
36
|
-
'product-service.Product': {
|
|
37
|
-
id: 'Product',
|
|
38
|
-
name: 'Product',
|
|
39
|
-
description: 'Product entity',
|
|
40
|
-
microservice: 'product-service',
|
|
41
|
-
version: '1.0.0',
|
|
42
|
-
attributes: [
|
|
43
|
-
{
|
|
44
|
-
name: 'id',
|
|
45
|
-
description: 'Product ID',
|
|
46
|
-
type: AttributeType.STRING,
|
|
47
|
-
required: true
|
|
48
|
-
},
|
|
49
|
-
{
|
|
50
|
-
name: 'name',
|
|
51
|
-
description: 'Product name',
|
|
52
|
-
type: AttributeType.STRING,
|
|
53
|
-
required: true
|
|
54
|
-
},
|
|
55
|
-
{
|
|
56
|
-
name: 'price',
|
|
57
|
-
description: 'Product price',
|
|
58
|
-
type: AttributeType.NUMBER,
|
|
59
|
-
required: true
|
|
60
|
-
}
|
|
61
|
-
]
|
|
62
|
-
}
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
// Mock functions
|
|
66
|
-
export const listMicroservices = jest.fn().mockImplementation(async () => {
|
|
67
|
-
return Promise.resolve(mockMicroservices);
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
export const listMicroserviceEntities = jest.fn().mockImplementation(async (microservice: string) => {
|
|
71
|
-
return Promise.resolve(mockEntities[microservice] || []);
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
export const listAllEntities = jest.fn().mockImplementation(async () => {
|
|
75
|
-
const allEntities: { microservice: string; entity: string }[] = [];
|
|
76
|
-
|
|
77
|
-
for (const microservice of mockMicroservices) {
|
|
78
|
-
for (const entity of mockEntities[microservice] || []) {
|
|
79
|
-
allEntities.push({ microservice, entity });
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
return Promise.resolve(allEntities);
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
export const readEntityFile = jest.fn().mockImplementation(async (microservice: string, entity: string) => {
|
|
87
|
-
const key = `${microservice}.${entity}`;
|
|
88
|
-
return Promise.resolve(mockEntityData[key] || null);
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
export const writeEntityFile = jest.fn().mockImplementation(async (entity: Entity) => {
|
|
92
|
-
const key = `${entity.microservice}.${entity.id}`;
|
|
93
|
-
mockEntityData[key] = entity;
|
|
94
|
-
return Promise.resolve(true);
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
export const deleteEntityFile = jest.fn().mockImplementation(async (microservice: string, entity: string) => {
|
|
98
|
-
const key = `${microservice}.${entity}`;
|
|
99
|
-
if (mockEntityData[key]) {
|
|
100
|
-
delete mockEntityData[key];
|
|
101
|
-
return Promise.resolve(true);
|
|
102
|
-
}
|
|
103
|
-
return Promise.resolve(false);
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
export const createDirectory = jest.fn().mockImplementation(async (path: string) => {
|
|
107
|
-
return Promise.resolve(true);
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
export const ensureDirectoryStructure = jest.fn().mockResolvedValue(undefined);
|
|
111
|
-
|
|
112
|
-
export const listAllDictionaries = jest.fn().mockResolvedValue([]);
|
|
113
|
-
|
|
114
|
-
export const writeDictionaryMetadata = jest.fn().mockResolvedValue(undefined);
|
|
115
|
-
|
|
116
|
-
export const commitChanges = jest.fn().mockResolvedValue({ success: true });
|