@openhps/protobuf 1.0.1 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +58 -38
  3. package/dist/cjs/InternalProtobufDeserializer.js +30 -15
  4. package/dist/cjs/InternalProtobufDeserializer.js.map +1 -1
  5. package/dist/cjs/InternalProtobufSerializer.js +7 -7
  6. package/dist/cjs/InternalProtobufSerializer.js.map +1 -1
  7. package/dist/cjs/PrimitiveWrapper.js +13 -0
  8. package/dist/cjs/PrimitiveWrapper.js.map +1 -0
  9. package/dist/cjs/ProtobufSerializer.js +27 -2
  10. package/dist/cjs/ProtobufSerializer.js.map +1 -1
  11. package/dist/cjs/bin/generator.js +3 -3
  12. package/dist/cjs/bin/generator.js.map +1 -1
  13. package/dist/cjs/generator/ObjectGenerator.js +30 -12
  14. package/dist/cjs/generator/ObjectGenerator.js.map +1 -1
  15. package/dist/cjs/generator/ProjectGenerator.js +89 -38
  16. package/dist/cjs/generator/ProjectGenerator.js.map +1 -1
  17. package/dist/cjs/generator/constants.js +11 -4
  18. package/dist/cjs/generator/constants.js.map +1 -1
  19. package/dist/cjs/package.json +3 -0
  20. package/dist/cjs/tsconfig.bundle.cjs.tsbuildinfo +1 -0
  21. package/dist/esm/InternalProtobufDeserializer.js +30 -14
  22. package/dist/esm/InternalProtobufDeserializer.js.map +1 -1
  23. package/dist/esm/InternalProtobufSerializer.js +7 -6
  24. package/dist/esm/InternalProtobufSerializer.js.map +1 -1
  25. package/dist/esm/PrimitiveWrapper.js +9 -0
  26. package/dist/esm/PrimitiveWrapper.js.map +1 -0
  27. package/dist/esm/ProtobufSerializer.js +30 -5
  28. package/dist/esm/ProtobufSerializer.js.map +1 -1
  29. package/dist/esm/bin/generator.js +5 -5
  30. package/dist/esm/bin/generator.js.map +1 -1
  31. package/dist/esm/decorators/index.js +1 -1
  32. package/dist/esm/generator/ObjectGenerator.js +32 -14
  33. package/dist/esm/generator/ObjectGenerator.js.map +1 -1
  34. package/dist/esm/generator/ProjectGenerator.js +92 -40
  35. package/dist/esm/generator/ProjectGenerator.js.map +1 -1
  36. package/dist/esm/generator/ServiceGenerator.js +1 -1
  37. package/dist/esm/generator/constants.js +11 -4
  38. package/dist/esm/generator/constants.js.map +1 -1
  39. package/dist/esm/generator/index.js +3 -3
  40. package/dist/esm/index.js +2 -2
  41. package/dist/esm/package.json +3 -0
  42. package/dist/esm/tsconfig.bundle.esm.tsbuildinfo +1 -0
  43. package/dist/esm/tsconfig.bundle.types.tsbuildinfo +1 -0
  44. package/dist/types/InternalProtobufDeserializer.d.ts +0 -2
  45. package/dist/types/InternalProtobufDeserializer.d.ts.map +1 -1
  46. package/dist/types/InternalProtobufSerializer.d.ts +0 -2
  47. package/dist/types/InternalProtobufSerializer.d.ts.map +1 -1
  48. package/dist/types/PrimitiveWrapper.d.ts +8 -0
  49. package/dist/types/PrimitiveWrapper.d.ts.map +1 -0
  50. package/dist/types/ProtobufSerializer.d.ts +6 -0
  51. package/dist/types/ProtobufSerializer.d.ts.map +1 -1
  52. package/dist/types/generator/ObjectGenerator.d.ts +2 -8
  53. package/dist/types/generator/ObjectGenerator.d.ts.map +1 -1
  54. package/dist/types/generator/ProjectGenerator.d.ts +1 -1
  55. package/dist/types/generator/ProjectGenerator.d.ts.map +1 -1
  56. package/dist/types/generator/constants.d.ts +1 -1
  57. package/dist/types/generator/constants.d.ts.map +1 -1
  58. package/dist/web/openhps-protobuf.es.js +17112 -12881
  59. package/dist/web/openhps-protobuf.es.js.map +1 -1
  60. package/dist/web/openhps-protobuf.es.min.js +2 -1
  61. package/dist/web/openhps-protobuf.es.min.js.LICENSE.txt +19 -0
  62. package/dist/web/openhps-protobuf.es.min.js.map +1 -1
  63. package/dist/web/openhps-protobuf.js +17434 -14605
  64. package/dist/web/openhps-protobuf.js.map +1 -1
  65. package/dist/web/openhps-protobuf.min.js +2 -1
  66. package/dist/web/openhps-protobuf.min.js.LICENSE.txt +19 -0
  67. package/dist/web/openhps-protobuf.min.js.map +1 -1
  68. package/package.json +125 -94
  69. package/src/InternalProtobufDeserializer.ts +52 -34
  70. package/src/InternalProtobufSerializer.ts +9 -10
  71. package/src/PrimitiveWrapper.ts +9 -0
  72. package/src/ProtobufSerializer.ts +33 -2
  73. package/src/bin/generator.ts +4 -4
  74. package/src/generator/ObjectGenerator.ts +34 -21
  75. package/src/generator/ProjectGenerator.ts +100 -42
  76. package/src/generator/constants.ts +11 -4
  77. package/dist/esm5/InternalProtobufDeserializer.js +0 -147
  78. package/dist/esm5/InternalProtobufDeserializer.js.map +0 -1
  79. package/dist/esm5/InternalProtobufSerializer.js +0 -132
  80. package/dist/esm5/InternalProtobufSerializer.js.map +0 -1
  81. package/dist/esm5/ProtobufSerializer.js +0 -131
  82. package/dist/esm5/ProtobufSerializer.js.map +0 -1
  83. package/dist/esm5/bin/generator.js +0 -104
  84. package/dist/esm5/bin/generator.js.map +0 -1
  85. package/dist/esm5/decorators/index.js +0 -2
  86. package/dist/esm5/decorators/index.js.map +0 -1
  87. package/dist/esm5/decorators/options.js +0 -2
  88. package/dist/esm5/decorators/options.js.map +0 -1
  89. package/dist/esm5/generator/ObjectGenerator.js +0 -311
  90. package/dist/esm5/generator/ObjectGenerator.js.map +0 -1
  91. package/dist/esm5/generator/ProjectGenerator.js +0 -115
  92. package/dist/esm5/generator/ProjectGenerator.js.map +0 -1
  93. package/dist/esm5/generator/ProtobufGenerator.js +0 -27
  94. package/dist/esm5/generator/ProtobufGenerator.js.map +0 -1
  95. package/dist/esm5/generator/ServiceGenerator.js +0 -10
  96. package/dist/esm5/generator/ServiceGenerator.js.map +0 -1
  97. package/dist/esm5/generator/constants.js +0 -18
  98. package/dist/esm5/generator/constants.js.map +0 -1
  99. package/dist/esm5/generator/index.js +0 -4
  100. package/dist/esm5/generator/index.js.map +0 -1
  101. package/dist/esm5/generator/types.js +0 -2
  102. package/dist/esm5/generator/types.js.map +0 -1
  103. package/dist/esm5/index.js +0 -3
  104. package/dist/esm5/index.js.map +0 -1
