@aptre/protobuf-es-lite 0.4.1 → 0.4.3
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/binary.js +29 -19
- package/dist/codegen-info.d.ts +2 -1
- package/dist/codegen-info.js +2 -1
- package/dist/field-wrapper.d.ts +6 -1
- package/dist/field-wrapper.js +15 -5
- package/dist/google/protobuf/timestamp.pb.d.ts +1 -0
- package/dist/google/protobuf/timestamp.pb.js +22 -0
- package/dist/is-message.js +8 -4
- package/dist/json.js +44 -22
- package/dist/message.d.ts +1 -1
- package/dist/message.js +15 -8
- package/dist/names.js +5 -1
- package/dist/partial.js +13 -7
- package/dist/protoc-gen-es-lite/typescript.js +49 -49
- package/dist/protoplugin/ecmascript/transpile.js +0 -1
- package/dist/scalar.d.ts +4 -3
- package/dist/scalar.js +33 -0
- package/dist/text-format.js +5 -0
- package/dist/util.js +33 -16
- package/example/example.pb.ts +4 -4
- package/example/tsconfig.json +1 -0
- package/package.json +7 -1
- package/tsconfig.base.json +4 -4
- package/tsconfig.json +0 -3
package/dist/binary.js
CHANGED
|
@@ -22,9 +22,10 @@ function makeWriteOptions(options) {
|
|
|
22
22
|
}
|
|
23
23
|
function readField(target, // eslint-disable-line @typescript-eslint/no-explicit-any -- `any` is the best choice for dynamic access
|
|
24
24
|
reader, field, wireType, options) {
|
|
25
|
-
|
|
25
|
+
const { repeated } = field;
|
|
26
|
+
let { localName } = field;
|
|
26
27
|
if (field.oneof) {
|
|
27
|
-
|
|
28
|
+
let oneofMsg = target[field.oneof.localName];
|
|
28
29
|
if (!oneofMsg) {
|
|
29
30
|
oneofMsg = target[field.oneof.localName] = Object.create(null);
|
|
30
31
|
}
|
|
@@ -37,7 +38,7 @@ reader, field, wireType, options) {
|
|
|
37
38
|
}
|
|
38
39
|
switch (field.kind) {
|
|
39
40
|
case "scalar":
|
|
40
|
-
case "enum":
|
|
41
|
+
case "enum": {
|
|
41
42
|
const scalarType = field.kind == "enum" ? ScalarType.INT32 : field.T;
|
|
42
43
|
let read = readScalar;
|
|
43
44
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison -- acceptable since it's covered by tests
|
|
@@ -45,7 +46,7 @@ reader, field, wireType, options) {
|
|
|
45
46
|
read = readScalarLTString;
|
|
46
47
|
}
|
|
47
48
|
if (repeated) {
|
|
48
|
-
|
|
49
|
+
let tgtArr = target[localName];
|
|
49
50
|
if (!Array.isArray(tgtArr)) {
|
|
50
51
|
tgtArr = target[localName] = [];
|
|
51
52
|
}
|
|
@@ -53,7 +54,7 @@ reader, field, wireType, options) {
|
|
|
53
54
|
scalarType != ScalarType.STRING &&
|
|
54
55
|
scalarType != ScalarType.BYTES;
|
|
55
56
|
if (isPacked) {
|
|
56
|
-
|
|
57
|
+
const e = reader.uint32() + reader.pos;
|
|
57
58
|
while (reader.pos < e) {
|
|
58
59
|
tgtArr.push(read(reader, scalarType));
|
|
59
60
|
}
|
|
@@ -66,11 +67,12 @@ reader, field, wireType, options) {
|
|
|
66
67
|
target[localName] = read(reader, scalarType);
|
|
67
68
|
}
|
|
68
69
|
break;
|
|
69
|
-
|
|
70
|
+
}
|
|
71
|
+
case "message": {
|
|
70
72
|
const fieldT = field.T;
|
|
71
73
|
const messageType = fieldT instanceof Function ? fieldT() : fieldT;
|
|
72
74
|
if (repeated) {
|
|
73
|
-
|
|
75
|
+
let tgtArr = target[localName];
|
|
74
76
|
if (!Array.isArray(tgtArr)) {
|
|
75
77
|
tgtArr = target[localName] = [];
|
|
76
78
|
}
|
|
@@ -80,14 +82,16 @@ reader, field, wireType, options) {
|
|
|
80
82
|
target[localName] = unwrapField(messageType.fieldWrapper, readMessageField(reader, Object.create(null), messageType.fields, options, field));
|
|
81
83
|
}
|
|
82
84
|
break;
|
|
83
|
-
|
|
84
|
-
|
|
85
|
+
}
|
|
86
|
+
case "map": {
|
|
87
|
+
const [mapKey, mapVal] = readMapEntry(field, reader, options);
|
|
85
88
|
if (typeof target[localName] !== "object") {
|
|
86
89
|
target[localName] = Object.create(null);
|
|
87
90
|
}
|
|
88
91
|
// safe to assume presence of map object, oneof cannot contain repeated values
|
|
89
92
|
target[localName][mapKey] = mapVal;
|
|
90
93
|
break;
|
|
94
|
+
}
|
|
91
95
|
}
|
|
92
96
|
}
|
|
93
97
|
// Read a map field, expecting key field = 1, value field = 2
|
|
@@ -108,10 +112,10 @@ function readMapEntry(field, reader, options) {
|
|
|
108
112
|
case "enum":
|
|
109
113
|
val = reader.int32();
|
|
110
114
|
break;
|
|
111
|
-
case "message":
|
|
112
|
-
|
|
113
|
-
val = readMessageField(reader, Object.create(null), messageType.fields, options, undefined);
|
|
115
|
+
case "message": {
|
|
116
|
+
val = readMessageField(reader, Object.create(null), resolveMessageType(field.V.T).fields, options, undefined);
|
|
114
117
|
break;
|
|
118
|
+
}
|
|
115
119
|
}
|
|
116
120
|
break;
|
|
117
121
|
}
|
|
@@ -119,8 +123,8 @@ function readMapEntry(field, reader, options) {
|
|
|
119
123
|
if (key === undefined) {
|
|
120
124
|
key = scalarZeroValue(field.K, LongType.BIGINT);
|
|
121
125
|
}
|
|
122
|
-
if (typeof key
|
|
123
|
-
key = key
|
|
126
|
+
if (typeof key !== "string" && typeof key !== "number") {
|
|
127
|
+
key = key?.toString() ?? "";
|
|
124
128
|
}
|
|
125
129
|
if (val === undefined) {
|
|
126
130
|
const fieldKind = field.V.kind;
|
|
@@ -170,6 +174,10 @@ function readScalar(reader, type) {
|
|
|
170
174
|
return reader.uint32();
|
|
171
175
|
case ScalarType.SINT32:
|
|
172
176
|
return reader.sint32();
|
|
177
|
+
case ScalarType.DATE:
|
|
178
|
+
throw new Error("cannot read a date with readScalar");
|
|
179
|
+
default:
|
|
180
|
+
throw new Error("unknown scalar type");
|
|
173
181
|
}
|
|
174
182
|
}
|
|
175
183
|
// Read a scalar value, but return 64 bit integral types (int64, uint64,
|
|
@@ -234,8 +242,8 @@ function writeField(field, value, writer, options) {
|
|
|
234
242
|
const repeated = field.repeated;
|
|
235
243
|
switch (field.kind) {
|
|
236
244
|
case "scalar":
|
|
237
|
-
case "enum":
|
|
238
|
-
|
|
245
|
+
case "enum": {
|
|
246
|
+
const scalarType = field.kind == "enum" ? ScalarType.INT32 : field.T;
|
|
239
247
|
if (repeated) {
|
|
240
248
|
assert(Array.isArray(value));
|
|
241
249
|
if (field.packed) {
|
|
@@ -251,6 +259,7 @@ function writeField(field, value, writer, options) {
|
|
|
251
259
|
writeScalar(writer, scalarType, field.no, value);
|
|
252
260
|
}
|
|
253
261
|
break;
|
|
262
|
+
}
|
|
254
263
|
case "message":
|
|
255
264
|
if (repeated) {
|
|
256
265
|
assert(Array.isArray(value));
|
|
@@ -296,7 +305,7 @@ function writeMessageField(writer, options, field, value) {
|
|
|
296
305
|
}
|
|
297
306
|
function writeScalar(writer, type, fieldNo, value) {
|
|
298
307
|
assert(value !== undefined);
|
|
299
|
-
|
|
308
|
+
const [wireType, method] = scalarTypeInfo(type);
|
|
300
309
|
writer.tag(fieldNo, wireType)[method](value);
|
|
301
310
|
}
|
|
302
311
|
function writePacked(writer, type, fieldNo, value) {
|
|
@@ -304,7 +313,7 @@ function writePacked(writer, type, fieldNo, value) {
|
|
|
304
313
|
return;
|
|
305
314
|
}
|
|
306
315
|
writer.tag(fieldNo, WireType.LengthDelimited).fork();
|
|
307
|
-
|
|
316
|
+
const [, method] = scalarTypeInfo(type);
|
|
308
317
|
for (let i = 0; i < value.length; i++) {
|
|
309
318
|
writer[method](value[i]);
|
|
310
319
|
}
|
|
@@ -373,13 +382,14 @@ function writeMapEntry(writer, options, field, key, value) {
|
|
|
373
382
|
case "enum":
|
|
374
383
|
writeScalar(writer, ScalarType.INT32, 2, value);
|
|
375
384
|
break;
|
|
376
|
-
case "message":
|
|
385
|
+
case "message": {
|
|
377
386
|
assert(value !== undefined);
|
|
378
387
|
const messageType = resolveMessageType(field.V.T);
|
|
379
388
|
writer
|
|
380
389
|
.tag(2, WireType.LengthDelimited)
|
|
381
390
|
.bytes(messageType.toBinary(value, options));
|
|
382
391
|
break;
|
|
392
|
+
}
|
|
383
393
|
}
|
|
384
394
|
writer.join();
|
|
385
395
|
}
|
package/dist/codegen-info.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { localName } from "./names.js";
|
|
2
|
-
import { getUnwrappedFieldType } from "./field-wrapper.js";
|
|
2
|
+
import { getUnwrappedFieldType, getUnwrappedMessageType } from "./field-wrapper.js";
|
|
3
3
|
import { scalarZeroValue } from "./scalar.js";
|
|
4
4
|
type RuntimeSymbolInfo = {
|
|
5
5
|
typeOnly: boolean;
|
|
@@ -11,6 +11,7 @@ export declare const codegenInfo: {
|
|
|
11
11
|
readonly packageName: "@aptre/protobuf-es-lite";
|
|
12
12
|
readonly localName: typeof localName;
|
|
13
13
|
readonly getUnwrappedFieldType: typeof getUnwrappedFieldType;
|
|
14
|
+
readonly getUnwrappedMessageType: typeof getUnwrappedMessageType;
|
|
14
15
|
readonly scalarZeroValue: typeof scalarZeroValue;
|
|
15
16
|
readonly safeIdentifier: (name: string) => string;
|
|
16
17
|
readonly safeObjectProperty: (name: string) => string;
|
package/dist/codegen-info.js
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
// See the License for the specific language governing permissions and
|
|
14
14
|
// limitations under the License.
|
|
15
15
|
import { localName, safeIdentifier, safeObjectProperty } from "./names.js";
|
|
16
|
-
import { getUnwrappedFieldType } from "./field-wrapper.js";
|
|
16
|
+
import { getUnwrappedFieldType, getUnwrappedMessageType, } from "./field-wrapper.js";
|
|
17
17
|
import { scalarZeroValue } from "./scalar.js";
|
|
18
18
|
export const packageName = "@aptre/protobuf-es-lite";
|
|
19
19
|
const symbolInfo = (typeOnly, privateImportPath) => ({
|
|
@@ -55,6 +55,7 @@ export const codegenInfo = {
|
|
|
55
55
|
packageName,
|
|
56
56
|
localName,
|
|
57
57
|
getUnwrappedFieldType,
|
|
58
|
+
getUnwrappedMessageType,
|
|
58
59
|
scalarZeroValue,
|
|
59
60
|
safeIdentifier,
|
|
60
61
|
safeObjectProperty,
|
package/dist/field-wrapper.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DescExtension, DescField } from "./descriptor-set.js";
|
|
1
|
+
import { DescExtension, DescField, DescMessage } from "./descriptor-set.js";
|
|
2
2
|
import { ScalarType } from "./scalar.js";
|
|
3
3
|
/**
|
|
4
4
|
* A field wrapper unwraps a message to a primitive value that is more
|
|
@@ -31,3 +31,8 @@ export declare function unwrapField<T, U = T>(fieldWrapper: FieldWrapper<T> | un
|
|
|
31
31
|
* the primitive type it wraps.
|
|
32
32
|
*/
|
|
33
33
|
export declare function getUnwrappedFieldType(field: DescField | DescExtension): ScalarType | undefined;
|
|
34
|
+
/**
|
|
35
|
+
* If the given field uses one of the well-known wrapper types, return
|
|
36
|
+
* the primitive type it wraps.
|
|
37
|
+
*/
|
|
38
|
+
export declare function getUnwrappedMessageType(msg: DescMessage): ScalarType | undefined;
|
package/dist/field-wrapper.js
CHANGED
|
@@ -14,7 +14,7 @@ export function wrapField(fieldWrapper, value) {
|
|
|
14
14
|
* message. This function is idempotent.
|
|
15
15
|
*/
|
|
16
16
|
export function unwrapField(fieldWrapper, value) {
|
|
17
|
-
return
|
|
17
|
+
return fieldWrapper ? fieldWrapper.unwrapField(value) : value;
|
|
18
18
|
}
|
|
19
19
|
/**
|
|
20
20
|
* If the given field uses one of the well-known wrapper types, return
|
|
@@ -24,15 +24,25 @@ export function getUnwrappedFieldType(field) {
|
|
|
24
24
|
if (field.fieldKind !== "message") {
|
|
25
25
|
return undefined;
|
|
26
26
|
}
|
|
27
|
-
if (field.
|
|
28
|
-
|
|
27
|
+
if (field.message.typeName !== "google.protobuf.Timestamp") {
|
|
28
|
+
if (field.repeated || field.oneof != null) {
|
|
29
|
+
return undefined;
|
|
30
|
+
}
|
|
29
31
|
}
|
|
30
|
-
|
|
32
|
+
return getUnwrappedMessageType(field.message);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* If the given field uses one of the well-known wrapper types, return
|
|
36
|
+
* the primitive type it wraps.
|
|
37
|
+
*/
|
|
38
|
+
export function getUnwrappedMessageType(msg) {
|
|
39
|
+
if (msg.kind !== "message") {
|
|
31
40
|
return undefined;
|
|
32
41
|
}
|
|
33
|
-
return wktWrapperToScalarType[
|
|
42
|
+
return wktWrapperToScalarType[msg.typeName];
|
|
34
43
|
}
|
|
35
44
|
const wktWrapperToScalarType = {
|
|
45
|
+
"google.protobuf.Timestamp": ScalarType.DATE,
|
|
36
46
|
"google.protobuf.DoubleValue": ScalarType.DOUBLE,
|
|
37
47
|
"google.protobuf.FloatValue": ScalarType.FLOAT,
|
|
38
48
|
"google.protobuf.Int64Value": ScalarType.INT64,
|
|
@@ -120,6 +120,7 @@ declare const Timestamp_Wkt: {
|
|
|
120
120
|
toJson(msg: Timestamp): JsonValue;
|
|
121
121
|
toDate(msg: Timestamp | null | undefined): Date | null;
|
|
122
122
|
fromDate(value: Date | null | undefined): Timestamp;
|
|
123
|
+
equals(a: Timestamp | Date | undefined | null, b: Timestamp | Date | undefined | null): boolean;
|
|
123
124
|
};
|
|
124
125
|
export declare const Timestamp: MessageType<Timestamp> & typeof Timestamp_Wkt;
|
|
125
126
|
export {};
|
|
@@ -103,6 +103,17 @@ const Timestamp_Wkt = {
|
|
|
103
103
|
const nanos = (ms % 1000) * 1000000;
|
|
104
104
|
return { seconds: protoInt64.parse(seconds), nanos: nanos };
|
|
105
105
|
},
|
|
106
|
+
equals(a, b) {
|
|
107
|
+
const aDate = a instanceof Date ? a : Timestamp_Wkt.toDate(a);
|
|
108
|
+
const bDate = b instanceof Date ? b : Timestamp_Wkt.toDate(b);
|
|
109
|
+
if (aDate === bDate) {
|
|
110
|
+
return true;
|
|
111
|
+
}
|
|
112
|
+
if (aDate == null || bDate == null) {
|
|
113
|
+
return aDate === bDate;
|
|
114
|
+
}
|
|
115
|
+
return +aDate === +bDate;
|
|
116
|
+
},
|
|
106
117
|
};
|
|
107
118
|
// Timestamp contains the message type declaration for Timestamp.
|
|
108
119
|
export const Timestamp = createMessageType({
|
|
@@ -112,4 +123,15 @@ export const Timestamp = createMessageType({
|
|
|
112
123
|
{ no: 2, name: "nanos", kind: "scalar", T: ScalarType.INT32 },
|
|
113
124
|
],
|
|
114
125
|
packedByDefault: true,
|
|
126
|
+
fieldWrapper: {
|
|
127
|
+
wrapField(value) {
|
|
128
|
+
if (value == null || value instanceof Date) {
|
|
129
|
+
return Timestamp_Wkt.fromDate(value);
|
|
130
|
+
}
|
|
131
|
+
return Timestamp.createComplete(value);
|
|
132
|
+
},
|
|
133
|
+
unwrapField(msg) {
|
|
134
|
+
return Timestamp_Wkt.toDate(msg);
|
|
135
|
+
},
|
|
136
|
+
},
|
|
115
137
|
}, Timestamp_Wkt);
|
package/dist/is-message.js
CHANGED
|
@@ -41,9 +41,10 @@ export function isField(value, field) {
|
|
|
41
41
|
switch (fieldKind) {
|
|
42
42
|
case "scalar":
|
|
43
43
|
return true;
|
|
44
|
-
case "message":
|
|
44
|
+
case "message": {
|
|
45
45
|
const messageType = resolveMessageType(field.T);
|
|
46
46
|
return isMessage(value, messageType.fields.list());
|
|
47
|
+
}
|
|
47
48
|
case "enum":
|
|
48
49
|
return typeof value === "number";
|
|
49
50
|
case "map":
|
|
@@ -54,9 +55,10 @@ export function isField(value, field) {
|
|
|
54
55
|
return true;
|
|
55
56
|
case "enum":
|
|
56
57
|
return typeof val === "number";
|
|
57
|
-
case "message":
|
|
58
|
+
case "message": {
|
|
58
59
|
const messageType = resolveMessageType(field.V.T);
|
|
59
60
|
return isMessage(val, messageType.fields.list());
|
|
61
|
+
}
|
|
60
62
|
default:
|
|
61
63
|
return valueKind;
|
|
62
64
|
}
|
|
@@ -102,9 +104,10 @@ export function isCompleteField(value, field) {
|
|
|
102
104
|
switch (fieldKind) {
|
|
103
105
|
case "scalar":
|
|
104
106
|
return true;
|
|
105
|
-
case "message":
|
|
107
|
+
case "message": {
|
|
106
108
|
const messageType = resolveMessageType(field.T);
|
|
107
109
|
return isCompleteMessage(value, messageType.fields.list());
|
|
110
|
+
}
|
|
108
111
|
case "enum":
|
|
109
112
|
return typeof value === "number";
|
|
110
113
|
case "map":
|
|
@@ -115,9 +118,10 @@ export function isCompleteField(value, field) {
|
|
|
115
118
|
return true;
|
|
116
119
|
case "enum":
|
|
117
120
|
return typeof val === "number";
|
|
118
|
-
case "message":
|
|
121
|
+
case "message": {
|
|
119
122
|
const messageType = resolveMessageType(field.V.T);
|
|
120
123
|
return isCompleteMessage(val, messageType.fields.list());
|
|
124
|
+
}
|
|
121
125
|
default:
|
|
122
126
|
return valueKind;
|
|
123
127
|
}
|
package/dist/json.js
CHANGED
|
@@ -5,6 +5,7 @@ import { unwrapField, wrapField } from "./field-wrapper.js";
|
|
|
5
5
|
import { enumZeroValue, normalizeEnumValue } from "./enum.js";
|
|
6
6
|
import { protoInt64 } from "./proto-int64.js";
|
|
7
7
|
import { protoBase64 } from "./proto-base64.js";
|
|
8
|
+
import { throwSanitizeKey } from "./names.js";
|
|
8
9
|
// Default options for parsing JSON.
|
|
9
10
|
const jsonReadDefaults = {
|
|
10
11
|
ignoreUnknownFields: false,
|
|
@@ -57,7 +58,7 @@ function readMessage(fields, typeName, json, options, message) {
|
|
|
57
58
|
readField(message, jsonValue, field, options);
|
|
58
59
|
}
|
|
59
60
|
else {
|
|
60
|
-
|
|
61
|
+
const found = false;
|
|
61
62
|
if (!found && !options.ignoreUnknownFields) {
|
|
62
63
|
throw new Error(`cannot decode message ${typeName} from JSON: key "${jsonKey}" is unknown`);
|
|
63
64
|
}
|
|
@@ -113,7 +114,7 @@ function readField(target, jsonValue, field, options) {
|
|
|
113
114
|
if (!Array.isArray(jsonValue)) {
|
|
114
115
|
throw new Error(`cannot decode field ${field.name} from JSON: ${jsonDebugValue(jsonValue)}`);
|
|
115
116
|
}
|
|
116
|
-
|
|
117
|
+
let targetArray = target[localName];
|
|
117
118
|
if (!Array.isArray(targetArray)) {
|
|
118
119
|
targetArray = target[localName] = [];
|
|
119
120
|
}
|
|
@@ -122,16 +123,18 @@ function readField(target, jsonValue, field, options) {
|
|
|
122
123
|
throw new Error(`cannot decode field ${field.name} from JSON: ${jsonDebugValue(jsonItem)}`);
|
|
123
124
|
}
|
|
124
125
|
switch (field.kind) {
|
|
125
|
-
case "message":
|
|
126
|
+
case "message": {
|
|
126
127
|
const messageType = resolveMessageType(field.T);
|
|
127
128
|
targetArray.push(unwrapField(messageType.fieldWrapper, messageType.fromJson(jsonItem, options)));
|
|
128
129
|
break;
|
|
129
|
-
|
|
130
|
+
}
|
|
131
|
+
case "enum": {
|
|
130
132
|
const enumValue = readEnum(field.T, jsonItem, options.ignoreUnknownFields, true);
|
|
131
133
|
if (enumValue !== tokenIgnoredUnknownEnum) {
|
|
132
134
|
targetArray.push(enumValue);
|
|
133
135
|
}
|
|
134
136
|
break;
|
|
137
|
+
}
|
|
135
138
|
case "scalar":
|
|
136
139
|
try {
|
|
137
140
|
targetArray.push(readScalar(field.T, jsonItem, field.L, true));
|
|
@@ -154,7 +157,7 @@ function readField(target, jsonValue, field, options) {
|
|
|
154
157
|
if (typeof jsonValue != "object" || Array.isArray(jsonValue)) {
|
|
155
158
|
throw new Error(`cannot decode field ${field.name} from JSON: ${jsonDebugValue(jsonValue)}`);
|
|
156
159
|
}
|
|
157
|
-
|
|
160
|
+
let targetMap = target[localName];
|
|
158
161
|
if (typeof targetMap !== "object") {
|
|
159
162
|
targetMap = target[localName] = Object.create(null);
|
|
160
163
|
}
|
|
@@ -173,17 +176,20 @@ function readField(target, jsonValue, field, options) {
|
|
|
173
176
|
}
|
|
174
177
|
throw new Error(m);
|
|
175
178
|
}
|
|
179
|
+
throwSanitizeKey(key);
|
|
176
180
|
switch (field.V.kind) {
|
|
177
|
-
case "message":
|
|
181
|
+
case "message": {
|
|
178
182
|
const messageType = resolveMessageType(field.V.T);
|
|
179
183
|
targetMap[key] = messageType.fromJson(jsonMapValue, options);
|
|
180
184
|
break;
|
|
181
|
-
|
|
185
|
+
}
|
|
186
|
+
case "enum": {
|
|
182
187
|
const enumValue = readEnum(field.V.T, jsonMapValue, options.ignoreUnknownFields, true);
|
|
183
188
|
if (enumValue !== tokenIgnoredUnknownEnum) {
|
|
184
189
|
targetMap[key] = enumValue;
|
|
185
190
|
}
|
|
186
191
|
break;
|
|
192
|
+
}
|
|
187
193
|
case "scalar":
|
|
188
194
|
try {
|
|
189
195
|
targetMap[key] = readScalar(field.V.T, jsonMapValue, LongType.BIGINT, true);
|
|
@@ -205,7 +211,7 @@ function readField(target, jsonValue, field, options) {
|
|
|
205
211
|
localName = "value";
|
|
206
212
|
}
|
|
207
213
|
switch (field.kind) {
|
|
208
|
-
case "message":
|
|
214
|
+
case "message": {
|
|
209
215
|
const messageType = resolveMessageType(field.T);
|
|
210
216
|
if (jsonValue === null &&
|
|
211
217
|
messageType.typeName != "google.protobuf.Value") {
|
|
@@ -213,7 +219,8 @@ function readField(target, jsonValue, field, options) {
|
|
|
213
219
|
}
|
|
214
220
|
target[localName] = unwrapField(messageType.fieldWrapper, messageType.fromJson(jsonValue, options));
|
|
215
221
|
break;
|
|
216
|
-
|
|
222
|
+
}
|
|
223
|
+
case "enum": {
|
|
217
224
|
const enumValue = readEnum(field.T, jsonValue, options.ignoreUnknownFields, false);
|
|
218
225
|
switch (enumValue) {
|
|
219
226
|
case tokenNull:
|
|
@@ -226,6 +233,7 @@ function readField(target, jsonValue, field, options) {
|
|
|
226
233
|
break;
|
|
227
234
|
}
|
|
228
235
|
break;
|
|
236
|
+
}
|
|
229
237
|
case "scalar":
|
|
230
238
|
try {
|
|
231
239
|
const scalarValue = readScalar(field.T, jsonValue, field.L, false);
|
|
@@ -265,7 +273,7 @@ function readEnum(type, json, ignoreUnknownFields, nullAsZeroValue) {
|
|
|
265
273
|
return json;
|
|
266
274
|
}
|
|
267
275
|
break;
|
|
268
|
-
case "string":
|
|
276
|
+
case "string": {
|
|
269
277
|
const value = type.findName(json);
|
|
270
278
|
if (value !== undefined) {
|
|
271
279
|
return value.no;
|
|
@@ -274,6 +282,7 @@ function readEnum(type, json, ignoreUnknownFields, nullAsZeroValue) {
|
|
|
274
282
|
return tokenIgnoredUnknownEnum;
|
|
275
283
|
}
|
|
276
284
|
break;
|
|
285
|
+
}
|
|
277
286
|
}
|
|
278
287
|
throw new Error(`cannot decode enum ${type.typeName} from JSON: ${jsonDebugValue(json)}`);
|
|
279
288
|
}
|
|
@@ -290,7 +299,7 @@ function readScalar(type, json, longType = LongType.BIGINT, nullAsZeroValue = tr
|
|
|
290
299
|
// float, double: JSON value will be a number or one of the special string values "NaN", "Infinity", and "-Infinity".
|
|
291
300
|
// Either numbers or strings are accepted. Exponent notation is also accepted.
|
|
292
301
|
case ScalarType.DOUBLE:
|
|
293
|
-
case ScalarType.FLOAT:
|
|
302
|
+
case ScalarType.FLOAT: {
|
|
294
303
|
if (json === "NaN")
|
|
295
304
|
return Number.NaN;
|
|
296
305
|
if (json === "Infinity")
|
|
@@ -320,12 +329,13 @@ function readScalar(type, json, longType = LongType.BIGINT, nullAsZeroValue = tr
|
|
|
320
329
|
if (type == ScalarType.FLOAT)
|
|
321
330
|
assertFloat32(float);
|
|
322
331
|
return float;
|
|
332
|
+
}
|
|
323
333
|
// int32, fixed32, uint32: JSON value will be a decimal number. Either numbers or strings are accepted.
|
|
324
334
|
case ScalarType.INT32:
|
|
325
335
|
case ScalarType.FIXED32:
|
|
326
336
|
case ScalarType.SFIXED32:
|
|
327
337
|
case ScalarType.SINT32:
|
|
328
|
-
case ScalarType.UINT32:
|
|
338
|
+
case ScalarType.UINT32: {
|
|
329
339
|
let int32;
|
|
330
340
|
if (typeof json == "number")
|
|
331
341
|
int32 = json;
|
|
@@ -340,22 +350,25 @@ function readScalar(type, json, longType = LongType.BIGINT, nullAsZeroValue = tr
|
|
|
340
350
|
else
|
|
341
351
|
assertInt32(int32);
|
|
342
352
|
return int32;
|
|
353
|
+
}
|
|
343
354
|
// int64, fixed64, uint64: JSON value will be a decimal string. Either numbers or strings are accepted.
|
|
344
355
|
case ScalarType.INT64:
|
|
345
356
|
case ScalarType.SFIXED64:
|
|
346
|
-
case ScalarType.SINT64:
|
|
357
|
+
case ScalarType.SINT64: {
|
|
347
358
|
if (typeof json != "number" && typeof json != "string")
|
|
348
359
|
break;
|
|
349
360
|
const long = protoInt64.parse(json);
|
|
350
361
|
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
|
|
351
362
|
return longType ? long.toString() : long;
|
|
363
|
+
}
|
|
352
364
|
case ScalarType.FIXED64:
|
|
353
|
-
case ScalarType.UINT64:
|
|
365
|
+
case ScalarType.UINT64: {
|
|
354
366
|
if (typeof json != "number" && typeof json != "string")
|
|
355
367
|
break;
|
|
356
368
|
const uLong = protoInt64.uParse(json);
|
|
357
369
|
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
|
|
358
370
|
return longType ? uLong.toString() : uLong;
|
|
371
|
+
}
|
|
359
372
|
// bool:
|
|
360
373
|
case ScalarType.BOOL:
|
|
361
374
|
if (typeof json !== "boolean")
|
|
@@ -398,7 +411,7 @@ function readMapKey(type, json) {
|
|
|
398
411
|
break;
|
|
399
412
|
}
|
|
400
413
|
}
|
|
401
|
-
return readScalar(type, json, LongType.BIGINT, true)
|
|
414
|
+
return readScalar(type, json, LongType.BIGINT, true)?.toString() ?? "";
|
|
402
415
|
}
|
|
403
416
|
/**
|
|
404
417
|
* Resets the field, so that isFieldSet() will return false.
|
|
@@ -468,13 +481,14 @@ function writeField(field, value, options) {
|
|
|
468
481
|
jsonObj[entryKey.toString()] = messageType.toJson(entryValue, options);
|
|
469
482
|
}
|
|
470
483
|
break;
|
|
471
|
-
case "enum":
|
|
484
|
+
case "enum": {
|
|
472
485
|
const enumType = field.V.T;
|
|
473
486
|
for (const [entryKey, entryValue] of entries) {
|
|
474
487
|
// JSON standard allows only (double quoted) string as property key
|
|
475
488
|
jsonObj[entryKey.toString()] = writeEnum(enumType, entryValue, options.enumAsInteger);
|
|
476
489
|
}
|
|
477
490
|
break;
|
|
491
|
+
}
|
|
478
492
|
}
|
|
479
493
|
return options.emitDefaultValues || entries.length > 0 ?
|
|
480
494
|
jsonObj
|
|
@@ -496,12 +510,13 @@ function writeField(field, value, options) {
|
|
|
496
510
|
jsonArr.push(writeEnum(field.T, valueArr[i], options.enumAsInteger));
|
|
497
511
|
}
|
|
498
512
|
break;
|
|
499
|
-
case "message":
|
|
513
|
+
case "message": {
|
|
500
514
|
const messageType = resolveMessageType(field.T);
|
|
501
515
|
for (let i = 0; i < valueArr.length; i++) {
|
|
502
516
|
jsonArr.push(messageType.toJson(wrapField(messageType.fieldWrapper, valueArr[i])));
|
|
503
517
|
}
|
|
504
518
|
break;
|
|
519
|
+
}
|
|
505
520
|
}
|
|
506
521
|
}
|
|
507
522
|
return options.emitDefaultValues || jsonArr.length > 0 ?
|
|
@@ -509,25 +524,28 @@ function writeField(field, value, options) {
|
|
|
509
524
|
: undefined;
|
|
510
525
|
}
|
|
511
526
|
switch (field.kind) {
|
|
512
|
-
case "scalar":
|
|
527
|
+
case "scalar": {
|
|
513
528
|
const scalarValue = normalizeScalarValue(field.T, value, false);
|
|
514
|
-
if (!options.emitDefaultValues
|
|
515
|
-
|
|
529
|
+
if (!options.emitDefaultValues &&
|
|
530
|
+
isScalarZeroValue(field.T, scalarValue)) {
|
|
516
531
|
return undefined;
|
|
517
532
|
}
|
|
518
533
|
return writeScalar(field.T, value);
|
|
519
|
-
|
|
534
|
+
}
|
|
535
|
+
case "enum": {
|
|
520
536
|
const enumValue = normalizeEnumValue(field.T, value);
|
|
521
537
|
if (!options.emitDefaultValues && enumZeroValue(field.T) === enumValue) {
|
|
522
538
|
return undefined;
|
|
523
539
|
}
|
|
524
540
|
return writeEnum(field.T, value, options.enumAsInteger);
|
|
525
|
-
|
|
541
|
+
}
|
|
542
|
+
case "message": {
|
|
526
543
|
if (!options.emitDefaultValues && value == null) {
|
|
527
544
|
return undefined;
|
|
528
545
|
}
|
|
529
546
|
const messageType = resolveMessageType(field.T);
|
|
530
547
|
return messageType.toJson(wrapField(messageType.fieldWrapper, value));
|
|
548
|
+
}
|
|
531
549
|
}
|
|
532
550
|
}
|
|
533
551
|
function writeScalar(type, value) {
|
|
@@ -576,6 +594,10 @@ function writeScalar(type, value) {
|
|
|
576
594
|
case ScalarType.BYTES:
|
|
577
595
|
assert(value instanceof Uint8Array);
|
|
578
596
|
return protoBase64.enc(value);
|
|
597
|
+
case ScalarType.DATE:
|
|
598
|
+
throw new Error("cannot write date with writeScalar");
|
|
599
|
+
default:
|
|
600
|
+
throw new Error("unknown scalar type");
|
|
579
601
|
}
|
|
580
602
|
}
|
|
581
603
|
function writeEnum(type, value, enumAsInteger) {
|
package/dist/message.d.ts
CHANGED
|
@@ -109,7 +109,7 @@ export type MessageTypeParams<T extends Message<T>> = Pick<MessageType<T>, "fiel
|
|
|
109
109
|
* The argument `packedByDefault` specifies whether fields that do not specify
|
|
110
110
|
* `packed` should be packed (proto3) or unpacked (proto2).
|
|
111
111
|
*/
|
|
112
|
-
export declare function createMessageType<T extends Message<T>, E extends
|
|
112
|
+
export declare function createMessageType<T extends Message<T>, E extends Partial<MessageType<T>> = Partial<MessageType<T>>>(params: MessageTypeParams<T>, exts?: E): MessageType<T> & E;
|
|
113
113
|
export declare function compareMessages<T extends Message<T>>(fields: FieldList, a: T | undefined | null, b: T | undefined | null): boolean;
|
|
114
114
|
export declare function cloneMessage<T extends Message<T>>(message: T | null | undefined, fields: FieldList): T | null;
|
|
115
115
|
/**
|
package/dist/message.js
CHANGED
|
@@ -119,9 +119,10 @@ export function compareMessages(fields, a, b) {
|
|
|
119
119
|
}
|
|
120
120
|
// eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check -- repeated fields are never "map"
|
|
121
121
|
switch (m.kind) {
|
|
122
|
-
case "message":
|
|
122
|
+
case "message": {
|
|
123
123
|
const messageType = resolveMessageType(m.T);
|
|
124
124
|
return va.every((a, i) => messageType.equals(a, vb[i]));
|
|
125
|
+
}
|
|
125
126
|
case "scalar":
|
|
126
127
|
return va.every((a, i) => scalarEquals(m.T, a, vb[i]));
|
|
127
128
|
case "enum":
|
|
@@ -136,7 +137,7 @@ export function compareMessages(fields, a, b) {
|
|
|
136
137
|
return scalarEquals(ScalarType.INT32, va, vb);
|
|
137
138
|
case "scalar":
|
|
138
139
|
return scalarEquals(m.T, va, vb);
|
|
139
|
-
case "oneof":
|
|
140
|
+
case "oneof": {
|
|
140
141
|
if (va?.case !== vb?.case) {
|
|
141
142
|
return false;
|
|
142
143
|
}
|
|
@@ -149,27 +150,32 @@ export function compareMessages(fields, a, b) {
|
|
|
149
150
|
}
|
|
150
151
|
// eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check -- oneof fields are never "map"
|
|
151
152
|
switch (s.kind) {
|
|
152
|
-
case "message":
|
|
153
|
+
case "message": {
|
|
153
154
|
const messageType = resolveMessageType(s.T);
|
|
154
155
|
return messageType.equals(va.value, vb.value);
|
|
156
|
+
}
|
|
155
157
|
case "enum":
|
|
156
158
|
return scalarEquals(ScalarType.INT32, va.value, vb.value);
|
|
157
159
|
case "scalar":
|
|
158
160
|
return scalarEquals(s.T, va.value, vb.value);
|
|
159
161
|
}
|
|
160
162
|
throw new Error(`oneof cannot contain ${s.kind}`);
|
|
161
|
-
|
|
163
|
+
}
|
|
164
|
+
case "map": {
|
|
162
165
|
const keys = Object.keys(va).concat(Object.keys(vb));
|
|
163
166
|
switch (m.V.kind) {
|
|
164
|
-
case "message":
|
|
167
|
+
case "message": {
|
|
165
168
|
const messageType = resolveMessageType(m.V.T);
|
|
166
169
|
return keys.every((k) => messageType.equals(va[k], vb[k]));
|
|
170
|
+
}
|
|
167
171
|
case "enum":
|
|
168
172
|
return keys.every((k) => scalarEquals(ScalarType.INT32, va[k], vb[k]));
|
|
169
|
-
case "scalar":
|
|
173
|
+
case "scalar": {
|
|
170
174
|
const scalarType = m.V.T;
|
|
171
175
|
return keys.every((k) => scalarEquals(scalarType, va[k], vb[k]));
|
|
176
|
+
}
|
|
172
177
|
}
|
|
178
|
+
}
|
|
173
179
|
}
|
|
174
180
|
});
|
|
175
181
|
}
|
|
@@ -205,7 +211,7 @@ export function createCompleteMessage(fields) {
|
|
|
205
211
|
case "enum":
|
|
206
212
|
message[localName] = field.repeated ? [] : enumZeroValue(field.T);
|
|
207
213
|
break;
|
|
208
|
-
case "message":
|
|
214
|
+
case "message": {
|
|
209
215
|
// oneofs are handled above
|
|
210
216
|
if (field.oneof) {
|
|
211
217
|
break;
|
|
@@ -216,10 +222,11 @@ export function createCompleteMessage(fields) {
|
|
|
216
222
|
}
|
|
217
223
|
const messageType = resolveMessageType(field.T);
|
|
218
224
|
message[localName] =
|
|
219
|
-
|
|
225
|
+
messageType.fieldWrapper ?
|
|
220
226
|
messageType.fieldWrapper.unwrapField(null)
|
|
221
227
|
: createCompleteMessage(messageType.fields);
|
|
222
228
|
break;
|
|
229
|
+
}
|
|
223
230
|
case "map":
|
|
224
231
|
message[localName] = Object.create(null);
|
|
225
232
|
break;
|
package/dist/names.js
CHANGED
|
@@ -209,6 +209,8 @@ const reservedObjectProperties = new Set([
|
|
|
209
209
|
"toString",
|
|
210
210
|
"toJSON",
|
|
211
211
|
"valueOf",
|
|
212
|
+
"__proto__",
|
|
213
|
+
"prototype",
|
|
212
214
|
]);
|
|
213
215
|
/**
|
|
214
216
|
* Names that cannot be used for object properties because they are reserved
|
|
@@ -246,7 +248,9 @@ export const safeIdentifier = (name) => {
|
|
|
246
248
|
return name;
|
|
247
249
|
};
|
|
248
250
|
export function checkSanitizeKey(key) {
|
|
249
|
-
return typeof key === "string" &&
|
|
251
|
+
return (typeof key === "string" &&
|
|
252
|
+
!!key.length &&
|
|
253
|
+
!reservedObjectProperties.has(key));
|
|
250
254
|
}
|
|
251
255
|
export function throwSanitizeKey(key) {
|
|
252
256
|
if (typeof key !== "string") {
|
package/dist/partial.js
CHANGED
|
@@ -23,7 +23,7 @@ export function applyPartialMessage(source, target, fields, clone = false) {
|
|
|
23
23
|
continue;
|
|
24
24
|
}
|
|
25
25
|
switch (member.kind) {
|
|
26
|
-
case "oneof":
|
|
26
|
+
case "oneof": {
|
|
27
27
|
if (typeof sourceValue !== "object") {
|
|
28
28
|
throw new Error(`field ${localName}: invalid oneof: must be an object with case and value`);
|
|
29
29
|
}
|
|
@@ -70,7 +70,8 @@ export function applyPartialMessage(source, target, fields, clone = false) {
|
|
|
70
70
|
dv.value = sv;
|
|
71
71
|
}
|
|
72
72
|
break;
|
|
73
|
-
|
|
73
|
+
}
|
|
74
|
+
case "scalar": {
|
|
74
75
|
if (member.repeated) {
|
|
75
76
|
if (!Array.isArray(sourceValue)) {
|
|
76
77
|
throw new Error(`field ${localName}: invalid value: must be array`);
|
|
@@ -84,10 +85,12 @@ export function applyPartialMessage(source, target, fields, clone = false) {
|
|
|
84
85
|
}
|
|
85
86
|
t[localName] = normalizeScalarValue(member.T, sourceValue, clone);
|
|
86
87
|
break;
|
|
87
|
-
|
|
88
|
+
}
|
|
89
|
+
case "enum": {
|
|
88
90
|
t[localName] = normalizeEnumValue(member.T, sourceValue);
|
|
89
91
|
break;
|
|
90
|
-
|
|
92
|
+
}
|
|
93
|
+
case "map": {
|
|
91
94
|
if (typeof sourceValue !== "object") {
|
|
92
95
|
throw new Error(`field ${member.localName}: invalid value: must be object`);
|
|
93
96
|
}
|
|
@@ -97,7 +100,8 @@ export function applyPartialMessage(source, target, fields, clone = false) {
|
|
|
97
100
|
}
|
|
98
101
|
applyPartialMap(sourceValue, tMap, member.V, clone);
|
|
99
102
|
break;
|
|
100
|
-
|
|
103
|
+
}
|
|
104
|
+
case "message": {
|
|
101
105
|
const mt = resolveMessageType(member.T);
|
|
102
106
|
if (member.repeated) {
|
|
103
107
|
// skip null or undefined values
|
|
@@ -135,6 +139,7 @@ export function applyPartialMessage(source, target, fields, clone = false) {
|
|
|
135
139
|
applyPartialMessage(sourceValue, destMsg, mt.fields);
|
|
136
140
|
}
|
|
137
141
|
break;
|
|
142
|
+
}
|
|
138
143
|
}
|
|
139
144
|
}
|
|
140
145
|
}
|
|
@@ -169,7 +174,7 @@ export function applyPartialMap(sourceMap, targetMap, value, clone) {
|
|
|
169
174
|
}
|
|
170
175
|
}
|
|
171
176
|
break;
|
|
172
|
-
case "message":
|
|
177
|
+
case "message": {
|
|
173
178
|
const messageType = resolveMessageType(value.T);
|
|
174
179
|
for (const [k, v] of Object.entries(sourceMap)) {
|
|
175
180
|
throwSanitizeKey(k);
|
|
@@ -181,7 +186,7 @@ export function applyPartialMap(sourceMap, targetMap, value, clone) {
|
|
|
181
186
|
throw new Error(`invalid value: must be object`);
|
|
182
187
|
}
|
|
183
188
|
let val = targetMap[k];
|
|
184
|
-
if (
|
|
189
|
+
if (messageType.fieldWrapper) {
|
|
185
190
|
// For wrapper type messages, call createCompleteMessage.
|
|
186
191
|
val = targetMap[k] = createCompleteMessage(messageType.fields);
|
|
187
192
|
}
|
|
@@ -192,5 +197,6 @@ export function applyPartialMap(sourceMap, targetMap, value, clone) {
|
|
|
192
197
|
applyPartialMessage(v, val, messageType.fields);
|
|
193
198
|
}
|
|
194
199
|
break;
|
|
200
|
+
}
|
|
195
201
|
}
|
|
196
202
|
}
|
|
@@ -28,32 +28,8 @@ export function generateTs(schema) {
|
|
|
28
28
|
}
|
|
29
29
|
const messageTypes = [];
|
|
30
30
|
const dependencies = new Map();
|
|
31
|
-
function collectMessages(message) {
|
|
32
|
-
if (message.file !== file) {
|
|
33
|
-
return;
|
|
34
|
-
}
|
|
35
|
-
for (const nestedEnum of message.nestedEnums) {
|
|
36
|
-
generateEnum(schema, f, nestedEnum);
|
|
37
|
-
}
|
|
38
|
-
messageTypes.push(message);
|
|
39
|
-
const deps = new Set();
|
|
40
|
-
for (const field of message.fields) {
|
|
41
|
-
if (field.fieldKind === "message" && field.message.file === file) {
|
|
42
|
-
deps.add(field.message);
|
|
43
|
-
}
|
|
44
|
-
else if (field.fieldKind === "map" &&
|
|
45
|
-
field.mapValue.kind === "message" &&
|
|
46
|
-
field.mapValue.message.file === file) {
|
|
47
|
-
deps.add(field.mapValue.message);
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
dependencies.set(message, deps);
|
|
51
|
-
for (const nestedMessage of message.nestedMessages) {
|
|
52
|
-
collectMessages(nestedMessage);
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
31
|
for (const message of file.messages) {
|
|
56
|
-
collectMessages(message);
|
|
32
|
+
collectMessages(schema, file, message, messageTypes, dependencies, f);
|
|
57
33
|
}
|
|
58
34
|
// Topological sort to ensure consts are declared in the right order.
|
|
59
35
|
const sortedMessageTypes = topologicalSort(messageTypes, dependencies);
|
|
@@ -63,6 +39,31 @@ export function generateTs(schema) {
|
|
|
63
39
|
// We do not generate anything for services or extensions
|
|
64
40
|
}
|
|
65
41
|
}
|
|
42
|
+
// collectMessages collects a list of all message types and their dependencies.
|
|
43
|
+
function collectMessages(schema, file, message, messageTypes, dependencies, f) {
|
|
44
|
+
if (message.file !== file) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
for (const nestedEnum of message.nestedEnums) {
|
|
48
|
+
generateEnum(schema, f, nestedEnum);
|
|
49
|
+
}
|
|
50
|
+
messageTypes.push(message);
|
|
51
|
+
const deps = new Set();
|
|
52
|
+
for (const field of message.fields) {
|
|
53
|
+
if (field.fieldKind === "message" && field.message.file === file) {
|
|
54
|
+
deps.add(field.message);
|
|
55
|
+
}
|
|
56
|
+
else if (field.fieldKind === "map" &&
|
|
57
|
+
field.mapValue.kind === "message" &&
|
|
58
|
+
field.mapValue.message.file === file) {
|
|
59
|
+
deps.add(field.mapValue.message);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
dependencies.set(message, deps);
|
|
63
|
+
for (const nestedMessage of message.nestedMessages) {
|
|
64
|
+
collectMessages(schema, file, nestedMessage, messageTypes, dependencies, f);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
66
67
|
// topologicalSort sorts the list of messages by dependency order.
|
|
67
68
|
function topologicalSort(messages, dependencies) {
|
|
68
69
|
const result = [];
|
|
@@ -162,7 +163,7 @@ function generateField(f, field) {
|
|
|
162
163
|
function generateOneof(f, oneof) {
|
|
163
164
|
f.print();
|
|
164
165
|
f.print(f.jsDoc(oneof, " "));
|
|
165
|
-
|
|
166
|
+
const oneOfCases = oneof.fields
|
|
166
167
|
.map((field) => {
|
|
167
168
|
const { typing } = getFieldTypeInfo(field);
|
|
168
169
|
const doc = f.jsDoc(field, " ");
|
|
@@ -186,7 +187,7 @@ export function generateFieldInfo(f, schema, field) {
|
|
|
186
187
|
f.print(" ", getFieldInfoLiteral(schema, field), ",");
|
|
187
188
|
}
|
|
188
189
|
export const createTypeImport = (desc) => {
|
|
189
|
-
|
|
190
|
+
let name = localName(desc);
|
|
190
191
|
if (desc.kind === "enum") {
|
|
191
192
|
name += "_Enum";
|
|
192
193
|
}
|
|
@@ -395,6 +396,17 @@ function generateWktMethods(schema, f, message, ref) {
|
|
|
395
396
|
f.print(" const nanos = (ms % 1000) * 1000000;");
|
|
396
397
|
f.print(" return { ", localName(ref.seconds), ": ", protoInt64, ".parse(seconds), ", localName(ref.nanos), ": nanos };");
|
|
397
398
|
f.print(" },");
|
|
399
|
+
f.print(" equals(a: ", message, " | Date | undefined | null, b: ", message, " | Date | undefined | null): boolean {");
|
|
400
|
+
f.print(" const aDate = a instanceof Date ? a : ", message, "_Wkt.toDate(a);");
|
|
401
|
+
f.print(" const bDate = b instanceof Date ? b : ", message, "_Wkt.toDate(b);");
|
|
402
|
+
f.print(" if (aDate === bDate) {");
|
|
403
|
+
f.print(" return true;");
|
|
404
|
+
f.print(" }");
|
|
405
|
+
f.print(" if (aDate == null || bDate == null) {");
|
|
406
|
+
f.print(" return aDate === bDate;");
|
|
407
|
+
f.print(" }");
|
|
408
|
+
f.print(" return +aDate === +bDate;");
|
|
409
|
+
f.print(" },");
|
|
398
410
|
break;
|
|
399
411
|
case "google.protobuf.Duration":
|
|
400
412
|
f.print(" fromJson(json: ", JsonValue, " | null | undefined, _options?: Partial<", JsonReadOptions, ">): ", message, " {");
|
|
@@ -560,30 +572,18 @@ function generateWktMethods(schema, f, message, ref) {
|
|
|
560
572
|
}
|
|
561
573
|
function generateWktFieldWrapper(f, message, ref) {
|
|
562
574
|
switch (ref?.typeName) {
|
|
563
|
-
/* TODO Wrap Timestamp => Date
|
|
564
575
|
case "google.protobuf.Timestamp": {
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
"
|
|
568
|
-
message,
|
|
569
|
-
"
|
|
570
|
-
message,
|
|
571
|
-
"
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
message,
|
|
576
|
-
"_Wkt.fromDate(value); }",
|
|
577
|
-
);
|
|
578
|
-
f.print(" return ", message, ".createComplete(value);");
|
|
579
|
-
f.print(" },");
|
|
580
|
-
f.print(" unwrapField(msg: ", message, "): Date | null {");
|
|
581
|
-
f.print(" return ", message, "_Wkt.toDate(msg);");
|
|
582
|
-
f.print(" }");
|
|
583
|
-
f.print(" } as const,");
|
|
584
|
-
break;
|
|
576
|
+
f.print(" fieldWrapper: {");
|
|
577
|
+
f.print(" wrapField(value: ", message, " | Date | null | undefined): ", message, " {");
|
|
578
|
+
f.print(" if (value == null || value instanceof Date) { return ", message, "_Wkt.fromDate(value); }");
|
|
579
|
+
f.print(" return ", message, ".createComplete(value);");
|
|
580
|
+
f.print(" },");
|
|
581
|
+
f.print(" unwrapField(msg: ", message, "): Date | null {");
|
|
582
|
+
f.print(" return ", message, "_Wkt.toDate(msg);");
|
|
583
|
+
f.print(" }");
|
|
584
|
+
f.print(" } as const,");
|
|
585
|
+
break;
|
|
585
586
|
}
|
|
586
|
-
*/
|
|
587
587
|
case "google.protobuf.DoubleValue":
|
|
588
588
|
case "google.protobuf.FloatValue":
|
|
589
589
|
case "google.protobuf.Int64Value":
|
|
@@ -13,7 +13,6 @@
|
|
|
13
13
|
// limitations under the License.
|
|
14
14
|
import ts from "typescript";
|
|
15
15
|
import { createDefaultMapFromNodeModules, createSystem, createVirtualCompilerHost, } from "@typescript/vfs";
|
|
16
|
-
/* eslint-disable import/no-named-as-default-member */
|
|
17
16
|
// The default options used to auto-transpile if needed.
|
|
18
17
|
const defaultOptions = {
|
|
19
18
|
// Type checking
|
package/dist/scalar.d.ts
CHANGED
|
@@ -18,7 +18,8 @@ export declare enum ScalarType {
|
|
|
18
18
|
SFIXED32 = 15,
|
|
19
19
|
SFIXED64 = 16,
|
|
20
20
|
SINT32 = 17,// Uses ZigZag encoding.
|
|
21
|
-
SINT64 = 18
|
|
21
|
+
SINT64 = 18,// Uses ZigZag encoding.
|
|
22
|
+
DATE = 100
|
|
22
23
|
}
|
|
23
24
|
/**
|
|
24
25
|
* JavaScript representation of fields with 64 bit integral types (int64, uint64,
|
|
@@ -50,11 +51,11 @@ export declare enum LongType {
|
|
|
50
51
|
/**
|
|
51
52
|
* ScalarValue maps from a scalar field type to a TypeScript value type.
|
|
52
53
|
*/
|
|
53
|
-
export type ScalarValue<T = ScalarType, L extends LongType = LongType.STRING | LongType.BIGINT> = T extends ScalarType.STRING ? string : T extends ScalarType.INT32 ? number : T extends ScalarType.UINT32 ? number : T extends ScalarType.UINT32 ? number : T extends ScalarType.SINT32 ? number : T extends ScalarType.FIXED32 ? number : T extends ScalarType.SFIXED32 ? number : T extends ScalarType.FLOAT ? number : T extends ScalarType.DOUBLE ? number : T extends ScalarType.INT64 ? (L extends LongType.STRING ? string : bigint) : T extends ScalarType.SINT64 ? (L extends LongType.STRING ? string : bigint) : T extends ScalarType.SFIXED64 ? (L extends LongType.STRING ? string : bigint) : T extends ScalarType.UINT64 ? (L extends LongType.STRING ? string : bigint) : T extends ScalarType.FIXED64 ? (L extends LongType.STRING ? string : bigint) : T extends ScalarType.BOOL ? boolean : T extends ScalarType.BYTES ? Uint8Array : never;
|
|
54
|
+
export type ScalarValue<T = ScalarType, L extends LongType = LongType.STRING | LongType.BIGINT> = T extends ScalarType.STRING ? string : T extends ScalarType.INT32 ? number : T extends ScalarType.UINT32 ? number : T extends ScalarType.UINT32 ? number : T extends ScalarType.SINT32 ? number : T extends ScalarType.FIXED32 ? number : T extends ScalarType.SFIXED32 ? number : T extends ScalarType.FLOAT ? number : T extends ScalarType.DOUBLE ? number : T extends ScalarType.INT64 ? (L extends LongType.STRING ? string : bigint) : T extends ScalarType.SINT64 ? (L extends LongType.STRING ? string : bigint) : T extends ScalarType.SFIXED64 ? (L extends LongType.STRING ? string : bigint) : T extends ScalarType.UINT64 ? (L extends LongType.STRING ? string : bigint) : T extends ScalarType.FIXED64 ? (L extends LongType.STRING ? string : bigint) : T extends ScalarType.BOOL ? boolean : T extends ScalarType.BYTES ? Uint8Array : T extends ScalarType.DATE ? null : never;
|
|
54
55
|
/**
|
|
55
56
|
* Returns true if both scalar values are equal.
|
|
56
57
|
*/
|
|
57
|
-
export declare function scalarEquals(type: ScalarType, a: string | boolean | number | bigint | Uint8Array | undefined, b: string | boolean | number | bigint | Uint8Array | undefined): boolean;
|
|
58
|
+
export declare function scalarEquals(type: ScalarType, a: string | boolean | number | bigint | Uint8Array | Date | null | undefined, b: string | boolean | number | bigint | Uint8Array | Date | null | undefined): boolean;
|
|
58
59
|
/**
|
|
59
60
|
* Returns the zero value for the given scalar type.
|
|
60
61
|
*/
|
package/dist/scalar.js
CHANGED
|
@@ -48,6 +48,8 @@ export var ScalarType;
|
|
|
48
48
|
ScalarType[ScalarType["SFIXED64"] = 16] = "SFIXED64";
|
|
49
49
|
ScalarType[ScalarType["SINT32"] = 17] = "SINT32";
|
|
50
50
|
ScalarType[ScalarType["SINT64"] = 18] = "SINT64";
|
|
51
|
+
// DATE is not a Protobuf scalar type but used internally for the Timestamp wkt.
|
|
52
|
+
ScalarType[ScalarType["DATE"] = 100] = "DATE";
|
|
51
53
|
})(ScalarType || (ScalarType = {}));
|
|
52
54
|
/**
|
|
53
55
|
* JavaScript representation of fields with 64 bit integral types (int64, uint64,
|
|
@@ -85,6 +87,10 @@ export function scalarEquals(type, a, b) {
|
|
|
85
87
|
// This correctly matches equal values except BYTES and (possibly) 64-bit integers.
|
|
86
88
|
return true;
|
|
87
89
|
}
|
|
90
|
+
// Special case null/undefined - only equal if both are null/undefined
|
|
91
|
+
if (a == null || b == null) {
|
|
92
|
+
return a === b;
|
|
93
|
+
}
|
|
88
94
|
// Special case BYTES - we need to compare each byte individually
|
|
89
95
|
if (type == ScalarType.BYTES) {
|
|
90
96
|
if (!(a instanceof Uint8Array) || !(b instanceof Uint8Array)) {
|
|
@@ -100,6 +106,15 @@ export function scalarEquals(type, a, b) {
|
|
|
100
106
|
}
|
|
101
107
|
return true;
|
|
102
108
|
}
|
|
109
|
+
// Special case DATE - we need to compare the numeric value
|
|
110
|
+
if (type == ScalarType.DATE) {
|
|
111
|
+
const dateA = toDate(a, false);
|
|
112
|
+
const dateB = toDate(b, false);
|
|
113
|
+
if (dateA == null || dateB == null) {
|
|
114
|
+
return dateA === dateB;
|
|
115
|
+
}
|
|
116
|
+
return dateA != null && dateB != null && +dateA === +dateB;
|
|
117
|
+
}
|
|
103
118
|
// Special case 64-bit integers - we support number, string and bigint representation.
|
|
104
119
|
// eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check
|
|
105
120
|
switch (type) {
|
|
@@ -136,12 +151,15 @@ export function scalarZeroValue(type, longType) {
|
|
|
136
151
|
return new Uint8Array(0);
|
|
137
152
|
case ScalarType.STRING:
|
|
138
153
|
return "";
|
|
154
|
+
case ScalarType.DATE:
|
|
155
|
+
return null;
|
|
139
156
|
default:
|
|
140
157
|
// Handles INT32, UINT32, SINT32, FIXED32, SFIXED32.
|
|
141
158
|
// We do not use individual cases to save a few bytes code size.
|
|
142
159
|
return 0;
|
|
143
160
|
}
|
|
144
161
|
}
|
|
162
|
+
const dateZeroValue = +new Date(0);
|
|
145
163
|
/**
|
|
146
164
|
* Returns true for a zero-value. For example, an integer has the zero-value `0`,
|
|
147
165
|
* a boolean is `false`, a string is `""`, and bytes is an empty Uint8Array.
|
|
@@ -151,6 +169,8 @@ export function scalarZeroValue(type, longType) {
|
|
|
151
169
|
*/
|
|
152
170
|
export function isScalarZeroValue(type, value) {
|
|
153
171
|
switch (type) {
|
|
172
|
+
case ScalarType.DATE:
|
|
173
|
+
return value == null || +value === dateZeroValue;
|
|
154
174
|
case ScalarType.BOOL:
|
|
155
175
|
return value === false;
|
|
156
176
|
case ScalarType.STRING:
|
|
@@ -178,6 +198,9 @@ export function normalizeScalarValue(type, value, clone, longType = LongType.BIG
|
|
|
178
198
|
if (isScalarZeroValue(type, value)) {
|
|
179
199
|
return scalarZeroValue(type, longType);
|
|
180
200
|
}
|
|
201
|
+
if (type === ScalarType.DATE) {
|
|
202
|
+
return toDate(value, clone);
|
|
203
|
+
}
|
|
181
204
|
return value;
|
|
182
205
|
}
|
|
183
206
|
// converts any ArrayLike<number> to Uint8Array if necessary.
|
|
@@ -185,3 +208,13 @@ export function normalizeScalarValue(type, value, clone, longType = LongType.BIG
|
|
|
185
208
|
export function toU8Arr(input, clone) {
|
|
186
209
|
return !clone && input instanceof Uint8Array ? input : new Uint8Array(input);
|
|
187
210
|
}
|
|
211
|
+
function toDate(input, clone) {
|
|
212
|
+
if (input instanceof Date) {
|
|
213
|
+
return clone ? new Date(input.getTime()) : input;
|
|
214
|
+
}
|
|
215
|
+
if (typeof input === "string" || typeof input === "number") {
|
|
216
|
+
const date = new Date(input);
|
|
217
|
+
return isNaN(date.getTime()) ? null : date;
|
|
218
|
+
}
|
|
219
|
+
return null;
|
|
220
|
+
}
|
package/dist/text-format.js
CHANGED
|
@@ -57,6 +57,11 @@ export function parseTextFormatScalarValue(type, value) {
|
|
|
57
57
|
case ScalarType.FIXED32:
|
|
58
58
|
case ScalarType.SFIXED32:
|
|
59
59
|
return parseInt(value, 10);
|
|
60
|
+
case ScalarType.DATE:
|
|
61
|
+
// TODO
|
|
62
|
+
throw new Error("unimplemented: parse Date from text format");
|
|
63
|
+
default:
|
|
64
|
+
throw new Error(`cannot parse ${ScalarType[type]}`);
|
|
60
65
|
}
|
|
61
66
|
}
|
|
62
67
|
/**
|
package/dist/util.js
CHANGED
|
@@ -29,17 +29,7 @@ export function getFieldTypeInfo(field) {
|
|
|
29
29
|
typingInferrableFromZeroValue = true;
|
|
30
30
|
break;
|
|
31
31
|
case "message": {
|
|
32
|
-
|
|
33
|
-
if (baseType !== undefined) {
|
|
34
|
-
typing.push(scalarTypeScriptType(baseType, LongType.BIGINT));
|
|
35
|
-
}
|
|
36
|
-
else {
|
|
37
|
-
typing.push({
|
|
38
|
-
kind: "es_ref_message",
|
|
39
|
-
type: field.message,
|
|
40
|
-
typeOnly: true,
|
|
41
|
-
});
|
|
42
|
-
}
|
|
32
|
+
typing.push(getUnwrappedFieldScriptType(field));
|
|
43
33
|
optional = true;
|
|
44
34
|
typingInferrableFromZeroValue = true;
|
|
45
35
|
break;
|
|
@@ -75,11 +65,7 @@ export function getFieldTypeInfo(field) {
|
|
|
75
65
|
valueType = scalarTypeScriptType(field.mapValue.scalar, LongType.BIGINT);
|
|
76
66
|
break;
|
|
77
67
|
case "message":
|
|
78
|
-
valueType =
|
|
79
|
-
kind: "es_ref_message",
|
|
80
|
-
type: field.mapValue.message,
|
|
81
|
-
typeOnly: true,
|
|
82
|
-
};
|
|
68
|
+
valueType = getUnwrappedMessageScriptType(field.mapValue.message);
|
|
83
69
|
break;
|
|
84
70
|
case "enum":
|
|
85
71
|
valueType = {
|
|
@@ -127,6 +113,8 @@ export function getFieldDefaultValueExpression(field, enumAs = "enum_value_as_is
|
|
|
127
113
|
}
|
|
128
114
|
case "scalar":
|
|
129
115
|
return literalScalarValue(defaultValue, field);
|
|
116
|
+
default:
|
|
117
|
+
return undefined;
|
|
130
118
|
}
|
|
131
119
|
}
|
|
132
120
|
/**
|
|
@@ -205,6 +193,13 @@ function literalScalarValue(value, field) {
|
|
|
205
193
|
longType: field.longType,
|
|
206
194
|
value,
|
|
207
195
|
};
|
|
196
|
+
case ScalarType.DATE:
|
|
197
|
+
if (value == null) {
|
|
198
|
+
return `null`;
|
|
199
|
+
}
|
|
200
|
+
return `new Date(${(value instanceof Date ? +value : value).toString()})`;
|
|
201
|
+
default:
|
|
202
|
+
throw new Error("unsupported scalar type for literalScalarValue");
|
|
208
203
|
}
|
|
209
204
|
}
|
|
210
205
|
function literalEnumValue(value, enumAs) {
|
|
@@ -251,7 +246,29 @@ function scalarTypeScriptType(type, longType) {
|
|
|
251
246
|
return "bigint";
|
|
252
247
|
case ScalarType.BYTES:
|
|
253
248
|
return "Uint8Array";
|
|
249
|
+
case ScalarType.DATE:
|
|
250
|
+
return "Date";
|
|
254
251
|
default:
|
|
255
252
|
return "number";
|
|
256
253
|
}
|
|
257
254
|
}
|
|
255
|
+
function getUnwrappedFieldScriptType(field, longType) {
|
|
256
|
+
const baseType = codegenInfo.getUnwrappedFieldType(field);
|
|
257
|
+
return baseType ?
|
|
258
|
+
scalarTypeScriptType(baseType, longType ?? field.longType ?? LongType.BIGINT)
|
|
259
|
+
: {
|
|
260
|
+
kind: "es_ref_message",
|
|
261
|
+
type: field.message,
|
|
262
|
+
typeOnly: true,
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
function getUnwrappedMessageScriptType(msg, longType = LongType.BIGINT) {
|
|
266
|
+
const baseType = codegenInfo.getUnwrappedMessageType(msg);
|
|
267
|
+
return baseType !== undefined ?
|
|
268
|
+
scalarTypeScriptType(baseType, longType)
|
|
269
|
+
: {
|
|
270
|
+
kind: "es_ref_message",
|
|
271
|
+
type: msg,
|
|
272
|
+
typeOnly: true,
|
|
273
|
+
};
|
|
274
|
+
}
|
package/example/example.pb.ts
CHANGED
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
// @generated from file example/example.proto (package example, syntax proto3)
|
|
3
3
|
/* eslint-disable */
|
|
4
4
|
|
|
5
|
-
import type { MessageType, PartialFieldInfo } from "
|
|
5
|
+
import type { MessageType, PartialFieldInfo } from "../src/index.js";
|
|
6
6
|
import {
|
|
7
7
|
createEnumType,
|
|
8
8
|
createMessageType,
|
|
9
9
|
Message,
|
|
10
10
|
ScalarType,
|
|
11
11
|
Timestamp,
|
|
12
|
-
} from "
|
|
12
|
+
} from "../src/index.js";
|
|
13
13
|
|
|
14
14
|
export const protobufPackage = "example";
|
|
15
15
|
|
|
@@ -55,11 +55,11 @@ export type EchoMsg = Message<{
|
|
|
55
55
|
/**
|
|
56
56
|
* @generated from field: google.protobuf.Timestamp ts = 2;
|
|
57
57
|
*/
|
|
58
|
-
ts?:
|
|
58
|
+
ts?: Date;
|
|
59
59
|
/**
|
|
60
60
|
* @generated from field: repeated google.protobuf.Timestamp timestamps = 5;
|
|
61
61
|
*/
|
|
62
|
-
timestamps?:
|
|
62
|
+
timestamps?: Date[];
|
|
63
63
|
|
|
64
64
|
/**
|
|
65
65
|
* @generated from oneof example.EchoMsg.demo
|
package/example/tsconfig.json
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aptre/protobuf-es-lite",
|
|
3
3
|
"description": "Lightweight Protobuf codegen for TypeScript and JavaScript.",
|
|
4
|
-
"version": "0.4.
|
|
4
|
+
"version": "0.4.3",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
7
7
|
"url": "git+ssh://git@github.com/aperturerobotics/protobuf-es-lite.git"
|
|
@@ -56,6 +56,7 @@
|
|
|
56
56
|
"format": "prettier --write './src/**/(*.ts|*.tsx|*.html|*.css|*.scss)'",
|
|
57
57
|
"precommit": "lint-staged",
|
|
58
58
|
"test": "vitest run",
|
|
59
|
+
"lint": "ESLINT_USE_FLAT_CONFIG=false eslint -c .eslintrc.cjs ./",
|
|
59
60
|
"release:version": "npm version patch -m \"release: v%s\" --no-git-tag-version",
|
|
60
61
|
"release:version:minor": "npm version minor -m \"release: v%s\" --no-git-tag-version",
|
|
61
62
|
"release:commit": "git reset && git add package.json && git commit -s -m \"release: v$npm_package_version\" && git tag v$npm_package_version",
|
|
@@ -73,6 +74,11 @@
|
|
|
73
74
|
},
|
|
74
75
|
"devDependencies": {
|
|
75
76
|
"@types/node": "^20.12.7",
|
|
77
|
+
"@typescript-eslint/eslint-plugin": "^7.8.0",
|
|
78
|
+
"@typescript-eslint/parser": "^7.8.0",
|
|
79
|
+
"eslint": "^8.0.0",
|
|
80
|
+
"eslint-config-prettier": "^9.1.0",
|
|
81
|
+
"eslint-plugin-unused-imports": "^3.2.0",
|
|
76
82
|
"lint-staged": ">=10",
|
|
77
83
|
"pre-commit": "^1.2.2",
|
|
78
84
|
"prettier": "^3.2.5",
|
package/tsconfig.base.json
CHANGED
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
"target": "es2022",
|
|
4
4
|
"module": "Node16",
|
|
5
5
|
"moduleResolution": "Node16",
|
|
6
|
-
"esModuleInterop": false,
|
|
7
6
|
"forceConsistentCasingInFileNames": true,
|
|
8
7
|
"strict": true,
|
|
9
8
|
"noImplicitAny": true,
|
|
@@ -17,8 +16,9 @@
|
|
|
17
16
|
"noImplicitReturns": true,
|
|
18
17
|
"noFallthroughCasesInSwitch": true,
|
|
19
18
|
"noImplicitOverride": true,
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
"
|
|
19
|
+
"declaration": true,
|
|
20
|
+
"verbatimModuleSyntax": false,
|
|
21
|
+
"esModuleInterop": true,
|
|
22
|
+
"skipLibCheck": true,
|
|
23
23
|
}
|
|
24
24
|
}
|
package/tsconfig.json
CHANGED
|
@@ -2,9 +2,6 @@
|
|
|
2
2
|
"files": ["src/protoc-gen-es-lite/protoc-gen-es-lite-plugin.ts", "src/index.ts", "src/protoplugin/index.ts", "src/protoplugin/ecmascript/index.ts"],
|
|
3
3
|
"extends": "./tsconfig.base.json",
|
|
4
4
|
"compilerOptions": {
|
|
5
|
-
"verbatimModuleSyntax": false,
|
|
6
|
-
"esModuleInterop": true,
|
|
7
|
-
"skipLibCheck": true,
|
|
8
5
|
"rootDir": "./src"
|
|
9
6
|
}
|
|
10
7
|
}
|