@aptre/protobuf-es-lite 0.4.2 → 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 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
- let { repeated, localName } = field;
25
+ const { repeated } = field;
26
+ let { localName } = field;
26
27
  if (field.oneof) {
27
- var oneofMsg = target[field.oneof.localName];
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
- var tgtArr = target[localName];
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
- let e = reader.uint32() + reader.pos;
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
- case "message":
70
+ }
71
+ case "message": {
70
72
  const fieldT = field.T;
71
73
  const messageType = fieldT instanceof Function ? fieldT() : fieldT;
72
74
  if (repeated) {
73
- var tgtArr = target[localName];
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
- case "map":
84
- let [mapKey, mapVal] = readMapEntry(field, reader, options);
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
- const messageType = resolveMessageType(field.V.T);
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 != "string" && typeof key != "number") {
123
- key = key.toString();
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
- let scalarType = field.kind == "enum" ? ScalarType.INT32 : field.T;
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
- let [wireType, method] = scalarTypeInfo(type);
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
- let [, method] = scalarTypeInfo(type);
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
  }
@@ -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;
@@ -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,
@@ -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;
@@ -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 !!fieldWrapper ? fieldWrapper.unwrapField(value) : value;
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.repeated) {
28
- return undefined;
27
+ if (field.message.typeName !== "google.protobuf.Timestamp") {
28
+ if (field.repeated || field.oneof != null) {
29
+ return undefined;
30
+ }
29
31
  }
30
- if (field.oneof != undefined) {
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[field.message.typeName];
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);
@@ -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
@@ -58,7 +58,7 @@ function readMessage(fields, typeName, json, options, message) {
58
58
  readField(message, jsonValue, field, options);
59
59
  }
60
60
  else {
61
- let found = false;
61
+ const found = false;
62
62
  if (!found && !options.ignoreUnknownFields) {
63
63
  throw new Error(`cannot decode message ${typeName} from JSON: key "${jsonKey}" is unknown`);
64
64
  }
@@ -114,7 +114,7 @@ function readField(target, jsonValue, field, options) {
114
114
  if (!Array.isArray(jsonValue)) {
115
115
  throw new Error(`cannot decode field ${field.name} from JSON: ${jsonDebugValue(jsonValue)}`);
116
116
  }
117
- var targetArray = target[localName];
117
+ let targetArray = target[localName];
118
118
  if (!Array.isArray(targetArray)) {
119
119
  targetArray = target[localName] = [];
120
120
  }
@@ -123,16 +123,18 @@ function readField(target, jsonValue, field, options) {
123
123
  throw new Error(`cannot decode field ${field.name} from JSON: ${jsonDebugValue(jsonItem)}`);
124
124
  }
125
125
  switch (field.kind) {
126
- case "message":
126
+ case "message": {
127
127
  const messageType = resolveMessageType(field.T);
128
128
  targetArray.push(unwrapField(messageType.fieldWrapper, messageType.fromJson(jsonItem, options)));
129
129
  break;
130
- case "enum":
130
+ }
131
+ case "enum": {
131
132
  const enumValue = readEnum(field.T, jsonItem, options.ignoreUnknownFields, true);
132
133
  if (enumValue !== tokenIgnoredUnknownEnum) {
133
134
  targetArray.push(enumValue);
134
135
  }
135
136
  break;
137
+ }
136
138
  case "scalar":
137
139
  try {
138
140
  targetArray.push(readScalar(field.T, jsonItem, field.L, true));
@@ -155,7 +157,7 @@ function readField(target, jsonValue, field, options) {
155
157
  if (typeof jsonValue != "object" || Array.isArray(jsonValue)) {
156
158
  throw new Error(`cannot decode field ${field.name} from JSON: ${jsonDebugValue(jsonValue)}`);
157
159
  }
158
- var targetMap = target[localName];
160
+ let targetMap = target[localName];
159
161
  if (typeof targetMap !== "object") {
160
162
  targetMap = target[localName] = Object.create(null);
161
163
  }
@@ -176,16 +178,18 @@ function readField(target, jsonValue, field, options) {
176
178
  }
177
179
  throwSanitizeKey(key);
178
180
  switch (field.V.kind) {
179
- case "message":
181
+ case "message": {
180
182
  const messageType = resolveMessageType(field.V.T);
181
183
  targetMap[key] = messageType.fromJson(jsonMapValue, options);
182
184
  break;
183
- case "enum":
185
+ }
186
+ case "enum": {
184
187
  const enumValue = readEnum(field.V.T, jsonMapValue, options.ignoreUnknownFields, true);
185
188
  if (enumValue !== tokenIgnoredUnknownEnum) {
186
189
  targetMap[key] = enumValue;
187
190
  }
188
191
  break;
192
+ }
189
193
  case "scalar":
190
194
  try {
191
195
  targetMap[key] = readScalar(field.V.T, jsonMapValue, LongType.BIGINT, true);
@@ -207,7 +211,7 @@ function readField(target, jsonValue, field, options) {
207
211
  localName = "value";
208
212
  }
209
213
  switch (field.kind) {
210
- case "message":
214
+ case "message": {
211
215
  const messageType = resolveMessageType(field.T);
212
216
  if (jsonValue === null &&
213
217
  messageType.typeName != "google.protobuf.Value") {
@@ -215,7 +219,8 @@ function readField(target, jsonValue, field, options) {
215
219
  }
216
220
  target[localName] = unwrapField(messageType.fieldWrapper, messageType.fromJson(jsonValue, options));
217
221
  break;
218
- case "enum":
222
+ }
223
+ case "enum": {
219
224
  const enumValue = readEnum(field.T, jsonValue, options.ignoreUnknownFields, false);
220
225
  switch (enumValue) {
221
226
  case tokenNull:
@@ -228,6 +233,7 @@ function readField(target, jsonValue, field, options) {
228
233
  break;
229
234
  }
230
235
  break;
236
+ }
231
237
  case "scalar":
232
238
  try {
233
239
  const scalarValue = readScalar(field.T, jsonValue, field.L, false);
@@ -267,7 +273,7 @@ function readEnum(type, json, ignoreUnknownFields, nullAsZeroValue) {
267
273
  return json;
268
274
  }
269
275
  break;
270
- case "string":
276
+ case "string": {
271
277
  const value = type.findName(json);
272
278
  if (value !== undefined) {
273
279
  return value.no;
@@ -276,6 +282,7 @@ function readEnum(type, json, ignoreUnknownFields, nullAsZeroValue) {
276
282
  return tokenIgnoredUnknownEnum;
277
283
  }
278
284
  break;
285
+ }
279
286
  }
280
287
  throw new Error(`cannot decode enum ${type.typeName} from JSON: ${jsonDebugValue(json)}`);
281
288
  }
@@ -292,7 +299,7 @@ function readScalar(type, json, longType = LongType.BIGINT, nullAsZeroValue = tr
292
299
  // float, double: JSON value will be a number or one of the special string values "NaN", "Infinity", and "-Infinity".
293
300
  // Either numbers or strings are accepted. Exponent notation is also accepted.
294
301
  case ScalarType.DOUBLE:
295
- case ScalarType.FLOAT:
302
+ case ScalarType.FLOAT: {
296
303
  if (json === "NaN")
297
304
  return Number.NaN;
298
305
  if (json === "Infinity")
@@ -322,12 +329,13 @@ function readScalar(type, json, longType = LongType.BIGINT, nullAsZeroValue = tr
322
329
  if (type == ScalarType.FLOAT)
323
330
  assertFloat32(float);
324
331
  return float;
332
+ }
325
333
  // int32, fixed32, uint32: JSON value will be a decimal number. Either numbers or strings are accepted.
326
334
  case ScalarType.INT32:
327
335
  case ScalarType.FIXED32:
328
336
  case ScalarType.SFIXED32:
329
337
  case ScalarType.SINT32:
330
- case ScalarType.UINT32:
338
+ case ScalarType.UINT32: {
331
339
  let int32;
332
340
  if (typeof json == "number")
333
341
  int32 = json;
@@ -342,22 +350,25 @@ function readScalar(type, json, longType = LongType.BIGINT, nullAsZeroValue = tr
342
350
  else
343
351
  assertInt32(int32);
344
352
  return int32;
353
+ }
345
354
  // int64, fixed64, uint64: JSON value will be a decimal string. Either numbers or strings are accepted.
346
355
  case ScalarType.INT64:
347
356
  case ScalarType.SFIXED64:
348
- case ScalarType.SINT64:
357
+ case ScalarType.SINT64: {
349
358
  if (typeof json != "number" && typeof json != "string")
350
359
  break;
351
360
  const long = protoInt64.parse(json);
352
361
  // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
353
362
  return longType ? long.toString() : long;
363
+ }
354
364
  case ScalarType.FIXED64:
355
- case ScalarType.UINT64:
365
+ case ScalarType.UINT64: {
356
366
  if (typeof json != "number" && typeof json != "string")
357
367
  break;
358
368
  const uLong = protoInt64.uParse(json);
359
369
  // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
360
370
  return longType ? uLong.toString() : uLong;
371
+ }
361
372
  // bool:
362
373
  case ScalarType.BOOL:
363
374
  if (typeof json !== "boolean")
@@ -400,7 +411,7 @@ function readMapKey(type, json) {
400
411
  break;
401
412
  }
402
413
  }
403
- return readScalar(type, json, LongType.BIGINT, true).toString();
414
+ return readScalar(type, json, LongType.BIGINT, true)?.toString() ?? "";
404
415
  }
405
416
  /**
406
417
  * Resets the field, so that isFieldSet() will return false.
@@ -470,13 +481,14 @@ function writeField(field, value, options) {
470
481
  jsonObj[entryKey.toString()] = messageType.toJson(entryValue, options);
471
482
  }
472
483
  break;
473
- case "enum":
484
+ case "enum": {
474
485
  const enumType = field.V.T;
475
486
  for (const [entryKey, entryValue] of entries) {
476
487
  // JSON standard allows only (double quoted) string as property key
477
488
  jsonObj[entryKey.toString()] = writeEnum(enumType, entryValue, options.enumAsInteger);
478
489
  }
479
490
  break;
491
+ }
480
492
  }
481
493
  return options.emitDefaultValues || entries.length > 0 ?
482
494
  jsonObj
@@ -498,12 +510,13 @@ function writeField(field, value, options) {
498
510
  jsonArr.push(writeEnum(field.T, valueArr[i], options.enumAsInteger));
499
511
  }
500
512
  break;
501
- case "message":
513
+ case "message": {
502
514
  const messageType = resolveMessageType(field.T);
503
515
  for (let i = 0; i < valueArr.length; i++) {
504
516
  jsonArr.push(messageType.toJson(wrapField(messageType.fieldWrapper, valueArr[i])));
505
517
  }
506
518
  break;
519
+ }
507
520
  }
508
521
  }
509
522
  return options.emitDefaultValues || jsonArr.length > 0 ?
@@ -511,25 +524,28 @@ function writeField(field, value, options) {
511
524
  : undefined;
512
525
  }
513
526
  switch (field.kind) {
514
- case "scalar":
527
+ case "scalar": {
515
528
  const scalarValue = normalizeScalarValue(field.T, value, false);
516
- if (!options.emitDefaultValues
517
- && isScalarZeroValue(field.T, scalarValue)) {
529
+ if (!options.emitDefaultValues &&
530
+ isScalarZeroValue(field.T, scalarValue)) {
518
531
  return undefined;
519
532
  }
520
533
  return writeScalar(field.T, value);
521
- case "enum":
534
+ }
535
+ case "enum": {
522
536
  const enumValue = normalizeEnumValue(field.T, value);
523
537
  if (!options.emitDefaultValues && enumZeroValue(field.T) === enumValue) {
524
538
  return undefined;
525
539
  }
526
540
  return writeEnum(field.T, value, options.enumAsInteger);
527
- case "message":
541
+ }
542
+ case "message": {
528
543
  if (!options.emitDefaultValues && value == null) {
529
544
  return undefined;
530
545
  }
531
546
  const messageType = resolveMessageType(field.T);
532
547
  return messageType.toJson(wrapField(messageType.fieldWrapper, value));
548
+ }
533
549
  }
534
550
  }
535
551
  function writeScalar(type, value) {
@@ -578,6 +594,10 @@ function writeScalar(type, value) {
578
594
  case ScalarType.BYTES:
579
595
  assert(value instanceof Uint8Array);
580
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");
581
601
  }
582
602
  }
583
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 Record<string, Function> = {}>(params: MessageTypeParams<T>, exts?: E): MessageType<T> & E;
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
- case "map":
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
- !!messageType.fieldWrapper ?
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
@@ -248,7 +248,9 @@ export const safeIdentifier = (name) => {
248
248
  return name;
249
249
  };
250
250
  export function checkSanitizeKey(key) {
251
- return typeof key === "string" && !!key.length && !reservedObjectProperties.has(key);
251
+ return (typeof key === "string" &&
252
+ !!key.length &&
253
+ !reservedObjectProperties.has(key));
252
254
  }
253
255
  export function throwSanitizeKey(key) {
254
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
- case "scalar":
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
- case "enum":
88
+ }
89
+ case "enum": {
88
90
  t[localName] = normalizeEnumValue(member.T, sourceValue);
89
91
  break;
90
- case "map":
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
- case "message":
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 (!!messageType.fieldWrapper) {
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
- var oneOfCases = oneof.fields
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
- var name = localName(desc);
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
- f.print(" fieldWrapper: {");
566
- f.print(
567
- " wrapField(value: ",
568
- message,
569
- " | Date | null | undefined): ",
570
- message,
571
- " {",
572
- );
573
- f.print(
574
- " if (value == null || value instanceof Date) { return ",
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
+ }
@@ -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
- const baseType = codegenInfo.getUnwrappedFieldType(field);
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
+ }
@@ -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 "@aptre/protobuf-es-lite";
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 "@aptre/protobuf-es-lite";
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?: Timestamp;
58
+ ts?: Date;
59
59
  /**
60
60
  * @generated from field: repeated google.protobuf.Timestamp timestamps = 5;
61
61
  */
62
- timestamps?: Timestamp[];
62
+ timestamps?: Date[];
63
63
 
64
64
  /**
65
65
  * @generated from oneof example.EchoMsg.demo
@@ -2,6 +2,7 @@
2
2
  "extends": "../tsconfig.json",
3
3
  "files": ["example.pb.ts"],
4
4
  "compilerOptions": {
5
+ "rootDir": "../",
5
6
  "paths": {
6
7
  "@aptre/protobuf-es-lite": [
7
8
  "../src",
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.2",
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",
@@ -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
- "verbatimModuleSyntax": true,
21
- "skipLibCheck": false,
22
- "declaration": true
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
  }