package/package.json CHANGED
@@ -1,96 +1,127 @@
1
1
  {
2
- "name": "@openhps/protobuf",
3
- "version": "1.0.1",
4
- "description": "OpenHPS Protocol Buffer Generator",
5
- "main": "dist/cjs/bin/generator.js",
6
- "bin": {
7
- "openhps-protobuf": "./dist/cjs/bin/generator.js"
8
- },
9
- "publishConfig": {
10
- "access": "public"
11
- },
12
- "scripts": {
13
- "benchmark:1": "ts-node test/bench/serialization.bench.ts",
14
- "benchmark:2": "ts-node test/bench/socket.bench.ts",
15
- "benchmark:3": "ts-node test/bench/mqtt.bench.ts",
16
- "start": "node dist/cjs/bin/generator.js",
17
- "start:debug": "ts-node src/bin/generator.ts",
18
- "test": "mocha --config test/.mocharc.json",
19
- "cover": "nyc mocha --config test/.mocharc.json && nyc report --reporter=cobertura",
20
- "cover:ci": "nyc mocha --config test/.mocharc.json --reporter mocha-junit-reporter && nyc report --reporter=cobertura",
21
- "lint": "eslint src/**",
22
- "clean": "shx rm -rf ./dist && shx rm -rf ./docs/out",
23
- "build": "npm run clean && npm-run-all --parallel build:ts:* && npm run build:webpack",
24
- "build:quick": "npm-run-all --parallel build:ts:* && npm run build:webpack",
25
- "build:typedoc": "typedoc --options docs/typedoc.json",
26
- "build:ts:cjs": "tsc --build ./tsconfig/tsconfig.bundle.cjs.json",
27
- "build:ts:esm": "tsc --build ./tsconfig/tsconfig.bundle.esm.json",
28
- "build:ts:esm5": "tsc --build ./tsconfig/tsconfig.bundle.esm5.json",
29
- "build:ts:types": "tsc --build ./tsconfig/tsconfig.bundle.types.json",
30
- "build:webpack": "npm-run-all --parallel build:webpack:*",
31
- "build:webpack:prod": "webpack --env prod --",
32
- "build:webpack:dev": "webpack --env dev --",
33
- "publish:development": "npm run bump:beta && npm publish --tag dev",
34
- "publish:beta": "npm run bump:beta && npm publish --tag beta",
35
- "publish:release": "npm run bump:beta && npm publish --tag latest",
36
- "bump:development": "standard-version --prerelease alpha -m 'chore(alpha): %s' --author='ci <ci@openhps.org>'",
37
- "bump:beta": "standard-version --prerelease beta -m 'chore(beta): %s' --author='ci <ci@openhps.org>'",
38
- "bump:release": "standard-version -m 'chore(release): %s' --author='ci <ci@openhps.org>'"
39
- },
40
- "files": [
41
- "dist/**/*",
42
- "src/**/*",
43
- "LICENSE"
44
- ],
45
- "author": "Maxim Van de Wynckel",
46
- "license": "Apache-2.0",
47
- "devDependencies": {
48
- "@commitlint/cli": "^19.3.0",
49
- "@commitlint/config-conventional": "^19.2.2",
50
- "@openhps/core": "^0.7.2",
51
- "@openhps/mqtt": "^0.1.9",
52
- "@openhps/rdf": "^0.4.64",
53
- "@openhps/rf": "^0.1.62",
54
- "@openhps/socket": "^0.1.8",
55
- "@types/benchmark": "^2.1.5",
56
- "@types/chai": "^4.3.16",
57
- "@types/fs-extra": "^11.0.4",
58
- "@types/long": "^5.0.0",
59
- "@types/mocha": "^10.0.6",
60
- "@types/node": "^20.14.2",
61
- "@typescript-eslint/eslint-plugin": ">=7.13.0",
62
- "@typescript-eslint/parser": ">=7.13.0",
63
- "benchmark": "^2.1.4",
64
- "buffer": "^6.0.3",
65
- "eslint": "^8.56.0",
66
- "eslint-config-prettier": "^9.1.0",
67
- "eslint-plugin-deprecation": "^2.0.0",
68
- "eslint-plugin-import": "^2.29.1",
69
- "eslint-plugin-jsdoc": "^48.0.3",
70
- "eslint-plugin-prettier": "^5.1.3",
71
- "husky": "^9.0.11",
72
- "mocha": "^10.4.0",
73
- "mocha-junit-reporter": "^2.2.1",
74
- "npm-run-all": "^4.1.5",
75
- "nyc": "^17.0.0",
76
- "prettier": "^3.3.2",
77
- "reflect-metadata": ">=0.2.2",
78
- "shx": "^0.3.4",
79
- "standard-version": "^9.5.0",
80
- "ts-node": "^10.9.2",
81
- "typedoc": ">=0.25.13",
82
- "typescript": "^5.4.5",
83
- "webpack": "^5.92.0",
84
- "webpack-cli": "^5.1.4",
85
- "wkt": "^0.1.1"
86
- },
87
- "dependencies": {
88
- "@inquirer/prompts": "^5.0.5",
89
- "chai": "^4",
90
- "chalk": "4.x",
91
- "fs-extra": "^11.2.0",
92
- "long": "^5.2.3",
93
- "protobufjs": "^7.3.2",
94
- "yargs": "^17.7.2"
95
- }
2
+ "name": "@openhps/protobuf",
3
+ "version": "1.1.0",
4
+ "description": "OpenHPS Protocol Buffer Generator",
5
+ "author": "Maxim Van de Wynckel",
6
+ "license": "Apache-2.0",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/OpenHPS/openhps-protobuf.git"
10
+ },
11
+ "bugs": {
12
+ "url": "https://github.com/OpenHPS/openhps-protobuf/issues"
13
+ },
14
+ "homepage": "https://openhps.org",
15
+ "publishConfig": {
16
+ "access": "public"
17
+ },
18
+ "type": "commonjs",
19
+ "sideEffects": false,
20
+ "main": "./dist/cjs/index.js",
21
+ "types": "./dist/types/index.d.ts",
22
+ "module": "./dist/esm/index.js",
23
+ "es2015": "./dist/esm/index.js",
24
+ "unpkg": "./dist/web/openhps-protobuf.min.js",
25
+ "jsdelivr": "./dist/web/openhps-protobuf.min.js",
26
+ "bin": {
27
+ "openhps-protobuf": "./dist/cjs/bin/generator.js"
28
+ },
29
+ "exports": {
30
+ ".": {
31
+ "types": "./dist/types/index.d.ts",
32
+ "import": "./dist/esm/index.js",
33
+ "require": "./dist/cjs/index.js"
34
+ },
35
+ "./package.json": "./package.json"
36
+ },
37
+ "files": [
38
+ "dist/**/*",
39
+ "src/**/*",
40
+ "LICENSE"
41
+ ],
42
+ "scripts": {
43
+ "benchmark:1": "ts-node test/bench/serialization.bench.ts",
44
+ "benchmark:2": "ts-node test/bench/socket.bench.ts",
45
+ "benchmark:3": "ts-node test/bench/mqtt.bench.ts",
46
+ "start": "node dist/cjs/bin/generator.js",
47
+ "start:debug": "ts-node src/bin/generator.ts",
48
+ "test": "mocha --config test/.mocharc.json",
49
+ "cover": "c8 mocha --config test/.mocharc.json",
50
+ "cover:ci": "c8 mocha --config test/.mocharc.ci.json && c8 report --reporter=cobertura",
51
+ "lint": "eslint . && node scripts/check-peers.mjs",
52
+ "clean": "shx rm -rf ./dist && shx rm -rf ./docs/out",
53
+ "build": "npm run clean && npm-run-all --parallel build:ts:* && npm run build:webpack",
54
+ "build:quick": "npm-run-all --parallel build:ts:* && npm run build:webpack",
55
+ "build:typedoc": "typedoc --options docs/typedoc.json",
56
+ "build:ts:cjs": "tsc --build ./tsconfig/tsconfig.bundle.cjs.json",
57
+ "build:ts:esm": "tsc --build ./tsconfig/tsconfig.bundle.esm.json && node ./scripts/finalize-esm.mjs",
58
+ "build:ts:types": "tsc --build ./tsconfig/tsconfig.bundle.types.json",
59
+ "build:webpack": "npm-run-all --parallel build:webpack:*",
60
+ "build:webpack:prod": "webpack --env prod --",
61
+ "build:webpack:dev": "webpack --env dev --",
62
+ "publish:development": "npm run bump:beta && npm publish --tag dev",
63
+ "publish:beta": "npm run bump:beta && npm publish --tag beta",
64
+ "publish:release": "npm run bump:beta && npm publish --tag latest",
65
+ "bump:development": "commit-and-tag-version --prerelease alpha -m 'chore(alpha): %s' --skip.changelog",
66
+ "bump:beta": "commit-and-tag-version --prerelease beta -m 'chore(beta): %s' --skip.changelog",
67
+ "bump:release": "commit-and-tag-version -m 'chore(release): %s' --skip.changelog",
68
+ "prepare": "husky",
69
+ "build:golden": "shx rm -rf test/golden/protos && node -r ./test/tsconfig.js test/helpers/build-protos.ts test/golden/protos"
70
+ },
71
+ "dependencies": {
72
+ "@inquirer/prompts": "^5.0.5",
73
+ "chalk": "^4.1.2",
74
+ "fs-extra": "^11.4.1",
75
+ "long": "^5.2.3",
76
+ "protobufjs": "^8.8.1",
77
+ "tslib": "^2.9.1",
78
+ "yargs": "^17.7.2"
79
+ },
80
+ "devDependencies": {
81
+ "@commitlint/cli": "^21.2.4",
82
+ "@commitlint/config-conventional": "^21.2.4",
83
+ "@eslint/js": "^9.39.5",
84
+ "@openhps/core": "^1.0.16",
85
+ "@openhps/mqtt": "^1.0.2",
86
+ "@openhps/rdf": "^1.1.7",
87
+ "@openhps/rf": "^1.0.4",
88
+ "@openhps/socket": "^0.1.8",
89
+ "@types/benchmark": "^2.1.5",
90
+ "@types/chai": "^5.2.2",
91
+ "@types/fs-extra": "^11.0.4",
92
+ "@types/mocha": "^10.0.10",
93
+ "@types/node": "^26.6.6",
94
+ "benchmark": "^2.1.4",
95
+ "buffer": "^6.0.3",
96
+ "c8": "^12.0.0",
97
+ "chai": "^6.3.0",
98
+ "commit-and-tag-version": "^13.3.0",
99
+ "eslint": "^9.39.5",
100
+ "eslint-config-prettier": "^10.1.8",
101
+ "eslint-plugin-import": "^2.32.0",
102
+ "eslint-plugin-jsdoc": "^65.4.5",
103
+ "eslint-plugin-prettier": "^5.5.7",
104
+ "globals": "^17.14.0",
105
+ "husky": "^9.1.7",
106
+ "lint-staged": "^17.6.0",
107
+ "mocha": "^11.8.0",
108
+ "mocha-junit-reporter": "^2.2.1",
109
+ "mocha-multi-reporters": "^1.5.2",
110
+ "npm-run-all": "^4.1.5",
111
+ "prettier": "^3.10.0",
112
+ "reflect-metadata": ">=0.2.2",
113
+ "shx": "^0.4.0",
114
+ "terser-webpack-plugin": "^5.3.14",
115
+ "ts-node": "^10.9.2",
116
+ "typedoc": "^0.28.20",
117
+ "typescript": "^5.9.3",
118
+ "typescript-eslint": "^8.72.2",
119
+ "webpack": "^5.112.2",
120
+ "webpack-cli": "^7.3.1",
121
+ "wkt": "^0.1.1"
122
+ },
123
+ "engines": {
124
+ "node": ">=22.0.0"
125
+ },
126
+ "packageManager": "npm@10.9.2"
96
127
  }
