@api-client/core 0.15.1 → 0.16.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.
Files changed (126) hide show
  1. package/TESTING_READY.md +114 -0
  2. package/TESTING_SETUP.md +198 -0
  3. package/build/src/modeling/Semantics.d.ts +126 -2
  4. package/build/src/modeling/Semantics.d.ts.map +1 -1
  5. package/build/src/modeling/Semantics.js +281 -13
  6. package/build/src/modeling/Semantics.js.map +1 -1
  7. package/build/src/modeling/definitions/Calculated.d.ts +54 -0
  8. package/build/src/modeling/definitions/Calculated.d.ts.map +1 -0
  9. package/build/src/modeling/definitions/Calculated.js +31 -0
  10. package/build/src/modeling/definitions/Calculated.js.map +1 -0
  11. package/build/src/modeling/definitions/Categories.d.ts +60 -0
  12. package/build/src/modeling/definitions/Categories.d.ts.map +1 -0
  13. package/build/src/modeling/definitions/Categories.js +33 -0
  14. package/build/src/modeling/definitions/Categories.js.map +1 -0
  15. package/build/src/modeling/definitions/Derived.d.ts +54 -0
  16. package/build/src/modeling/definitions/Derived.d.ts.map +1 -0
  17. package/build/src/modeling/definitions/Derived.js +31 -0
  18. package/build/src/modeling/definitions/Derived.js.map +1 -0
  19. package/build/src/modeling/definitions/Description.d.ts +36 -0
  20. package/build/src/modeling/definitions/Description.d.ts.map +1 -0
  21. package/build/src/modeling/definitions/Description.js +28 -0
  22. package/build/src/modeling/definitions/Description.js.map +1 -0
  23. package/build/src/modeling/definitions/Email.d.ts +66 -0
  24. package/build/src/modeling/definitions/Email.d.ts.map +1 -0
  25. package/build/src/modeling/definitions/Email.js +33 -0
  26. package/build/src/modeling/definitions/Email.js.map +1 -0
  27. package/build/src/modeling/definitions/GeospatialCoordinates.d.ts +212 -0
  28. package/build/src/modeling/definitions/GeospatialCoordinates.d.ts.map +1 -0
  29. package/build/src/modeling/definitions/GeospatialCoordinates.js +129 -0
  30. package/build/src/modeling/definitions/GeospatialCoordinates.js.map +1 -0
  31. package/build/src/modeling/definitions/HTML.d.ts +88 -0
  32. package/build/src/modeling/definitions/HTML.d.ts.map +1 -0
  33. package/build/src/modeling/definitions/HTML.js +42 -0
  34. package/build/src/modeling/definitions/HTML.js.map +1 -0
  35. package/build/src/modeling/definitions/Markdown.d.ts +84 -0
  36. package/build/src/modeling/definitions/Markdown.d.ts.map +1 -0
  37. package/build/src/modeling/definitions/Markdown.js +41 -0
  38. package/build/src/modeling/definitions/Markdown.js.map +1 -0
  39. package/build/src/modeling/definitions/Password.d.ts +112 -0
  40. package/build/src/modeling/definitions/Password.d.ts.map +1 -0
  41. package/build/src/modeling/definitions/Password.js +57 -0
  42. package/build/src/modeling/definitions/Password.js.map +1 -0
  43. package/build/src/modeling/definitions/Phone.d.ts +83 -0
  44. package/build/src/modeling/definitions/Phone.d.ts.map +1 -0
  45. package/build/src/modeling/definitions/Phone.js +39 -0
  46. package/build/src/modeling/definitions/Phone.js.map +1 -0
  47. package/build/src/modeling/definitions/Price.d.ts +102 -0
  48. package/build/src/modeling/definitions/Price.d.ts.map +1 -0
  49. package/build/src/modeling/definitions/Price.js +99 -0
  50. package/build/src/modeling/definitions/Price.js.map +1 -0
  51. package/build/src/modeling/definitions/PublicUniqueName.d.ts +69 -0
  52. package/build/src/modeling/definitions/PublicUniqueName.d.ts.map +1 -0
  53. package/build/src/modeling/definitions/PublicUniqueName.js +34 -0
  54. package/build/src/modeling/definitions/PublicUniqueName.js.map +1 -0
  55. package/build/src/modeling/definitions/SKU.d.ts +127 -0
  56. package/build/src/modeling/definitions/SKU.d.ts.map +1 -0
  57. package/build/src/modeling/definitions/SKU.js +142 -0
  58. package/build/src/modeling/definitions/SKU.js.map +1 -0
  59. package/build/src/modeling/definitions/Status.d.ts +150 -0
  60. package/build/src/modeling/definitions/Status.d.ts.map +1 -0
  61. package/build/src/modeling/definitions/Status.js +60 -0
  62. package/build/src/modeling/definitions/Status.js.map +1 -0
  63. package/build/src/modeling/definitions/Summary.d.ts +53 -0
  64. package/build/src/modeling/definitions/Summary.d.ts.map +1 -0
  65. package/build/src/modeling/definitions/Summary.js +50 -0
  66. package/build/src/modeling/definitions/Summary.js.map +1 -0
  67. package/build/src/modeling/definitions/Tags.d.ts +52 -0
  68. package/build/src/modeling/definitions/Tags.d.ts.map +1 -0
  69. package/build/src/modeling/definitions/Tags.js +32 -0
  70. package/build/src/modeling/definitions/Tags.js.map +1 -0
  71. package/build/src/modeling/definitions/URL.d.ts +68 -0
  72. package/build/src/modeling/definitions/URL.d.ts.map +1 -0
  73. package/build/src/modeling/definitions/URL.js +37 -0
  74. package/build/src/modeling/definitions/URL.js.map +1 -0
  75. package/build/src/modeling/validation/semantic_validation.d.ts +4 -0
  76. package/build/src/modeling/validation/semantic_validation.d.ts.map +1 -1
  77. package/build/src/modeling/validation/semantic_validation.js +32 -1
  78. package/build/src/modeling/validation/semantic_validation.js.map +1 -1
  79. package/build/tsconfig.tsbuildinfo +1 -1
  80. package/data/models/example-generator-api.json +11 -11
  81. package/package.json +1 -1
  82. package/src/modeling/Semantics.ts +297 -14
  83. package/src/modeling/definitions/Calculated.ts +76 -0
  84. package/src/modeling/definitions/Categories.ts +84 -0
  85. package/src/modeling/definitions/Derived.ts +76 -0
  86. package/src/modeling/definitions/Description.ts +55 -0
  87. package/src/modeling/definitions/Email.ts +90 -0
  88. package/src/modeling/definitions/GeospatialCoordinates.ts +274 -0
  89. package/src/modeling/definitions/HTML.ts +121 -0
  90. package/src/modeling/definitions/Markdown.ts +116 -0
  91. package/src/modeling/definitions/Password.ts +156 -0
  92. package/src/modeling/definitions/Phone.ts +116 -0
  93. package/src/modeling/definitions/Price.examples.md +158 -0
  94. package/src/modeling/definitions/Price.ts +180 -0
  95. package/src/modeling/definitions/PublicUniqueName.ts +98 -0
  96. package/src/modeling/definitions/SKU.examples.md +230 -0
  97. package/src/modeling/definitions/SKU.ts +254 -0
  98. package/src/modeling/definitions/Status.ts +227 -0
  99. package/src/modeling/definitions/Summary.ts +73 -0
  100. package/src/modeling/definitions/Tags.ts +75 -0
  101. package/src/modeling/definitions/URL.ts +96 -0
  102. package/src/modeling/validation/semantic_validation.ts +35 -1
  103. package/tests/example-test-setup.ts +133 -0
  104. package/tests/template-node.spec.ts +75 -0
  105. package/tests/test-utils.ts +293 -0
  106. package/tests/unit/modeling/definitions/calculated.spec.ts +33 -0
  107. package/tests/unit/modeling/definitions/categories.spec.ts +38 -0
  108. package/tests/unit/modeling/definitions/derived.spec.ts +34 -0
  109. package/tests/unit/modeling/definitions/description.spec.ts +38 -0
  110. package/tests/unit/modeling/definitions/email.spec.ts +38 -0
  111. package/tests/unit/modeling/definitions/geospatial-coordinates.spec.ts +41 -0
  112. package/tests/unit/modeling/definitions/html.spec.ts +38 -0
  113. package/tests/unit/modeling/definitions/markdown.spec.ts +38 -0
  114. package/tests/unit/modeling/definitions/password.spec.ts +347 -0
  115. package/tests/unit/modeling/definitions/phone.spec.ts +38 -0
  116. package/tests/unit/modeling/definitions/price.spec.ts +465 -0
  117. package/tests/unit/modeling/definitions/public-unique-name.spec.ts +38 -0
  118. package/tests/unit/modeling/definitions/sku.spec.ts +240 -0
  119. package/tests/unit/modeling/definitions/status.spec.ts +37 -0
  120. package/tests/unit/modeling/definitions/summary.spec.ts +36 -0
  121. package/tests/unit/modeling/definitions/tags.spec.ts +38 -0
  122. package/tests/unit/modeling/definitions/url.spec.ts +38 -0
  123. package/tests/unit/modeling/domain_property.spec.ts +106 -0
  124. package/tests/unit/modeling/domain_validation.spec.ts +5 -5
  125. package/tests/unit/modeling/semantic-configs.spec.ts +569 -0
  126. package/tests/unit/modeling/semantics.spec.ts +52 -0
