@openhps/protobuf 1.0.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/LICENSE +190 -0
- package/README.md +165 -0
- package/dist/cjs/InternalProtobufDeserializer.js +152 -0
- package/dist/cjs/InternalProtobufDeserializer.js.map +1 -0
- package/dist/cjs/InternalProtobufSerializer.js +137 -0
- package/dist/cjs/InternalProtobufSerializer.js.map +1 -0
- package/dist/cjs/ProtobufSerializer.js +136 -0
- package/dist/cjs/ProtobufSerializer.js.map +1 -0
- package/dist/cjs/bin/generator.js +107 -0
- package/dist/cjs/bin/generator.js.map +1 -0
- package/dist/cjs/decorators/index.js +4 -0
- package/dist/cjs/decorators/index.js.map +1 -0
- package/dist/cjs/decorators/options.js +3 -0
- package/dist/cjs/decorators/options.js.map +1 -0
- package/dist/cjs/generator/ObjectGenerator.js +316 -0
- package/dist/cjs/generator/ObjectGenerator.js.map +1 -0
- package/dist/cjs/generator/ProjectGenerator.js +120 -0
- package/dist/cjs/generator/ProjectGenerator.js.map +1 -0
- package/dist/cjs/generator/ProtobufGenerator.js +31 -0
- package/dist/cjs/generator/ProtobufGenerator.js.map +1 -0
- package/dist/cjs/generator/ServiceGenerator.js +14 -0
- package/dist/cjs/generator/ServiceGenerator.js.map +1 -0
- package/dist/cjs/generator/constants.js +21 -0
- package/dist/cjs/generator/constants.js.map +1 -0
- package/dist/cjs/generator/index.js +7 -0
- package/dist/cjs/generator/index.js.map +1 -0
- package/dist/cjs/generator/types.js +3 -0
- package/dist/cjs/generator/types.js.map +1 -0
- package/dist/cjs/index.js +6 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/esm/InternalProtobufDeserializer.js +147 -0
- package/dist/esm/InternalProtobufDeserializer.js.map +1 -0
- package/dist/esm/InternalProtobufSerializer.js +132 -0
- package/dist/esm/InternalProtobufSerializer.js.map +1 -0
- package/dist/esm/ProtobufSerializer.js +131 -0
- package/dist/esm/ProtobufSerializer.js.map +1 -0
- package/dist/esm/bin/generator.js +104 -0
- package/dist/esm/bin/generator.js.map +1 -0
- package/dist/esm/decorators/index.js +2 -0
- package/dist/esm/decorators/index.js.map +1 -0
- package/dist/esm/decorators/options.js +2 -0
- package/dist/esm/decorators/options.js.map +1 -0
- package/dist/esm/generator/ObjectGenerator.js +311 -0
- package/dist/esm/generator/ObjectGenerator.js.map +1 -0
- package/dist/esm/generator/ProjectGenerator.js +115 -0
- package/dist/esm/generator/ProjectGenerator.js.map +1 -0
- package/dist/esm/generator/ProtobufGenerator.js +27 -0
- package/dist/esm/generator/ProtobufGenerator.js.map +1 -0
- package/dist/esm/generator/ServiceGenerator.js +10 -0
- package/dist/esm/generator/ServiceGenerator.js.map +1 -0
- package/dist/esm/generator/constants.js +18 -0
- package/dist/esm/generator/constants.js.map +1 -0
- package/dist/esm/generator/index.js +4 -0
- package/dist/esm/generator/index.js.map +1 -0
- package/dist/esm/generator/types.js +2 -0
- package/dist/esm/generator/types.js.map +1 -0
- package/dist/esm/index.js +3 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm5/InternalProtobufDeserializer.js +147 -0
- package/dist/esm5/InternalProtobufDeserializer.js.map +1 -0
- package/dist/esm5/InternalProtobufSerializer.js +132 -0
- package/dist/esm5/InternalProtobufSerializer.js.map +1 -0
- package/dist/esm5/ProtobufSerializer.js +131 -0
- package/dist/esm5/ProtobufSerializer.js.map +1 -0
- package/dist/esm5/bin/generator.js +104 -0
- package/dist/esm5/bin/generator.js.map +1 -0
- package/dist/esm5/decorators/index.js +2 -0
- package/dist/esm5/decorators/index.js.map +1 -0
- package/dist/esm5/decorators/options.js +2 -0
- package/dist/esm5/decorators/options.js.map +1 -0
- package/dist/esm5/generator/ObjectGenerator.js +311 -0
- package/dist/esm5/generator/ObjectGenerator.js.map +1 -0
- package/dist/esm5/generator/ProjectGenerator.js +115 -0
- package/dist/esm5/generator/ProjectGenerator.js.map +1 -0
- package/dist/esm5/generator/ProtobufGenerator.js +27 -0
- package/dist/esm5/generator/ProtobufGenerator.js.map +1 -0
- package/dist/esm5/generator/ServiceGenerator.js +10 -0
- package/dist/esm5/generator/ServiceGenerator.js.map +1 -0
- package/dist/esm5/generator/constants.js +18 -0
- package/dist/esm5/generator/constants.js.map +1 -0
- package/dist/esm5/generator/index.js +4 -0
- package/dist/esm5/generator/index.js.map +1 -0
- package/dist/esm5/generator/types.js +2 -0
- package/dist/esm5/generator/types.js.map +1 -0
- package/dist/esm5/index.js +3 -0
- package/dist/esm5/index.js.map +1 -0
- package/dist/types/InternalProtobufDeserializer.d.ts +9 -0
- package/dist/types/InternalProtobufDeserializer.d.ts.map +1 -0
- package/dist/types/InternalProtobufSerializer.d.ts +23 -0
- package/dist/types/InternalProtobufSerializer.d.ts.map +1 -0
- package/dist/types/ProtobufSerializer.d.ts +32 -0
- package/dist/types/ProtobufSerializer.d.ts.map +1 -0
- package/dist/types/bin/generator.d.ts +3 -0
- package/dist/types/bin/generator.d.ts.map +1 -0
- package/dist/types/decorators/index.d.ts +2 -0
- package/dist/types/decorators/index.d.ts.map +1 -0
- package/dist/types/decorators/options.d.ts +30 -0
- package/dist/types/decorators/options.d.ts.map +1 -0
- package/dist/types/generator/ObjectGenerator.d.ts +22 -0
- package/dist/types/generator/ObjectGenerator.d.ts.map +1 -0
- package/dist/types/generator/ProjectGenerator.d.ts +17 -0
- package/dist/types/generator/ProjectGenerator.d.ts.map +1 -0
- package/dist/types/generator/ProtobufGenerator.d.ts +26 -0
- package/dist/types/generator/ProtobufGenerator.d.ts.map +1 -0
- package/dist/types/generator/ServiceGenerator.d.ts +7 -0
- package/dist/types/generator/ServiceGenerator.d.ts.map +1 -0
- package/dist/types/generator/constants.d.ts +3 -0
- package/dist/types/generator/constants.d.ts.map +1 -0
- package/dist/types/generator/index.d.ts +4 -0
- package/dist/types/generator/index.d.ts.map +1 -0
- package/dist/types/generator/types.d.ts +5 -0
- package/dist/types/generator/types.d.ts.map +1 -0
- package/dist/types/index.d.ts +3 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/web/openhps-protobuf.es.js +15165 -0
- package/dist/web/openhps-protobuf.es.js.map +1 -0
- package/dist/web/openhps-protobuf.es.min.js +2 -0
- package/dist/web/openhps-protobuf.es.min.js.map +1 -0
- package/dist/web/openhps-protobuf.js +16722 -0
- package/dist/web/openhps-protobuf.js.map +1 -0
- package/dist/web/openhps-protobuf.min.js +2 -0
- package/dist/web/openhps-protobuf.min.js.map +1 -0
- package/package.json +96 -0
- package/src/InternalProtobufDeserializer.ts +245 -0
- package/src/InternalProtobufSerializer.ts +212 -0
- package/src/ProtobufSerializer.ts +168 -0
- package/src/bin/generator.ts +131 -0
- package/src/decorators/index.ts +1 -0
- package/src/decorators/options.ts +30 -0
- package/src/generator/ObjectGenerator.ts +377 -0
- package/src/generator/ProjectGenerator.ts +130 -0
- package/src/generator/ProtobufGenerator.ts +49 -0
- package/src/generator/ServiceGenerator.ts +11 -0
- package/src/generator/constants.ts +19 -0
- package/src/generator/index.ts +3 -0
- package/src/generator/types.ts +4 -0
- package/src/index.ts +2 -0
|
@@ -0,0 +1,377 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ArrayTypeDescriptor,
|
|
3
|
+
DataSerializerUtils,
|
|
4
|
+
MapTypeDescriptor,
|
|
5
|
+
ObjectMemberMetadata,
|
|
6
|
+
ObjectMetadata,
|
|
7
|
+
SerializableMemberOptions,
|
|
8
|
+
TypeDescriptor,
|
|
9
|
+
SerializationUtils,
|
|
10
|
+
ConcreteTypeDescriptor,
|
|
11
|
+
} from '@openhps/core';
|
|
12
|
+
import chalk from 'chalk';
|
|
13
|
+
import { AnyT, Constructor } from 'typedjson';
|
|
14
|
+
import { HEADER } from './constants';
|
|
15
|
+
import { ProtobufGenerator, ProtobufMessage } from './ProtobufGenerator';
|
|
16
|
+
import { ProjectBuildOptions } from './types';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Protobuf object generator
|
|
20
|
+
*/
|
|
21
|
+
export class ObjectGenerator extends ProtobufGenerator<Object> { // eslint-disable-line
|
|
22
|
+
processObject(object: Constructor<Object>, metaData: ObjectMemberMetadata): Promise<void> { // eslint-disable-line
|
|
23
|
+
throw new Error('Method not implemented.');
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
generate(object: Constructor<Object>, metaData: ObjectMemberMetadata): Promise<ProtobufMessage> { // eslint-disable-line
|
|
27
|
+
throw new Error('Method not implemented.');
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
protected static typeMapping(
|
|
31
|
+
object: ObjectMetadata,
|
|
32
|
+
type: TypeDescriptor,
|
|
33
|
+
memberOptions: ObjectMemberMetadata,
|
|
34
|
+
buildOptions: ProjectBuildOptions,
|
|
35
|
+
): TypeMapping {
|
|
36
|
+
switch (type.ctor) {
|
|
37
|
+
case String:
|
|
38
|
+
return {
|
|
39
|
+
syntax: 'string',
|
|
40
|
+
};
|
|
41
|
+
case Number: {
|
|
42
|
+
const options: SerializableMemberOptions = memberOptions.options;
|
|
43
|
+
const numberType = options ? this.getNumberType(options.numberType) : 'int32';
|
|
44
|
+
if (numberType === 'string' && buildOptions.logLevel > 1) {
|
|
45
|
+
console.warn(
|
|
46
|
+
chalk.yellow(
|
|
47
|
+
`${object.classType.name}[${memberOptions.name}] defines a number without specifing a type. This will affect performance.`,
|
|
48
|
+
),
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
return {
|
|
52
|
+
syntax: numberType,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
case Boolean:
|
|
56
|
+
return {
|
|
57
|
+
syntax: 'bool',
|
|
58
|
+
};
|
|
59
|
+
case Array: {
|
|
60
|
+
const mappings = this.typeMapping(
|
|
61
|
+
object,
|
|
62
|
+
(type as ArrayTypeDescriptor).elementType,
|
|
63
|
+
memberOptions,
|
|
64
|
+
buildOptions,
|
|
65
|
+
);
|
|
66
|
+
return {
|
|
67
|
+
syntax: `repeated ${mappings.syntax}`,
|
|
68
|
+
types: [mappings],
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
case Map: {
|
|
72
|
+
const key = this.typeMapping(object, (type as MapTypeDescriptor).keyType, memberOptions, buildOptions);
|
|
73
|
+
const value = this.typeMapping(
|
|
74
|
+
object,
|
|
75
|
+
(type as MapTypeDescriptor).valueType,
|
|
76
|
+
memberOptions,
|
|
77
|
+
buildOptions,
|
|
78
|
+
);
|
|
79
|
+
if (key === undefined || value === undefined) {
|
|
80
|
+
return undefined;
|
|
81
|
+
}
|
|
82
|
+
return {
|
|
83
|
+
syntax: `map<${key.syntax},${value.syntax}>`,
|
|
84
|
+
types: [value, key],
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
case Set:
|
|
88
|
+
case Object:
|
|
89
|
+
case Function:
|
|
90
|
+
// Non-serializable types
|
|
91
|
+
return undefined;
|
|
92
|
+
case Buffer:
|
|
93
|
+
case Uint8Array:
|
|
94
|
+
return {
|
|
95
|
+
syntax: 'bytes',
|
|
96
|
+
};
|
|
97
|
+
default: {
|
|
98
|
+
const memberMetadata = DataSerializerUtils.getOwnMetadata(type.ctor);
|
|
99
|
+
if (!memberMetadata) {
|
|
100
|
+
return {
|
|
101
|
+
syntax: 'google.protobuf.Any',
|
|
102
|
+
};
|
|
103
|
+
} else if (
|
|
104
|
+
memberMetadata.knownTypes.size > 1 &&
|
|
105
|
+
memberMetadata.protobuf.generator.type &&
|
|
106
|
+
memberMetadata.protobuf.generator.type !== object.classType
|
|
107
|
+
) {
|
|
108
|
+
return this.typeMapping(
|
|
109
|
+
DataSerializerUtils.getOwnMetadata(memberMetadata.protobuf.generator.type),
|
|
110
|
+
type,
|
|
111
|
+
memberOptions,
|
|
112
|
+
buildOptions,
|
|
113
|
+
);
|
|
114
|
+
} else if (
|
|
115
|
+
memberMetadata.knownTypes.size > 1 &&
|
|
116
|
+
!memberMetadata.protobuf.generator.type &&
|
|
117
|
+
memberOptions &&
|
|
118
|
+
(buildOptions.useAnyType || !memberMetadata.protobuf.generator.allowOverride)
|
|
119
|
+
) {
|
|
120
|
+
return {
|
|
121
|
+
syntax: 'google.protobuf.Any',
|
|
122
|
+
};
|
|
123
|
+
} else {
|
|
124
|
+
const packageStr = type.ctor.prototype._module ? type.ctor.prototype._module : '@openhps/core';
|
|
125
|
+
return {
|
|
126
|
+
syntax: type.ctor.name,
|
|
127
|
+
package: packageStr,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
static processObject(object: ObjectMetadata, buildOptions: ProjectBuildOptions): void {
|
|
135
|
+
object.protobuf = object.protobuf ?? {
|
|
136
|
+
generator: {
|
|
137
|
+
subModules: new Set(),
|
|
138
|
+
subTypes: [],
|
|
139
|
+
allowOverride: true,
|
|
140
|
+
},
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
const dataMembers = object.dataMembers;
|
|
144
|
+
// Parse object itself
|
|
145
|
+
if (object.knownTypes.size > 1) {
|
|
146
|
+
const subTypes = [];
|
|
147
|
+
const modules = new Set<string>();
|
|
148
|
+
const dataMembersClone = SerializationUtils.cloneDeep(dataMembers);
|
|
149
|
+
object.knownTypes.forEach((knownType) => {
|
|
150
|
+
const knownTypeMeta = DataSerializerUtils.getOwnMetadata(knownType);
|
|
151
|
+
const knownTypeDataMembers = knownTypeMeta.dataMembers;
|
|
152
|
+
modules.add(knownType.prototype._module);
|
|
153
|
+
|
|
154
|
+
if (knownType !== object.classType && knownType.prototype instanceof object.classType) {
|
|
155
|
+
subTypes.push(knownType);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
knownTypeDataMembers.forEach((member, key) => {
|
|
159
|
+
member.options = member.options ?? {};
|
|
160
|
+
member.options.protobuf = member.options.protobuf ?? {};
|
|
161
|
+
|
|
162
|
+
if (!dataMembers.has(key)) {
|
|
163
|
+
const memberClone = SerializationUtils.cloneDeep(member);
|
|
164
|
+
// Optional
|
|
165
|
+
memberClone.options.protobuf = {
|
|
166
|
+
optional: true,
|
|
167
|
+
subMembers: new Map(),
|
|
168
|
+
};
|
|
169
|
+
dataMembersClone.set(key, memberClone);
|
|
170
|
+
} else if (dataMembers.get(key).type().ctor !== member.type().ctor) {
|
|
171
|
+
const memberClone = dataMembersClone.get(member.key);
|
|
172
|
+
object.protobuf.generator.allowOverride = false;
|
|
173
|
+
memberClone.options = memberClone.options ?? {};
|
|
174
|
+
memberClone.options.protobuf = memberClone.options.protobuf ?? { subMembers: new Map() };
|
|
175
|
+
const subMembers = (memberClone.options.protobuf as any).subMembers ?? new Map();
|
|
176
|
+
const memberName = member.name + '_' + member.type().ctor.name.toLowerCase();
|
|
177
|
+
subMembers.set(memberName, member);
|
|
178
|
+
member.options = member.options ?? {};
|
|
179
|
+
member.options.protobuf = member.options.protobuf ?? {};
|
|
180
|
+
member.options.protobuf.name = memberName;
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
object.protobuf.generator.subTypes = subTypes;
|
|
186
|
+
object.protobuf.generator.subModules = modules;
|
|
187
|
+
if (subTypes.length > 0 && (modules.size === 1 || !buildOptions.useAnyType)) {
|
|
188
|
+
object.protobuf.generator.dataMembers = dataMembersClone;
|
|
189
|
+
object.protobuf.generator.type = object.protobuf.generator.type ?? object.classType;
|
|
190
|
+
subTypes.forEach((type) => {
|
|
191
|
+
const subTypeMeta = DataSerializerUtils.getOwnMetadata(type);
|
|
192
|
+
subTypeMeta.protobuf = subTypeMeta.protobuf ?? { generator: {} };
|
|
193
|
+
subTypeMeta.protobuf.generator.type = object.classType;
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
static createProtoMessage(object: ObjectMetadata, buildOptions: ProjectBuildOptions): [string, string] {
|
|
200
|
+
const rootMeta = DataSerializerUtils.getRootMetadata(object.classType);
|
|
201
|
+
const dataMembers = object.protobuf.generator.dataMembers ?? object.dataMembers;
|
|
202
|
+
const packageStr = object.classType.prototype._module ? object.classType.prototype._module : '@openhps/core';
|
|
203
|
+
const imports = [];
|
|
204
|
+
|
|
205
|
+
// Parse object itself
|
|
206
|
+
let dataTypesEnum = undefined;
|
|
207
|
+
|
|
208
|
+
if (object.knownTypes.size > 1) {
|
|
209
|
+
if (
|
|
210
|
+
object.protobuf.generator.subTypes.length > 0 &&
|
|
211
|
+
(object.protobuf.generator.subModules.size === 1 || !buildOptions.useAnyType)
|
|
212
|
+
) {
|
|
213
|
+
imports.push(`import "../../common.proto";`);
|
|
214
|
+
dataTypesEnum =
|
|
215
|
+
`\nenum ${object.classType.name}Type {\n` +
|
|
216
|
+
`\tUNSPECIFIED = 0;\n` +
|
|
217
|
+
[object.classType, ...object.protobuf.generator.subTypes]
|
|
218
|
+
.map((type) => {
|
|
219
|
+
return `\t${type.name
|
|
220
|
+
.replace(/(?:^|\.?)(([A-Z0-9][a-z0-9]|$)|([0-9]+[A-Z]))/g, (_, y) => {
|
|
221
|
+
return '_' + y;
|
|
222
|
+
})
|
|
223
|
+
.replace(/(^_)|(_$)/g, '')
|
|
224
|
+
.toUpperCase()} = ${
|
|
225
|
+
Array.from(rootMeta.knownTypes.values()).indexOf(type) + 1
|
|
226
|
+
} [\n\t\t(className) = "${type.name}",\n\t\t(packageName) = "${type.prototype._module}"\n\t]`;
|
|
227
|
+
})
|
|
228
|
+
.join(';\n') +
|
|
229
|
+
`;\n}\n`;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
if (rootMeta.classType !== object.classType) {
|
|
234
|
+
const rootMetaType = this.typeMapping(
|
|
235
|
+
rootMeta,
|
|
236
|
+
new ConcreteTypeDescriptor(rootMeta.classType),
|
|
237
|
+
undefined,
|
|
238
|
+
buildOptions,
|
|
239
|
+
);
|
|
240
|
+
if (rootMetaType.package && rootMetaType.package === packageStr) {
|
|
241
|
+
imports.push(`import "${rootMetaType.syntax}.proto";`);
|
|
242
|
+
} else if (rootMetaType.package) {
|
|
243
|
+
imports.push(`import "../../${rootMetaType.package}/${rootMetaType.syntax}.proto";`);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
let index = 1;
|
|
248
|
+
const members = Array.from(dataMembers.values())
|
|
249
|
+
.map((member) => {
|
|
250
|
+
const options: any =
|
|
251
|
+
member.options && (member.options as any).protobuf ? (member.options as any).protobuf : {};
|
|
252
|
+
let type: TypeMapping = undefined;
|
|
253
|
+
const memberName = options.name ?? member.name;
|
|
254
|
+
|
|
255
|
+
if (memberName === 'uid') {
|
|
256
|
+
// Handle as UUID or string
|
|
257
|
+
type = {
|
|
258
|
+
syntax: 'oneof',
|
|
259
|
+
types: [
|
|
260
|
+
{
|
|
261
|
+
syntax: 'string',
|
|
262
|
+
name: 'uid_string',
|
|
263
|
+
},
|
|
264
|
+
{
|
|
265
|
+
syntax: 'bytes',
|
|
266
|
+
name: 'uid_bytes',
|
|
267
|
+
},
|
|
268
|
+
],
|
|
269
|
+
};
|
|
270
|
+
} else if (member.type() === AnyT) {
|
|
271
|
+
if (options.subMembers && options.subMembers.size > 0) {
|
|
272
|
+
type = {
|
|
273
|
+
syntax: 'oneof',
|
|
274
|
+
types: [
|
|
275
|
+
...Array.from(options.subMembers.keys()).map((key: string) => {
|
|
276
|
+
const subMember = options.subMembers.get(key);
|
|
277
|
+
const typeMapping = this.typeMapping(
|
|
278
|
+
object,
|
|
279
|
+
subMember.type(),
|
|
280
|
+
subMember,
|
|
281
|
+
buildOptions,
|
|
282
|
+
);
|
|
283
|
+
typeMapping.name = key;
|
|
284
|
+
return typeMapping;
|
|
285
|
+
}),
|
|
286
|
+
{
|
|
287
|
+
syntax: 'google.protobuf.Any',
|
|
288
|
+
name: memberName + '_' + 'any',
|
|
289
|
+
},
|
|
290
|
+
],
|
|
291
|
+
};
|
|
292
|
+
} else {
|
|
293
|
+
type = {
|
|
294
|
+
syntax: 'google.protobuf.Any',
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
} else if (member.serializer && member.type === undefined) {
|
|
298
|
+
// Custom serializer
|
|
299
|
+
return undefined;
|
|
300
|
+
} else {
|
|
301
|
+
type = this.typeMapping(object, member.type(), member, buildOptions);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
if (!type) {
|
|
305
|
+
return undefined;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
if (type.package && type.package === packageStr) {
|
|
309
|
+
imports.push(`import "${type.syntax}.proto";`);
|
|
310
|
+
} else if (type.package) {
|
|
311
|
+
imports.push(`import "../../${type.package}/${type.syntax}.proto";`);
|
|
312
|
+
} else if (type.syntax === 'google.protobuf.Any') {
|
|
313
|
+
imports.push(`import "google/protobuf/any.proto";`);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
if (type.types) {
|
|
317
|
+
type.types.forEach((dependency) => {
|
|
318
|
+
if (dependency.package && dependency.package === packageStr) {
|
|
319
|
+
imports.push(`import "${dependency.syntax}.proto";`);
|
|
320
|
+
} else if (dependency.package) {
|
|
321
|
+
imports.push(`import "../../${dependency.package}/${dependency.syntax}.proto";`);
|
|
322
|
+
} else if (dependency.syntax === 'google.protobuf.Any') {
|
|
323
|
+
imports.push(`import "google/protobuf/any.proto";`);
|
|
324
|
+
}
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
if (type.syntax === 'oneof') {
|
|
329
|
+
return (
|
|
330
|
+
`\toneof ${memberName} {\n` +
|
|
331
|
+
type.types
|
|
332
|
+
.map((subType) => {
|
|
333
|
+
return `\t\t${subType.syntax} ${subType.name} = ${index++}`;
|
|
334
|
+
})
|
|
335
|
+
.join(';\n') +
|
|
336
|
+
`;\n\t}`
|
|
337
|
+
);
|
|
338
|
+
} else {
|
|
339
|
+
return `\t${
|
|
340
|
+
options.optional && !(type.syntax.includes('<') || type.syntax.includes('repeated'))
|
|
341
|
+
? 'optional '
|
|
342
|
+
: ''
|
|
343
|
+
}${type.syntax} ${memberName} = ${index++};`;
|
|
344
|
+
}
|
|
345
|
+
})
|
|
346
|
+
.filter((value) => value !== undefined);
|
|
347
|
+
|
|
348
|
+
return [
|
|
349
|
+
packageStr,
|
|
350
|
+
HEADER +
|
|
351
|
+
`package ${packageStr.replace('@', '').replace('/', '.')};\n` +
|
|
352
|
+
`syntax = "proto3";\n` +
|
|
353
|
+
imports
|
|
354
|
+
.filter((value, idx) => {
|
|
355
|
+
return imports.indexOf(value) === idx;
|
|
356
|
+
})
|
|
357
|
+
.join('\n') +
|
|
358
|
+
`\n` +
|
|
359
|
+
(dataTypesEnum ? dataTypesEnum : '') +
|
|
360
|
+
`\nmessage ${object.classType.name} {\n` +
|
|
361
|
+
(rootMeta.protobuf.generator.type
|
|
362
|
+
? `\t${rootMeta.protobuf.generator.type.name}Type _type = 0;\n`
|
|
363
|
+
: '') +
|
|
364
|
+
members.join('\n') +
|
|
365
|
+
`\n` +
|
|
366
|
+
`}\n`,
|
|
367
|
+
];
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
export type ProtobufPrimitive = 'string' | 'int32' | 'bool' | 'bytes';
|
|
372
|
+
export interface TypeMapping {
|
|
373
|
+
syntax: ProtobufPrimitive | string;
|
|
374
|
+
types?: TypeMapping[];
|
|
375
|
+
package?: string;
|
|
376
|
+
name?: string;
|
|
377
|
+
}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { DataSerializer, DataSerializerUtils, ObjectMetadata, Serializable } from '@openhps/core';
|
|
2
|
+
import { ObjectGenerator } from './ObjectGenerator';
|
|
3
|
+
import * as fs from 'fs-extra';
|
|
4
|
+
import * as path from 'path';
|
|
5
|
+
import chalk from 'chalk';
|
|
6
|
+
import { COMMON } from './constants';
|
|
7
|
+
import { ProjectBuildOptions } from './types';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Project generator
|
|
11
|
+
*/
|
|
12
|
+
export class ProjectGenerator extends DataSerializer {
|
|
13
|
+
private static _modules: Set<string> = new Set();
|
|
14
|
+
private static _packages: Set<string> = new Set();
|
|
15
|
+
|
|
16
|
+
static findModule(dir: string): string {
|
|
17
|
+
const packageFile = path.join(dir, 'package.json');
|
|
18
|
+
if (fs.existsSync(packageFile)) {
|
|
19
|
+
const packageJson = JSON.parse(fs.readFileSync(packageFile, { encoding: 'utf-8' }));
|
|
20
|
+
return packageJson.name;
|
|
21
|
+
} else {
|
|
22
|
+
const completeDir = dir.split(path.sep);
|
|
23
|
+
completeDir.pop();
|
|
24
|
+
return this.findModule(completeDir.join(path.sep));
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
static loadModules(objects: Array<Serializable<any>>, module: NodeModule = require.main) {
|
|
29
|
+
if (module === undefined) {
|
|
30
|
+
// Use cache instead
|
|
31
|
+
Object.values(require.cache).map((m) => this.loadModules(objects, m));
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
this._modules.add(module.id);
|
|
35
|
+
Object.keys(module.exports).forEach((key) => {
|
|
36
|
+
const childModule = module.exports[key];
|
|
37
|
+
if (objects.includes(childModule)) {
|
|
38
|
+
childModule.prototype._module = this.findModule(path.dirname(require.resolve(module.id)));
|
|
39
|
+
this._packages.add(childModule.prototype._module);
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
module.children.forEach((module) => {
|
|
43
|
+
if (!this._modules.has(module.id)) {
|
|
44
|
+
this.loadModules(objects, module);
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
static getPackages(): string[] {
|
|
50
|
+
if (this._packages.size === 0) {
|
|
51
|
+
this.loadClasses();
|
|
52
|
+
}
|
|
53
|
+
return Array.from(this._packages.values());
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
static loadClasses(): Array<ObjectMetadata> {
|
|
57
|
+
const declarations: Array<ObjectMetadata> = [];
|
|
58
|
+
this.knownTypes.forEach((value) => {
|
|
59
|
+
const metadata = DataSerializerUtils.getOwnMetadata(value);
|
|
60
|
+
if (metadata) {
|
|
61
|
+
declarations.push(metadata);
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
this.loadModules(declarations.map((d) => d.classType));
|
|
65
|
+
return declarations;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
static generateProtoMessages(options: ProjectBuildOptions): Promise<Map<string, [string, string]>> {
|
|
69
|
+
return new Promise((resolve) => {
|
|
70
|
+
const classes = new Map();
|
|
71
|
+
const metaData = this.loadClasses();
|
|
72
|
+
|
|
73
|
+
metaData.forEach((objectMetadata) => {
|
|
74
|
+
ObjectGenerator.processObject(objectMetadata, options);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
metaData.forEach((objectMetadata) => {
|
|
78
|
+
if (options.logLevel > 2) {
|
|
79
|
+
console.log(
|
|
80
|
+
chalk.italic(
|
|
81
|
+
`Generating ${objectMetadata.classType.name}`,
|
|
82
|
+
objectMetadata.classType.prototype._module
|
|
83
|
+
? `of module ${objectMetadata.classType.prototype._module}`
|
|
84
|
+
: '',
|
|
85
|
+
),
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
const javaClass = ObjectGenerator.createProtoMessage(objectMetadata, options);
|
|
89
|
+
classes.set(objectMetadata.classType.name, javaClass);
|
|
90
|
+
});
|
|
91
|
+
resolve(classes);
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
static buildProject(directory: string, options: ProjectBuildOptions = {}): Promise<number> {
|
|
96
|
+
return new Promise((resolve, reject) => {
|
|
97
|
+
// Prepare directories
|
|
98
|
+
if (fs.existsSync(directory)) {
|
|
99
|
+
fs.rmSync(directory, { recursive: true });
|
|
100
|
+
}
|
|
101
|
+
fs.mkdirSync(directory, { recursive: true });
|
|
102
|
+
|
|
103
|
+
// Get all class sources
|
|
104
|
+
if (options.logLevel > 0) {
|
|
105
|
+
console.log('Generating protocol buffer messages ...');
|
|
106
|
+
console.log('Use of any types = ', options.useAnyType);
|
|
107
|
+
}
|
|
108
|
+
ProjectGenerator.generateProtoMessages(options)
|
|
109
|
+
.then((classes) => {
|
|
110
|
+
if (options.logLevel > 0) console.log('Saving generating protocol buffer messages ...');
|
|
111
|
+
classes.forEach((value, key) => {
|
|
112
|
+
const packageDir = path.join(directory, ...value[0].split('.'));
|
|
113
|
+
if (!fs.existsSync(packageDir)) {
|
|
114
|
+
fs.mkdirsSync(packageDir);
|
|
115
|
+
}
|
|
116
|
+
fs.writeFileSync(path.join(packageDir, key + '.proto'), value[1], {
|
|
117
|
+
encoding: 'utf-8',
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
fs.writeFileSync(path.join(directory, 'common.proto'), COMMON, {
|
|
122
|
+
encoding: 'utf-8',
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
resolve(classes.size);
|
|
126
|
+
})
|
|
127
|
+
.catch(reject);
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { Constructor, NumberType, ObjectMemberMetadata } from '@openhps/core';
|
|
2
|
+
|
|
3
|
+
export abstract class ProtobufGenerator<T> {
|
|
4
|
+
protected options: ProtobufGeneratorOptions;
|
|
5
|
+
/**
|
|
6
|
+
* Logger
|
|
7
|
+
*/
|
|
8
|
+
logger: (level: string, message: any) => void = () => {};
|
|
9
|
+
|
|
10
|
+
constructor(options?: ProtobufGeneratorOptions) {
|
|
11
|
+
this.options = options;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
protected static getNumberType(numberType: NumberType): string {
|
|
15
|
+
switch (numberType) {
|
|
16
|
+
case NumberType.DECIMAL:
|
|
17
|
+
case NumberType.DOUBLE:
|
|
18
|
+
return 'double';
|
|
19
|
+
case NumberType.FLOAT:
|
|
20
|
+
return 'float';
|
|
21
|
+
case NumberType.LONG:
|
|
22
|
+
return 'int64';
|
|
23
|
+
case NumberType.INTEGER:
|
|
24
|
+
case NumberType.SHORT:
|
|
25
|
+
return 'int32';
|
|
26
|
+
default:
|
|
27
|
+
return 'string';
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
abstract processObject(object: Constructor<T>, metaData: ObjectMemberMetadata): Promise<void>;
|
|
32
|
+
|
|
33
|
+
abstract generate(object: Constructor<T>, metaData: ObjectMemberMetadata): Promise<ProtobufMessage>;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface ProtobufGeneratorOptions {}
|
|
37
|
+
|
|
38
|
+
export interface ProtobufMessage {
|
|
39
|
+
body: string;
|
|
40
|
+
namespace: string;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export type ProtobufPrimitive = 'string' | 'int32' | 'bool' | 'bytes';
|
|
44
|
+
export interface TypeMapping {
|
|
45
|
+
syntax: ProtobufPrimitive | string;
|
|
46
|
+
types?: TypeMapping[];
|
|
47
|
+
package?: string;
|
|
48
|
+
name?: string;
|
|
49
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Constructor, ObjectMemberMetadata, Service } from '@openhps/core';
|
|
2
|
+
import { ProtobufGenerator, ProtobufMessage } from './ProtobufGenerator';
|
|
3
|
+
|
|
4
|
+
export class ServiceGenerator extends ProtobufGenerator<Service> {
|
|
5
|
+
processObject(object: Constructor<Service>, metaData: ObjectMemberMetadata): Promise<void> { // eslint-disable-line
|
|
6
|
+
throw new Error('Method not implemented.');
|
|
7
|
+
}
|
|
8
|
+
generate(object: Constructor<Service>, metaData: ObjectMemberMetadata): Promise<ProtobufMessage> { // eslint-disable-line
|
|
9
|
+
throw new Error('Method not implemented.');
|
|
10
|
+
}
|
|
11
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export const HEADER = `/**
|
|
2
|
+
* OpenHPS Protocol Buffer
|
|
3
|
+
* This file was automatically generated with @openhps/protobuf
|
|
4
|
+
*
|
|
5
|
+
* (c) 2019-2023 Maxim Van de Wynckel & Vrije Universiteit Brussel
|
|
6
|
+
**/\n
|
|
7
|
+
`;
|
|
8
|
+
|
|
9
|
+
export const COMMON =
|
|
10
|
+
HEADER +
|
|
11
|
+
`syntax = "proto3";` +
|
|
12
|
+
`\n\nextend google.protobuf.EnumValueOptions {\n` +
|
|
13
|
+
`\toptional string className = 1;\n` +
|
|
14
|
+
`\toptional string packageName = 2;\n` +
|
|
15
|
+
`}\n`;
|
|
16
|
+
// `\nextend google.protobuf.MessageOptions {\n` +
|
|
17
|
+
// `\toptional string className = 1001;\n` +
|
|
18
|
+
// `\toptional string packageName = 1002;\n` +
|
|
19
|
+
// `}\n`;
|
package/src/index.ts
ADDED