@@ -10,18 +10,14 @@ import {
10
10
  TypedJSON,
11
11
  UUID,
12
12
  } from '@openhps/core';
13
- import * as protobuf from 'protobufjs';
14
13
  import { AnyT, JsonObjectMetadata } from 'typedjson';
14
+ import type { Type } from 'protobufjs';
15
+ import { primitiveWrapper } from './PrimitiveWrapper';
15
16
 
16
17
  export class InternalProtobufDeserializer extends Deserializer {
17
- protected static primitiveWrapper: protobuf.Type;
18
-
19
18
  constructor() {
20
19
  super();
21
20
 
22
- InternalProtobufDeserializer.primitiveWrapper = new protobuf.Type('PrimitiveWrapperMessage');
23
- InternalProtobufDeserializer.primitiveWrapper.add(new protobuf.Field('value', 1, 'string'));
24
-
25
21
  this.setDeserializationStrategy(Number, (object: any) => {
26
22
  if (typeof object === 'number') {
27
23
  return object;
@@ -121,7 +117,7 @@ export class InternalProtobufDeserializer extends Deserializer {
121
117
  ): IndexedObject | T | undefined {
122
118
  let expectedSelfType = typeDescriptor.ctor;
123
119
  let sourceObjectMetadata: ObjectMetadata = JsonObjectMetadata.getFromConstructor(expectedSelfType);
124
- if (sourceObject.hasOwnProperty('_type') && sourceObject._type !== 0) {
120
+ if (Object.prototype.hasOwnProperty.call(sourceObject, '_type') && sourceObject._type !== 0) {
125
121
  const enumTypeClassname = sourceObjectMetadata.protobuf.enumMapping.get(sourceObject._type);
126
122
  if (enumTypeClassname) {
127
123
  const enumType = knownTypes.get(enumTypeClassname);
@@ -131,18 +127,30 @@ export class InternalProtobufDeserializer extends Deserializer {
131
127
  }
132
128
  }
133
129
  } else if (sourceObject.type_url && sourceObject.value) {
134
- const MessageType = serializerOptions.types.get(sourceObject.type_url) as protobuf.Type;
135
- const message = MessageType.decode(sourceObject.value);
136
- const data = this.convertAsObject(
137
- message,
138
- new ConcreteTypeDescriptor(knownTypes.get(sourceObject.type_url)),
139
- knownTypes,
140
- memberName,
141
- deserializer,
142
- memberOptions,
143
- serializerOptions,
144
- );
145
- return data;
130
+ const MessageType = serializerOptions.types.get(sourceObject.type_url) as Type;
131
+ if (MessageType) {
132
+ const message = MessageType.decode(sourceObject.value);
133
+ const data = this.convertAsObject(
134
+ message,
135
+ new ConcreteTypeDescriptor(knownTypes.get(sourceObject.type_url)),
136
+ knownTypes,
137
+ memberName,
138
+ deserializer,
139
+ memberOptions,
140
+ serializerOptions,
141
+ );
142
+ return data;
143
+ }
144
+ // Unknown type: fall back to the primitive wrapper for primitive values
145
+ const message = primitiveWrapper.decode(sourceObject.value) as any;
146
+ switch (sourceObject.type_url) {
147
+ case 'Boolean':
148
+ return (message.value === 'true') as any;
149
+ case 'Number':
150
+ return Number(message.value) as any;
151
+ default:
152
+ return message.value as any;
153
+ }
146
154
  }
147
155
 
148
156
  const sourceMetadata = sourceObjectMetadata;
@@ -162,32 +170,42 @@ export class InternalProtobufDeserializer extends Deserializer {
162
170
 
163
171
  let revivedValue;
164
172
  if (objMemberMetadata.name === 'uid') {
165
- if (sourceObject.hasOwnProperty('uid_bytes') && sourceObject['uid_bytes'].byteLength > 0) {
173
+ if (
174
+ Object.prototype.hasOwnProperty.call(sourceObject, 'uid_bytes') &&
175
+ sourceObject['uid_bytes'].byteLength > 0
176
+ ) {
166
177
  revivedValue = UUID.fromBuffer(sourceObject['uid_bytes']).toString();
167
- } else if (sourceObject.hasOwnProperty('uid_string')) {
178
+ } else if (Object.prototype.hasOwnProperty.call(sourceObject, 'uid_string')) {
168
179
  revivedValue = sourceObject['uid_string'];
169
180
  } else {
170
181
  return;
171
182
  }
172
- } else if (!sourceObject.hasOwnProperty(memberName) || !objMemberValue) {
183
+ } else if (
184
+ !Object.prototype.hasOwnProperty.call(sourceObject, memberName) ||
185
+ objMemberValue === undefined ||
186
+ objMemberValue === null
187
+ ) {
173
188
  return;
174
189
  } else if (objMemberMetadata.type() === AnyT && objMemberValue.type_url) {
175
- const MessageType = serializerOptions.types.get(sourceObject[memberName].type_url) as protobuf.Type;
190
+ const MessageType = serializerOptions.types.get(sourceObject[memberName].type_url) as Type;
176
191
  if (MessageType) {
177
- const message = MessageType.decode(objMemberValue.value);
178
- revivedValue = deserializer.convertSingleValue(
179
- message,
180
- new ConcreteTypeDescriptor(knownTypes.get(objMemberValue.type_url)),
181
- knownTypes,
182
- objMemberDebugName,
183
- objMemberOptions,
184
- serializerOptions,
185
- );
192
+ const messageType = knownTypes.get(objMemberValue.type_url);
193
+ if (messageType !== undefined) {
194
+ const message = MessageType.decode(objMemberValue.value);
195
+ revivedValue = deserializer.convertSingleValue(
196
+ message,
197
+ new ConcreteTypeDescriptor(messageType),
198
+ knownTypes,
199
+ objMemberDebugName,
200
+ objMemberOptions,
201
+ serializerOptions,
202
+ );
203
+ }
186
204
  } else if (objMemberValue.value) {
187
- const message = InternalProtobufDeserializer.primitiveWrapper.decode(objMemberValue.value) as any;
205
+ const message = primitiveWrapper.decode(objMemberValue.value) as any;
188
206
  switch (objMemberValue.type_url) {
189
207
  case 'Boolean':
190
- revivedValue = Boolean(message.value);
208
+ revivedValue = message.value === 'true';
191
209
  break;
192
210
  case 'Number':
193
211
  revivedValue = Number(message.value);
@@ -9,18 +9,14 @@ import {
9
9
  TypedJSON,
10
10
  UUID,
11
11
  } from '@openhps/core';
12
- import { Type } from 'protobufjs';
13
12
  import { AnyT, JsonObjectMetadata } from 'typedjson';
14
- import * as protobuf from 'protobufjs';
13
+ import type { Type } from 'protobufjs';
14
+ import { primitiveWrapper } from './PrimitiveWrapper';
15
15
 
16
16
  export class InternalProtobufSerializer extends Serializer {
17
- protected static primitiveWrapper: Type;
18
-
19
17
  constructor() {
20
18
  super();
21
19
  this.setSerializationStrategy(Map, this.convertAsMap.bind(this));
22
- InternalProtobufSerializer.primitiveWrapper = new protobuf.Type('PrimitiveWrapperMessage');
23
- InternalProtobufSerializer.primitiveWrapper.add(new protobuf.Field('value', 1, 'string'));
24
20
  }
25
21
 
26
22
  convertSingleValue(
@@ -122,7 +118,10 @@ export class InternalProtobufSerializer extends Serializer {
122
118
  }
123
119
  } else {
124
120
  const MessageType = sourceTypeMetadata.protobuf.messageType;
125
- const field = MessageType.get(objMemberMetadata.name);
121
+ // Look the field up by its wire name: members renamed through
122
+ // `options.protobuf.name` are emitted under that name, so the
123
+ // metadata name would not resolve for them.
124
+ const field = MessageType.get(memberName);
126
125
  serialized = this.convertSingleValue(
127
126
  sourceObject[objMemberMetadata.key],
128
127
  objMemberMetadata.type(),
@@ -139,7 +138,7 @@ export class InternalProtobufSerializer extends Serializer {
139
138
  if (objMemberMetadata.type() === AnyT) {
140
139
  const MessageType = serializerOptions.types.get(
141
140
  sourceObject[objMemberMetadata.key].constructor.name,
142
- ) as protobuf.Type;
141
+ ) as Type;
143
142
  if (MessageType) {
144
143
  const message = MessageType.create(serialized);
145
144
  serialized = {
@@ -147,12 +146,12 @@ export class InternalProtobufSerializer extends Serializer {
147
146
  value: MessageType.encode(message).finish(),
148
147
  };
149
148
  } else {
150
- const message = InternalProtobufSerializer.primitiveWrapper.create({
149
+ const message = primitiveWrapper.create({
151
150
  value: String(sourceObject[objMemberMetadata.key]),
152
151
  });
153
152
  serialized = {
154
153
  type_url: sourceObject[objMemberMetadata.key].constructor.name,
155
- value: InternalProtobufSerializer.primitiveWrapper.encode(message).finish(),
154
+ value: primitiveWrapper.encode(message).finish(),
156
155
  };
157
156
  }
158
157
  }
@@ -0,0 +1,9 @@
1
+ import * as protobuf from 'protobufjs';
2
+
3
+ /**
4
+ * Protobuf type wrapping a primitive value as a string.
5
+ * Shared by the serializer and the deserializer as the `google.protobuf.Any`
6
+ * fallback for primitive values that protobuf cannot express directly.
7
+ */
8
+ export const primitiveWrapper: protobuf.Type = new protobuf.Type('PrimitiveWrapperMessage');
9
+ primitiveWrapper.add(new protobuf.Field('value', 1, 'string'));
@@ -8,6 +8,12 @@ import { InternalProtobufSerializer } from './InternalProtobufSerializer';
8
8
 
9
9
  export class ProtobufSerializer extends DataSerializer {
10
10
  protected static wrapperMessage: protobuf.Type;
11
+ /**
12
+ * Root holding {@link wrapperMessage}. protobufjs 8 resolves edition features by
13
+ * walking up to a root, and throws "Unable to find a parent for WrapperMessage" for
14
+ * a Type that was never added to one. Held as a field so it stays reachable.
15
+ */
16
+ protected static wrapperRoot: protobuf.Root;
11
17
  protected static options: ProtobufSerializerConfig = {
12
18
  serializer: new InternalProtobufSerializer(),
13
19
  deserializer: new InternalProtobufDeserializer(),
@@ -39,6 +45,26 @@ export class ProtobufSerializer extends DataSerializer {
39
45
  static initialize(directory?: string): Promise<void> {
40
46
  return new Promise((resolve, reject) => {
41
47
  ProtobufSerializer.root = new protobuf.Root();
48
+ // Reinitialisation (e.g. per test) must not accumulate stale type entries:
49
+ // build the new map first and only swap it in once the schemas have
50
+ // loaded, so a failed load keeps the previous types instead of wiping them
51
+ const types = new Map<string, protobuf.Type>();
52
+ // The generated schemas extend google.protobuf.EnumValueOptions, which is
53
+ // declared in descriptor.proto. protobufjs resolves imports relative to the
54
+ // origin file, so it looked for google/protobuf/descriptor.proto inside the
55
+ // generated output directory and failed with "unresolvable extensions".
56
+ // protobufjs ships the well-known types itself; point the resolver at them.
57
+ // Resolve the package root from a literal specifier: a template literal here
58
+ // makes webpack build a context module over the whole protobufjs package,
59
+ // which then tries to parse its .d.ts and tsconfig.json as bundle input.
60
+ const protobufRoot = path.dirname(require.resolve('protobufjs/package.json'));
61
+ const defaultResolve = ProtobufSerializer.root.resolvePath.bind(ProtobufSerializer.root);
62
+ ProtobufSerializer.root.resolvePath = (origin: string, target: string) => {
63
+ if (target.startsWith('google/protobuf/')) {
64
+ return path.join(protobufRoot, target);
65
+ }
66
+ return defaultResolve(origin, target);
67
+ };
42
68
  Promise.resolve(
43
69
  !directory ? (ProjectGenerator.buildProject(path.resolve('tmp')) as any) : Promise.resolve(),
44
70
  )
@@ -88,9 +114,10 @@ export class ProtobufSerializer extends DataSerializer {
88
114
  messageTypeEnum: enumNumber,
89
115
  enumMapping,
90
116
  };
91
- this.options.types.set(className, MessageType);
117
+ types.set(className, MessageType);
92
118
  }
93
119
  });
120
+ this.options.types = types;
94
121
  resolve();
95
122
  })
96
123
  .catch((error) => {
@@ -98,13 +125,14 @@ export class ProtobufSerializer extends DataSerializer {
98
125
  });
99
126
  });
100
127
 
128
+ this.wrapperRoot = new protobuf.Root();
101
129
  this.wrapperMessage = new protobuf.Type('WrapperMessage');
102
130
  this.wrapperMessage.add(new protobuf.Field('data', 1, 'google.protobuf.Any'));
103
131
  this.wrapperMessage.addJSON(protobuf.common['google/protobuf/any.proto'].nested);
132
+ this.wrapperRoot.add(this.wrapperMessage);
104
133
  return loadPromise;
105
134
  })
106
135
  .then(() => {
107
- console.log(ProtobufSerializer.root.toJSON());
108
136
  resolve();
109
137
  })
110
138
  .catch(reject);
@@ -147,6 +175,9 @@ export class ProtobufSerializer extends DataSerializer {
147
175
  const decodedData: any = this.wrapperMessage.decode(serializedData);
148
176
  const typeURL = decodedData.data.type_url;
149
177
  const MessageType = this.options.types.get(typeURL) as protobuf.Type;
178
+ if (MessageType === undefined) {
179
+ throw new Error(`Unknown protobuf type '${typeURL}'`);
180
+ }
150
181
  const decodedMessage = MessageType.decode(decodedData.data.value);
151
182
  const finalType = dataType ?? (this.knownTypes.get(typeURL) as Constructor<T>);
152
183
  return this.options.deserializer.convertSingleValue(
@@ -20,9 +20,9 @@ import {
20
20
  RelativeDistance,
21
21
  } from '@openhps/core';
22
22
  import { ProtobufSerializer } from '../ProtobufSerializer';
23
- import { expect } from 'chai';
23
+ import assert from 'node:assert/strict';
24
24
 
25
- const args: [K: string] = yargs.argv as any;
25
+ const args = yargs.argv;
26
26
  const data = {
27
27
  directory: path.normalize('tmp'),
28
28
  };
@@ -114,13 +114,13 @@ function test(): Promise<void> {
114
114
  frame.addObject(new DataObject('test2', 'Test Object 2'));
115
115
  const buffer = ProtobufSerializer.serialize(frame);
116
116
  const deserialized: DataFrame = ProtobufSerializer.deserialize(buffer);
117
- expect(deserialized).to.not.be.undefined;
117
+ assert.notStrictEqual(deserialized, undefined, 'deserialization returned undefined');
118
118
  const compare1 = JSON.stringify(DataSerializer.serialize(deserialized), null, 2);
119
119
  const compare2 = JSON.stringify(DataSerializer.serialize(frame), null, 2);
120
120
  // console.log(compare1);
121
121
  // console.log('\n');
122
122
  // console.log(compare2);
123
- expect(compare1).to.eql(compare2);
123
+ assert.deepStrictEqual(compare1, compare2, 'round-tripped frame differs from the original');
124
124
  console.log(chalk.green(`Basic serialization and deserialization test completed!`));
125
125
  resolve();
126
126
  })