@@ -0,0 +1,569 @@
1
+ import { test } from '@japa/runner'
2
+ import { SemanticType } from '../../../src/modeling/Semantics.js'
3
+
4
+ // Import semantic configuration modules that exist
5
+ import {
6
+ createGeospatialCoordinatesSemantic,
7
+ isGeospatialCoordinatesSemantic,
8
+ type GeospatialCoordinatesConfig,
9
+ DEFAULT_GEOSPATIAL_CONFIG,
10
+ GeospatialCoordinateFormat,
11
+ GeospatialDistanceUnit,
12
+ GeospatialSpatialReferenceSystem,
13
+ } from '../../../src/modeling/definitions/GeospatialCoordinates.js'
14
+
15
+ import {
16
+ createPasswordSemantic,
17
+ isPasswordSemantic,
18
+ type PasswordConfig,
19
+ DEFAULT_PASSWORD_CONFIG,
20
+ } from '../../../src/modeling/definitions/Password.js'
21
+
22
+ import {
23
+ createStatusSemantic,
24
+ isStatusSemantic,
25
+ type StatusConfig,
26
+ DEFAULT_STATUS_CONFIG,
27
+ } from '../../../src/modeling/definitions/Status.js'
28
+
29
+ import {
30
+ createPublicUniqueNameSemantic,
31
+ isPublicUniqueNameSemantic,
32
+ type PublicUniqueNameConfig,
33
+ DEFAULT_PUBLIC_UNIQUE_NAME_CONFIG,
34
+ } from '../../../src/modeling/definitions/PublicUniqueName.js'
35
+
36
+ import {
37
+ createMarkdownSemantic,
38
+ isMarkdownSemantic,
39
+ type MarkdownConfig,
40
+ DEFAULT_MARKDOWN_CONFIG,
41
+ } from '../../../src/modeling/definitions/Markdown.js'
42
+
43
+ import {
44
+ createHTMLSemantic,
45
+ isHTMLSemantic,
46
+ type HTMLConfig,
47
+ DEFAULT_HTML_CONFIG,
48
+ } from '../../../src/modeling/definitions/HTML.js'
49
+
50
+ import {
51
+ createEmailSemantic,
52
+ isEmailSemantic,
53
+ type EmailConfig,
54
+ DEFAULT_EMAIL_CONFIG,
55
+ } from '../../../src/modeling/definitions/Email.js'
56
+
57
+ import {
58
+ createPhoneSemantic,
59
+ isPhoneSemantic,
60
+ type PhoneConfig,
61
+ DEFAULT_PHONE_CONFIG,
62
+ } from '../../../src/modeling/definitions/Phone.js'
63
+
64
+ import {
65
+ createURLSemantic,
66
+ isURLSemantic,
67
+ type URLConfig,
68
+ DEFAULT_URL_CONFIG,
69
+ } from '../../../src/modeling/definitions/URL.js'
70
+
71
+ import {
72
+ createPriceSemantic,
73
+ isPriceSemantic,
74
+ type PriceConfig,
75
+ DEFAULT_PRICE_CONFIG,
76
+ PRICE_PRESETS,
77
+ } from '../../../src/modeling/definitions/Price.js'
78
+
79
+ import {
80
+ createSKUSemantic,
81
+ isSKUSemantic,
82
+ type SKUConfig,
83
+ DEFAULT_SKU_CONFIG,
84
+ SKU_PRESETS,
85
+ } from '../../../src/modeling/definitions/SKU.js'
86
+
87
+ import {
88
+ createDescriptionSemantic,
89
+ isDescriptionSemantic,
90
+ type DescriptionConfig,
91
+ DEFAULT_DESCRIPTION_CONFIG,
92
+ } from '../../../src/modeling/definitions/Description.js'
93
+
94
+ import {
95
+ createSummarySemantic,
96
+ isSummarySemantic,
97
+ type SummaryConfig,
98
+ DEFAULT_SUMMARY_CONFIG,
99
+ } from '../../../src/modeling/definitions/Summary.js'
100
+
101
+ import {
102
+ createCalculatedSemantic,
103
+ isCalculatedSemantic,
104
+ type CalculatedConfig,
105
+ } from '../../../src/modeling/definitions/Calculated.js'
106
+
107
+ import {
108
+ createDerivedSemantic,
109
+ isDerivedSemantic,
110
+ type DerivedConfig,
111
+ } from '../../../src/modeling/definitions/Derived.js'
112
+
113
+ import {
114
+ createTagsSemantic,
115
+ isTagsSemantic,
116
+ type TagsConfig,
117
+ DEFAULT_TAGS_CONFIG,
118
+ } from '../../../src/modeling/definitions/Tags.js'
119
+
120
+ import {
121
+ createCategoriesSemantic,
122
+ isCategoriesSemantic,
123
+ type CategoriesConfig,
124
+ DEFAULT_CATEGORIES_CONFIG,
125
+ } from '../../../src/modeling/definitions/Categories.js'
126
+
127
+ test.group('Semantic Configurations', () => {
128
+ test('GeospatialCoordinates: should create semantic with default config', ({ assert }) => {
129
+ const semantic = createGeospatialCoordinatesSemantic()
130
+ assert.equal(semantic.id, SemanticType.GeospatialCoordinates)
131
+ assert.deepEqual(semantic.config, DEFAULT_GEOSPATIAL_CONFIG)
132
+ })
133
+
134
+ test('GeospatialCoordinates: should create semantic with custom config', ({ assert }) => {
135
+ const config: GeospatialCoordinatesConfig = {
136
+ format: GeospatialCoordinateFormat.LatLon,
137
+ defaultDistanceUnit: GeospatialDistanceUnit.Kilometers,
138
+ spatialReferenceSystem: GeospatialSpatialReferenceSystem.WGS84,
139
+ }
140
+ const semantic = createGeospatialCoordinatesSemantic(config)
141
+ assert.equal(semantic.id, SemanticType.GeospatialCoordinates)
142
+ assert.deepEqual(semantic.config, { ...DEFAULT_GEOSPATIAL_CONFIG, ...config })
143
+ })
144
+
145
+ test('GeospatialCoordinates: should identify geospatial semantic', ({ assert }) => {
146
+ const semantic = createGeospatialCoordinatesSemantic()
147
+ assert.isTrue(isGeospatialCoordinatesSemantic(semantic))
148
+ })
149
+
150
+ test('Password: should create semantic with default config', ({ assert }) => {
151
+ const semantic = createPasswordSemantic()
152
+ assert.equal(semantic.id, SemanticType.Password)
153
+ assert.deepEqual(semantic.config, DEFAULT_PASSWORD_CONFIG)
154
+ })
155
+
156
+ test('Password: should create semantic with custom config', ({ assert }) => {
157
+ const config: PasswordConfig = {
158
+ minLength: 12,
159
+ requireUppercase: true,
160
+ requireNumbers: true,
161
+ }
162
+ const semantic = createPasswordSemantic(config)
163
+ assert.equal(semantic.id, SemanticType.Password)
164
+ assert.deepEqual(semantic.config, { ...DEFAULT_PASSWORD_CONFIG, ...config })
165
+ })
166
+
167
+ test('Password: should identify password semantic', ({ assert }) => {
168
+ const semantic = createPasswordSemantic()
169
+ assert.isTrue(isPasswordSemantic(semantic))
170
+ })
171
+
172
+ test('Status: should create semantic with default config', ({ assert }) => {
173
+ const semantic = createStatusSemantic()
174
+ assert.equal(semantic.id, SemanticType.Status)
175
+ assert.deepEqual(semantic.config, DEFAULT_STATUS_CONFIG)
176
+ })
177
+
178
+ test('Status: should create semantic with custom config', ({ assert }) => {
179
+ const config: StatusConfig = {
180
+ allowedStates: ['active', 'inactive'],
181
+ defaultState: 'active',
182
+ }
183
+ const semantic = createStatusSemantic(config)
184
+ assert.equal(semantic.id, SemanticType.Status)
185
+ assert.deepEqual(semantic.config, { ...DEFAULT_STATUS_CONFIG, ...config })
186
+ })
187
+
188
+ test('Status: should identify status semantic', ({ assert }) => {
189
+ const semantic = createStatusSemantic()
190
+ assert.isTrue(isStatusSemantic(semantic))
191
+ })
192
+
193
+ test('PublicUniqueName: should create semantic with default config', ({ assert }) => {
194
+ const semantic = createPublicUniqueNameSemantic()
195
+ assert.equal(semantic.id, SemanticType.PublicUniqueName)
196
+ assert.deepEqual(semantic.config, DEFAULT_PUBLIC_UNIQUE_NAME_CONFIG)
197
+ })
198
+
199
+ test('PublicUniqueName: should create semantic with custom config', ({ assert }) => {
200
+ const config: PublicUniqueNameConfig = {
201
+ sourceField: 'title',
202
+ separator: '-',
203
+ maxLength: 50,
204
+ }
205
+ const semantic = createPublicUniqueNameSemantic(config)
206
+ assert.equal(semantic.id, SemanticType.PublicUniqueName)
207
+ assert.deepEqual(semantic.config, { ...DEFAULT_PUBLIC_UNIQUE_NAME_CONFIG, ...config })
208
+ })
209
+
210
+ test('PublicUniqueName: should identify public unique name semantic', ({ assert }) => {
211
+ const semantic = createPublicUniqueNameSemantic()
212
+ assert.isTrue(isPublicUniqueNameSemantic(semantic))
213
+ })
214
+
215
+ test('Markdown: should create semantic with default config', ({ assert }) => {
216
+ const semantic = createMarkdownSemantic()
217
+ assert.equal(semantic.id, SemanticType.Markdown)
218
+ assert.deepEqual(semantic.config, DEFAULT_MARKDOWN_CONFIG)
219
+ })
220
+
221
+ test('Markdown: should create semantic with custom config', ({ assert }) => {
222
+ const config: MarkdownConfig = {
223
+ renderToHTML: true,
224
+ allowedTags: ['p', 'h1', 'h2'],
225
+ sanitize: true,
226
+ }
227
+ const semantic = createMarkdownSemantic(config)
228
+ assert.equal(semantic.id, SemanticType.Markdown)
229
+ assert.deepEqual(semantic.config, { ...DEFAULT_MARKDOWN_CONFIG, ...config })
230
+ })
231
+
232
+ test('Markdown: should identify markdown semantic', ({ assert }) => {
233
+ const semantic = createMarkdownSemantic()
234
+ assert.isTrue(isMarkdownSemantic(semantic))
235
+ })
236
+
237
+ test('HTML: should create semantic with default config', ({ assert }) => {
238
+ const semantic = createHTMLSemantic()
239
+ assert.equal(semantic.id, SemanticType.HTML)
240
+ assert.deepEqual(semantic.config, DEFAULT_HTML_CONFIG)
241
+ })
242
+
243
+ test('HTML: should create semantic with custom config', ({ assert }) => {
244
+ const config: HTMLConfig = {
245
+ renderAsHTML: true,
246
+ allowedTags: ['p', 'div', 'span'],
247
+ sanitize: true,
248
+ }
249
+ const semantic = createHTMLSemantic(config)
250
+ assert.equal(semantic.id, SemanticType.HTML)
251
+ assert.deepEqual(semantic.config, { ...DEFAULT_HTML_CONFIG, ...config })
252
+ })
253
+
254
+ test('HTML: should identify HTML semantic', ({ assert }) => {
255
+ const semantic = createHTMLSemantic()
256
+ assert.isTrue(isHTMLSemantic(semantic))
257
+ })
258
+
259
+ test('Email: should create semantic with default config', ({ assert }) => {
260
+ const semantic = createEmailSemantic()
261
+ assert.equal(semantic.id, SemanticType.Email)
262
+ assert.deepEqual(semantic.config, DEFAULT_EMAIL_CONFIG)
263
+ })
264
+
265
+ test('Email: should create semantic with custom config', ({ assert }) => {
266
+ const config: EmailConfig = {
267
+ allowedDomains: ['example.com'],
268
+ requireVerification: true,
269
+ verificationMethod: 'email',
270
+ }
271
+ const semantic = createEmailSemantic(config)
272
+ assert.equal(semantic.id, SemanticType.Email)
273
+ assert.deepEqual(semantic.config, { ...DEFAULT_EMAIL_CONFIG, ...config })
274
+ })
275
+
276
+ test('Email: should identify email semantic', ({ assert }) => {
277
+ const semantic = createEmailSemantic()
278
+ assert.isTrue(isEmailSemantic(semantic))
279
+ })
280
+
281
+ test('Phone: should create semantic with default config', ({ assert }) => {
282
+ const semantic = createPhoneSemantic()
283
+ assert.equal(semantic.id, SemanticType.Phone)
284
+ assert.deepEqual(semantic.config, DEFAULT_PHONE_CONFIG)
285
+ })
286
+
287
+ test('Phone: should create semantic with custom config', ({ assert }) => {
288
+ const config: PhoneConfig = {
289
+ allowedCountries: ['US', 'CA'],
290
+ format: 'E.164',
291
+ requireVerification: true,
292
+ }
293
+ const semantic = createPhoneSemantic(config)
294
+ assert.equal(semantic.id, SemanticType.Phone)
295
+ assert.deepEqual(semantic.config, { ...DEFAULT_PHONE_CONFIG, ...config })
296
+ })
297
+
298
+ test('Phone: should identify phone semantic', ({ assert }) => {
299
+ const semantic = createPhoneSemantic()
300
+ assert.isTrue(isPhoneSemantic(semantic))
301
+ })
302
+
303
+ test('URL: should create semantic with default config', ({ assert }) => {
304
+ const semantic = createURLSemantic()
305
+ assert.equal(semantic.id, SemanticType.URL)
306
+ assert.deepEqual(semantic.config, DEFAULT_URL_CONFIG)
307
+ })
308
+
309
+ test('URL: should create semantic with custom config', ({ assert }) => {
310
+ const config: URLConfig = {
311
+ allowedProtocols: ['https'],
312
+ allowedDomains: ['example.com'],
313
+ requireHTTPS: true,
314
+ }
315
+ const semantic = createURLSemantic(config)
316
+ assert.equal(semantic.id, SemanticType.URL)
317
+ assert.deepEqual(semantic.config, { ...DEFAULT_URL_CONFIG, ...config })
318
+ })
319
+
320
+ test('URL: should identify URL semantic', ({ assert }) => {
321
+ const semantic = createURLSemantic()
322
+ assert.isTrue(isURLSemantic(semantic))
323
+ })
324
+
325
+ test('Price: should create semantic with default config', ({ assert }) => {
326
+ const semantic = createPriceSemantic()
327
+ assert.equal(semantic.id, SemanticType.Price)
328
+ assert.deepEqual(semantic.config, DEFAULT_PRICE_CONFIG)
329
+ })
330
+
331
+ test('Price: should create semantic with custom config', ({ assert }) => {
332
+ const config: PriceConfig = {
333
+ storageFormat: 'complex_object',
334
+ allowedCurrencies: ['USD', 'EUR'],
335
+ decimalPlaces: 4,
336
+ allowNegative: true,
337
+ }
338
+ const semantic = createPriceSemantic(config)
339
+ assert.equal(semantic.id, SemanticType.Price)
340
+ assert.deepEqual(semantic.config, { ...DEFAULT_PRICE_CONFIG, ...config })
341
+ })
342
+
343
+ test('Price: should identify price semantic', ({ assert }) => {
344
+ const semantic = createPriceSemantic()
345
+ assert.isTrue(isPriceSemantic(semantic))
346
+ })
347
+
348
+ test('SKU: should create semantic with default config', ({ assert }) => {
349
+ const semantic = createSKUSemantic()
350
+ assert.equal(semantic.id, SemanticType.SKU)
351
+ assert.deepEqual(semantic.config, DEFAULT_SKU_CONFIG)
352
+ })
353
+
354
+ test('SKU: should create semantic with custom config', ({ assert }) => {
355
+ const config: SKUConfig = {
356
+ validationMode: 'lenient',
357
+ caseMode: 'lowercase',
358
+ prefix: 'SKU-',
359
+ enforceUniqueness: false,
360
+ }
361
+ const semantic = createSKUSemantic(config)
362
+ assert.equal(semantic.id, SemanticType.SKU)
363
+ assert.deepEqual(semantic.config, { ...DEFAULT_SKU_CONFIG, ...config })
364
+ })
365
+
366
+ test('SKU: should identify SKU semantic', ({ assert }) => {
367
+ const semantic = createSKUSemantic()
368
+ assert.isTrue(isSKUSemantic(semantic))
369
+ })
370
+
371
+ test('Description: should create semantic with default config', ({ assert }) => {
372
+ const semantic = createDescriptionSemantic()
373
+ assert.equal(semantic.id, SemanticType.Description)
374
+ assert.deepEqual(semantic.config, DEFAULT_DESCRIPTION_CONFIG)
375
+ })
376
+
377
+ test('Description: should create semantic with custom config', ({ assert }) => {
378
+ const config: DescriptionConfig = {
379
+ minLength: 10,
380
+ maxLength: 1000,
381
+ allowMarkdown: true,
382
+ }
383
+ const semantic = createDescriptionSemantic(config)
384
+ assert.equal(semantic.id, SemanticType.Description)
385
+ assert.deepEqual(semantic.config, { ...DEFAULT_DESCRIPTION_CONFIG, ...config })
386
+ })
387
+
388
+ test('Description: should identify description semantic', ({ assert }) => {
389
+ const semantic = createDescriptionSemantic()
390
+ assert.isTrue(isDescriptionSemantic(semantic))
391
+ })
392
+
393
+ test('Summary: should create semantic with default config', ({ assert }) => {
394
+ const semantic = createSummarySemantic()
395
+ assert.equal(semantic.id, SemanticType.Summary)
396
+ assert.deepEqual(semantic.config, DEFAULT_SUMMARY_CONFIG)
397
+ })
398
+
399
+ test('Summary: should create semantic with custom config', ({ assert }) => {
400
+ const config: SummaryConfig = {
401
+ metadata: { customField: 'value' },
402
+ }
403
+ const semantic = createSummarySemantic(config)
404
+ assert.equal(semantic.id, SemanticType.Summary)
405
+ assert.deepEqual(semantic.config, { ...DEFAULT_SUMMARY_CONFIG, ...config })
406
+ })
407
+
408
+ test('Summary: should identify summary semantic', ({ assert }) => {
409
+ const semantic = createSummarySemantic()
410
+ assert.isTrue(isSummarySemantic(semantic))
411
+ })
412
+
413
+ test('Calculated: should create semantic with custom config', ({ assert }) => {
414
+ const config: CalculatedConfig = {
415
+ formula: 'price * quantity',
416
+ dependencies: ['price', 'quantity'],
417
+ recalculateOnUpdate: true,
418
+ allowManualOverride: true,
419
+ }
420
+ const semantic = createCalculatedSemantic(config)
421
+ assert.equal(semantic.id, SemanticType.Calculated)
422
+ assert.deepEqual(semantic.config, config)
423
+ })
424
+
425
+ test('Calculated: should identify calculated semantic', ({ assert }) => {
426
+ const config: CalculatedConfig = { formula: 'price * quantity' }
427
+ const semantic = createCalculatedSemantic(config)
428
+ assert.isTrue(isCalculatedSemantic(semantic))
429
+ })
430
+
431
+ test('Derived: should create semantic with custom config', ({ assert }) => {
432
+ const config: DerivedConfig = {
433
+ sourceFields: ['firstName', 'lastName'],
434
+ derivationRule: 'concat',
435
+ updateOnChange: true,
436
+ allowManualOverride: true,
437
+ recalculateOnUpdate: false,
438
+ }
439
+ const semantic = createDerivedSemantic(config)
440
+ assert.equal(semantic.id, SemanticType.Derived)
441
+ assert.deepEqual(semantic.config, config)
442
+ })
443
+
444
+ test('Derived: should identify derived semantic', ({ assert }) => {
445
+ const config: DerivedConfig = { sourceFields: ['firstName', 'lastName'] }
446
+ const semantic = createDerivedSemantic(config)
447
+ assert.isTrue(isDerivedSemantic(semantic))
448
+ })
449
+
450
+ test('Tags: should create semantic with default config', ({ assert }) => {
451
+ const semantic = createTagsSemantic()
452
+ assert.equal(semantic.id, SemanticType.Tags)
453
+ assert.deepEqual(semantic.config, DEFAULT_TAGS_CONFIG)
454
+ })
455
+
456
+ test('Tags: should create semantic with custom config', ({ assert }) => {
457
+ const config: TagsConfig = {
458
+ maxTags: 10,
459
+ allowCustomTags: true,
460
+ predefinedTags: ['urgent', 'important'],
461
+ }
462
+ const semantic = createTagsSemantic(config)
463
+ assert.equal(semantic.id, SemanticType.Tags)
464
+ assert.deepEqual(semantic.config, { ...DEFAULT_TAGS_CONFIG, ...config })
465
+ })
466
+
467
+ test('Tags: should identify tags semantic', ({ assert }) => {
468
+ const semantic = createTagsSemantic()
469
+ assert.isTrue(isTagsSemantic(semantic))
470
+ })
471
+
472
+ test('Categories: should create semantic with default config', ({ assert }) => {
473
+ const semantic = createCategoriesSemantic()
474
+ assert.equal(semantic.id, SemanticType.Categories)
475
+ assert.deepEqual(semantic.config, DEFAULT_CATEGORIES_CONFIG)
476
+ })
477
+
478
+ test('Categories: should create semantic with custom config', ({ assert }) => {
479
+ const config: CategoriesConfig = {
480
+ maxCategories: 5,
481
+ allowMultiple: true,
482
+ predefinedCategories: ['feature', 'bug', 'enhancement'],
483
+ }
484
+ const semantic = createCategoriesSemantic(config)
485
+ assert.equal(semantic.id, SemanticType.Categories)
486
+ assert.deepEqual(semantic.config, { ...DEFAULT_CATEGORIES_CONFIG, ...config })
487
+ })
488
+
489
+ test('Categories: should identify categories semantic', ({ assert }) => {
490
+ const semantic = createCategoriesSemantic()
491
+ assert.isTrue(isCategoriesSemantic(semantic))
492
+ })
493
+
494
+ test('Price: should create semantic with default config', ({ assert }) => {
495
+ const semantic = createPriceSemantic()
496
+ assert.equal(semantic.id, SemanticType.Price)
497
+ assert.deepEqual(semantic.config, DEFAULT_PRICE_CONFIG)
498
+ })
499
+
500
+ test('Price: should create semantic with custom config', ({ assert }) => {
501
+ const config: PriceConfig = {
502
+ storageFormat: 'complex_object',
503
+ allowedCurrencies: ['USD', 'EUR'],
504
+ decimalPlaces: 4,
505
+ allowNegative: true,
506
+ }
507
+ const semantic = createPriceSemantic(config)
508
+ assert.equal(semantic.id, SemanticType.Price)
509
+ assert.deepEqual(semantic.config, { ...DEFAULT_PRICE_CONFIG, ...config })
510
+ })
511
+
512
+ test('Price: should identify price semantic', ({ assert }) => {
513
+ const semantic = createPriceSemantic()
514
+ assert.isTrue(isPriceSemantic(semantic))
515
+ })
516
+
517
+ test('Price: presets should be valid', ({ assert }) => {
518
+ Object.values(PRICE_PRESETS).forEach((preset) => {
519
+ assert.isTrue(isPriceSemantic(preset))
520
+ assert.equal(preset.id, SemanticType.Price)
521
+ })
522
+ })
523
+
524
+ test('SKU: presets should be valid', ({ assert }) => {
525
+ Object.values(SKU_PRESETS).forEach((preset) => {
526
+ assert.isTrue(isSKUSemantic(preset))
527
+ assert.equal(preset.id, SemanticType.SKU)
528
+ })
529
+ })
530
+
531
+ test('Cross-semantic type guards: should correctly identify different semantic types', ({ assert }) => {
532
+ const emailSemantic = createEmailSemantic()
533
+ const phoneSemantic = createPhoneSemantic()
534
+ const statusSemantic = createStatusSemantic()
535
+ const priceSemantic = createPriceSemantic()
536
+ const skuSemantic = createSKUSemantic()
537
+
538
+ // Each should only be identified as its own type
539
+ assert.isTrue(isEmailSemantic(emailSemantic))
540
+ assert.isFalse(isEmailSemantic(phoneSemantic))
541
+ assert.isFalse(isEmailSemantic(statusSemantic))
542
+ assert.isFalse(isEmailSemantic(priceSemantic))
543
+ assert.isFalse(isEmailSemantic(skuSemantic))
544
+
545
+ assert.isFalse(isPhoneSemantic(emailSemantic))
546
+ assert.isTrue(isPhoneSemantic(phoneSemantic))
547
+ assert.isFalse(isPhoneSemantic(statusSemantic))
548
+ assert.isFalse(isPhoneSemantic(priceSemantic))
549
+ assert.isFalse(isPhoneSemantic(skuSemantic))
550
+
551
+ assert.isFalse(isStatusSemantic(emailSemantic))
552
+ assert.isFalse(isStatusSemantic(phoneSemantic))
553
+ assert.isTrue(isStatusSemantic(statusSemantic))
554
+ assert.isFalse(isStatusSemantic(priceSemantic))
555
+ assert.isFalse(isStatusSemantic(skuSemantic))
556
+
557
+ assert.isFalse(isPriceSemantic(emailSemantic))
558
+ assert.isFalse(isPriceSemantic(phoneSemantic))
559
+ assert.isFalse(isPriceSemantic(statusSemantic))
560
+ assert.isTrue(isPriceSemantic(priceSemantic))
561
+ assert.isFalse(isPriceSemantic(skuSemantic))
562
+
563
+ assert.isFalse(isSKUSemantic(emailSemantic))
564
+ assert.isFalse(isSKUSemantic(phoneSemantic))
565
+ assert.isFalse(isSKUSemantic(statusSemantic))
566
+ assert.isFalse(isSKUSemantic(priceSemantic))
567
+ assert.isTrue(isSKUSemantic(skuSemantic))
568
+ })
569
+ })
@@ -20,8 +20,17 @@ test.group('Semantics', () => {
20
20
  assert.equal(SemanticType.DeletedTimestamp, 'Semantic#DeletedTimestamp')
21
21
  assert.equal(SemanticType.DeletedFlag, 'Semantic#DeletedFlag')
22
22
  assert.equal(SemanticType.PublicUniqueName, 'Semantic#PublicUniqueName')
23
+ assert.equal(SemanticType.Title, 'Semantic#Title')
23
24
  assert.equal(SemanticType.UserRole, 'Semantic#UserRole')
25
+ assert.equal(SemanticType.Status, 'Semantic#Status')
26
+ assert.equal(SemanticType.Version, 'Semantic#Version')
27
+ assert.equal(SemanticType.ImageURL, 'Semantic#ImageURL')
28
+ assert.equal(SemanticType.FileURL, 'Semantic#FileURL')
29
+ assert.equal(SemanticType.Markdown, 'Semantic#Markdown')
30
+ assert.equal(SemanticType.GeospatialCoordinates, 'Semantic#GeospatialCoordinates')
31
+ assert.equal(SemanticType.Price, 'Semantic#Price')
24
32
  assert.equal(SemanticType.ResourceOwnerIdentifier, 'Semantic#ResourceOwnerIdentifier')
33
+ assert.equal(SemanticType.SKU, 'Semantic#SKU')
25
34
  })
