@kubun/protocol 0.3.11 → 0.4.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/lib/models/cluster.d.ts +134 -300
- package/lib/models/cluster.d.ts.map +1 -1
- package/lib/models/cluster.js +14 -201
- package/lib/models/document.d.ts +890 -148
- package/lib/models/document.d.ts.map +1 -1
- package/lib/models/document.js +300 -2
- package/lib/services/graph.d.ts +648 -162
- package/lib/services/graph.d.ts.map +1 -1
- package/package.json +3 -2
package/lib/models/cluster.js
CHANGED
|
@@ -1,156 +1,9 @@
|
|
|
1
1
|
import { toB64 } from '@enkaku/codec';
|
|
2
2
|
import { assertType, createValidator } from '@enkaku/schema';
|
|
3
|
-
import { DocumentModelID, digestJSON
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
3
|
+
import { DocumentModelID, digestJSON } from '@kubun/id';
|
|
4
|
+
import { getKubunLogger } from '@kubun/logger';
|
|
5
|
+
import { DocumentModelNormalizer, documentModelsCluster } from './document.js';
|
|
6
6
|
import { binaryStringValue } from './value.js';
|
|
7
|
-
const JSONObjectSchema = {
|
|
8
|
-
type: 'object',
|
|
9
|
-
title: 'JSONObject',
|
|
10
|
-
additionalProperties: true
|
|
11
|
-
};
|
|
12
|
-
export const REFERENCE_PREFIX = '#/$defs/';
|
|
13
|
-
function toReference(id) {
|
|
14
|
-
return `${REFERENCE_PREFIX}${id}`;
|
|
15
|
-
}
|
|
16
|
-
function resolveReference(root, ref) {
|
|
17
|
-
if (!ref.startsWith('#')) {
|
|
18
|
-
throw new Error(`Invalid reference format: ${ref}`);
|
|
19
|
-
}
|
|
20
|
-
// Handle #/$defs/ references
|
|
21
|
-
if (ref.startsWith(REFERENCE_PREFIX)) {
|
|
22
|
-
const key = ref.slice(REFERENCE_PREFIX.length);
|
|
23
|
-
const resolved = root.$defs?.[key];
|
|
24
|
-
if (resolved == null) {
|
|
25
|
-
throw new Error(`Reference not found: ${ref}`);
|
|
26
|
-
}
|
|
27
|
-
return resolved;
|
|
28
|
-
}
|
|
29
|
-
// Handle other JSON Schema references like #/properties/, #/items/, etc.
|
|
30
|
-
const segments = ref.split('/').slice(1);
|
|
31
|
-
// biome-ignore lint/suspicious/noExplicitAny: mixed type
|
|
32
|
-
let current = root;
|
|
33
|
-
for (const segment of segments){
|
|
34
|
-
if (current == null || typeof current !== 'object') {
|
|
35
|
-
throw new Error(`Invalid reference path: ${ref}`);
|
|
36
|
-
}
|
|
37
|
-
current = current[segment];
|
|
38
|
-
if (current == null) {
|
|
39
|
-
throw new Error(`Reference not found: ${ref}`);
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
return current;
|
|
43
|
-
}
|
|
44
|
-
function addScalar(refs, schema) {
|
|
45
|
-
const id = ScalarModelID.create(schema);
|
|
46
|
-
let normalizedSchema = schema;
|
|
47
|
-
if (schema.type === 'boolean') {
|
|
48
|
-
const { title: _, ...rest } = schema;
|
|
49
|
-
normalizedSchema = rest;
|
|
50
|
-
} else if (schema.title != null) {
|
|
51
|
-
normalizedSchema = {
|
|
52
|
-
...schema,
|
|
53
|
-
title: pascalCase(schema.title)
|
|
54
|
-
};
|
|
55
|
-
}
|
|
56
|
-
refs[id.toString()] = normalizedSchema;
|
|
57
|
-
return toReference(id);
|
|
58
|
-
}
|
|
59
|
-
function addShape(refs, schema) {
|
|
60
|
-
const id = ShapeModelID.create(schema);
|
|
61
|
-
refs[id.toString()] = schema;
|
|
62
|
-
return toReference(id);
|
|
63
|
-
}
|
|
64
|
-
function encodeSchema(root, refs, schema) {
|
|
65
|
-
if (schema.$ref != null) {
|
|
66
|
-
const resolvedSchema = resolveReference(root, schema.$ref);
|
|
67
|
-
return encodeSchema(root, refs, resolvedSchema);
|
|
68
|
-
}
|
|
69
|
-
const type = schema.type;
|
|
70
|
-
if (type == null) {
|
|
71
|
-
throw new Error('Invalid schema: missing type');
|
|
72
|
-
}
|
|
73
|
-
switch(type){
|
|
74
|
-
case 'array':
|
|
75
|
-
{
|
|
76
|
-
if (schema.title == null) {
|
|
77
|
-
throw new Error('Invalid array schema: missing title');
|
|
78
|
-
}
|
|
79
|
-
if (schema.items == null) {
|
|
80
|
-
throw new Error('Invalid array schema: missing items');
|
|
81
|
-
}
|
|
82
|
-
const { default: _, ...rest } = schema;
|
|
83
|
-
return addShape(refs, {
|
|
84
|
-
...rest,
|
|
85
|
-
title: pascalCase(schema.title),
|
|
86
|
-
items: {
|
|
87
|
-
$ref: encodeSchema(root, refs, schema.items)
|
|
88
|
-
}
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
case 'object':
|
|
92
|
-
{
|
|
93
|
-
if (schema.additionalProperties) {
|
|
94
|
-
return addShape(refs, JSONObjectSchema);
|
|
95
|
-
}
|
|
96
|
-
if (schema.title == null) {
|
|
97
|
-
throw new Error('Invalid object schema: missing title');
|
|
98
|
-
}
|
|
99
|
-
const entries = Object.entries(schema.properties ?? {});
|
|
100
|
-
if (entries.length === 0) {
|
|
101
|
-
throw new Error('Invalid object schema: must contain at least one property');
|
|
102
|
-
}
|
|
103
|
-
const properties = {};
|
|
104
|
-
for (const [key, value] of entries){
|
|
105
|
-
properties[key] = {
|
|
106
|
-
$ref: encodeSchema(root, refs, value)
|
|
107
|
-
};
|
|
108
|
-
}
|
|
109
|
-
return addShape(refs, {
|
|
110
|
-
type: 'object',
|
|
111
|
-
title: pascalCase(schema.title),
|
|
112
|
-
properties,
|
|
113
|
-
required: schema.required ?? [],
|
|
114
|
-
additionalProperties: false
|
|
115
|
-
});
|
|
116
|
-
}
|
|
117
|
-
default:
|
|
118
|
-
return addScalar(refs, schema);
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
function normalizeDocumentSchema(schema) {
|
|
122
|
-
const entries = Object.entries(schema.properties ?? {});
|
|
123
|
-
if (entries.length === 0) {
|
|
124
|
-
throw new Error('Document schema must contain at least one property');
|
|
125
|
-
}
|
|
126
|
-
const properties = {};
|
|
127
|
-
const refs = schema.$defs ?? {};
|
|
128
|
-
for (const [key, value] of entries){
|
|
129
|
-
properties[key] = {
|
|
130
|
-
$ref: encodeSchema(schema, refs, value)
|
|
131
|
-
};
|
|
132
|
-
}
|
|
133
|
-
return {
|
|
134
|
-
type: 'object',
|
|
135
|
-
properties,
|
|
136
|
-
additionalProperties: false,
|
|
137
|
-
required: schema.required ?? [],
|
|
138
|
-
$defs: refs
|
|
139
|
-
};
|
|
140
|
-
}
|
|
141
|
-
const LOCAL_ID_REGEXP = /^#([0-9]+)$/;
|
|
142
|
-
function normalizeFieldsMeta(fields) {
|
|
143
|
-
const meta = {};
|
|
144
|
-
for (const [key, field] of Object.entries(fields)){
|
|
145
|
-
const match = field.relationModel?.match(LOCAL_ID_REGEXP);
|
|
146
|
-
meta[key] = match == null ? field : {
|
|
147
|
-
...field,
|
|
148
|
-
relationModel: DocumentModelID.local(Number.parseInt(match[1], 10)).toString()
|
|
149
|
-
};
|
|
150
|
-
}
|
|
151
|
-
return meta;
|
|
152
|
-
}
|
|
153
|
-
export const validateDocumentModel = createValidator(documentModel);
|
|
154
7
|
export const clusterModel = {
|
|
155
8
|
$id: 'urn:kubun:protocol:model:cluster',
|
|
156
9
|
type: 'object',
|
|
@@ -202,6 +55,10 @@ export function verifyCluster(cluster) {
|
|
|
202
55
|
}
|
|
203
56
|
export class ClusterBuilder {
|
|
204
57
|
#cluster = [];
|
|
58
|
+
#logger;
|
|
59
|
+
constructor(params = {}){
|
|
60
|
+
this.#logger = params.logger ?? getKubunLogger('protocol');
|
|
61
|
+
}
|
|
205
62
|
get cluster() {
|
|
206
63
|
return this.#cluster;
|
|
207
64
|
}
|
|
@@ -248,13 +105,7 @@ export class ClusterBuilder {
|
|
|
248
105
|
return model;
|
|
249
106
|
}
|
|
250
107
|
add(inputModel) {
|
|
251
|
-
const inputSchema = inputModel.schema ?? {};
|
|
252
108
|
const interfaceIDs = inputModel.interfaces ?? [];
|
|
253
|
-
const interfaces = new Set();
|
|
254
|
-
const schemaProperties = {};
|
|
255
|
-
const schemaReferences = {};
|
|
256
|
-
const schemaRequired = new Set();
|
|
257
|
-
const fieldsMeta = {};
|
|
258
109
|
const normalizedInterfaceIDs = interfaceIDs.map((id)=>{
|
|
259
110
|
if (id.startsWith('#')) {
|
|
260
111
|
const index = Number.parseInt(id.slice(1), 10);
|
|
@@ -265,55 +116,17 @@ export class ClusterBuilder {
|
|
|
265
116
|
}
|
|
266
117
|
return id;
|
|
267
118
|
});
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
schemaRequired.add(requiredKey);
|
|
275
|
-
}
|
|
276
|
-
Object.assign(schemaProperties, interfaceModel.schema.properties);
|
|
277
|
-
Object.assign(schemaReferences, interfaceModel.schema.$defs);
|
|
278
|
-
Object.assign(fieldsMeta, interfaceModel.fieldsMeta ?? {});
|
|
279
|
-
}
|
|
280
|
-
// Add model extra fields
|
|
281
|
-
for (const interfaceID of normalizedInterfaceIDs){
|
|
282
|
-
interfaces.add(interfaceID);
|
|
283
|
-
}
|
|
284
|
-
for (const requiredKey of inputSchema.required ?? []){
|
|
285
|
-
schemaRequired.add(requiredKey);
|
|
286
|
-
}
|
|
287
|
-
Object.assign(schemaProperties, inputSchema.properties ?? {});
|
|
288
|
-
Object.assign(fieldsMeta, inputModel.fieldsMeta ?? {});
|
|
119
|
+
const model = new DocumentModelNormalizer({
|
|
120
|
+
inputModel,
|
|
121
|
+
interfaceModels: normalizedInterfaceIDs.map((id)=>this.get(id)),
|
|
122
|
+
logger: this.#logger,
|
|
123
|
+
normalizedInterfaceIDs
|
|
124
|
+
}).toDocumentModel();
|
|
289
125
|
const index = this.#cluster.length;
|
|
290
|
-
const model = {
|
|
291
|
-
version: '1.0',
|
|
292
|
-
behavior: 'default',
|
|
293
|
-
...inputModel,
|
|
294
|
-
interfaces: Array.from(interfaces),
|
|
295
|
-
schema: normalizeDocumentSchema({
|
|
296
|
-
...inputSchema,
|
|
297
|
-
type: 'object',
|
|
298
|
-
properties: schemaProperties,
|
|
299
|
-
required: Array.from(schemaRequired),
|
|
300
|
-
additionalProperties: false,
|
|
301
|
-
$defs: {
|
|
302
|
-
...inputSchema.$defs,
|
|
303
|
-
...schemaReferences
|
|
304
|
-
}
|
|
305
|
-
}),
|
|
306
|
-
fieldsMeta: normalizeFieldsMeta(fieldsMeta)
|
|
307
|
-
};
|
|
308
|
-
assertType(validateDocumentModel, model);
|
|
309
126
|
this.#cluster.push(model);
|
|
310
127
|
return DocumentModelID.local(index);
|
|
311
128
|
}
|
|
312
129
|
addAll(models) {
|
|
313
|
-
|
|
314
|
-
for (const model of models){
|
|
315
|
-
ids.push(this.add(model));
|
|
316
|
-
}
|
|
317
|
-
return ids;
|
|
130
|
+
return models.map((input)=>this.add(input));
|
|
318
131
|
}
|
|
319
132
|
}
|