@alepha/protobuf 0.9.4 → 0.10.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/dist/index.cjs +74 -45
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -27
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +7 -27
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +75 -46
- package/dist/index.js.map +1 -1
- package/package.json +5 -3
- package/src/providers/ProtobufProvider.ts +134 -56
package/dist/index.cjs
CHANGED
|
@@ -31,27 +31,18 @@ var ProtobufProvider = class {
|
|
|
31
31
|
protobuf = protobufjs.default;
|
|
32
32
|
/**
|
|
33
33
|
* Encode an object to a Uint8Array.
|
|
34
|
-
*
|
|
35
|
-
* @param schema - TypeBox schema used to generate the Protobuf schema.
|
|
36
|
-
* @param data - Object to encode. Can be any object or string.
|
|
37
34
|
*/
|
|
38
35
|
encode(schema, data) {
|
|
39
36
|
return this.parse(schema).encode(this.alepha.parse(schema, data)).finish();
|
|
40
37
|
}
|
|
41
38
|
/**
|
|
42
39
|
* Decode a Uint8Array to an object.
|
|
43
|
-
*
|
|
44
|
-
* @param schema
|
|
45
|
-
* @param data
|
|
46
40
|
*/
|
|
47
41
|
decode(schema, data) {
|
|
48
42
|
return this.alepha.parse(schema, this.parse(schema).decode(data));
|
|
49
43
|
}
|
|
50
44
|
/**
|
|
51
45
|
* Parse a TypeBox schema to a Protobuf Type schema ready for encoding/decoding.
|
|
52
|
-
*
|
|
53
|
-
* @param schema
|
|
54
|
-
* @param typeName
|
|
55
46
|
*/
|
|
56
47
|
parse(schema, typeName = "root.Target") {
|
|
57
48
|
const exists = this.schemas.get(schema);
|
|
@@ -64,9 +55,6 @@ var ProtobufProvider = class {
|
|
|
64
55
|
}
|
|
65
56
|
/**
|
|
66
57
|
* Convert a TypeBox schema to a Protobuf schema as a string.
|
|
67
|
-
*
|
|
68
|
-
* @param schema
|
|
69
|
-
* @param options
|
|
70
58
|
*/
|
|
71
59
|
createProtobufSchema(schema, options = {}) {
|
|
72
60
|
const { rootName = "root", mainMessageName = "Target" } = options;
|
|
@@ -74,59 +62,100 @@ var ProtobufProvider = class {
|
|
|
74
62
|
proto: `package ${rootName};\nsyntax = "proto3";\n\n`,
|
|
75
63
|
fieldIndex: 1
|
|
76
64
|
};
|
|
77
|
-
if (__alepha_core.
|
|
78
|
-
const
|
|
79
|
-
context.proto +=
|
|
65
|
+
if (__alepha_core.t.schema.isObject(schema)) {
|
|
66
|
+
const { message, subMessages } = this.parseObjectWithDependencies(schema, mainMessageName);
|
|
67
|
+
context.proto += subMessages.join("");
|
|
68
|
+
context.proto += message;
|
|
80
69
|
}
|
|
81
70
|
return context.proto;
|
|
82
71
|
}
|
|
83
72
|
/**
|
|
84
|
-
* Parse an object schema
|
|
85
|
-
*
|
|
86
|
-
* @param obj
|
|
87
|
-
* @param parentName
|
|
88
|
-
* @param context
|
|
89
|
-
* @protected
|
|
73
|
+
* Parse an object schema with dependencies (sub-messages).
|
|
90
74
|
*/
|
|
91
|
-
|
|
92
|
-
if (!__alepha_core.
|
|
75
|
+
parseObjectWithDependencies(obj, parentName) {
|
|
76
|
+
if (!__alepha_core.t.schema.isObject(obj)) return {
|
|
77
|
+
message: "",
|
|
78
|
+
subMessages: []
|
|
79
|
+
};
|
|
93
80
|
const fields = [];
|
|
81
|
+
const subMessages = [];
|
|
82
|
+
let fieldIndex = 1;
|
|
94
83
|
for (const [key, value] of Object.entries(obj.properties)) {
|
|
95
|
-
if (__alepha_core.
|
|
96
|
-
if (__alepha_core.
|
|
97
|
-
const subMessageName = value.items.title
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
});
|
|
102
|
-
fields.push(` repeated ${subMessageName} ${key} = ${context.fieldIndex++};`);
|
|
84
|
+
if (__alepha_core.t.schema.isArray(value)) {
|
|
85
|
+
if (__alepha_core.t.schema.isObject(value.items)) {
|
|
86
|
+
const subMessageName = "title" in value.items && typeof value.items.title === "string" ? value.items.title : `${parentName}_${key}`;
|
|
87
|
+
const { message: subMessage, subMessages: nestedSubMessages } = this.parseObjectWithDependencies(value.items, subMessageName);
|
|
88
|
+
subMessages.push(...nestedSubMessages);
|
|
89
|
+
subMessages.push(subMessage);
|
|
90
|
+
fields.push(` repeated ${subMessageName} ${key} = ${fieldIndex++};`);
|
|
103
91
|
continue;
|
|
104
92
|
}
|
|
105
93
|
const itemType = this.convertType(value.items);
|
|
106
|
-
fields.push(` repeated ${itemType} ${key} = ${
|
|
94
|
+
fields.push(` repeated ${itemType} ${key} = ${fieldIndex++};`);
|
|
107
95
|
continue;
|
|
108
96
|
}
|
|
109
|
-
if (__alepha_core.
|
|
110
|
-
const subMessageName = `${parentName}_${key}`;
|
|
111
|
-
|
|
112
|
-
|
|
97
|
+
if (__alepha_core.t.schema.isObject(value)) {
|
|
98
|
+
const subMessageName = "title" in value && typeof value.title === "string" ? value.title : `${parentName}_${key}`;
|
|
99
|
+
const { message: subMessage, subMessages: nestedSubMessages } = this.parseObjectWithDependencies(value, subMessageName);
|
|
100
|
+
subMessages.push(...nestedSubMessages);
|
|
101
|
+
subMessages.push(subMessage);
|
|
102
|
+
fields.push(` ${subMessageName} ${key} = ${fieldIndex++};`);
|
|
113
103
|
continue;
|
|
114
104
|
}
|
|
115
|
-
|
|
105
|
+
if (__alepha_core.t.schema.isUnion(value)) {
|
|
106
|
+
const nonNullType = value.anyOf.find((type) => !__alepha_core.t.schema.isNull(type));
|
|
107
|
+
if (nonNullType) {
|
|
108
|
+
if (__alepha_core.t.schema.isObject(nonNullType)) {
|
|
109
|
+
const subMessageName = "title" in nonNullType && typeof nonNullType.title === "string" ? nonNullType.title : `${parentName}_${key}`;
|
|
110
|
+
const { message: subMessage, subMessages: nestedSubMessages } = this.parseObjectWithDependencies(nonNullType, subMessageName);
|
|
111
|
+
subMessages.push(...nestedSubMessages);
|
|
112
|
+
subMessages.push(subMessage);
|
|
113
|
+
fields.push(` ${subMessageName} ${key} = ${fieldIndex++};`);
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
const fieldType$1 = this.convertType(nonNullType);
|
|
117
|
+
fields.push(` ${fieldType$1} ${key} = ${fieldIndex++};`);
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
if (__alepha_core.t.schema.isRecord(value)) {
|
|
122
|
+
let valueSchema;
|
|
123
|
+
if ("additionalProperties" in value && value.additionalProperties && typeof value.additionalProperties === "object") valueSchema = value.additionalProperties;
|
|
124
|
+
else if (value.patternProperties && typeof value.patternProperties === "object") {
|
|
125
|
+
const patterns = Object.values(value.patternProperties);
|
|
126
|
+
if (patterns.length > 0 && typeof patterns[0] === "object") valueSchema = patterns[0];
|
|
127
|
+
}
|
|
128
|
+
if (valueSchema) {
|
|
129
|
+
const valueType = this.convertType(valueSchema);
|
|
130
|
+
fields.push(` map<string, ${valueType}> ${key} = ${fieldIndex++};`);
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
const fieldType = this.convertType(value);
|
|
135
|
+
fields.push(` ${fieldType} ${key} = ${fieldIndex++};`);
|
|
116
136
|
}
|
|
117
|
-
|
|
137
|
+
const message = `message ${parentName} {\n${fields.join("\n")}\n}\n`;
|
|
138
|
+
return {
|
|
139
|
+
message,
|
|
140
|
+
subMessages
|
|
141
|
+
};
|
|
118
142
|
}
|
|
119
143
|
/**
|
|
120
144
|
* Convert a primitive TypeBox schema type to a Protobuf spec type.
|
|
121
|
-
*
|
|
122
|
-
* @param schema
|
|
123
|
-
* @protected
|
|
124
145
|
*/
|
|
125
146
|
convertType(schema) {
|
|
126
|
-
if (__alepha_core.
|
|
127
|
-
if (__alepha_core.
|
|
128
|
-
if (__alepha_core.
|
|
129
|
-
if (__alepha_core.
|
|
147
|
+
if (__alepha_core.t.schema.isBoolean(schema)) return "bool";
|
|
148
|
+
if (__alepha_core.t.schema.isNumber(schema) && schema.format === "int64") return "int64";
|
|
149
|
+
if (__alepha_core.t.schema.isNumber(schema)) return "double";
|
|
150
|
+
if (__alepha_core.t.schema.isInteger(schema)) return "int32";
|
|
151
|
+
if (__alepha_core.t.schema.isBigInt(schema)) return "int64";
|
|
152
|
+
if (__alepha_core.t.schema.isString(schema)) return "string";
|
|
153
|
+
if (__alepha_core.t.schema.isUnion(schema)) {
|
|
154
|
+
const nonNullType = schema.anyOf.find((type) => !__alepha_core.t.schema.isNull(type));
|
|
155
|
+
if (nonNullType) return this.convertType(nonNullType);
|
|
156
|
+
}
|
|
157
|
+
if (__alepha_core.t.schema.isOptional(schema)) return this.convertType(schema);
|
|
158
|
+
if (__alepha_core.t.schema.isUnsafe(schema)) return "string";
|
|
130
159
|
throw new Error(`Unsupported type: ${JSON.stringify(schema)}`);
|
|
131
160
|
}
|
|
132
161
|
};
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["Alepha","schema: TObject","data: any","schema: T","data: Uint8Array","schema: ProtobufSchema | TObject","schema: TSchema","options: CreateProtobufSchemaOptions","TypeGuard","obj: TSchema","parentName: string","context: { proto: string; fieldIndex: number }","fields: string[]"],"sources":["../src/providers/ProtobufProvider.ts"],"sourcesContent":["import type { Static, TObject, TProperties, TSchema } from \"@alepha/core\";\nimport { $inject, Alepha, TypeGuard } from \"@alepha/core\";\nimport type { Type } from \"protobufjs\";\nimport protobufjs from \"protobufjs\";\n\nexport class ProtobufProvider {\n\tprotected readonly alepha = $inject(Alepha);\n\tprotected readonly schemas: Map<string | TObject<TProperties>, Type> =\n\t\tnew Map();\n\tprotected readonly protobuf: typeof protobufjs = protobufjs;\n\n\t/**\n\t * Encode an object to a Uint8Array.\n\t *\n\t * @param schema - TypeBox schema used to generate the Protobuf schema.\n\t * @param data - Object to encode. Can be any object or string.\n\t */\n\tpublic encode(schema: TObject, data: any): Uint8Array {\n\t\treturn this.parse(schema).encode(this.alepha.parse(schema, data)).finish();\n\t}\n\n\t/**\n\t * Decode a Uint8Array to an object.\n\t *\n\t * @param schema\n\t * @param data\n\t */\n\tpublic decode<T extends TObject>(schema: T, data: Uint8Array): Static<T> {\n\t\treturn this.alepha.parse(schema, this.parse(schema).decode(data));\n\t}\n\n\t/**\n\t * Parse a TypeBox schema to a Protobuf Type schema ready for encoding/decoding.\n\t *\n\t * @param schema\n\t * @param typeName\n\t */\n\tpublic parse(\n\t\tschema: ProtobufSchema | TObject,\n\t\ttypeName = \"root.Target\",\n\t): Type {\n\t\tconst exists = this.schemas.get(schema);\n\t\tif (exists) return exists;\n\n\t\tconst pbSchema =\n\t\t\ttypeof schema === \"string\" ? schema : this.createProtobufSchema(schema);\n\t\tconst result = this.protobuf.parse(pbSchema);\n\t\tconst type = result.root.lookupType(typeName);\n\t\tthis.schemas.set(schema, type);\n\t\treturn type;\n\t}\n\n\t/**\n\t * Convert a TypeBox schema to a Protobuf schema as a string.\n\t *\n\t * @param schema\n\t * @param options\n\t */\n\tpublic createProtobufSchema(\n\t\tschema: TSchema,\n\t\toptions: CreateProtobufSchemaOptions = {},\n\t): string {\n\t\tconst { rootName = \"root\", mainMessageName = \"Target\" } = options;\n\t\tconst context = {\n\t\t\tproto: `package ${rootName};\\nsyntax = \"proto3\";\\n\\n`,\n\t\t\tfieldIndex: 1,\n\t\t};\n\n\t\tif (TypeGuard.IsObject(schema)) {\n\t\t\tconst proto = this.parseObject(schema, mainMessageName, context);\n\t\t\tcontext.proto += proto;\n\t\t}\n\n\t\treturn context.proto;\n\t}\n\n\t/**\n\t * Parse an object schema to a Protobuf message.\n\t *\n\t * @param obj\n\t * @param parentName\n\t * @param context\n\t * @protected\n\t */\n\tprotected parseObject(\n\t\tobj: TSchema,\n\t\tparentName: string,\n\t\tcontext: { proto: string; fieldIndex: number },\n\t): string {\n\t\tif (!TypeGuard.IsObject(obj)) {\n\t\t\treturn \"\";\n\t\t}\n\n\t\tconst fields: string[] = [];\n\n\t\tfor (const [key, value] of Object.entries(obj.properties)) {\n\t\t\tif (TypeGuard.IsArray(value)) {\n\t\t\t\tif (TypeGuard.IsObject(value.items)) {\n\t\t\t\t\tconst subMessageName = value.items.title ?? `${parentName}_${key}`;\n\t\t\t\t\tcontext.proto += this.parseObject(value.items, subMessageName, {\n\t\t\t\t\t\t...context,\n\t\t\t\t\t\tfieldIndex: 1,\n\t\t\t\t\t});\n\t\t\t\t\tfields.push(\n\t\t\t\t\t\t` repeated ${subMessageName} ${key} = ${context.fieldIndex++};`,\n\t\t\t\t\t);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst itemType = this.convertType(value.items);\n\t\t\t\tfields.push(` repeated ${itemType} ${key} = ${context.fieldIndex++};`);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (TypeGuard.IsObject(value)) {\n\t\t\t\tconst subMessageName = `${parentName}_${key}`;\n\t\t\t\tcontext.proto += this.parseObject(value, subMessageName, context);\n\t\t\t\tfields.push(` ${subMessageName} ${key} = ${context.fieldIndex++};`);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tfields.push(\n\t\t\t\t` ${this.convertType(value)} ${key} = ${context.fieldIndex++};`,\n\t\t\t);\n\t\t}\n\n\t\treturn `message ${parentName} {\\n${fields.join(\"\\n\")}\\n}\\n`;\n\t}\n\n\t/**\n\t * Convert a primitive TypeBox schema type to a Protobuf spec type.\n\t *\n\t * @param schema\n\t * @protected\n\t */\n\tprotected convertType(schema: TSchema): string {\n\t\tif (TypeGuard.IsInteger(schema)) return \"int32\";\n\t\tif (TypeGuard.IsNumber(schema)) return \"double\";\n\t\tif (TypeGuard.IsString(schema)) return \"string\";\n\t\tif (TypeGuard.IsBoolean(schema)) return \"bool\";\n\n\t\tthrow new Error(`Unsupported type: ${JSON.stringify(schema)}`);\n\t}\n}\n\nexport type ProtobufSchema = string;\n\nexport interface CreateProtobufSchemaOptions {\n\trootName?: string;\n\tmainMessageName?: string;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["Alepha","t","fields: string[]","subMessages: string[]","fieldType","valueSchema: TSchema | undefined"],"sources":["../src/providers/ProtobufProvider.ts"],"sourcesContent":["import {\n\t$inject,\n\tAlepha,\n\ttype Static,\n\ttype TObject,\n\ttype TSchema,\n\tt,\n} from \"@alepha/core\";\nimport type { Type } from \"protobufjs\";\nimport protobufjs from \"protobufjs\";\n\nexport class ProtobufProvider {\n\tprotected readonly alepha = $inject(Alepha);\n\tprotected readonly schemas: Map<string | TObject, Type> = new Map();\n\tprotected readonly protobuf: typeof protobufjs = protobufjs;\n\n\t/**\n\t * Encode an object to a Uint8Array.\n\t */\n\tpublic encode(schema: TObject, data: any): Uint8Array {\n\t\treturn this.parse(schema).encode(this.alepha.parse(schema, data)).finish();\n\t}\n\n\t/**\n\t * Decode a Uint8Array to an object.\n\t */\n\tpublic decode<T extends TObject>(schema: T, data: Uint8Array): Static<T> {\n\t\treturn this.alepha.parse(schema, this.parse(schema).decode(data));\n\t}\n\n\t/**\n\t * Parse a TypeBox schema to a Protobuf Type schema ready for encoding/decoding.\n\t */\n\tpublic parse(\n\t\tschema: ProtobufSchema | TObject,\n\t\ttypeName = \"root.Target\",\n\t): Type {\n\t\tconst exists = this.schemas.get(schema);\n\t\tif (exists) return exists;\n\n\t\tconst pbSchema =\n\t\t\ttypeof schema === \"string\" ? schema : this.createProtobufSchema(schema);\n\t\tconst result = this.protobuf.parse(pbSchema);\n\t\tconst type = result.root.lookupType(typeName);\n\t\tthis.schemas.set(schema, type);\n\t\treturn type;\n\t}\n\n\t/**\n\t * Convert a TypeBox schema to a Protobuf schema as a string.\n\t */\n\tpublic createProtobufSchema(\n\t\tschema: TSchema,\n\t\toptions: CreateProtobufSchemaOptions = {},\n\t): string {\n\t\tconst { rootName = \"root\", mainMessageName = \"Target\" } = options;\n\t\tconst context = {\n\t\t\tproto: `package ${rootName};\\nsyntax = \"proto3\";\\n\\n`,\n\t\t\tfieldIndex: 1,\n\t\t};\n\n\t\tif (t.schema.isObject(schema)) {\n\t\t\tconst { message, subMessages } = this.parseObjectWithDependencies(\n\t\t\t\tschema,\n\t\t\t\tmainMessageName,\n\t\t\t);\n\t\t\t// Add all sub-messages first\n\t\t\tcontext.proto += subMessages.join(\"\");\n\t\t\t// Then add the main message\n\t\t\tcontext.proto += message;\n\t\t}\n\n\t\treturn context.proto;\n\t}\n\n\t/**\n\t * Parse an object schema with dependencies (sub-messages).\n\t */\n\tprotected parseObjectWithDependencies(\n\t\tobj: TSchema,\n\t\tparentName: string,\n\t): { message: string; subMessages: string[] } {\n\t\tif (!t.schema.isObject(obj)) {\n\t\t\treturn { message: \"\", subMessages: [] };\n\t\t}\n\n\t\tconst fields: string[] = [];\n\t\tconst subMessages: string[] = [];\n\t\tlet fieldIndex = 1;\n\n\t\tfor (const [key, value] of Object.entries(obj.properties)) {\n\t\t\t// Handle arrays\n\t\t\tif (t.schema.isArray(value)) {\n\t\t\t\tif (t.schema.isObject(value.items)) {\n\t\t\t\t\tconst subMessageName =\n\t\t\t\t\t\t\"title\" in value.items && typeof value.items.title === \"string\"\n\t\t\t\t\t\t\t? value.items.title\n\t\t\t\t\t\t\t: `${parentName}_${key}`;\n\t\t\t\t\tconst { message: subMessage, subMessages: nestedSubMessages } =\n\t\t\t\t\t\tthis.parseObjectWithDependencies(value.items, subMessageName);\n\t\t\t\t\tsubMessages.push(...nestedSubMessages);\n\t\t\t\t\tsubMessages.push(subMessage);\n\t\t\t\t\tfields.push(` repeated ${subMessageName} ${key} = ${fieldIndex++};`);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst itemType = this.convertType(value.items);\n\t\t\t\tfields.push(` repeated ${itemType} ${key} = ${fieldIndex++};`);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Handle nested objects\n\t\t\tif (t.schema.isObject(value)) {\n\t\t\t\tconst subMessageName =\n\t\t\t\t\t\"title\" in value && typeof value.title === \"string\"\n\t\t\t\t\t\t? value.title\n\t\t\t\t\t\t: `${parentName}_${key}`;\n\t\t\t\tconst { message: subMessage, subMessages: nestedSubMessages } =\n\t\t\t\t\tthis.parseObjectWithDependencies(value, subMessageName);\n\t\t\t\tsubMessages.push(...nestedSubMessages);\n\t\t\t\tsubMessages.push(subMessage);\n\t\t\t\tfields.push(` ${subMessageName} ${key} = ${fieldIndex++};`);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Handle union types (nullable fields)\n\t\t\tif (t.schema.isUnion(value)) {\n\t\t\t\tconst nonNullType = value.anyOf.find(\n\t\t\t\t\t(type: TSchema) => !t.schema.isNull(type),\n\t\t\t\t);\n\t\t\t\tif (nonNullType) {\n\t\t\t\t\tif (t.schema.isObject(nonNullType)) {\n\t\t\t\t\t\tconst subMessageName =\n\t\t\t\t\t\t\t\"title\" in nonNullType && typeof nonNullType.title === \"string\"\n\t\t\t\t\t\t\t\t? nonNullType.title\n\t\t\t\t\t\t\t\t: `${parentName}_${key}`;\n\t\t\t\t\t\tconst { message: subMessage, subMessages: nestedSubMessages } =\n\t\t\t\t\t\t\tthis.parseObjectWithDependencies(nonNullType, subMessageName);\n\t\t\t\t\t\tsubMessages.push(...nestedSubMessages);\n\t\t\t\t\t\tsubMessages.push(subMessage);\n\t\t\t\t\t\tfields.push(` ${subMessageName} ${key} = ${fieldIndex++};`);\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tconst fieldType = this.convertType(nonNullType);\n\t\t\t\t\tfields.push(` ${fieldType} ${key} = ${fieldIndex++};`);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Handle records (maps)\n\t\t\tif (t.schema.isRecord(value)) {\n\t\t\t\t// TypeBox records use additionalProperties or patternProperties for the value type\n\t\t\t\tlet valueSchema: TSchema | undefined;\n\t\t\t\tif (\n\t\t\t\t\t\"additionalProperties\" in value &&\n\t\t\t\t\tvalue.additionalProperties &&\n\t\t\t\t\ttypeof value.additionalProperties === \"object\"\n\t\t\t\t) {\n\t\t\t\t\tvalueSchema = value.additionalProperties;\n\t\t\t\t} else if (\n\t\t\t\t\tvalue.patternProperties &&\n\t\t\t\t\ttypeof value.patternProperties === \"object\"\n\t\t\t\t) {\n\t\t\t\t\t// Get the first pattern property (usually \"^(.*)$\" or similar)\n\t\t\t\t\tconst patterns = Object.values(value.patternProperties);\n\t\t\t\t\tif (patterns.length > 0 && typeof patterns[0] === \"object\") {\n\t\t\t\t\t\tvalueSchema = patterns[0] as TSchema;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (valueSchema) {\n\t\t\t\t\tconst valueType = this.convertType(valueSchema);\n\t\t\t\t\tfields.push(` map<string, ${valueType}> ${key} = ${fieldIndex++};`);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Handle regular fields\n\t\t\tconst fieldType = this.convertType(value);\n\t\t\tfields.push(` ${fieldType} ${key} = ${fieldIndex++};`);\n\t\t}\n\n\t\tconst message = `message ${parentName} {\\n${fields.join(\"\\n\")}\\n}\\n`;\n\t\treturn { message, subMessages };\n\t}\n\n\t/**\n\t * Convert a primitive TypeBox schema type to a Protobuf spec type.\n\t */\n\tprotected convertType(schema: TSchema): string {\n\t\tif (t.schema.isBoolean(schema)) return \"bool\";\n\t\tif (t.schema.isNumber(schema) && schema.format === \"int64\") return \"int64\";\n\t\tif (t.schema.isNumber(schema)) return \"double\";\n\t\tif (t.schema.isInteger(schema)) return \"int32\";\n\t\tif (t.schema.isBigInt(schema)) return \"int64\";\n\t\tif (t.schema.isString(schema)) return \"string\";\n\n\t\t// Handle union types (nullable)\n\t\tif (t.schema.isUnion(schema)) {\n\t\t\t// Find the non-null type in the union\n\t\t\tconst nonNullType = schema.anyOf.find(\n\t\t\t\t(type: TSchema) => !t.schema.isNull(type),\n\t\t\t);\n\t\t\tif (nonNullType) {\n\t\t\t\treturn this.convertType(nonNullType);\n\t\t\t}\n\t\t}\n\n\t\t// Handle optional types\n\t\tif (t.schema.isOptional(schema)) {\n\t\t\treturn this.convertType(schema);\n\t\t}\n\n\t\t// Handle unsafe types (like enums)\n\t\tif (t.schema.isUnsafe(schema)) {\n\t\t\t// if it's an enum or other unsafe types, default to string\n\t\t\treturn \"string\";\n\t\t}\n\n\t\tthrow new Error(`Unsupported type: ${JSON.stringify(schema)}`);\n\t}\n}\n\nexport type ProtobufSchema = string;\n\nexport interface CreateProtobufSchemaOptions {\n\trootName?: string;\n\tmainMessageName?: string;\n}\n"],"mappings":"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"}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,56 +1,36 @@
|
|
|
1
|
-
import { Alepha, Static, TObject,
|
|
1
|
+
import { Alepha, Static, TObject, TSchema } from "@alepha/core";
|
|
2
2
|
import protobufjs, { Type } from "protobufjs";
|
|
3
3
|
|
|
4
4
|
//#region src/providers/ProtobufProvider.d.ts
|
|
5
5
|
declare class ProtobufProvider {
|
|
6
6
|
protected readonly alepha: Alepha;
|
|
7
|
-
protected readonly schemas: Map<string | TObject
|
|
7
|
+
protected readonly schemas: Map<string | TObject, Type>;
|
|
8
8
|
protected readonly protobuf: typeof protobufjs;
|
|
9
9
|
/**
|
|
10
10
|
* Encode an object to a Uint8Array.
|
|
11
|
-
*
|
|
12
|
-
* @param schema - TypeBox schema used to generate the Protobuf schema.
|
|
13
|
-
* @param data - Object to encode. Can be any object or string.
|
|
14
11
|
*/
|
|
15
12
|
encode(schema: TObject, data: any): Uint8Array;
|
|
16
13
|
/**
|
|
17
14
|
* Decode a Uint8Array to an object.
|
|
18
|
-
*
|
|
19
|
-
* @param schema
|
|
20
|
-
* @param data
|
|
21
15
|
*/
|
|
22
16
|
decode<T extends TObject>(schema: T, data: Uint8Array): Static<T>;
|
|
23
17
|
/**
|
|
24
18
|
* Parse a TypeBox schema to a Protobuf Type schema ready for encoding/decoding.
|
|
25
|
-
*
|
|
26
|
-
* @param schema
|
|
27
|
-
* @param typeName
|
|
28
19
|
*/
|
|
29
20
|
parse(schema: ProtobufSchema | TObject, typeName?: string): Type;
|
|
30
21
|
/**
|
|
31
22
|
* Convert a TypeBox schema to a Protobuf schema as a string.
|
|
32
|
-
*
|
|
33
|
-
* @param schema
|
|
34
|
-
* @param options
|
|
35
23
|
*/
|
|
36
24
|
createProtobufSchema(schema: TSchema, options?: CreateProtobufSchemaOptions): string;
|
|
37
25
|
/**
|
|
38
|
-
* Parse an object schema
|
|
39
|
-
*
|
|
40
|
-
* @param obj
|
|
41
|
-
* @param parentName
|
|
42
|
-
* @param context
|
|
43
|
-
* @protected
|
|
26
|
+
* Parse an object schema with dependencies (sub-messages).
|
|
44
27
|
*/
|
|
45
|
-
protected
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
}
|
|
28
|
+
protected parseObjectWithDependencies(obj: TSchema, parentName: string): {
|
|
29
|
+
message: string;
|
|
30
|
+
subMessages: string[];
|
|
31
|
+
};
|
|
49
32
|
/**
|
|
50
33
|
* Convert a primitive TypeBox schema type to a Protobuf spec type.
|
|
51
|
-
*
|
|
52
|
-
* @param schema
|
|
53
|
-
* @protected
|
|
54
34
|
*/
|
|
55
35
|
protected convertType(schema: TSchema): string;
|
|
56
36
|
}
|
package/dist/index.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.cts","names":[],"sources":["../src/providers/ProtobufProvider.ts"],"sourcesContent":[],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"index.d.cts","names":[],"sources":["../src/providers/ProtobufProvider.ts"],"sourcesContent":[],"mappings":";;;;cAWa,gBAAA;EAAA,mBAAgB,MAAA,EACH,MADG;EAAA,mBAAA,OAAA,EAEA,GAFA,CAAA,MAAA,GAEa,OAFb,EAEsB,IAFtB,CAAA;qBACH,QAAA,EAAA,OAEW,UAFX;;;;QAEW,CAAA,MAAA,EAKd,OALc,EAAA,IAAA,EAAA,GAAA,CAAA,EAKO,UALP;;;;QAYK,CAAA,UAAjB,OAAiB,CAAA,CAAA,MAAA,EAAA,CAAA,EAAA,IAAA,EAAS,UAAT,CAAA,EAAsB,MAAtB,CAA6B,CAA7B,CAAA;;;;OAQhC,CAAA,MAAA,EAAA,cAAA,GAAiB,OAAjB,EAAA,QAAA,CAAA,EAAA,MAAA,CAAA,EAEN,IAFM;;;;sBAmBC,CAAA,MAAA,EADD,OACC,EAAA,OAAA,CAAA,EAAA,2BAAA,CAAA,EAAA,MAAA;;;;EA0KC,UAAA,2BAAc,CAAA,GAAA,EAhJnB,OAgJmB,EAAA,UAAA,EAAA,MAAA,CAAA,EAAA;IAET,OAAA,EAAA,MAAA;;;;;;gCApCc;;KAkCnB,cAAA;UAEK,2BAAA"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,56 +1,36 @@
|
|
|
1
|
-
import { Alepha, Static, TObject,
|
|
1
|
+
import { Alepha, Static, TObject, TSchema } from "@alepha/core";
|
|
2
2
|
import protobufjs, { Type } from "protobufjs";
|
|
3
3
|
|
|
4
4
|
//#region src/providers/ProtobufProvider.d.ts
|
|
5
5
|
declare class ProtobufProvider {
|
|
6
6
|
protected readonly alepha: Alepha;
|
|
7
|
-
protected readonly schemas: Map<string | TObject
|
|
7
|
+
protected readonly schemas: Map<string | TObject, Type>;
|
|
8
8
|
protected readonly protobuf: typeof protobufjs;
|
|
9
9
|
/**
|
|
10
10
|
* Encode an object to a Uint8Array.
|
|
11
|
-
*
|
|
12
|
-
* @param schema - TypeBox schema used to generate the Protobuf schema.
|
|
13
|
-
* @param data - Object to encode. Can be any object or string.
|
|
14
11
|
*/
|
|
15
12
|
encode(schema: TObject, data: any): Uint8Array;
|
|
16
13
|
/**
|
|
17
14
|
* Decode a Uint8Array to an object.
|
|
18
|
-
*
|
|
19
|
-
* @param schema
|
|
20
|
-
* @param data
|
|
21
15
|
*/
|
|
22
16
|
decode<T extends TObject>(schema: T, data: Uint8Array): Static<T>;
|
|
23
17
|
/**
|
|
24
18
|
* Parse a TypeBox schema to a Protobuf Type schema ready for encoding/decoding.
|
|
25
|
-
*
|
|
26
|
-
* @param schema
|
|
27
|
-
* @param typeName
|
|
28
19
|
*/
|
|
29
20
|
parse(schema: ProtobufSchema | TObject, typeName?: string): Type;
|
|
30
21
|
/**
|
|
31
22
|
* Convert a TypeBox schema to a Protobuf schema as a string.
|
|
32
|
-
*
|
|
33
|
-
* @param schema
|
|
34
|
-
* @param options
|
|
35
23
|
*/
|
|
36
24
|
createProtobufSchema(schema: TSchema, options?: CreateProtobufSchemaOptions): string;
|
|
37
25
|
/**
|
|
38
|
-
* Parse an object schema
|
|
39
|
-
*
|
|
40
|
-
* @param obj
|
|
41
|
-
* @param parentName
|
|
42
|
-
* @param context
|
|
43
|
-
* @protected
|
|
26
|
+
* Parse an object schema with dependencies (sub-messages).
|
|
44
27
|
*/
|
|
45
|
-
protected
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
}
|
|
28
|
+
protected parseObjectWithDependencies(obj: TSchema, parentName: string): {
|
|
29
|
+
message: string;
|
|
30
|
+
subMessages: string[];
|
|
31
|
+
};
|
|
49
32
|
/**
|
|
50
33
|
* Convert a primitive TypeBox schema type to a Protobuf spec type.
|
|
51
|
-
*
|
|
52
|
-
* @param schema
|
|
53
|
-
* @protected
|
|
54
34
|
*/
|
|
55
35
|
protected convertType(schema: TSchema): string;
|
|
56
36
|
}
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/providers/ProtobufProvider.ts"],"sourcesContent":[],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/providers/ProtobufProvider.ts"],"sourcesContent":[],"mappings":";;;;cAWa,gBAAA;EAAA,mBAAgB,MAAA,EACH,MADG;EAAA,mBAAA,OAAA,EAEA,GAFA,CAAA,MAAA,GAEa,OAFb,EAEsB,IAFtB,CAAA;qBACH,QAAA,EAAA,OAEW,UAFX;;;;QAEW,CAAA,MAAA,EAKd,OALc,EAAA,IAAA,EAAA,GAAA,CAAA,EAKO,UALP;;;;QAYK,CAAA,UAAjB,OAAiB,CAAA,CAAA,MAAA,EAAA,CAAA,EAAA,IAAA,EAAS,UAAT,CAAA,EAAsB,MAAtB,CAA6B,CAA7B,CAAA;;;;OAQhC,CAAA,MAAA,EAAA,cAAA,GAAiB,OAAjB,EAAA,QAAA,CAAA,EAAA,MAAA,CAAA,EAEN,IAFM;;;;sBAmBC,CAAA,MAAA,EADD,OACC,EAAA,OAAA,CAAA,EAAA,2BAAA,CAAA,EAAA,MAAA;;;;EA0KC,UAAA,2BAAc,CAAA,GAAA,EAhJnB,OAgJmB,EAAA,UAAA,EAAA,MAAA,CAAA,EAAA;IAET,OAAA,EAAA,MAAA;;;;;;gCApCc;;KAkCnB,cAAA;UAEK,2BAAA"}
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $inject, Alepha,
|
|
1
|
+
import { $inject, Alepha, t } from "@alepha/core";
|
|
2
2
|
import protobufjs from "protobufjs";
|
|
3
3
|
|
|
4
4
|
//#region src/providers/ProtobufProvider.ts
|
|
@@ -8,27 +8,18 @@ var ProtobufProvider = class {
|
|
|
8
8
|
protobuf = protobufjs;
|
|
9
9
|
/**
|
|
10
10
|
* Encode an object to a Uint8Array.
|
|
11
|
-
*
|
|
12
|
-
* @param schema - TypeBox schema used to generate the Protobuf schema.
|
|
13
|
-
* @param data - Object to encode. Can be any object or string.
|
|
14
11
|
*/
|
|
15
12
|
encode(schema, data) {
|
|
16
13
|
return this.parse(schema).encode(this.alepha.parse(schema, data)).finish();
|
|
17
14
|
}
|
|
18
15
|
/**
|
|
19
16
|
* Decode a Uint8Array to an object.
|
|
20
|
-
*
|
|
21
|
-
* @param schema
|
|
22
|
-
* @param data
|
|
23
17
|
*/
|
|
24
18
|
decode(schema, data) {
|
|
25
19
|
return this.alepha.parse(schema, this.parse(schema).decode(data));
|
|
26
20
|
}
|
|
27
21
|
/**
|
|
28
22
|
* Parse a TypeBox schema to a Protobuf Type schema ready for encoding/decoding.
|
|
29
|
-
*
|
|
30
|
-
* @param schema
|
|
31
|
-
* @param typeName
|
|
32
23
|
*/
|
|
33
24
|
parse(schema, typeName = "root.Target") {
|
|
34
25
|
const exists = this.schemas.get(schema);
|
|
@@ -41,9 +32,6 @@ var ProtobufProvider = class {
|
|
|
41
32
|
}
|
|
42
33
|
/**
|
|
43
34
|
* Convert a TypeBox schema to a Protobuf schema as a string.
|
|
44
|
-
*
|
|
45
|
-
* @param schema
|
|
46
|
-
* @param options
|
|
47
35
|
*/
|
|
48
36
|
createProtobufSchema(schema, options = {}) {
|
|
49
37
|
const { rootName = "root", mainMessageName = "Target" } = options;
|
|
@@ -51,59 +39,100 @@ var ProtobufProvider = class {
|
|
|
51
39
|
proto: `package ${rootName};\nsyntax = "proto3";\n\n`,
|
|
52
40
|
fieldIndex: 1
|
|
53
41
|
};
|
|
54
|
-
if (
|
|
55
|
-
const
|
|
56
|
-
context.proto +=
|
|
42
|
+
if (t.schema.isObject(schema)) {
|
|
43
|
+
const { message, subMessages } = this.parseObjectWithDependencies(schema, mainMessageName);
|
|
44
|
+
context.proto += subMessages.join("");
|
|
45
|
+
context.proto += message;
|
|
57
46
|
}
|
|
58
47
|
return context.proto;
|
|
59
48
|
}
|
|
60
49
|
/**
|
|
61
|
-
* Parse an object schema
|
|
62
|
-
*
|
|
63
|
-
* @param obj
|
|
64
|
-
* @param parentName
|
|
65
|
-
* @param context
|
|
66
|
-
* @protected
|
|
50
|
+
* Parse an object schema with dependencies (sub-messages).
|
|
67
51
|
*/
|
|
68
|
-
|
|
69
|
-
if (!
|
|
52
|
+
parseObjectWithDependencies(obj, parentName) {
|
|
53
|
+
if (!t.schema.isObject(obj)) return {
|
|
54
|
+
message: "",
|
|
55
|
+
subMessages: []
|
|
56
|
+
};
|
|
70
57
|
const fields = [];
|
|
58
|
+
const subMessages = [];
|
|
59
|
+
let fieldIndex = 1;
|
|
71
60
|
for (const [key, value] of Object.entries(obj.properties)) {
|
|
72
|
-
if (
|
|
73
|
-
if (
|
|
74
|
-
const subMessageName = value.items.title
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
});
|
|
79
|
-
fields.push(` repeated ${subMessageName} ${key} = ${context.fieldIndex++};`);
|
|
61
|
+
if (t.schema.isArray(value)) {
|
|
62
|
+
if (t.schema.isObject(value.items)) {
|
|
63
|
+
const subMessageName = "title" in value.items && typeof value.items.title === "string" ? value.items.title : `${parentName}_${key}`;
|
|
64
|
+
const { message: subMessage, subMessages: nestedSubMessages } = this.parseObjectWithDependencies(value.items, subMessageName);
|
|
65
|
+
subMessages.push(...nestedSubMessages);
|
|
66
|
+
subMessages.push(subMessage);
|
|
67
|
+
fields.push(` repeated ${subMessageName} ${key} = ${fieldIndex++};`);
|
|
80
68
|
continue;
|
|
81
69
|
}
|
|
82
70
|
const itemType = this.convertType(value.items);
|
|
83
|
-
fields.push(` repeated ${itemType} ${key} = ${
|
|
71
|
+
fields.push(` repeated ${itemType} ${key} = ${fieldIndex++};`);
|
|
84
72
|
continue;
|
|
85
73
|
}
|
|
86
|
-
if (
|
|
87
|
-
const subMessageName = `${parentName}_${key}`;
|
|
88
|
-
|
|
89
|
-
|
|
74
|
+
if (t.schema.isObject(value)) {
|
|
75
|
+
const subMessageName = "title" in value && typeof value.title === "string" ? value.title : `${parentName}_${key}`;
|
|
76
|
+
const { message: subMessage, subMessages: nestedSubMessages } = this.parseObjectWithDependencies(value, subMessageName);
|
|
77
|
+
subMessages.push(...nestedSubMessages);
|
|
78
|
+
subMessages.push(subMessage);
|
|
79
|
+
fields.push(` ${subMessageName} ${key} = ${fieldIndex++};`);
|
|
90
80
|
continue;
|
|
91
81
|
}
|
|
92
|
-
|
|
82
|
+
if (t.schema.isUnion(value)) {
|
|
83
|
+
const nonNullType = value.anyOf.find((type) => !t.schema.isNull(type));
|
|
84
|
+
if (nonNullType) {
|
|
85
|
+
if (t.schema.isObject(nonNullType)) {
|
|
86
|
+
const subMessageName = "title" in nonNullType && typeof nonNullType.title === "string" ? nonNullType.title : `${parentName}_${key}`;
|
|
87
|
+
const { message: subMessage, subMessages: nestedSubMessages } = this.parseObjectWithDependencies(nonNullType, subMessageName);
|
|
88
|
+
subMessages.push(...nestedSubMessages);
|
|
89
|
+
subMessages.push(subMessage);
|
|
90
|
+
fields.push(` ${subMessageName} ${key} = ${fieldIndex++};`);
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
const fieldType$1 = this.convertType(nonNullType);
|
|
94
|
+
fields.push(` ${fieldType$1} ${key} = ${fieldIndex++};`);
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
if (t.schema.isRecord(value)) {
|
|
99
|
+
let valueSchema;
|
|
100
|
+
if ("additionalProperties" in value && value.additionalProperties && typeof value.additionalProperties === "object") valueSchema = value.additionalProperties;
|
|
101
|
+
else if (value.patternProperties && typeof value.patternProperties === "object") {
|
|
102
|
+
const patterns = Object.values(value.patternProperties);
|
|
103
|
+
if (patterns.length > 0 && typeof patterns[0] === "object") valueSchema = patterns[0];
|
|
104
|
+
}
|
|
105
|
+
if (valueSchema) {
|
|
106
|
+
const valueType = this.convertType(valueSchema);
|
|
107
|
+
fields.push(` map<string, ${valueType}> ${key} = ${fieldIndex++};`);
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
const fieldType = this.convertType(value);
|
|
112
|
+
fields.push(` ${fieldType} ${key} = ${fieldIndex++};`);
|
|
93
113
|
}
|
|
94
|
-
|
|
114
|
+
const message = `message ${parentName} {\n${fields.join("\n")}\n}\n`;
|
|
115
|
+
return {
|
|
116
|
+
message,
|
|
117
|
+
subMessages
|
|
118
|
+
};
|
|
95
119
|
}
|
|
96
120
|
/**
|
|
97
121
|
* Convert a primitive TypeBox schema type to a Protobuf spec type.
|
|
98
|
-
*
|
|
99
|
-
* @param schema
|
|
100
|
-
* @protected
|
|
101
122
|
*/
|
|
102
123
|
convertType(schema) {
|
|
103
|
-
if (
|
|
104
|
-
if (
|
|
105
|
-
if (
|
|
106
|
-
if (
|
|
124
|
+
if (t.schema.isBoolean(schema)) return "bool";
|
|
125
|
+
if (t.schema.isNumber(schema) && schema.format === "int64") return "int64";
|
|
126
|
+
if (t.schema.isNumber(schema)) return "double";
|
|
127
|
+
if (t.schema.isInteger(schema)) return "int32";
|
|
128
|
+
if (t.schema.isBigInt(schema)) return "int64";
|
|
129
|
+
if (t.schema.isString(schema)) return "string";
|
|
130
|
+
if (t.schema.isUnion(schema)) {
|
|
131
|
+
const nonNullType = schema.anyOf.find((type) => !t.schema.isNull(type));
|
|
132
|
+
if (nonNullType) return this.convertType(nonNullType);
|
|
133
|
+
}
|
|
134
|
+
if (t.schema.isOptional(schema)) return this.convertType(schema);
|
|
135
|
+
if (t.schema.isUnsafe(schema)) return "string";
|
|
107
136
|
throw new Error(`Unsupported type: ${JSON.stringify(schema)}`);
|
|
108
137
|
}
|
|
109
138
|
};
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["schema: TObject","data: any","schema: T","data: Uint8Array","schema: ProtobufSchema | TObject","schema: TSchema","options: CreateProtobufSchemaOptions","obj: TSchema","parentName: string","context: { proto: string; fieldIndex: number }","fields: string[]"],"sources":["../src/providers/ProtobufProvider.ts"],"sourcesContent":["import type { Static, TObject, TProperties, TSchema } from \"@alepha/core\";\nimport { $inject, Alepha, TypeGuard } from \"@alepha/core\";\nimport type { Type } from \"protobufjs\";\nimport protobufjs from \"protobufjs\";\n\nexport class ProtobufProvider {\n\tprotected readonly alepha = $inject(Alepha);\n\tprotected readonly schemas: Map<string | TObject<TProperties>, Type> =\n\t\tnew Map();\n\tprotected readonly protobuf: typeof protobufjs = protobufjs;\n\n\t/**\n\t * Encode an object to a Uint8Array.\n\t *\n\t * @param schema - TypeBox schema used to generate the Protobuf schema.\n\t * @param data - Object to encode. Can be any object or string.\n\t */\n\tpublic encode(schema: TObject, data: any): Uint8Array {\n\t\treturn this.parse(schema).encode(this.alepha.parse(schema, data)).finish();\n\t}\n\n\t/**\n\t * Decode a Uint8Array to an object.\n\t *\n\t * @param schema\n\t * @param data\n\t */\n\tpublic decode<T extends TObject>(schema: T, data: Uint8Array): Static<T> {\n\t\treturn this.alepha.parse(schema, this.parse(schema).decode(data));\n\t}\n\n\t/**\n\t * Parse a TypeBox schema to a Protobuf Type schema ready for encoding/decoding.\n\t *\n\t * @param schema\n\t * @param typeName\n\t */\n\tpublic parse(\n\t\tschema: ProtobufSchema | TObject,\n\t\ttypeName = \"root.Target\",\n\t): Type {\n\t\tconst exists = this.schemas.get(schema);\n\t\tif (exists) return exists;\n\n\t\tconst pbSchema =\n\t\t\ttypeof schema === \"string\" ? schema : this.createProtobufSchema(schema);\n\t\tconst result = this.protobuf.parse(pbSchema);\n\t\tconst type = result.root.lookupType(typeName);\n\t\tthis.schemas.set(schema, type);\n\t\treturn type;\n\t}\n\n\t/**\n\t * Convert a TypeBox schema to a Protobuf schema as a string.\n\t *\n\t * @param schema\n\t * @param options\n\t */\n\tpublic createProtobufSchema(\n\t\tschema: TSchema,\n\t\toptions: CreateProtobufSchemaOptions = {},\n\t): string {\n\t\tconst { rootName = \"root\", mainMessageName = \"Target\" } = options;\n\t\tconst context = {\n\t\t\tproto: `package ${rootName};\\nsyntax = \"proto3\";\\n\\n`,\n\t\t\tfieldIndex: 1,\n\t\t};\n\n\t\tif (TypeGuard.IsObject(schema)) {\n\t\t\tconst proto = this.parseObject(schema, mainMessageName, context);\n\t\t\tcontext.proto += proto;\n\t\t}\n\n\t\treturn context.proto;\n\t}\n\n\t/**\n\t * Parse an object schema to a Protobuf message.\n\t *\n\t * @param obj\n\t * @param parentName\n\t * @param context\n\t * @protected\n\t */\n\tprotected parseObject(\n\t\tobj: TSchema,\n\t\tparentName: string,\n\t\tcontext: { proto: string; fieldIndex: number },\n\t): string {\n\t\tif (!TypeGuard.IsObject(obj)) {\n\t\t\treturn \"\";\n\t\t}\n\n\t\tconst fields: string[] = [];\n\n\t\tfor (const [key, value] of Object.entries(obj.properties)) {\n\t\t\tif (TypeGuard.IsArray(value)) {\n\t\t\t\tif (TypeGuard.IsObject(value.items)) {\n\t\t\t\t\tconst subMessageName = value.items.title ?? `${parentName}_${key}`;\n\t\t\t\t\tcontext.proto += this.parseObject(value.items, subMessageName, {\n\t\t\t\t\t\t...context,\n\t\t\t\t\t\tfieldIndex: 1,\n\t\t\t\t\t});\n\t\t\t\t\tfields.push(\n\t\t\t\t\t\t` repeated ${subMessageName} ${key} = ${context.fieldIndex++};`,\n\t\t\t\t\t);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst itemType = this.convertType(value.items);\n\t\t\t\tfields.push(` repeated ${itemType} ${key} = ${context.fieldIndex++};`);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (TypeGuard.IsObject(value)) {\n\t\t\t\tconst subMessageName = `${parentName}_${key}`;\n\t\t\t\tcontext.proto += this.parseObject(value, subMessageName, context);\n\t\t\t\tfields.push(` ${subMessageName} ${key} = ${context.fieldIndex++};`);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tfields.push(\n\t\t\t\t` ${this.convertType(value)} ${key} = ${context.fieldIndex++};`,\n\t\t\t);\n\t\t}\n\n\t\treturn `message ${parentName} {\\n${fields.join(\"\\n\")}\\n}\\n`;\n\t}\n\n\t/**\n\t * Convert a primitive TypeBox schema type to a Protobuf spec type.\n\t *\n\t * @param schema\n\t * @protected\n\t */\n\tprotected convertType(schema: TSchema): string {\n\t\tif (TypeGuard.IsInteger(schema)) return \"int32\";\n\t\tif (TypeGuard.IsNumber(schema)) return \"double\";\n\t\tif (TypeGuard.IsString(schema)) return \"string\";\n\t\tif (TypeGuard.IsBoolean(schema)) return \"bool\";\n\n\t\tthrow new Error(`Unsupported type: ${JSON.stringify(schema)}`);\n\t}\n}\n\nexport type ProtobufSchema = string;\n\nexport interface CreateProtobufSchemaOptions {\n\trootName?: string;\n\tmainMessageName?: string;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["fields: string[]","subMessages: string[]","fieldType","valueSchema: TSchema | undefined"],"sources":["../src/providers/ProtobufProvider.ts"],"sourcesContent":["import {\n\t$inject,\n\tAlepha,\n\ttype Static,\n\ttype TObject,\n\ttype TSchema,\n\tt,\n} from \"@alepha/core\";\nimport type { Type } from \"protobufjs\";\nimport protobufjs from \"protobufjs\";\n\nexport class ProtobufProvider {\n\tprotected readonly alepha = $inject(Alepha);\n\tprotected readonly schemas: Map<string | TObject, Type> = new Map();\n\tprotected readonly protobuf: typeof protobufjs = protobufjs;\n\n\t/**\n\t * Encode an object to a Uint8Array.\n\t */\n\tpublic encode(schema: TObject, data: any): Uint8Array {\n\t\treturn this.parse(schema).encode(this.alepha.parse(schema, data)).finish();\n\t}\n\n\t/**\n\t * Decode a Uint8Array to an object.\n\t */\n\tpublic decode<T extends TObject>(schema: T, data: Uint8Array): Static<T> {\n\t\treturn this.alepha.parse(schema, this.parse(schema).decode(data));\n\t}\n\n\t/**\n\t * Parse a TypeBox schema to a Protobuf Type schema ready for encoding/decoding.\n\t */\n\tpublic parse(\n\t\tschema: ProtobufSchema | TObject,\n\t\ttypeName = \"root.Target\",\n\t): Type {\n\t\tconst exists = this.schemas.get(schema);\n\t\tif (exists) return exists;\n\n\t\tconst pbSchema =\n\t\t\ttypeof schema === \"string\" ? schema : this.createProtobufSchema(schema);\n\t\tconst result = this.protobuf.parse(pbSchema);\n\t\tconst type = result.root.lookupType(typeName);\n\t\tthis.schemas.set(schema, type);\n\t\treturn type;\n\t}\n\n\t/**\n\t * Convert a TypeBox schema to a Protobuf schema as a string.\n\t */\n\tpublic createProtobufSchema(\n\t\tschema: TSchema,\n\t\toptions: CreateProtobufSchemaOptions = {},\n\t): string {\n\t\tconst { rootName = \"root\", mainMessageName = \"Target\" } = options;\n\t\tconst context = {\n\t\t\tproto: `package ${rootName};\\nsyntax = \"proto3\";\\n\\n`,\n\t\t\tfieldIndex: 1,\n\t\t};\n\n\t\tif (t.schema.isObject(schema)) {\n\t\t\tconst { message, subMessages } = this.parseObjectWithDependencies(\n\t\t\t\tschema,\n\t\t\t\tmainMessageName,\n\t\t\t);\n\t\t\t// Add all sub-messages first\n\t\t\tcontext.proto += subMessages.join(\"\");\n\t\t\t// Then add the main message\n\t\t\tcontext.proto += message;\n\t\t}\n\n\t\treturn context.proto;\n\t}\n\n\t/**\n\t * Parse an object schema with dependencies (sub-messages).\n\t */\n\tprotected parseObjectWithDependencies(\n\t\tobj: TSchema,\n\t\tparentName: string,\n\t): { message: string; subMessages: string[] } {\n\t\tif (!t.schema.isObject(obj)) {\n\t\t\treturn { message: \"\", subMessages: [] };\n\t\t}\n\n\t\tconst fields: string[] = [];\n\t\tconst subMessages: string[] = [];\n\t\tlet fieldIndex = 1;\n\n\t\tfor (const [key, value] of Object.entries(obj.properties)) {\n\t\t\t// Handle arrays\n\t\t\tif (t.schema.isArray(value)) {\n\t\t\t\tif (t.schema.isObject(value.items)) {\n\t\t\t\t\tconst subMessageName =\n\t\t\t\t\t\t\"title\" in value.items && typeof value.items.title === \"string\"\n\t\t\t\t\t\t\t? value.items.title\n\t\t\t\t\t\t\t: `${parentName}_${key}`;\n\t\t\t\t\tconst { message: subMessage, subMessages: nestedSubMessages } =\n\t\t\t\t\t\tthis.parseObjectWithDependencies(value.items, subMessageName);\n\t\t\t\t\tsubMessages.push(...nestedSubMessages);\n\t\t\t\t\tsubMessages.push(subMessage);\n\t\t\t\t\tfields.push(` repeated ${subMessageName} ${key} = ${fieldIndex++};`);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst itemType = this.convertType(value.items);\n\t\t\t\tfields.push(` repeated ${itemType} ${key} = ${fieldIndex++};`);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Handle nested objects\n\t\t\tif (t.schema.isObject(value)) {\n\t\t\t\tconst subMessageName =\n\t\t\t\t\t\"title\" in value && typeof value.title === \"string\"\n\t\t\t\t\t\t? value.title\n\t\t\t\t\t\t: `${parentName}_${key}`;\n\t\t\t\tconst { message: subMessage, subMessages: nestedSubMessages } =\n\t\t\t\t\tthis.parseObjectWithDependencies(value, subMessageName);\n\t\t\t\tsubMessages.push(...nestedSubMessages);\n\t\t\t\tsubMessages.push(subMessage);\n\t\t\t\tfields.push(` ${subMessageName} ${key} = ${fieldIndex++};`);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Handle union types (nullable fields)\n\t\t\tif (t.schema.isUnion(value)) {\n\t\t\t\tconst nonNullType = value.anyOf.find(\n\t\t\t\t\t(type: TSchema) => !t.schema.isNull(type),\n\t\t\t\t);\n\t\t\t\tif (nonNullType) {\n\t\t\t\t\tif (t.schema.isObject(nonNullType)) {\n\t\t\t\t\t\tconst subMessageName =\n\t\t\t\t\t\t\t\"title\" in nonNullType && typeof nonNullType.title === \"string\"\n\t\t\t\t\t\t\t\t? nonNullType.title\n\t\t\t\t\t\t\t\t: `${parentName}_${key}`;\n\t\t\t\t\t\tconst { message: subMessage, subMessages: nestedSubMessages } =\n\t\t\t\t\t\t\tthis.parseObjectWithDependencies(nonNullType, subMessageName);\n\t\t\t\t\t\tsubMessages.push(...nestedSubMessages);\n\t\t\t\t\t\tsubMessages.push(subMessage);\n\t\t\t\t\t\tfields.push(` ${subMessageName} ${key} = ${fieldIndex++};`);\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tconst fieldType = this.convertType(nonNullType);\n\t\t\t\t\tfields.push(` ${fieldType} ${key} = ${fieldIndex++};`);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Handle records (maps)\n\t\t\tif (t.schema.isRecord(value)) {\n\t\t\t\t// TypeBox records use additionalProperties or patternProperties for the value type\n\t\t\t\tlet valueSchema: TSchema | undefined;\n\t\t\t\tif (\n\t\t\t\t\t\"additionalProperties\" in value &&\n\t\t\t\t\tvalue.additionalProperties &&\n\t\t\t\t\ttypeof value.additionalProperties === \"object\"\n\t\t\t\t) {\n\t\t\t\t\tvalueSchema = value.additionalProperties;\n\t\t\t\t} else if (\n\t\t\t\t\tvalue.patternProperties &&\n\t\t\t\t\ttypeof value.patternProperties === \"object\"\n\t\t\t\t) {\n\t\t\t\t\t// Get the first pattern property (usually \"^(.*)$\" or similar)\n\t\t\t\t\tconst patterns = Object.values(value.patternProperties);\n\t\t\t\t\tif (patterns.length > 0 && typeof patterns[0] === \"object\") {\n\t\t\t\t\t\tvalueSchema = patterns[0] as TSchema;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (valueSchema) {\n\t\t\t\t\tconst valueType = this.convertType(valueSchema);\n\t\t\t\t\tfields.push(` map<string, ${valueType}> ${key} = ${fieldIndex++};`);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Handle regular fields\n\t\t\tconst fieldType = this.convertType(value);\n\t\t\tfields.push(` ${fieldType} ${key} = ${fieldIndex++};`);\n\t\t}\n\n\t\tconst message = `message ${parentName} {\\n${fields.join(\"\\n\")}\\n}\\n`;\n\t\treturn { message, subMessages };\n\t}\n\n\t/**\n\t * Convert a primitive TypeBox schema type to a Protobuf spec type.\n\t */\n\tprotected convertType(schema: TSchema): string {\n\t\tif (t.schema.isBoolean(schema)) return \"bool\";\n\t\tif (t.schema.isNumber(schema) && schema.format === \"int64\") return \"int64\";\n\t\tif (t.schema.isNumber(schema)) return \"double\";\n\t\tif (t.schema.isInteger(schema)) return \"int32\";\n\t\tif (t.schema.isBigInt(schema)) return \"int64\";\n\t\tif (t.schema.isString(schema)) return \"string\";\n\n\t\t// Handle union types (nullable)\n\t\tif (t.schema.isUnion(schema)) {\n\t\t\t// Find the non-null type in the union\n\t\t\tconst nonNullType = schema.anyOf.find(\n\t\t\t\t(type: TSchema) => !t.schema.isNull(type),\n\t\t\t);\n\t\t\tif (nonNullType) {\n\t\t\t\treturn this.convertType(nonNullType);\n\t\t\t}\n\t\t}\n\n\t\t// Handle optional types\n\t\tif (t.schema.isOptional(schema)) {\n\t\t\treturn this.convertType(schema);\n\t\t}\n\n\t\t// Handle unsafe types (like enums)\n\t\tif (t.schema.isUnsafe(schema)) {\n\t\t\t// if it's an enum or other unsafe types, default to string\n\t\t\treturn \"string\";\n\t\t}\n\n\t\tthrow new Error(`Unsupported type: ${JSON.stringify(schema)}`);\n\t}\n}\n\nexport type ProtobufSchema = string;\n\nexport interface CreateProtobufSchemaOptions {\n\trootName?: string;\n\tmainMessageName?: string;\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alepha/protobuf",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=22.0.0"
|
|
@@ -13,16 +13,18 @@
|
|
|
13
13
|
"src"
|
|
14
14
|
],
|
|
15
15
|
"dependencies": {
|
|
16
|
-
"@alepha/core": "0.
|
|
16
|
+
"@alepha/core": "0.10.0",
|
|
17
17
|
"protobufjs": "^7.5.4"
|
|
18
18
|
},
|
|
19
19
|
"devDependencies": {
|
|
20
|
-
"
|
|
20
|
+
"@biomejs/biome": "^2.2.4",
|
|
21
|
+
"tsdown": "^0.15.3",
|
|
21
22
|
"typescript": "^5.9.2",
|
|
22
23
|
"vitest": "^3.2.4"
|
|
23
24
|
},
|
|
24
25
|
"scripts": {
|
|
25
26
|
"test": "vitest run",
|
|
27
|
+
"lint": "biome check --write --unsafe",
|
|
26
28
|
"build": "tsdown -c ../../tsdown.config.ts",
|
|
27
29
|
"check": "tsc"
|
|
28
30
|
},
|
|
@@ -1,19 +1,21 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
1
|
+
import {
|
|
2
|
+
$inject,
|
|
3
|
+
Alepha,
|
|
4
|
+
type Static,
|
|
5
|
+
type TObject,
|
|
6
|
+
type TSchema,
|
|
7
|
+
t,
|
|
8
|
+
} from "@alepha/core";
|
|
3
9
|
import type { Type } from "protobufjs";
|
|
4
10
|
import protobufjs from "protobufjs";
|
|
5
11
|
|
|
6
12
|
export class ProtobufProvider {
|
|
7
13
|
protected readonly alepha = $inject(Alepha);
|
|
8
|
-
protected readonly schemas: Map<string | TObject
|
|
9
|
-
new Map();
|
|
14
|
+
protected readonly schemas: Map<string | TObject, Type> = new Map();
|
|
10
15
|
protected readonly protobuf: typeof protobufjs = protobufjs;
|
|
11
16
|
|
|
12
17
|
/**
|
|
13
18
|
* Encode an object to a Uint8Array.
|
|
14
|
-
*
|
|
15
|
-
* @param schema - TypeBox schema used to generate the Protobuf schema.
|
|
16
|
-
* @param data - Object to encode. Can be any object or string.
|
|
17
19
|
*/
|
|
18
20
|
public encode(schema: TObject, data: any): Uint8Array {
|
|
19
21
|
return this.parse(schema).encode(this.alepha.parse(schema, data)).finish();
|
|
@@ -21,9 +23,6 @@ export class ProtobufProvider {
|
|
|
21
23
|
|
|
22
24
|
/**
|
|
23
25
|
* Decode a Uint8Array to an object.
|
|
24
|
-
*
|
|
25
|
-
* @param schema
|
|
26
|
-
* @param data
|
|
27
26
|
*/
|
|
28
27
|
public decode<T extends TObject>(schema: T, data: Uint8Array): Static<T> {
|
|
29
28
|
return this.alepha.parse(schema, this.parse(schema).decode(data));
|
|
@@ -31,9 +30,6 @@ export class ProtobufProvider {
|
|
|
31
30
|
|
|
32
31
|
/**
|
|
33
32
|
* Parse a TypeBox schema to a Protobuf Type schema ready for encoding/decoding.
|
|
34
|
-
*
|
|
35
|
-
* @param schema
|
|
36
|
-
* @param typeName
|
|
37
33
|
*/
|
|
38
34
|
public parse(
|
|
39
35
|
schema: ProtobufSchema | TObject,
|
|
@@ -52,9 +48,6 @@ export class ProtobufProvider {
|
|
|
52
48
|
|
|
53
49
|
/**
|
|
54
50
|
* Convert a TypeBox schema to a Protobuf schema as a string.
|
|
55
|
-
*
|
|
56
|
-
* @param schema
|
|
57
|
-
* @param options
|
|
58
51
|
*/
|
|
59
52
|
public createProtobufSchema(
|
|
60
53
|
schema: TSchema,
|
|
@@ -66,78 +59,163 @@ export class ProtobufProvider {
|
|
|
66
59
|
fieldIndex: 1,
|
|
67
60
|
};
|
|
68
61
|
|
|
69
|
-
if (
|
|
70
|
-
const
|
|
71
|
-
|
|
62
|
+
if (t.schema.isObject(schema)) {
|
|
63
|
+
const { message, subMessages } = this.parseObjectWithDependencies(
|
|
64
|
+
schema,
|
|
65
|
+
mainMessageName,
|
|
66
|
+
);
|
|
67
|
+
// Add all sub-messages first
|
|
68
|
+
context.proto += subMessages.join("");
|
|
69
|
+
// Then add the main message
|
|
70
|
+
context.proto += message;
|
|
72
71
|
}
|
|
73
72
|
|
|
74
73
|
return context.proto;
|
|
75
74
|
}
|
|
76
75
|
|
|
77
76
|
/**
|
|
78
|
-
* Parse an object schema
|
|
79
|
-
*
|
|
80
|
-
* @param obj
|
|
81
|
-
* @param parentName
|
|
82
|
-
* @param context
|
|
83
|
-
* @protected
|
|
77
|
+
* Parse an object schema with dependencies (sub-messages).
|
|
84
78
|
*/
|
|
85
|
-
protected
|
|
79
|
+
protected parseObjectWithDependencies(
|
|
86
80
|
obj: TSchema,
|
|
87
81
|
parentName: string,
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
return "";
|
|
82
|
+
): { message: string; subMessages: string[] } {
|
|
83
|
+
if (!t.schema.isObject(obj)) {
|
|
84
|
+
return { message: "", subMessages: [] };
|
|
92
85
|
}
|
|
93
86
|
|
|
94
87
|
const fields: string[] = [];
|
|
88
|
+
const subMessages: string[] = [];
|
|
89
|
+
let fieldIndex = 1;
|
|
95
90
|
|
|
96
91
|
for (const [key, value] of Object.entries(obj.properties)) {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
);
|
|
92
|
+
// Handle arrays
|
|
93
|
+
if (t.schema.isArray(value)) {
|
|
94
|
+
if (t.schema.isObject(value.items)) {
|
|
95
|
+
const subMessageName =
|
|
96
|
+
"title" in value.items && typeof value.items.title === "string"
|
|
97
|
+
? value.items.title
|
|
98
|
+
: `${parentName}_${key}`;
|
|
99
|
+
const { message: subMessage, subMessages: nestedSubMessages } =
|
|
100
|
+
this.parseObjectWithDependencies(value.items, subMessageName);
|
|
101
|
+
subMessages.push(...nestedSubMessages);
|
|
102
|
+
subMessages.push(subMessage);
|
|
103
|
+
fields.push(` repeated ${subMessageName} ${key} = ${fieldIndex++};`);
|
|
107
104
|
continue;
|
|
108
105
|
}
|
|
109
106
|
|
|
110
107
|
const itemType = this.convertType(value.items);
|
|
111
|
-
fields.push(` repeated ${itemType} ${key} = ${
|
|
108
|
+
fields.push(` repeated ${itemType} ${key} = ${fieldIndex++};`);
|
|
112
109
|
continue;
|
|
113
110
|
}
|
|
114
111
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
112
|
+
// Handle nested objects
|
|
113
|
+
if (t.schema.isObject(value)) {
|
|
114
|
+
const subMessageName =
|
|
115
|
+
"title" in value && typeof value.title === "string"
|
|
116
|
+
? value.title
|
|
117
|
+
: `${parentName}_${key}`;
|
|
118
|
+
const { message: subMessage, subMessages: nestedSubMessages } =
|
|
119
|
+
this.parseObjectWithDependencies(value, subMessageName);
|
|
120
|
+
subMessages.push(...nestedSubMessages);
|
|
121
|
+
subMessages.push(subMessage);
|
|
122
|
+
fields.push(` ${subMessageName} ${key} = ${fieldIndex++};`);
|
|
119
123
|
continue;
|
|
120
124
|
}
|
|
121
125
|
|
|
122
|
-
fields
|
|
123
|
-
|
|
124
|
-
|
|
126
|
+
// Handle union types (nullable fields)
|
|
127
|
+
if (t.schema.isUnion(value)) {
|
|
128
|
+
const nonNullType = value.anyOf.find(
|
|
129
|
+
(type: TSchema) => !t.schema.isNull(type),
|
|
130
|
+
);
|
|
131
|
+
if (nonNullType) {
|
|
132
|
+
if (t.schema.isObject(nonNullType)) {
|
|
133
|
+
const subMessageName =
|
|
134
|
+
"title" in nonNullType && typeof nonNullType.title === "string"
|
|
135
|
+
? nonNullType.title
|
|
136
|
+
: `${parentName}_${key}`;
|
|
137
|
+
const { message: subMessage, subMessages: nestedSubMessages } =
|
|
138
|
+
this.parseObjectWithDependencies(nonNullType, subMessageName);
|
|
139
|
+
subMessages.push(...nestedSubMessages);
|
|
140
|
+
subMessages.push(subMessage);
|
|
141
|
+
fields.push(` ${subMessageName} ${key} = ${fieldIndex++};`);
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
const fieldType = this.convertType(nonNullType);
|
|
145
|
+
fields.push(` ${fieldType} ${key} = ${fieldIndex++};`);
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Handle records (maps)
|
|
151
|
+
if (t.schema.isRecord(value)) {
|
|
152
|
+
// TypeBox records use additionalProperties or patternProperties for the value type
|
|
153
|
+
let valueSchema: TSchema | undefined;
|
|
154
|
+
if (
|
|
155
|
+
"additionalProperties" in value &&
|
|
156
|
+
value.additionalProperties &&
|
|
157
|
+
typeof value.additionalProperties === "object"
|
|
158
|
+
) {
|
|
159
|
+
valueSchema = value.additionalProperties;
|
|
160
|
+
} else if (
|
|
161
|
+
value.patternProperties &&
|
|
162
|
+
typeof value.patternProperties === "object"
|
|
163
|
+
) {
|
|
164
|
+
// Get the first pattern property (usually "^(.*)$" or similar)
|
|
165
|
+
const patterns = Object.values(value.patternProperties);
|
|
166
|
+
if (patterns.length > 0 && typeof patterns[0] === "object") {
|
|
167
|
+
valueSchema = patterns[0] as TSchema;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (valueSchema) {
|
|
172
|
+
const valueType = this.convertType(valueSchema);
|
|
173
|
+
fields.push(` map<string, ${valueType}> ${key} = ${fieldIndex++};`);
|
|
174
|
+
continue;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Handle regular fields
|
|
179
|
+
const fieldType = this.convertType(value);
|
|
180
|
+
fields.push(` ${fieldType} ${key} = ${fieldIndex++};`);
|
|
125
181
|
}
|
|
126
182
|
|
|
127
|
-
|
|
183
|
+
const message = `message ${parentName} {\n${fields.join("\n")}\n}\n`;
|
|
184
|
+
return { message, subMessages };
|
|
128
185
|
}
|
|
129
186
|
|
|
130
187
|
/**
|
|
131
188
|
* Convert a primitive TypeBox schema type to a Protobuf spec type.
|
|
132
|
-
*
|
|
133
|
-
* @param schema
|
|
134
|
-
* @protected
|
|
135
189
|
*/
|
|
136
190
|
protected convertType(schema: TSchema): string {
|
|
137
|
-
if (
|
|
138
|
-
if (
|
|
139
|
-
if (
|
|
140
|
-
if (
|
|
191
|
+
if (t.schema.isBoolean(schema)) return "bool";
|
|
192
|
+
if (t.schema.isNumber(schema) && schema.format === "int64") return "int64";
|
|
193
|
+
if (t.schema.isNumber(schema)) return "double";
|
|
194
|
+
if (t.schema.isInteger(schema)) return "int32";
|
|
195
|
+
if (t.schema.isBigInt(schema)) return "int64";
|
|
196
|
+
if (t.schema.isString(schema)) return "string";
|
|
197
|
+
|
|
198
|
+
// Handle union types (nullable)
|
|
199
|
+
if (t.schema.isUnion(schema)) {
|
|
200
|
+
// Find the non-null type in the union
|
|
201
|
+
const nonNullType = schema.anyOf.find(
|
|
202
|
+
(type: TSchema) => !t.schema.isNull(type),
|
|
203
|
+
);
|
|
204
|
+
if (nonNullType) {
|
|
205
|
+
return this.convertType(nonNullType);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// Handle optional types
|
|
210
|
+
if (t.schema.isOptional(schema)) {
|
|
211
|
+
return this.convertType(schema);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// Handle unsafe types (like enums)
|
|
215
|
+
if (t.schema.isUnsafe(schema)) {
|
|
216
|
+
// if it's an enum or other unsafe types, default to string
|
|
217
|
+
return "string";
|
|
218
|
+
}
|
|
141
219
|
|
|
142
220
|
throw new Error(`Unsupported type: ${JSON.stringify(schema)}`);
|
|
143
221
|
}
|