26
35
 
27
36
  test('SemanticScope enum should have correct values', ({ assert }) => {
@@ -143,4 +152,47 @@ test.group('Semantics', () => {
143
152
  const resourceOwnerSemantic = DataSemantics[SemanticType.ResourceOwnerIdentifier]
144
153
  assert.equal(resourceOwnerSemantic.scope, SemanticScope.Association)
145
154
  })
155
+
156
+ test('GeospatialCoordinates semantic should have correct definition', ({ assert }) => {
157
+ const geospatialSemantic = DataSemantics[SemanticType.GeospatialCoordinates]
158
+
159
+ // Check basic properties
160
+ assert.equal(geospatialSemantic.id, SemanticType.GeospatialCoordinates)
161
+ assert.equal(geospatialSemantic.displayName, 'Geospatial Coordinates')
162
+ assert.equal(geospatialSemantic.scope, SemanticScope.Property)
163
+ assert.isString(geospatialSemantic.description)
164
+ assert.isNotEmpty(geospatialSemantic.description)
165
+
166
+ // Check that it's a PropertySemantic
167
+ assert.isTrue(isPropertySemantic(geospatialSemantic))
168
+
169
+ // Check applicable data types
170
+ if (isPropertySemantic(geospatialSemantic)) {
171
+ assert.isDefined(geospatialSemantic.applicableDataTypes)
172
+ assert.isArray(geospatialSemantic.applicableDataTypes)
173
+ assert.deepEqual(geospatialSemantic.applicableDataTypes, ['string'])
174
+ }
175
+ })
176
+
177
+ test('GeospatialCoordinates should work with type guards', ({ assert }) => {
178
+ const geospatialSemantic = DataSemantics[SemanticType.GeospatialCoordinates]
179
+
180
+ // Should be identified as a PropertySemantic
181
+ assert.isTrue(isPropertySemantic(geospatialSemantic))
182
+ assert.isFalse(isEntitySemantic(geospatialSemantic))
183
+ assert.isFalse(isAssociationSemantic(geospatialSemantic))
184
+ })
185
+
186
+ test('GeospatialCoordinates should be included in all semantic types', ({ assert }) => {
187
+ const semanticTypes = Object.values(SemanticType)
188
+ assert.include(semanticTypes, SemanticType.GeospatialCoordinates)
189
+ })
190
+
191
+ test('GeospatialCoordinates should have comprehensive description', ({ assert }) => {
192
+ const geospatialSemantic = DataSemantics[SemanticType.GeospatialCoordinates]
193
+ const description = geospatialSemantic.description
194
+
195
+ // Check that the description mentions key features
196
+ assert.equal(description, 'Annotates a field that holds geospatial coordinate data (latitude/longitude).')
197
+ })
146
198
  })