@kubun/protocol 0.9.0 → 0.11.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.
@@ -1 +1,550 @@
1
- import{asType as e,createValidator as t}from"@enkaku/schema";import{DocumentModelID as r,ScalarModelID as o,ShapeModelID as i}from"@kubun/id";import{pascalCase as s}from"change-case";import{baseObjectModel as n,nameString as a,referencesRecordModel as d}from"./json-schema.js";import{binaryStringValue as c,didStringValue as l}from"./value.js";export const documentModelVersion={type:"string",const:"1.0"};export const documentFieldMetaAccount={type:"object",properties:{type:{type:"string",const:"account"},searchable:{type:"boolean"}},required:["type"],additionalProperties:!1};export const documentFieldMetaAttachment={type:"object",properties:{type:{type:"string",const:"attachment"},searchable:{type:"boolean"}},required:["type"],additionalProperties:!1};export const documentFieldMetaDocument={type:"object",properties:{type:{type:"string",const:"document"},model:{anyOf:[{type:"string"},{type:"null"}]},searchable:{type:"boolean"}},required:["type","model"],additionalProperties:!1};export const documentFieldMeta={anyOf:[documentFieldMetaAccount,documentFieldMetaAttachment,documentFieldMetaDocument]};export const documentFieldsMeta={type:"object",additionalProperties:documentFieldMeta};export const documentModelSchema={type:"object",properties:{...n.properties,$defs:d},required:[...n.required,"$defs"],additionalProperties:!1};export const documentModelBase={type:"object",properties:{name:a,version:documentModelVersion,interfaces:{type:"array",items:{type:"string"}},schema:documentModelSchema,fieldsMeta:documentFieldsMeta},required:["name","version","interfaces","schema","fieldsMeta"],additionalProperties:!1};export const documentModelDefault={type:"object",properties:{...documentModelBase.properties,behavior:{type:"string",const:"default"}},required:[...documentModelBase.required,"behavior"],additionalProperties:!1};export const documentModelInterface={type:"object",properties:{...documentModelBase.properties,behavior:{type:"string",const:"interface"}},required:[...documentModelBase.required,"behavior"],additionalProperties:!1};export const documentModelUnique={type:"object",properties:{...documentModelBase.properties,behavior:{type:"string",const:"unique"},uniqueFields:{type:"array",items:{type:"string"}}},required:[...documentModelBase.required,"behavior","uniqueFields"],additionalProperties:!1};export const documentModel={$id:"urn:kubun:protocol:model:document",anyOf:[documentModelDefault,documentModelInterface,documentModelUnique]};export const documentModelsCluster={type:"array",items:documentModel};export const documentModelsRecord={type:"object",additionalProperties:documentModel};export const setDocumentMutation={$id:"urn:kubun:protocol:mutation:set",type:"object",properties:{typ:{type:"string",const:"set"},iss:l,aud:l,sub:{type:"string"},data:{type:"object",additionalProperties:!0},hlc:{type:"string"},unq:c,cap:{anyOf:[{type:"string"},{type:"array",items:{type:"string"}}]}},required:["iss","sub","typ","data","hlc","unq"],additionalProperties:!1};export const patchOperationSchema={type:"object",properties:{op:{type:"string"},path:{type:"string"},value:{},from:{type:"string"}},required:["op","path"],additionalProperties:!1};export const changeDocumentMutation={$id:"urn:kubun:protocol:mutation:change",type:"object",properties:{typ:{type:"string",const:"change"},iss:l,sub:{type:"string"},patch:{type:"array",items:patchOperationSchema},hlc:{type:"string"},cap:{anyOf:[{type:"string"},{type:"array",items:{type:"string"}}]}},required:["iss","sub","typ","patch","hlc"],additionalProperties:!1};export const documentMutation={$id:"urn:kubun:protocol:mutation",anyOf:[setDocumentMutation,changeDocumentMutation]};export const validateDocumentModel=t(documentModel);export const REFERENCE_PREFIX="#/$defs/";let p={type:"object",title:"JSONObject",additionalProperties:!0},u=/^#([0-9]+)$/;export class DocumentModelNormalizer{#e;#t=new Set;#r;#o;#i;#s;#n={};#a={};#d=new Set;#c={};constructor(e){this.#e=e.inputModel,this.#r=e.logger;let t=e.inputModel.schema??{};this.#l(e.interfaceModels),this.#p(t,e.normalizedInterfaceIDs),this.#i=t.$defs??{},this.#s={...t,type:"object",properties:this.#n,required:Array.from(this.#d),additionalProperties:!1,$defs:{...t.$defs,...this.#a}},this.#o=this.#u(),this.#m()}#l(e){for(let t of e){for(let e of t.interfaces)this.#t.add(e);for(let e of t.schema.required)this.#d.add(e);Object.assign(this.#n,t.schema.properties),Object.assign(this.#a,t.schema.$defs),Object.assign(this.#c,t.fieldsMeta??{})}}#p(e,t){for(let e of t)this.#t.add(e);for(let t of e.required??[])this.#d.add(t);Object.assign(this.#n,e.properties??{}),Object.assign(this.#c,this.#e.fieldsMeta??{})}#u(){let e=this.#s,t=Object.entries(e.properties??{});if(0===t.length)throw Error("Document schema must contain at least one property");let r={};for(let[e,o]of t)r[e]={$ref:this.#h(e,o)};return{type:"object",properties:r,additionalProperties:!1,required:e.required??[],$defs:this.#i}}#h(e,t){if(null!=t.$ref){let r=this.#f(t.$ref);return this.#h(e,r)}let r=t.type;if(null==r)throw Error("Invalid schema: missing type");switch(r){case"array":{if(null==t.title)throw Error("Invalid array schema: missing title");if(null==t.items)throw Error("Invalid array schema: missing items");let{default:r,...o}=t;return this.#y({...o,title:s(t.title),items:{$ref:this.#h(e,t.items)}})}case"object":{if(t.additionalProperties)return this.#y(p);if(null==t.title)throw Error("Invalid object schema: missing title");let e=Object.entries(t.properties??{});if(0===e.length)throw Error("Invalid object schema: must contain at least one property");let r={};for(let[t,o]of e)r[t]={$ref:this.#h(t,o)};return this.#y({type:"object",title:s(t.title),properties:r,required:t.required??[],additionalProperties:!1})}default:return this.#M(e,t)}}#f(e){if(!e.startsWith("#"))throw Error(`Invalid reference format: ${e}`);if(e.startsWith(REFERENCE_PREFIX)){let t=e.slice(REFERENCE_PREFIX.length),r=this.#s.$defs?.[t];if(null==r)throw Error(`Reference not found: ${e}`);return r}let t=e.split("/").slice(1),r=this.#s;for(let o of t){if(null==r||"object"!=typeof r)throw Error(`Invalid reference path: ${e}`);if(null==(r=r[o]))throw Error(`Reference not found: ${e}`)}return r}#M(e,t){let r=o.create(t),i=t;if("boolean"===t.type){let{title:e,...r}=t;i=r}else if(null!=t.title){let r=t.title.toLowerCase();"attachmentid"===r?(this.#c[e]={type:"attachment"},i={...t,title:"attachmentid"}):"did"===r?(this.#c[e]={type:"account"},i={...t,title:"did"}):"docid"===r?(null==this.#c[e]&&(this.#r.warn("Missing fieldMeta entry for document reference {fieldKey} of model {inputModel}",{fieldKey:e,inputModel:this.#e}),this.#c[e]={type:"document",model:null}),i={...t,title:"docid"}):i={...t,title:s(t.title)}}return this.#i[r.toString()]=i,`${REFERENCE_PREFIX}${r}`}#y(e){let t=i.create(e);return this.#i[t.toString()]=e,`${REFERENCE_PREFIX}${t}`}#m(){for(let[e,t]of Object.entries(this.#c)){if("document"!==t.type||null===t.model)continue;let o=t.model.match(u);null!=o&&(this.#c[e]={...t,model:r.local(Number.parseInt(o[1],10)).toString()})}}toDocumentModel(){return e(validateDocumentModel,{version:"1.0",behavior:"default",...this.#e,interfaces:Array.from(this.#t),schema:this.#o,fieldsMeta:this.#c})}}
1
+ import { DocumentModelID, ScalarModelID, ShapeModelID } from '@kubun/id';
2
+ import { asType, createValidator } from '@sozai/schema';
3
+ import { pascalCase } from 'change-case';
4
+ import { baseObjectModel, nameString, referencesRecordModel } from './json-schema.js';
5
+ import { binaryStringValue, didStringValue } from './value.js';
6
+ export const documentModelVersion = {
7
+ type: 'string',
8
+ const: '1.0'
9
+ };
10
+ export const documentFieldMetaAccount = {
11
+ type: 'object',
12
+ properties: {
13
+ type: {
14
+ type: 'string',
15
+ const: 'account'
16
+ },
17
+ searchable: {
18
+ type: 'boolean'
19
+ }
20
+ },
21
+ required: [
22
+ 'type'
23
+ ],
24
+ additionalProperties: false
25
+ };
26
+ export const documentFieldMetaAttachment = {
27
+ type: 'object',
28
+ properties: {
29
+ type: {
30
+ type: 'string',
31
+ const: 'attachment'
32
+ },
33
+ searchable: {
34
+ type: 'boolean'
35
+ }
36
+ },
37
+ required: [
38
+ 'type'
39
+ ],
40
+ additionalProperties: false
41
+ };
42
+ export const documentFieldMetaDocument = {
43
+ type: 'object',
44
+ properties: {
45
+ type: {
46
+ type: 'string',
47
+ const: 'document'
48
+ },
49
+ model: {
50
+ anyOf: [
51
+ {
52
+ type: 'string'
53
+ },
54
+ {
55
+ type: 'null'
56
+ }
57
+ ]
58
+ },
59
+ searchable: {
60
+ type: 'boolean'
61
+ }
62
+ },
63
+ required: [
64
+ 'type',
65
+ 'model'
66
+ ],
67
+ additionalProperties: false
68
+ };
69
+ export const documentFieldMeta = {
70
+ anyOf: [
71
+ documentFieldMetaAccount,
72
+ documentFieldMetaAttachment,
73
+ documentFieldMetaDocument
74
+ ]
75
+ };
76
+ export const documentFieldsMeta = {
77
+ type: 'object',
78
+ additionalProperties: documentFieldMeta
79
+ };
80
+ export const documentModelSchema = {
81
+ type: 'object',
82
+ properties: {
83
+ ...baseObjectModel.properties,
84
+ $defs: referencesRecordModel
85
+ },
86
+ required: [
87
+ ...baseObjectModel.required,
88
+ '$defs'
89
+ ],
90
+ additionalProperties: false
91
+ };
92
+ export const documentModelBase = {
93
+ type: 'object',
94
+ properties: {
95
+ name: nameString,
96
+ version: documentModelVersion,
97
+ interfaces: {
98
+ type: 'array',
99
+ items: {
100
+ type: 'string'
101
+ }
102
+ },
103
+ schema: documentModelSchema,
104
+ fieldsMeta: documentFieldsMeta
105
+ },
106
+ required: [
107
+ 'name',
108
+ 'version',
109
+ 'interfaces',
110
+ 'schema',
111
+ 'fieldsMeta'
112
+ ],
113
+ additionalProperties: false
114
+ };
115
+ export const documentModelDefault = {
116
+ type: 'object',
117
+ properties: {
118
+ ...documentModelBase.properties,
119
+ behavior: {
120
+ type: 'string',
121
+ const: 'default'
122
+ }
123
+ },
124
+ required: [
125
+ ...documentModelBase.required,
126
+ 'behavior'
127
+ ],
128
+ additionalProperties: false
129
+ };
130
+ export const documentModelInterface = {
131
+ type: 'object',
132
+ properties: {
133
+ ...documentModelBase.properties,
134
+ behavior: {
135
+ type: 'string',
136
+ const: 'interface'
137
+ }
138
+ },
139
+ required: [
140
+ ...documentModelBase.required,
141
+ 'behavior'
142
+ ],
143
+ additionalProperties: false
144
+ };
145
+ export const documentModelUnique = {
146
+ type: 'object',
147
+ properties: {
148
+ ...documentModelBase.properties,
149
+ behavior: {
150
+ type: 'string',
151
+ const: 'unique'
152
+ },
153
+ uniqueFields: {
154
+ type: 'array',
155
+ items: {
156
+ type: 'string'
157
+ }
158
+ }
159
+ },
160
+ required: [
161
+ ...documentModelBase.required,
162
+ 'behavior',
163
+ 'uniqueFields'
164
+ ],
165
+ additionalProperties: false
166
+ };
167
+ export const documentModel = {
168
+ $id: 'urn:kubun:protocol:model:document',
169
+ anyOf: [
170
+ documentModelDefault,
171
+ documentModelInterface,
172
+ documentModelUnique
173
+ ]
174
+ };
175
+ export const documentModelsCluster = {
176
+ type: 'array',
177
+ items: documentModel
178
+ };
179
+ export const documentModelsRecord = {
180
+ type: 'object',
181
+ additionalProperties: documentModel
182
+ };
183
+ export const setDocumentMutation = {
184
+ $id: 'urn:kubun:protocol:mutation:set',
185
+ type: 'object',
186
+ properties: {
187
+ typ: {
188
+ type: 'string',
189
+ const: 'set'
190
+ },
191
+ iss: didStringValue,
192
+ aud: didStringValue,
193
+ sub: {
194
+ type: 'string'
195
+ },
196
+ data: {
197
+ type: 'object',
198
+ additionalProperties: true
199
+ },
200
+ hlc: {
201
+ type: 'string'
202
+ },
203
+ unq: binaryStringValue,
204
+ cap: {
205
+ anyOf: [
206
+ {
207
+ type: 'string'
208
+ },
209
+ {
210
+ type: 'array',
211
+ items: {
212
+ type: 'string'
213
+ }
214
+ }
215
+ ]
216
+ }
217
+ },
218
+ required: [
219
+ 'iss',
220
+ 'sub',
221
+ 'typ',
222
+ 'data',
223
+ 'hlc',
224
+ 'unq'
225
+ ],
226
+ additionalProperties: false
227
+ };
228
+ export const patchOperationSchema = {
229
+ type: 'object',
230
+ properties: {
231
+ op: {
232
+ type: 'string'
233
+ },
234
+ path: {
235
+ type: 'string'
236
+ },
237
+ value: {},
238
+ from: {
239
+ type: 'string'
240
+ }
241
+ },
242
+ required: [
243
+ 'op',
244
+ 'path'
245
+ ],
246
+ additionalProperties: false
247
+ };
248
+ export const changeDocumentMutation = {
249
+ $id: 'urn:kubun:protocol:mutation:change',
250
+ type: 'object',
251
+ properties: {
252
+ typ: {
253
+ type: 'string',
254
+ const: 'change'
255
+ },
256
+ iss: didStringValue,
257
+ sub: {
258
+ type: 'string'
259
+ },
260
+ patch: {
261
+ type: 'array',
262
+ items: patchOperationSchema
263
+ },
264
+ hlc: {
265
+ type: 'string'
266
+ },
267
+ cap: {
268
+ anyOf: [
269
+ {
270
+ type: 'string'
271
+ },
272
+ {
273
+ type: 'array',
274
+ items: {
275
+ type: 'string'
276
+ }
277
+ }
278
+ ]
279
+ }
280
+ },
281
+ required: [
282
+ 'iss',
283
+ 'sub',
284
+ 'typ',
285
+ 'patch',
286
+ 'hlc'
287
+ ],
288
+ additionalProperties: false
289
+ };
290
+ export const documentMutation = {
291
+ $id: 'urn:kubun:protocol:mutation',
292
+ anyOf: [
293
+ setDocumentMutation,
294
+ changeDocumentMutation
295
+ ]
296
+ };
297
+ // Normalization logic
298
+ export const validateDocumentModel = createValidator(documentModel);
299
+ export const REFERENCE_PREFIX = '#/$defs/';
300
+ function toReference(id) {
301
+ return `${REFERENCE_PREFIX}${id}`;
302
+ }
303
+ const JSONObjectSchema = {
304
+ type: 'object',
305
+ title: 'JSONObject',
306
+ additionalProperties: true
307
+ };
308
+ const LOCAL_ID_REGEXP = /^#([0-9]+)$/;
309
+ // TODO: add fieldsMeta for account and attachment when walking the schema
310
+ export class DocumentModelNormalizer {
311
+ #inputModel;
312
+ #interfaces = new Set();
313
+ #logger;
314
+ #normalizedSchema;
315
+ #refs;
316
+ #root;
317
+ #schemaProperties = {};
318
+ #schemaReferences = {};
319
+ #schemaRequired = new Set();
320
+ #fieldsMeta = {};
321
+ constructor(params){
322
+ this.#inputModel = params.inputModel;
323
+ this.#logger = params.logger;
324
+ const inputSchema = params.inputModel.schema ?? {};
325
+ this.#processInterfaces(params.interfaceModels);
326
+ this.#processMeta(inputSchema, params.normalizedInterfaceIDs);
327
+ this.#refs = inputSchema.$defs ?? {};
328
+ this.#root = {
329
+ ...inputSchema,
330
+ type: 'object',
331
+ properties: this.#schemaProperties,
332
+ required: Array.from(this.#schemaRequired),
333
+ additionalProperties: false,
334
+ $defs: {
335
+ ...inputSchema.$defs,
336
+ ...this.#schemaReferences
337
+ }
338
+ };
339
+ this.#normalizedSchema = this.#normalizeSchema();
340
+ this.#processFieldsMeta();
341
+ }
342
+ #processInterfaces(interfaceModels) {
343
+ // Add interface fields
344
+ for (const interfaceModel of interfaceModels){
345
+ for (const interfaceID of interfaceModel.interfaces){
346
+ this.#interfaces.add(interfaceID);
347
+ }
348
+ for (const requiredKey of interfaceModel.schema.required){
349
+ this.#schemaRequired.add(requiredKey);
350
+ }
351
+ Object.assign(this.#schemaProperties, interfaceModel.schema.properties);
352
+ Object.assign(this.#schemaReferences, interfaceModel.schema.$defs);
353
+ Object.assign(this.#fieldsMeta, interfaceModel.fieldsMeta ?? {});
354
+ }
355
+ }
356
+ #processMeta(inputSchema, normalizedInterfaceIDs) {
357
+ for (const interfaceID of normalizedInterfaceIDs){
358
+ this.#interfaces.add(interfaceID);
359
+ }
360
+ for (const requiredKey of inputSchema.required ?? []){
361
+ this.#schemaRequired.add(requiredKey);
362
+ }
363
+ Object.assign(this.#schemaProperties, inputSchema.properties ?? {});
364
+ Object.assign(this.#fieldsMeta, this.#inputModel.fieldsMeta ?? {});
365
+ }
366
+ #normalizeSchema() {
367
+ const schema = this.#root;
368
+ const entries = Object.entries(schema.properties ?? {});
369
+ if (entries.length === 0) {
370
+ throw new Error('Document schema must contain at least one property');
371
+ }
372
+ const properties = {};
373
+ for (const [key, value] of entries){
374
+ properties[key] = {
375
+ $ref: this.#encodeSchema(key, value)
376
+ };
377
+ }
378
+ return {
379
+ type: 'object',
380
+ properties,
381
+ additionalProperties: false,
382
+ required: schema.required ?? [],
383
+ $defs: this.#refs
384
+ };
385
+ }
386
+ #encodeSchema(fieldKey, schema) {
387
+ if (schema.$ref != null) {
388
+ const resolvedSchema = this.#resolveReference(schema.$ref);
389
+ return this.#encodeSchema(fieldKey, resolvedSchema);
390
+ }
391
+ const type = schema.type;
392
+ if (type == null) {
393
+ throw new Error('Invalid schema: missing type');
394
+ }
395
+ switch(type){
396
+ case 'array':
397
+ {
398
+ if (schema.title == null) {
399
+ throw new Error('Invalid array schema: missing title');
400
+ }
401
+ if (schema.items == null) {
402
+ throw new Error('Invalid array schema: missing items');
403
+ }
404
+ const { default: _, ...rest } = schema;
405
+ return this.#addShape({
406
+ ...rest,
407
+ title: pascalCase(schema.title),
408
+ items: {
409
+ $ref: this.#encodeSchema(fieldKey, schema.items)
410
+ }
411
+ });
412
+ }
413
+ case 'object':
414
+ {
415
+ if (schema.additionalProperties) {
416
+ return this.#addShape(JSONObjectSchema);
417
+ }
418
+ if (schema.title == null) {
419
+ throw new Error('Invalid object schema: missing title');
420
+ }
421
+ const entries = Object.entries(schema.properties ?? {});
422
+ if (entries.length === 0) {
423
+ throw new Error('Invalid object schema: must contain at least one property');
424
+ }
425
+ const properties = {};
426
+ for (const [key, value] of entries){
427
+ properties[key] = {
428
+ $ref: this.#encodeSchema(key, value)
429
+ };
430
+ }
431
+ return this.#addShape({
432
+ type: 'object',
433
+ title: pascalCase(schema.title),
434
+ properties,
435
+ required: schema.required ?? [],
436
+ additionalProperties: false
437
+ });
438
+ }
439
+ default:
440
+ return this.#addScalar(fieldKey, schema);
441
+ }
442
+ }
443
+ #resolveReference(ref) {
444
+ if (!ref.startsWith('#')) {
445
+ throw new Error(`Invalid reference format: ${ref}`);
446
+ }
447
+ // Handle #/$defs/ references
448
+ if (ref.startsWith(REFERENCE_PREFIX)) {
449
+ const key = ref.slice(REFERENCE_PREFIX.length);
450
+ const resolved = this.#root.$defs?.[key];
451
+ if (resolved == null) {
452
+ throw new Error(`Reference not found: ${ref}`);
453
+ }
454
+ return resolved;
455
+ }
456
+ // Handle other JSON Schema references like #/properties/, #/items/, etc.
457
+ const segments = ref.split('/').slice(1);
458
+ // biome-ignore lint/suspicious/noExplicitAny: mixed type
459
+ let current = this.#root;
460
+ for (const segment of segments){
461
+ if (current == null || typeof current !== 'object') {
462
+ throw new Error(`Invalid reference path: ${ref}`);
463
+ }
464
+ current = current[segment];
465
+ if (current == null) {
466
+ throw new Error(`Reference not found: ${ref}`);
467
+ }
468
+ }
469
+ return current;
470
+ }
471
+ #addScalar(fieldKey, schema) {
472
+ const id = ScalarModelID.create(schema);
473
+ let normalizedSchema = schema;
474
+ if (schema.type === 'boolean') {
475
+ const { title: _, ...rest } = schema;
476
+ normalizedSchema = rest;
477
+ } else if (schema.title != null) {
478
+ const lowerCaseTitle = schema.title.toLowerCase();
479
+ if (lowerCaseTitle === 'attachmentid') {
480
+ this.#fieldsMeta[fieldKey] = {
481
+ type: 'attachment'
482
+ };
483
+ normalizedSchema = {
484
+ ...schema,
485
+ title: 'attachmentid'
486
+ };
487
+ } else if (lowerCaseTitle === 'did') {
488
+ this.#fieldsMeta[fieldKey] = {
489
+ type: 'account'
490
+ };
491
+ normalizedSchema = {
492
+ ...schema,
493
+ title: 'did'
494
+ };
495
+ } else if (lowerCaseTitle === 'docid') {
496
+ if (this.#fieldsMeta[fieldKey] == null) {
497
+ this.#logger.warn('Missing fieldMeta entry for document reference {fieldKey} of model {inputModel}', {
498
+ fieldKey,
499
+ inputModel: this.#inputModel
500
+ });
501
+ this.#fieldsMeta[fieldKey] = {
502
+ type: 'document',
503
+ model: null
504
+ };
505
+ }
506
+ normalizedSchema = {
507
+ ...schema,
508
+ title: 'docid'
509
+ };
510
+ } else {
511
+ normalizedSchema = {
512
+ ...schema,
513
+ title: pascalCase(schema.title)
514
+ };
515
+ }
516
+ }
517
+ this.#refs[id.toString()] = normalizedSchema;
518
+ return toReference(id);
519
+ }
520
+ #addShape(schema) {
521
+ const id = ShapeModelID.create(schema);
522
+ this.#refs[id.toString()] = schema;
523
+ return toReference(id);
524
+ }
525
+ #processFieldsMeta() {
526
+ // Convert model relations by index to local IDs
527
+ for (const [key, field] of Object.entries(this.#fieldsMeta)){
528
+ if (field.type !== 'document' || field.model === null) {
529
+ continue;
530
+ }
531
+ const match = field.model.match(LOCAL_ID_REGEXP);
532
+ if (match != null) {
533
+ this.#fieldsMeta[key] = {
534
+ ...field,
535
+ model: DocumentModelID.local(Number.parseInt(match[1], 10)).toString()
536
+ };
537
+ }
538
+ }
539
+ }
540
+ toDocumentModel() {
541
+ return asType(validateDocumentModel, {
542
+ version: '1.0',
543
+ behavior: 'default',
544
+ ...this.#inputModel,
545
+ interfaces: Array.from(this.#interfaces),
546
+ schema: this.#normalizedSchema,
547
+ fieldsMeta: this.#fieldsMeta
548
+ });
549
+ }
550
+ }
@@ -1 +1,55 @@
1
- import{verifyCluster as e}from"./cluster.js";export class GraphModel{static fromClusters(s){let r={};for(let a of Object.values(s.clusters).map(e))Object.assign(r,a);return new GraphModel({aliases:s.aliases,record:r})}#e;#s;constructor(e){null!=e.aliases&&0!==Object.keys(e.aliases).length?this.#e=e.aliases:this.#e=Object.entries(e.record).reduce((e,[s,r])=>(null==e[r.name]?e[r.name]=s:console.warn(`Duplicate model name ${r.name} in GraphModel record, ignoring model ID ${s} in aliases`),e),{}),this.#s=e.record}get aliases(){return this.#e}get record(){return this.#s}getAlias(e){for(let[s,r]of Object.entries(this.#e))if(r===e)return s;return null}getModel(e){let s=this.#e[e]??e;return this.#s[s]??null}toJSON(){return{aliases:this.#e,record:this.#s}}}
1
+ import { verifyCluster } from './cluster.js';
2
+ export class GraphModel {
3
+ static fromClusters(params) {
4
+ const record = {};
5
+ for (const clusterRecord of Object.values(params.clusters).map(verifyCluster)){
6
+ Object.assign(record, clusterRecord);
7
+ }
8
+ return new GraphModel({
9
+ aliases: params.aliases,
10
+ record
11
+ });
12
+ }
13
+ #aliases;
14
+ #record;
15
+ constructor(params){
16
+ if (params.aliases != null && Object.keys(params.aliases).length !== 0) {
17
+ this.#aliases = params.aliases;
18
+ } else {
19
+ // If no aliases are provided, fallback to using the model names
20
+ this.#aliases = Object.entries(params.record).reduce((acc, [id, model])=>{
21
+ if (acc[model.name] == null) {
22
+ acc[model.name] = id;
23
+ } else {
24
+ console.warn(`Duplicate model name ${model.name} in GraphModel record, ignoring model ID ${id} in aliases`);
25
+ }
26
+ return acc;
27
+ }, {});
28
+ }
29
+ this.#record = params.record;
30
+ }
31
+ get aliases() {
32
+ return this.#aliases;
33
+ }
34
+ get record() {
35
+ return this.#record;
36
+ }
37
+ getAlias(modelID) {
38
+ for (const [alias, id] of Object.entries(this.#aliases)){
39
+ if (id === modelID) {
40
+ return alias;
41
+ }
42
+ }
43
+ return null;
44
+ }
45
+ getModel(aliasOrID) {
46
+ const id = this.#aliases[aliasOrID] ?? aliasOrID;
47
+ return this.#record[id] ?? null;
48
+ }
49
+ toJSON() {
50
+ return {
51
+ aliases: this.#aliases,
52
+ record: this.#record
53
+ };
54
+ }
55
+ }
@@ -1 +1 @@
1
- export{};
1
+ export { };
@@ -1,4 +1,4 @@
1
- import type { FromSchema } from '@enkaku/schema';
1
+ import type { FromSchema } from '@sozai/schema';
2
2
  export declare const booleanModel: {
3
3
  readonly type: "object";
4
4
  readonly properties: {