@api-client/core 0.16.0 → 0.17.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/build/src/modeling/Semantics.d.ts +52 -0
- package/build/src/modeling/Semantics.d.ts.map +1 -1
- package/build/src/modeling/Semantics.js +206 -97
- package/build/src/modeling/Semantics.js.map +1 -1
- package/build/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/modeling/Semantics.ts +226 -101
- package/tests/unit/modeling/semantics.spec.ts +73 -1
package/package.json
CHANGED
|
@@ -227,6 +227,44 @@ export enum SemanticScope {
|
|
|
227
227
|
Association = 'Association',
|
|
228
228
|
}
|
|
229
229
|
|
|
230
|
+
/**
|
|
231
|
+
* Defines categories for organizing semantics in the UI.
|
|
232
|
+
*/
|
|
233
|
+
export enum SemanticCategory {
|
|
234
|
+
/**
|
|
235
|
+
* User management, authentication, and access control
|
|
236
|
+
*/
|
|
237
|
+
Identity = 'Identity & Authentication',
|
|
238
|
+
/**
|
|
239
|
+
* Timestamps, versioning, and record lifecycle
|
|
240
|
+
*/
|
|
241
|
+
Lifecycle = 'Timestamps & Versioning',
|
|
242
|
+
/**
|
|
243
|
+
* Text content, media, and rich content types
|
|
244
|
+
*/
|
|
245
|
+
Content = 'Content & Media',
|
|
246
|
+
/**
|
|
247
|
+
* Business-specific data like pricing, inventory, status
|
|
248
|
+
*/
|
|
249
|
+
Business = 'Business Data',
|
|
250
|
+
/**
|
|
251
|
+
* Contact information and communication
|
|
252
|
+
*/
|
|
253
|
+
Contact = 'Contact Information',
|
|
254
|
+
/**
|
|
255
|
+
* Organization, categorization, and tagging
|
|
256
|
+
*/
|
|
257
|
+
Organization = 'Classification & Organization',
|
|
258
|
+
/**
|
|
259
|
+
* Location and geographical data
|
|
260
|
+
*/
|
|
261
|
+
Location = 'Location & Geography',
|
|
262
|
+
/**
|
|
263
|
+
* Calculated and derived values
|
|
264
|
+
*/
|
|
265
|
+
Computed = 'Computed Values',
|
|
266
|
+
}
|
|
267
|
+
|
|
230
268
|
/**
|
|
231
269
|
* A base interface for all Data Semantics, containing common properties.
|
|
232
270
|
* A semantic is an annotation applied to a Data Entity, Property, or Association
|
|
@@ -250,6 +288,10 @@ interface BaseDataSemantic {
|
|
|
250
288
|
* Specifies whether the semantic applies to an Entity, Property, or Association.
|
|
251
289
|
*/
|
|
252
290
|
scope: SemanticScope
|
|
291
|
+
/**
|
|
292
|
+
* The category this semantic belongs to for UI organization.
|
|
293
|
+
*/
|
|
294
|
+
category: SemanticCategory
|
|
253
295
|
}
|
|
254
296
|
|
|
255
297
|
/**
|
|
@@ -307,213 +349,296 @@ export type DataSemantic = EntitySemantic | PropertySemantic | AssociationSemant
|
|
|
307
349
|
*/
|
|
308
350
|
export const DataSemantics: Record<SemanticType, DataSemantic> = {
|
|
309
351
|
//
|
|
310
|
-
//
|
|
352
|
+
// Identity & Authentication
|
|
311
353
|
//
|
|
312
354
|
|
|
313
355
|
[SemanticType.User]: {
|
|
314
356
|
id: SemanticType.User,
|
|
315
357
|
displayName: 'User Entity',
|
|
316
358
|
scope: SemanticScope.Entity,
|
|
317
|
-
description: '
|
|
359
|
+
description: 'System users and accounts',
|
|
360
|
+
category: SemanticCategory.Identity,
|
|
318
361
|
},
|
|
319
|
-
|
|
320
|
-
//
|
|
321
|
-
// Property-Level Definitions
|
|
322
|
-
//
|
|
323
|
-
|
|
324
362
|
[SemanticType.Password]: {
|
|
325
363
|
id: SemanticType.Password,
|
|
326
364
|
displayName: 'User Password',
|
|
327
365
|
scope: SemanticScope.Property,
|
|
328
|
-
description:
|
|
329
|
-
|
|
366
|
+
description: 'Secure password field',
|
|
367
|
+
category: SemanticCategory.Identity,
|
|
368
|
+
applicableDataTypes: ['string'],
|
|
369
|
+
},
|
|
370
|
+
[SemanticType.UserRole]: {
|
|
371
|
+
id: SemanticType.UserRole,
|
|
372
|
+
displayName: 'User Role Field',
|
|
373
|
+
scope: SemanticScope.Property,
|
|
374
|
+
description: 'User permissions and access level',
|
|
375
|
+
category: SemanticCategory.Identity,
|
|
330
376
|
applicableDataTypes: ['string'],
|
|
331
377
|
},
|
|
378
|
+
[SemanticType.ResourceOwnerIdentifier]: {
|
|
379
|
+
id: SemanticType.ResourceOwnerIdentifier,
|
|
380
|
+
displayName: 'Resource Owner Identifier',
|
|
381
|
+
scope: SemanticScope.Association,
|
|
382
|
+
description: 'Links record to owner user',
|
|
383
|
+
category: SemanticCategory.Identity,
|
|
384
|
+
},
|
|
385
|
+
|
|
386
|
+
//
|
|
387
|
+
// Timestamps & Versioning
|
|
388
|
+
//
|
|
389
|
+
|
|
332
390
|
[SemanticType.CreatedTimestamp]: {
|
|
333
391
|
id: SemanticType.CreatedTimestamp,
|
|
334
392
|
displayName: 'Creation Timestamp',
|
|
335
393
|
scope: SemanticScope.Property,
|
|
336
|
-
description:
|
|
394
|
+
description: 'When record was created',
|
|
395
|
+
category: SemanticCategory.Lifecycle,
|
|
337
396
|
applicableDataTypes: ['datetime'],
|
|
338
397
|
},
|
|
339
398
|
[SemanticType.UpdatedTimestamp]: {
|
|
340
399
|
id: SemanticType.UpdatedTimestamp,
|
|
341
400
|
displayName: 'Update Timestamp',
|
|
342
401
|
scope: SemanticScope.Property,
|
|
343
|
-
description:
|
|
402
|
+
description: 'When record was last modified',
|
|
403
|
+
category: SemanticCategory.Lifecycle,
|
|
344
404
|
applicableDataTypes: ['datetime'],
|
|
345
405
|
},
|
|
346
406
|
[SemanticType.DeletedTimestamp]: {
|
|
347
407
|
id: SemanticType.DeletedTimestamp,
|
|
348
408
|
displayName: 'Soft Delete Timestamp',
|
|
349
409
|
scope: SemanticScope.Property,
|
|
350
|
-
description:
|
|
410
|
+
description: 'When record was marked deleted',
|
|
411
|
+
category: SemanticCategory.Lifecycle,
|
|
351
412
|
applicableDataTypes: ['datetime'],
|
|
352
413
|
},
|
|
353
|
-
[SemanticType.
|
|
354
|
-
id: SemanticType.
|
|
355
|
-
displayName: '
|
|
414
|
+
[SemanticType.DeletedFlag]: {
|
|
415
|
+
id: SemanticType.DeletedFlag,
|
|
416
|
+
displayName: 'Soft Delete Flag',
|
|
356
417
|
scope: SemanticScope.Property,
|
|
357
|
-
description: '
|
|
358
|
-
|
|
418
|
+
description: 'Mark record as deleted',
|
|
419
|
+
category: SemanticCategory.Lifecycle,
|
|
420
|
+
applicableDataTypes: ['boolean'],
|
|
421
|
+
},
|
|
422
|
+
[SemanticType.Version]: {
|
|
423
|
+
id: SemanticType.Version,
|
|
424
|
+
displayName: 'Version Number',
|
|
425
|
+
scope: SemanticScope.Property,
|
|
426
|
+
description: 'Auto-incrementing version counter',
|
|
427
|
+
category: SemanticCategory.Lifecycle,
|
|
428
|
+
applicableDataTypes: ['number'],
|
|
359
429
|
},
|
|
430
|
+
|
|
431
|
+
//
|
|
432
|
+
// Content & Media
|
|
433
|
+
//
|
|
434
|
+
|
|
360
435
|
[SemanticType.Title]: {
|
|
361
436
|
id: SemanticType.Title,
|
|
362
437
|
displayName: 'Record Title',
|
|
363
438
|
scope: SemanticScope.Property,
|
|
364
|
-
description: '
|
|
439
|
+
description: 'Main title or heading',
|
|
440
|
+
category: SemanticCategory.Content,
|
|
365
441
|
applicableDataTypes: ['string'],
|
|
366
442
|
},
|
|
367
|
-
[SemanticType.
|
|
368
|
-
id: SemanticType.
|
|
369
|
-
displayName: '
|
|
443
|
+
[SemanticType.Description]: {
|
|
444
|
+
id: SemanticType.Description,
|
|
445
|
+
displayName: 'Description',
|
|
370
446
|
scope: SemanticScope.Property,
|
|
371
|
-
description:
|
|
447
|
+
description: 'Detailed description text',
|
|
448
|
+
category: SemanticCategory.Content,
|
|
372
449
|
applicableDataTypes: ['string'],
|
|
373
450
|
},
|
|
374
|
-
[SemanticType.
|
|
375
|
-
id: SemanticType.
|
|
376
|
-
displayName: '
|
|
451
|
+
[SemanticType.Summary]: {
|
|
452
|
+
id: SemanticType.Summary,
|
|
453
|
+
displayName: 'Summary',
|
|
377
454
|
scope: SemanticScope.Property,
|
|
378
|
-
description: '
|
|
455
|
+
description: 'Brief summary text',
|
|
456
|
+
category: SemanticCategory.Content,
|
|
379
457
|
applicableDataTypes: ['string'],
|
|
380
458
|
},
|
|
381
|
-
[SemanticType.
|
|
382
|
-
id: SemanticType.
|
|
383
|
-
displayName: '
|
|
459
|
+
[SemanticType.Markdown]: {
|
|
460
|
+
id: SemanticType.Markdown,
|
|
461
|
+
displayName: 'Markdown Content',
|
|
384
462
|
scope: SemanticScope.Property,
|
|
385
|
-
description: '
|
|
386
|
-
|
|
463
|
+
description: 'Formatted text content',
|
|
464
|
+
category: SemanticCategory.Content,
|
|
465
|
+
applicableDataTypes: ['string'],
|
|
466
|
+
},
|
|
467
|
+
[SemanticType.HTML]: {
|
|
468
|
+
id: SemanticType.HTML,
|
|
469
|
+
displayName: 'HTML Content',
|
|
470
|
+
scope: SemanticScope.Property,
|
|
471
|
+
description: 'Rich HTML content',
|
|
472
|
+
category: SemanticCategory.Content,
|
|
473
|
+
applicableDataTypes: ['string'],
|
|
387
474
|
},
|
|
388
475
|
[SemanticType.ImageURL]: {
|
|
389
476
|
id: SemanticType.ImageURL,
|
|
390
477
|
displayName: 'Image URL',
|
|
391
478
|
scope: SemanticScope.Property,
|
|
392
|
-
description: '
|
|
479
|
+
description: 'Link to image file',
|
|
480
|
+
category: SemanticCategory.Content,
|
|
393
481
|
applicableDataTypes: ['string'],
|
|
394
482
|
},
|
|
395
483
|
[SemanticType.FileURL]: {
|
|
396
484
|
id: SemanticType.FileURL,
|
|
397
485
|
displayName: 'File URL',
|
|
398
486
|
scope: SemanticScope.Property,
|
|
399
|
-
description: '
|
|
487
|
+
description: 'Link to file attachment',
|
|
488
|
+
category: SemanticCategory.Content,
|
|
400
489
|
applicableDataTypes: ['string'],
|
|
401
490
|
},
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
id: SemanticType.Markdown,
|
|
411
|
-
displayName: 'Markdown Content',
|
|
491
|
+
|
|
492
|
+
//
|
|
493
|
+
// Business Data
|
|
494
|
+
//
|
|
495
|
+
|
|
496
|
+
[SemanticType.Status]: {
|
|
497
|
+
id: SemanticType.Status,
|
|
498
|
+
displayName: 'Record Status',
|
|
412
499
|
scope: SemanticScope.Property,
|
|
413
|
-
description: '
|
|
500
|
+
description: 'Current state of record',
|
|
501
|
+
category: SemanticCategory.Business,
|
|
414
502
|
applicableDataTypes: ['string'],
|
|
415
503
|
},
|
|
416
|
-
[SemanticType.
|
|
417
|
-
id: SemanticType.
|
|
418
|
-
displayName: '
|
|
504
|
+
[SemanticType.Price]: {
|
|
505
|
+
id: SemanticType.Price,
|
|
506
|
+
displayName: 'Price',
|
|
419
507
|
scope: SemanticScope.Property,
|
|
420
|
-
description: '
|
|
421
|
-
|
|
508
|
+
description: 'Monetary value with currency',
|
|
509
|
+
category: SemanticCategory.Business,
|
|
510
|
+
applicableDataTypes: ['number', 'string'],
|
|
422
511
|
},
|
|
423
|
-
[SemanticType.
|
|
424
|
-
id: SemanticType.
|
|
425
|
-
displayName: '
|
|
512
|
+
[SemanticType.SKU]: {
|
|
513
|
+
id: SemanticType.SKU,
|
|
514
|
+
displayName: 'SKU',
|
|
426
515
|
scope: SemanticScope.Property,
|
|
427
|
-
description: '
|
|
516
|
+
description: 'Product identification code',
|
|
517
|
+
category: SemanticCategory.Business,
|
|
428
518
|
applicableDataTypes: ['string'],
|
|
429
519
|
},
|
|
520
|
+
|
|
521
|
+
//
|
|
522
|
+
// Contact Information
|
|
523
|
+
//
|
|
524
|
+
|
|
430
525
|
[SemanticType.Email]: {
|
|
431
526
|
id: SemanticType.Email,
|
|
432
527
|
displayName: 'Email',
|
|
433
528
|
scope: SemanticScope.Property,
|
|
434
|
-
description: '
|
|
529
|
+
description: 'Email address',
|
|
530
|
+
category: SemanticCategory.Contact,
|
|
435
531
|
applicableDataTypes: ['string'],
|
|
436
532
|
},
|
|
437
533
|
[SemanticType.Phone]: {
|
|
438
534
|
id: SemanticType.Phone,
|
|
439
535
|
displayName: 'Phone',
|
|
440
536
|
scope: SemanticScope.Property,
|
|
441
|
-
description: '
|
|
537
|
+
description: 'Phone number',
|
|
538
|
+
category: SemanticCategory.Contact,
|
|
442
539
|
applicableDataTypes: ['string'],
|
|
443
540
|
},
|
|
444
|
-
[SemanticType.Price]: {
|
|
445
|
-
id: SemanticType.Price,
|
|
446
|
-
displayName: 'Price',
|
|
447
|
-
scope: SemanticScope.Property,
|
|
448
|
-
description: 'Annotates a field as a monetary value with currency support and precision control.',
|
|
449
|
-
applicableDataTypes: ['number', 'string'],
|
|
450
|
-
},
|
|
451
541
|
[SemanticType.URL]: {
|
|
452
542
|
id: SemanticType.URL,
|
|
453
543
|
displayName: 'URL',
|
|
454
544
|
scope: SemanticScope.Property,
|
|
455
|
-
description: '
|
|
545
|
+
description: 'Web address or link',
|
|
546
|
+
category: SemanticCategory.Contact,
|
|
456
547
|
applicableDataTypes: ['string'],
|
|
457
548
|
},
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
549
|
+
|
|
550
|
+
//
|
|
551
|
+
// Classification & Organization
|
|
552
|
+
//
|
|
553
|
+
|
|
554
|
+
[SemanticType.PublicUniqueName]: {
|
|
555
|
+
id: SemanticType.PublicUniqueName,
|
|
556
|
+
displayName: 'Public Unique Name (Slug)',
|
|
461
557
|
scope: SemanticScope.Property,
|
|
462
|
-
description:
|
|
463
|
-
|
|
558
|
+
description: 'URL-friendly unique identifier',
|
|
559
|
+
category: SemanticCategory.Organization,
|
|
464
560
|
applicableDataTypes: ['string'],
|
|
465
561
|
},
|
|
466
|
-
[SemanticType.
|
|
467
|
-
id: SemanticType.
|
|
468
|
-
displayName: '
|
|
469
|
-
scope: SemanticScope.
|
|
470
|
-
description: '
|
|
471
|
-
|
|
562
|
+
[SemanticType.Tags]: {
|
|
563
|
+
id: SemanticType.Tags,
|
|
564
|
+
displayName: 'Tags',
|
|
565
|
+
scope: SemanticScope.Association,
|
|
566
|
+
description: 'Enable tagging functionality',
|
|
567
|
+
category: SemanticCategory.Organization,
|
|
472
568
|
},
|
|
473
|
-
[SemanticType.
|
|
474
|
-
id: SemanticType.
|
|
475
|
-
displayName: '
|
|
569
|
+
[SemanticType.Categories]: {
|
|
570
|
+
id: SemanticType.Categories,
|
|
571
|
+
displayName: 'Categories',
|
|
572
|
+
scope: SemanticScope.Association,
|
|
573
|
+
description: 'Enable categorization functionality',
|
|
574
|
+
category: SemanticCategory.Organization,
|
|
575
|
+
},
|
|
576
|
+
|
|
577
|
+
//
|
|
578
|
+
// Location & Geography
|
|
579
|
+
//
|
|
580
|
+
|
|
581
|
+
[SemanticType.GeospatialCoordinates]: {
|
|
582
|
+
id: SemanticType.GeospatialCoordinates,
|
|
583
|
+
displayName: 'Geospatial Coordinates',
|
|
476
584
|
scope: SemanticScope.Property,
|
|
477
|
-
description: '
|
|
585
|
+
description: 'Location coordinates',
|
|
586
|
+
category: SemanticCategory.Location,
|
|
478
587
|
applicableDataTypes: ['string'],
|
|
479
588
|
},
|
|
589
|
+
|
|
590
|
+
//
|
|
591
|
+
// Computed Values
|
|
592
|
+
//
|
|
593
|
+
|
|
480
594
|
[SemanticType.Calculated]: {
|
|
481
595
|
id: SemanticType.Calculated,
|
|
482
596
|
displayName: 'Calculated',
|
|
483
597
|
scope: SemanticScope.Property,
|
|
484
|
-
description: '
|
|
598
|
+
description: 'Auto-calculated field value',
|
|
599
|
+
category: SemanticCategory.Computed,
|
|
485
600
|
applicableDataTypes: ['string'],
|
|
486
601
|
},
|
|
487
602
|
[SemanticType.Derived]: {
|
|
488
603
|
id: SemanticType.Derived,
|
|
489
604
|
displayName: 'Derived',
|
|
490
605
|
scope: SemanticScope.Property,
|
|
491
|
-
description: '
|
|
606
|
+
description: 'Value derived from other fields',
|
|
607
|
+
category: SemanticCategory.Computed,
|
|
492
608
|
applicableDataTypes: ['string'],
|
|
493
609
|
},
|
|
610
|
+
}
|
|
494
611
|
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
612
|
+
/**
|
|
613
|
+
* Helper function to get all semantics grouped by category.
|
|
614
|
+
* Useful for organizing semantics in UI dropdowns and forms.
|
|
615
|
+
*/
|
|
616
|
+
export const getSemanticsByCategory = (): Record<SemanticCategory, DataSemantic[]> => {
|
|
617
|
+
const result: Record<SemanticCategory, DataSemantic[]> = {
|
|
618
|
+
[SemanticCategory.Identity]: [],
|
|
619
|
+
[SemanticCategory.Lifecycle]: [],
|
|
620
|
+
[SemanticCategory.Content]: [],
|
|
621
|
+
[SemanticCategory.Business]: [],
|
|
622
|
+
[SemanticCategory.Contact]: [],
|
|
623
|
+
[SemanticCategory.Organization]: [],
|
|
624
|
+
[SemanticCategory.Location]: [],
|
|
625
|
+
[SemanticCategory.Computed]: [],
|
|
626
|
+
}
|
|
498
627
|
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
displayName: 'Categories',
|
|
514
|
-
scope: SemanticScope.Association,
|
|
515
|
-
description: 'Annotates an association as supporting category functionality.',
|
|
516
|
-
},
|
|
628
|
+
Object.values(DataSemantics).forEach((semantic) => {
|
|
629
|
+
result[semantic.category].push(semantic)
|
|
630
|
+
})
|
|
631
|
+
|
|
632
|
+
return result
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
/**
|
|
636
|
+
* Helper function to get semantics for a specific category.
|
|
637
|
+
* @param category The category to filter by
|
|
638
|
+
* @returns Array of semantics in the specified category
|
|
639
|
+
*/
|
|
640
|
+
export const getSemanticsByCategoryType = (category: SemanticCategory): DataSemantic[] => {
|
|
641
|
+
return Object.values(DataSemantics).filter((semantic) => semantic.category === category)
|
|
517
642
|
}
|
|
518
643
|
|
|
519
644
|
/**
|
|
@@ -2,10 +2,13 @@ import { test } from '@japa/runner'
|
|
|
2
2
|
import {
|
|
3
3
|
SemanticType,
|
|
4
4
|
SemanticScope,
|
|
5
|
+
SemanticCategory,
|
|
5
6
|
isEntitySemantic,
|
|
6
7
|
isPropertySemantic,
|
|
7
8
|
isAssociationSemantic,
|
|
8
9
|
DataSemantics,
|
|
10
|
+
getSemanticsByCategory,
|
|
11
|
+
getSemanticsByCategoryType,
|
|
9
12
|
type EntitySemantic,
|
|
10
13
|
type PropertySemantic,
|
|
11
14
|
type AssociationSemantic,
|
|
@@ -45,18 +48,21 @@ test.group('Semantics', () => {
|
|
|
45
48
|
displayName: 'User Entity',
|
|
46
49
|
description: 'Test',
|
|
47
50
|
scope: SemanticScope.Entity,
|
|
51
|
+
category: SemanticCategory.Identity,
|
|
48
52
|
}
|
|
49
53
|
const propertySemantic: PropertySemantic = {
|
|
50
54
|
id: SemanticType.CreatedTimestamp,
|
|
51
55
|
displayName: 'Creation Timestamp',
|
|
52
56
|
description: 'Test',
|
|
53
57
|
scope: SemanticScope.Property,
|
|
58
|
+
category: SemanticCategory.Lifecycle,
|
|
54
59
|
}
|
|
55
60
|
const associationSemantic: AssociationSemantic = {
|
|
56
61
|
id: SemanticType.ResourceOwnerIdentifier,
|
|
57
62
|
displayName: 'Resource Owner Identifier',
|
|
58
63
|
description: 'Test',
|
|
59
64
|
scope: SemanticScope.Association,
|
|
65
|
+
category: SemanticCategory.Identity,
|
|
60
66
|
}
|
|
61
67
|
|
|
62
68
|
assert.isTrue(isEntitySemantic(entitySemantic))
|
|
@@ -70,18 +76,21 @@ test.group('Semantics', () => {
|
|
|
70
76
|
displayName: 'User Entity',
|
|
71
77
|
description: 'Test',
|
|
72
78
|
scope: SemanticScope.Entity,
|
|
79
|
+
category: SemanticCategory.Identity,
|
|
73
80
|
}
|
|
74
81
|
const propertySemantic: PropertySemantic = {
|
|
75
82
|
id: SemanticType.CreatedTimestamp,
|
|
76
83
|
displayName: 'Creation Timestamp',
|
|
77
84
|
description: 'Test',
|
|
78
85
|
scope: SemanticScope.Property,
|
|
86
|
+
category: SemanticCategory.Lifecycle,
|
|
79
87
|
}
|
|
80
88
|
const associationSemantic: AssociationSemantic = {
|
|
81
89
|
id: SemanticType.ResourceOwnerIdentifier,
|
|
82
90
|
displayName: 'Resource Owner Identifier',
|
|
83
91
|
description: 'Test',
|
|
84
92
|
scope: SemanticScope.Association,
|
|
93
|
+
category: SemanticCategory.Identity,
|
|
85
94
|
}
|
|
86
95
|
|
|
87
96
|
assert.isFalse(isPropertySemantic(entitySemantic))
|
|
@@ -95,18 +104,21 @@ test.group('Semantics', () => {
|
|
|
95
104
|
displayName: 'User Entity',
|
|
96
105
|
description: 'Test',
|
|
97
106
|
scope: SemanticScope.Entity,
|
|
107
|
+
category: SemanticCategory.Identity,
|
|
98
108
|
}
|
|
99
109
|
const propertySemantic: PropertySemantic = {
|
|
100
110
|
id: SemanticType.CreatedTimestamp,
|
|
101
111
|
displayName: 'Creation Timestamp',
|
|
102
112
|
description: 'Test',
|
|
103
113
|
scope: SemanticScope.Property,
|
|
114
|
+
category: SemanticCategory.Lifecycle,
|
|
104
115
|
}
|
|
105
116
|
const associationSemantic: AssociationSemantic = {
|
|
106
117
|
id: SemanticType.ResourceOwnerIdentifier,
|
|
107
118
|
displayName: 'Resource Owner Identifier',
|
|
108
119
|
description: 'Test',
|
|
109
120
|
scope: SemanticScope.Association,
|
|
121
|
+
category: SemanticCategory.Identity,
|
|
110
122
|
}
|
|
111
123
|
|
|
112
124
|
assert.isFalse(isAssociationSemantic(entitySemantic))
|
|
@@ -128,6 +140,11 @@ test.group('Semantics', () => {
|
|
|
128
140
|
assert.isNotEmpty(semantic.description, `description for ${type} should not be empty`)
|
|
129
141
|
|
|
130
142
|
assert.oneOf(semantic.scope, Object.values(SemanticScope), `scope for ${type} should be a valid SemanticScope`)
|
|
143
|
+
assert.oneOf(
|
|
144
|
+
semantic.category,
|
|
145
|
+
Object.values(SemanticCategory),
|
|
146
|
+
`category for ${type} should be a valid SemanticCategory`
|
|
147
|
+
)
|
|
131
148
|
|
|
132
149
|
if (isPropertySemantic(semantic)) {
|
|
133
150
|
if (semantic.applicableDataTypes) {
|
|
@@ -142,15 +159,18 @@ test.group('Semantics', () => {
|
|
|
142
159
|
// Specific checks for some semantics
|
|
143
160
|
const userSemantic = DataSemantics[SemanticType.User]
|
|
144
161
|
assert.equal(userSemantic.scope, SemanticScope.Entity)
|
|
162
|
+
assert.equal(userSemantic.category, SemanticCategory.Identity)
|
|
145
163
|
|
|
146
164
|
const createdTimestampSemantic = DataSemantics[SemanticType.CreatedTimestamp]
|
|
147
165
|
assert.equal(createdTimestampSemantic.scope, SemanticScope.Property)
|
|
166
|
+
assert.equal(createdTimestampSemantic.category, SemanticCategory.Lifecycle)
|
|
148
167
|
if (isPropertySemantic(createdTimestampSemantic)) {
|
|
149
168
|
assert.deepEqual(createdTimestampSemantic.applicableDataTypes, ['datetime'])
|
|
150
169
|
}
|
|
151
170
|
|
|
152
171
|
const resourceOwnerSemantic = DataSemantics[SemanticType.ResourceOwnerIdentifier]
|
|
153
172
|
assert.equal(resourceOwnerSemantic.scope, SemanticScope.Association)
|
|
173
|
+
assert.equal(resourceOwnerSemantic.category, SemanticCategory.Identity)
|
|
154
174
|
})
|
|
155
175
|
|
|
156
176
|
test('GeospatialCoordinates semantic should have correct definition', ({ assert }) => {
|
|
@@ -193,6 +213,58 @@ test.group('Semantics', () => {
|
|
|
193
213
|
const description = geospatialSemantic.description
|
|
194
214
|
|
|
195
215
|
// Check that the description mentions key features
|
|
196
|
-
assert.equal(description, '
|
|
216
|
+
assert.equal(description, 'Location coordinates')
|
|
217
|
+
})
|
|
218
|
+
|
|
219
|
+
test('getSemanticsByCategory should group semantics correctly', ({ assert }) => {
|
|
220
|
+
const semanticsByCategory = getSemanticsByCategory()
|
|
221
|
+
|
|
222
|
+
// Check that all categories are present
|
|
223
|
+
const expectedCategories = Object.values(SemanticCategory)
|
|
224
|
+
expectedCategories.forEach((category) => {
|
|
225
|
+
assert.isDefined(semanticsByCategory[category], `Category ${category} should be present`)
|
|
226
|
+
assert.isArray(semanticsByCategory[category], `Category ${category} should be an array`)
|
|
227
|
+
})
|
|
228
|
+
|
|
229
|
+
// Check that User semantic is in Identity category
|
|
230
|
+
const identitySemantics = semanticsByCategory[SemanticCategory.Identity]
|
|
231
|
+
const userSemantic = identitySemantics.find((s) => s.id === SemanticType.User)
|
|
232
|
+
assert.isDefined(userSemantic, 'User semantic should be in Identity category')
|
|
233
|
+
|
|
234
|
+
// Check that CreatedTimestamp is in Lifecycle category
|
|
235
|
+
const lifecycleSemantics = semanticsByCategory[SemanticCategory.Lifecycle]
|
|
236
|
+
const createdTimestampSemantic = lifecycleSemantics.find((s) => s.id === SemanticType.CreatedTimestamp)
|
|
237
|
+
assert.isDefined(createdTimestampSemantic, 'CreatedTimestamp semantic should be in Lifecycle category')
|
|
238
|
+
|
|
239
|
+
// Check that Title is in Content category
|
|
240
|
+
const contentSemantics = semanticsByCategory[SemanticCategory.Content]
|
|
241
|
+
const titleSemantic = contentSemantics.find((s) => s.id === SemanticType.Title)
|
|
242
|
+
assert.isDefined(titleSemantic, 'Title semantic should be in Content category')
|
|
243
|
+
|
|
244
|
+
// Verify all semantics are categorized (total count should match)
|
|
245
|
+
const totalSemantics = Object.values(semanticsByCategory).flat().length
|
|
246
|
+
const allSemantics = Object.values(DataSemantics).length
|
|
247
|
+
assert.equal(totalSemantics, allSemantics, 'All semantics should be categorized')
|
|
248
|
+
})
|
|
249
|
+
|
|
250
|
+
test('getSemanticsByCategoryType should filter semantics by category', ({ assert }) => {
|
|
251
|
+
const identitySemantics = getSemanticsByCategoryType(SemanticCategory.Identity)
|
|
252
|
+
|
|
253
|
+
// All returned semantics should be in Identity category
|
|
254
|
+
identitySemantics.forEach((semantic) => {
|
|
255
|
+
assert.equal(semantic.category, SemanticCategory.Identity, 'All semantics should be in Identity category')
|
|
256
|
+
})
|
|
257
|
+
|
|
258
|
+
// Should include User semantic
|
|
259
|
+
const userSemantic = identitySemantics.find((s) => s.id === SemanticType.User)
|
|
260
|
+
assert.isDefined(userSemantic, 'Should include User semantic')
|
|
261
|
+
|
|
262
|
+
// Should include Password semantic
|
|
263
|
+
const passwordSemantic = identitySemantics.find((s) => s.id === SemanticType.Password)
|
|
264
|
+
assert.isDefined(passwordSemantic, 'Should include Password semantic')
|
|
265
|
+
|
|
266
|
+
// Test empty result for a category with no semantics (if any)
|
|
267
|
+
const locationSemantics = getSemanticsByCategoryType(SemanticCategory.Location)
|
|
268
|
+
assert.isArray(locationSemantics, 'Should return an array even if empty')
|
|
197
269
|
})
|
|
198
270
|
})
|