@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,393 +0,0 @@
|
|
|
1
|
-
import { Validator } from 'jsonschema';
|
|
2
|
-
import { generateUUID, isValidUUID } from '../utils/uuid.js';
|
|
3
|
-
type Schema = any; // Using any as a workaround for missing type definitions
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Supported attribute types in the data dictionary
|
|
7
|
-
*/
|
|
8
|
-
export enum AttributeType {
|
|
9
|
-
STRING = 'string',
|
|
10
|
-
NUMBER = 'number',
|
|
11
|
-
INTEGER = 'integer',
|
|
12
|
-
BOOLEAN = 'boolean',
|
|
13
|
-
DATETIME = 'datetime',
|
|
14
|
-
DATE = 'date',
|
|
15
|
-
TIME = 'time',
|
|
16
|
-
DATE_TIME = 'date-time',
|
|
17
|
-
TIMESTAMP = 'timestamp',
|
|
18
|
-
DURATION = 'duration',
|
|
19
|
-
ENUM = 'enum',
|
|
20
|
-
OBJECT = 'object',
|
|
21
|
-
ARRAY = 'array'
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Cardinality for relationship ends
|
|
26
|
-
*/
|
|
27
|
-
export enum Cardinality {
|
|
28
|
-
ONE = 'one',
|
|
29
|
-
MANY = 'many'
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Metadata value types for typed metadata definitions
|
|
34
|
-
*/
|
|
35
|
-
export enum MetadataValueType {
|
|
36
|
-
STRING = 'string',
|
|
37
|
-
NUMBER = 'number',
|
|
38
|
-
BOOLEAN = 'boolean',
|
|
39
|
-
DATE = 'date',
|
|
40
|
-
FLAG = 'flag',
|
|
41
|
-
RULE = 'rule',
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export enum RuleSeverity {
|
|
45
|
-
INFO = 'info',
|
|
46
|
-
WARNING = 'warning',
|
|
47
|
-
ERROR = 'error',
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* A metadata definition (schema for metadata entries)
|
|
52
|
-
*/
|
|
53
|
-
export interface MetadataDefinition {
|
|
54
|
-
name: string;
|
|
55
|
-
type: MetadataValueType;
|
|
56
|
-
description?: string;
|
|
57
|
-
required?: boolean;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* A typed metadata entry
|
|
62
|
-
*/
|
|
63
|
-
export interface MetadataEntry {
|
|
64
|
-
name: string;
|
|
65
|
-
value: string | number | boolean;
|
|
66
|
-
severity?: RuleSeverity;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
export enum EntityStatus {
|
|
70
|
-
DRAFT = 'draft',
|
|
71
|
-
SUBMITTED = 'submitted',
|
|
72
|
-
APPROVED = 'approved',
|
|
73
|
-
RETURNED = 'returned',
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
export interface ReviewComment {
|
|
77
|
-
id: string;
|
|
78
|
-
author: string;
|
|
79
|
-
timestamp: string;
|
|
80
|
-
message: string;
|
|
81
|
-
targetField?: string;
|
|
82
|
-
resolved?: boolean;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
export type StereotypeTarget = 'package' | 'entity' | 'attribute';
|
|
86
|
-
|
|
87
|
-
export interface Stereotype {
|
|
88
|
-
id: string;
|
|
89
|
-
name: string;
|
|
90
|
-
description?: string;
|
|
91
|
-
appliesTo: StereotypeTarget;
|
|
92
|
-
metadataDefinitions: MetadataDefinition[];
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* A node in a perspective — annotates, sets frontier, or excludes a path
|
|
97
|
-
*/
|
|
98
|
-
export interface PerspectiveNode {
|
|
99
|
-
path: string;
|
|
100
|
-
traverse?: boolean;
|
|
101
|
-
exclude?: boolean;
|
|
102
|
-
metadata?: MetadataEntry[];
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* A perspective is a business view over a subset of the data model
|
|
107
|
-
*/
|
|
108
|
-
export interface Perspective {
|
|
109
|
-
uuid: string;
|
|
110
|
-
name: string;
|
|
111
|
-
description?: string;
|
|
112
|
-
rootEntities: string[];
|
|
113
|
-
nodes?: PerspectiveNode[];
|
|
114
|
-
maxDepth?: number;
|
|
115
|
-
metadata?: MetadataEntry[];
|
|
116
|
-
createdAt?: string;
|
|
117
|
-
updatedAt?: string;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* A resolved node from BFS traversal of a perspective
|
|
122
|
-
*/
|
|
123
|
-
export interface ResolvedNode {
|
|
124
|
-
entityUuid: string;
|
|
125
|
-
entityName: string;
|
|
126
|
-
service: string;
|
|
127
|
-
path: string;
|
|
128
|
-
hopDistance: number;
|
|
129
|
-
isRoot: boolean;
|
|
130
|
-
isFrontier: boolean;
|
|
131
|
-
isManualInclusion: boolean;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* A perspective with its resolved entity graph
|
|
136
|
-
*/
|
|
137
|
-
export interface ResolvedPerspective extends Perspective {
|
|
138
|
-
resolvedNodes: ResolvedNode[];
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
/**
|
|
142
|
-
* Grouped constraint fields for attributes
|
|
143
|
-
*/
|
|
144
|
-
export interface AttributeConstraints {
|
|
145
|
-
minLength?: number;
|
|
146
|
-
maxLength?: number;
|
|
147
|
-
pattern?: string;
|
|
148
|
-
format?: string;
|
|
149
|
-
minimum?: number;
|
|
150
|
-
maximum?: number;
|
|
151
|
-
precision?: number;
|
|
152
|
-
scale?: number;
|
|
153
|
-
enumValues?: string[];
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
/**
|
|
157
|
-
* Interface for entity attribute definition
|
|
158
|
-
*/
|
|
159
|
-
export interface Attribute {
|
|
160
|
-
uuid: string;
|
|
161
|
-
name: string;
|
|
162
|
-
description: string;
|
|
163
|
-
type: AttributeType;
|
|
164
|
-
required: boolean;
|
|
165
|
-
unique?: boolean;
|
|
166
|
-
primaryKey?: boolean;
|
|
167
|
-
defaultValue?: any;
|
|
168
|
-
examples?: any[];
|
|
169
|
-
constraints?: AttributeConstraints;
|
|
170
|
-
|
|
171
|
-
// For object and array types
|
|
172
|
-
items?: Attribute;
|
|
173
|
-
properties?: Attribute[];
|
|
174
|
-
|
|
175
|
-
// Typed metadata
|
|
176
|
-
metadata?: MetadataEntry[];
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
/**
|
|
180
|
-
* One end of a relationship
|
|
181
|
-
*/
|
|
182
|
-
export interface RelationshipEnd {
|
|
183
|
-
entity: string; // UUID of the entity
|
|
184
|
-
cardinality: Cardinality;
|
|
185
|
-
name?: string; // Navigation property name
|
|
186
|
-
referenceAttributes?: string[];
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
/**
|
|
190
|
-
* A relationship between two entities, stored at package level
|
|
191
|
-
*/
|
|
192
|
-
export type RelationshipType = 'structural' | 'lineage';
|
|
193
|
-
|
|
194
|
-
export interface Relationship {
|
|
195
|
-
uuid: string;
|
|
196
|
-
description?: string;
|
|
197
|
-
type?: RelationshipType;
|
|
198
|
-
source: RelationshipEnd;
|
|
199
|
-
target: RelationshipEnd;
|
|
200
|
-
metadata?: MetadataEntry[];
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
export interface LineageNode {
|
|
204
|
-
entityUuid: string;
|
|
205
|
-
entityName: string;
|
|
206
|
-
service: string;
|
|
207
|
-
direction: 'upstream' | 'downstream';
|
|
208
|
-
depth: number;
|
|
209
|
-
relationship: { uuid: string; description: string };
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
export interface LineageResult {
|
|
213
|
-
entity: { uuid: string; name: string; service: string };
|
|
214
|
-
upstream: LineageNode[];
|
|
215
|
-
downstream: LineageNode[];
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
/**
|
|
219
|
-
* Interface for entity definition
|
|
220
|
-
*/
|
|
221
|
-
export interface Entity {
|
|
222
|
-
uuid: string;
|
|
223
|
-
name: string;
|
|
224
|
-
description?: string;
|
|
225
|
-
stereotype?: string;
|
|
226
|
-
status?: EntityStatus;
|
|
227
|
-
attributes: Attribute[];
|
|
228
|
-
metadata?: MetadataEntry[];
|
|
229
|
-
createdAt?: string;
|
|
230
|
-
updatedAt?: string;
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
// Backward-compatible alias
|
|
234
|
-
export type EntityAttribute = Attribute;
|
|
235
|
-
|
|
236
|
-
/**
|
|
237
|
-
* JSON Schema for validating entity definitions
|
|
238
|
-
*/
|
|
239
|
-
export const entitySchema: Schema = {
|
|
240
|
-
type: 'object',
|
|
241
|
-
required: ['uuid', 'name', 'attributes'],
|
|
242
|
-
properties: {
|
|
243
|
-
uuid: { type: 'string', pattern: '^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$' },
|
|
244
|
-
name: { type: 'string' },
|
|
245
|
-
description: { type: 'string' },
|
|
246
|
-
attributes: {
|
|
247
|
-
type: 'array',
|
|
248
|
-
items: {
|
|
249
|
-
type: 'object',
|
|
250
|
-
required: ['uuid', 'name', 'description', 'type', 'required'],
|
|
251
|
-
properties: {
|
|
252
|
-
uuid: { type: 'string', pattern: '^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$' },
|
|
253
|
-
name: { type: 'string' },
|
|
254
|
-
description: { type: 'string' },
|
|
255
|
-
type: {
|
|
256
|
-
type: 'string',
|
|
257
|
-
enum: Object.values(AttributeType)
|
|
258
|
-
},
|
|
259
|
-
required: { type: 'boolean' },
|
|
260
|
-
unique: { type: 'boolean' },
|
|
261
|
-
primaryKey: { type: 'boolean' },
|
|
262
|
-
defaultValue: { },
|
|
263
|
-
examples: { type: 'array' },
|
|
264
|
-
constraints: {
|
|
265
|
-
type: 'object',
|
|
266
|
-
properties: {
|
|
267
|
-
minLength: { type: 'integer', minimum: 0 },
|
|
268
|
-
maxLength: { type: 'integer', minimum: 0 },
|
|
269
|
-
pattern: { type: 'string' },
|
|
270
|
-
format: { type: 'string' },
|
|
271
|
-
minimum: { type: 'number' },
|
|
272
|
-
maximum: { type: 'number' },
|
|
273
|
-
precision: { type: 'integer', minimum: 0 },
|
|
274
|
-
scale: { type: 'integer', minimum: 0 },
|
|
275
|
-
enumValues: {
|
|
276
|
-
type: 'array',
|
|
277
|
-
items: { type: 'string' }
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
},
|
|
281
|
-
items: { type: 'object' },
|
|
282
|
-
properties: { type: 'array' },
|
|
283
|
-
metadata: { type: 'array' }
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
},
|
|
287
|
-
metadata: { type: 'array' },
|
|
288
|
-
createdAt: { type: 'string', format: 'date-time' },
|
|
289
|
-
updatedAt: { type: 'string', format: 'date-time' }
|
|
290
|
-
}
|
|
291
|
-
};
|
|
292
|
-
|
|
293
|
-
/**
|
|
294
|
-
* JSON Schema for validating relationship definitions
|
|
295
|
-
*/
|
|
296
|
-
export const relationshipSchema: Schema = {
|
|
297
|
-
type: 'object',
|
|
298
|
-
required: ['uuid', 'source', 'target'],
|
|
299
|
-
properties: {
|
|
300
|
-
uuid: { type: 'string', pattern: '^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$' },
|
|
301
|
-
description: { type: 'string' },
|
|
302
|
-
source: {
|
|
303
|
-
type: 'object',
|
|
304
|
-
required: ['entity', 'cardinality'],
|
|
305
|
-
properties: {
|
|
306
|
-
entity: { type: 'string' },
|
|
307
|
-
cardinality: { type: 'string', enum: Object.values(Cardinality) },
|
|
308
|
-
name: { type: 'string' },
|
|
309
|
-
referenceAttributes: { type: 'array', items: { type: 'string' } }
|
|
310
|
-
}
|
|
311
|
-
},
|
|
312
|
-
target: {
|
|
313
|
-
type: 'object',
|
|
314
|
-
required: ['entity', 'cardinality'],
|
|
315
|
-
properties: {
|
|
316
|
-
entity: { type: 'string' },
|
|
317
|
-
cardinality: { type: 'string', enum: Object.values(Cardinality) },
|
|
318
|
-
name: { type: 'string' },
|
|
319
|
-
referenceAttributes: { type: 'array', items: { type: 'string' } }
|
|
320
|
-
}
|
|
321
|
-
},
|
|
322
|
-
metadata: { type: 'array' }
|
|
323
|
-
}
|
|
324
|
-
};
|
|
325
|
-
|
|
326
|
-
/**
|
|
327
|
-
* Validates an entity definition against the schema
|
|
328
|
-
*/
|
|
329
|
-
export function validateEntity(entity: Entity): { valid: boolean; errors: string[] } {
|
|
330
|
-
const validator = new Validator();
|
|
331
|
-
const result = validator.validate(entity, entitySchema);
|
|
332
|
-
|
|
333
|
-
const errors: string[] = result.errors.map((error: any) => error.stack);
|
|
334
|
-
|
|
335
|
-
// Additional UUID validation
|
|
336
|
-
if (!isValidUUID(entity.uuid)) {
|
|
337
|
-
errors.push('Entity UUID is invalid');
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
// Validate attribute UUIDs
|
|
341
|
-
if (entity.attributes) {
|
|
342
|
-
entity.attributes.forEach((attr, index) => {
|
|
343
|
-
if (!isValidUUID(attr.uuid)) {
|
|
344
|
-
errors.push(`Attribute ${index} UUID is invalid`);
|
|
345
|
-
}
|
|
346
|
-
});
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
return {
|
|
350
|
-
valid: result.valid && errors.length === 0,
|
|
351
|
-
errors
|
|
352
|
-
};
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
/**
|
|
356
|
-
* Validates a relationship definition against the schema
|
|
357
|
-
*/
|
|
358
|
-
export function validateRelationship(relationship: Relationship): { valid: boolean; errors: string[] } {
|
|
359
|
-
const validator = new Validator();
|
|
360
|
-
const result = validator.validate(relationship, relationshipSchema);
|
|
361
|
-
|
|
362
|
-
const errors: string[] = result.errors.map((error: any) => error.stack);
|
|
363
|
-
|
|
364
|
-
if (!isValidUUID(relationship.uuid)) {
|
|
365
|
-
errors.push('Relationship UUID is invalid');
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
return {
|
|
369
|
-
valid: result.valid && errors.length === 0,
|
|
370
|
-
errors
|
|
371
|
-
};
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
/**
|
|
375
|
-
* Creates a new entity with UUIDs for all components
|
|
376
|
-
*/
|
|
377
|
-
export function createEntityWithUUIDs(entityData: Omit<Entity, 'uuid' | 'attributes'> & {
|
|
378
|
-
attributes: Omit<Attribute, 'uuid'>[];
|
|
379
|
-
}): Entity {
|
|
380
|
-
return {
|
|
381
|
-
...entityData,
|
|
382
|
-
uuid: generateUUID(),
|
|
383
|
-
attributes: entityData.attributes.map(attr => ({
|
|
384
|
-
...attr,
|
|
385
|
-
uuid: generateUUID(),
|
|
386
|
-
properties: attr.properties ? attr.properties.map(prop => ({
|
|
387
|
-
...prop,
|
|
388
|
-
uuid: prop.uuid || generateUUID()
|
|
389
|
-
})) : attr.properties,
|
|
390
|
-
items: attr.items ? { ...attr.items, uuid: attr.items.uuid || generateUUID() } : attr.items
|
|
391
|
-
}))
|
|
392
|
-
};
|
|
393
|
-
}
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
import { Dictionary, DictionaryEntry } from '../Dictionary.js';
|
|
2
|
-
|
|
3
|
-
describe('Dictionary Model', () => {
|
|
4
|
-
describe('Dictionary Interface', () => {
|
|
5
|
-
it('should create a valid Dictionary object', () => {
|
|
6
|
-
const dictionary: Dictionary = {
|
|
7
|
-
id: 'test-dict-1',
|
|
8
|
-
name: 'Test Dictionary',
|
|
9
|
-
description: 'A test dictionary',
|
|
10
|
-
version: '1.0.0',
|
|
11
|
-
createdAt: new Date(),
|
|
12
|
-
updatedAt: new Date(),
|
|
13
|
-
rootPackage: { id: 'root', name: 'Root', entities: [], subPackages: [] },
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
expect(dictionary).toBeDefined();
|
|
17
|
-
expect(dictionary.id).toBe('test-dict-1');
|
|
18
|
-
expect(dictionary.name).toBe('Test Dictionary');
|
|
19
|
-
expect(dictionary.description).toBe('A test dictionary');
|
|
20
|
-
expect(dictionary.version).toBe('1.0.0');
|
|
21
|
-
expect(dictionary.createdAt).toBeInstanceOf(Date);
|
|
22
|
-
expect(dictionary.updatedAt).toBeInstanceOf(Date);
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
it('should create a Dictionary with only required fields', () => {
|
|
26
|
-
const dictionary: Dictionary = {
|
|
27
|
-
id: 'test-dict-2',
|
|
28
|
-
name: 'Minimal Dictionary',
|
|
29
|
-
rootPackage: { id: 'root', name: 'Root', entities: [], subPackages: [] },
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
expect(dictionary).toBeDefined();
|
|
33
|
-
expect(dictionary.id).toBe('test-dict-2');
|
|
34
|
-
expect(dictionary.name).toBe('Minimal Dictionary');
|
|
35
|
-
expect(dictionary.description).toBeUndefined();
|
|
36
|
-
expect(dictionary.version).toBeUndefined();
|
|
37
|
-
expect(dictionary.createdAt).toBeUndefined();
|
|
38
|
-
expect(dictionary.updatedAt).toBeUndefined();
|
|
39
|
-
});
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
describe('DictionaryEntry Interface', () => {
|
|
43
|
-
it('should create a valid DictionaryEntry object', () => {
|
|
44
|
-
const entry: DictionaryEntry = {
|
|
45
|
-
id: 'entry-1',
|
|
46
|
-
name: 'Test Entry',
|
|
47
|
-
description: 'A test entry',
|
|
48
|
-
type: 'string',
|
|
49
|
-
format: 'email',
|
|
50
|
-
required: true,
|
|
51
|
-
defaultValue: 'test@example.com',
|
|
52
|
-
examples: ['user@example.com', 'admin@example.com'],
|
|
53
|
-
metadata: {
|
|
54
|
-
source: 'user',
|
|
55
|
-
lastUpdated: '2023-01-01',
|
|
56
|
-
},
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
expect(entry).toBeDefined();
|
|
60
|
-
expect(entry.id).toBe('entry-1');
|
|
61
|
-
expect(entry.name).toBe('Test Entry');
|
|
62
|
-
expect(entry.description).toBe('A test entry');
|
|
63
|
-
expect(entry.type).toBe('string');
|
|
64
|
-
expect(entry.format).toBe('email');
|
|
65
|
-
expect(entry.required).toBe(true);
|
|
66
|
-
expect(entry.defaultValue).toBe('test@example.com');
|
|
67
|
-
expect(entry.examples).toHaveLength(2);
|
|
68
|
-
expect(entry.examples).toContain('user@example.com');
|
|
69
|
-
expect(entry.metadata).toHaveProperty('source', 'user');
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
it('should create a DictionaryEntry with only required fields', () => {
|
|
73
|
-
const entry: DictionaryEntry = {
|
|
74
|
-
id: 'entry-2',
|
|
75
|
-
name: 'Minimal Entry',
|
|
76
|
-
description: 'A minimal entry',
|
|
77
|
-
type: 'number',
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
expect(entry).toBeDefined();
|
|
81
|
-
expect(entry.id).toBe('entry-2');
|
|
82
|
-
expect(entry.name).toBe('Minimal Entry');
|
|
83
|
-
expect(entry.description).toBe('A minimal entry');
|
|
84
|
-
expect(entry.type).toBe('number');
|
|
85
|
-
expect(entry.format).toBeUndefined();
|
|
86
|
-
expect(entry.required).toBeUndefined();
|
|
87
|
-
expect(entry.defaultValue).toBeUndefined();
|
|
88
|
-
expect(entry.examples).toBeUndefined();
|
|
89
|
-
expect(entry.metadata).toBeUndefined();
|
|
90
|
-
});
|
|
91
|
-
});
|
|
92
|
-
});
|
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
import { AttributeType, validateEntity } from '../EntitySchema.js';
|
|
2
|
-
|
|
3
|
-
describe('EntitySchema', () => {
|
|
4
|
-
describe('validateEntity', () => {
|
|
5
|
-
it('should validate a valid entity', () => {
|
|
6
|
-
const validEntity = {
|
|
7
|
-
uuid: 'a38d1597-cc4f-4934-bb08-c876c023f693',
|
|
8
|
-
name: 'Test Entity',
|
|
9
|
-
attributes: [
|
|
10
|
-
{
|
|
11
|
-
uuid: 'b49e2608-dd5f-4045-aa09-d464c234e694',
|
|
12
|
-
name: 'id',
|
|
13
|
-
description: 'Primary identifier',
|
|
14
|
-
type: AttributeType.STRING,
|
|
15
|
-
required: true,
|
|
16
|
-
primaryKey: true,
|
|
17
|
-
},
|
|
18
|
-
{
|
|
19
|
-
uuid: 'c5af3719-ee6f-4156-bb1a-e575d345f7a5',
|
|
20
|
-
name: 'name',
|
|
21
|
-
description: 'Entity name',
|
|
22
|
-
type: AttributeType.STRING,
|
|
23
|
-
required: true,
|
|
24
|
-
},
|
|
25
|
-
],
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
const result = validateEntity(validEntity);
|
|
29
|
-
expect(result.valid).toBe(true);
|
|
30
|
-
expect(result.errors).toHaveLength(0);
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
it('should invalidate an entity with missing required fields', () => {
|
|
34
|
-
const invalidEntity = {
|
|
35
|
-
// Missing uuid
|
|
36
|
-
// Missing name
|
|
37
|
-
description: 'A test entity',
|
|
38
|
-
attributes: [],
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
const result = validateEntity(invalidEntity as any);
|
|
42
|
-
expect(result.valid).toBe(false);
|
|
43
|
-
expect(result.errors.length).toBeGreaterThan(0);
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
it('should validate an entity with constraints', () => {
|
|
47
|
-
const entityWithConstraints = {
|
|
48
|
-
uuid: 'd6b0482a-ff70-4267-8c2b-f686e456f8b6',
|
|
49
|
-
name: 'Test Entity',
|
|
50
|
-
description: 'A test entity',
|
|
51
|
-
attributes: [
|
|
52
|
-
{
|
|
53
|
-
uuid: 'e7c1593b-aa81-4378-9d3c-a797f567a9c7',
|
|
54
|
-
name: 'email',
|
|
55
|
-
description: 'Email address',
|
|
56
|
-
type: AttributeType.STRING,
|
|
57
|
-
required: true,
|
|
58
|
-
constraints: {
|
|
59
|
-
maxLength: 255,
|
|
60
|
-
pattern: '^[^@]+@[^@]+$',
|
|
61
|
-
format: 'email',
|
|
62
|
-
},
|
|
63
|
-
},
|
|
64
|
-
],
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
const result = validateEntity(entityWithConstraints);
|
|
68
|
-
expect(result.valid).toBe(true);
|
|
69
|
-
expect(result.errors).toHaveLength(0);
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
it('should invalidate an entity with invalid attribute type', () => {
|
|
73
|
-
const entityWithInvalidAttribute = {
|
|
74
|
-
uuid: 'a38d1597-cc4f-4934-bb08-c876c023f693',
|
|
75
|
-
name: 'Test Entity',
|
|
76
|
-
description: 'A test entity',
|
|
77
|
-
attributes: [
|
|
78
|
-
{
|
|
79
|
-
uuid: 'b49e2608-dd5f-4045-aa09-d464c234e694',
|
|
80
|
-
name: 'id',
|
|
81
|
-
description: 'Primary identifier',
|
|
82
|
-
type: 'invalid-type', // Invalid type
|
|
83
|
-
required: true,
|
|
84
|
-
},
|
|
85
|
-
],
|
|
86
|
-
};
|
|
87
|
-
|
|
88
|
-
const result = validateEntity(entityWithInvalidAttribute as any);
|
|
89
|
-
expect(result.valid).toBe(false);
|
|
90
|
-
expect(result.errors.length).toBeGreaterThan(0);
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
it('should validate an entity with metadata entries', () => {
|
|
94
|
-
const entityWithMetadata = {
|
|
95
|
-
uuid: 'a38d1597-cc4f-4934-bb08-c876c023f693',
|
|
96
|
-
name: 'Test Entity',
|
|
97
|
-
attributes: [
|
|
98
|
-
{
|
|
99
|
-
uuid: 'b49e2608-dd5f-4045-aa09-d464c234e694',
|
|
100
|
-
name: 'id',
|
|
101
|
-
description: 'Primary identifier',
|
|
102
|
-
type: AttributeType.STRING,
|
|
103
|
-
required: true,
|
|
104
|
-
metadata: [
|
|
105
|
-
{ name: 'sensitive', value: true },
|
|
106
|
-
],
|
|
107
|
-
},
|
|
108
|
-
],
|
|
109
|
-
metadata: [
|
|
110
|
-
{ name: 'owner', value: 'team-a' },
|
|
111
|
-
],
|
|
112
|
-
};
|
|
113
|
-
|
|
114
|
-
const result = validateEntity(entityWithMetadata);
|
|
115
|
-
expect(result.valid).toBe(true);
|
|
116
|
-
expect(result.errors).toHaveLength(0);
|
|
117
|
-
});
|
|
118
|
-
});
|
|
119
|
-
});
|