@aptre/protobuf-es-lite 0.3.1 → 0.4.1

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/message.d.ts CHANGED
@@ -38,10 +38,14 @@ export interface MessageType<T extends Message<T> = AnyMessage> {
38
38
  * When used as a field, unwrap this message to a simple value.
39
39
  */
40
40
  readonly fieldWrapper?: FieldWrapper<T>;
41
+ /**
42
+ * Create a new empty instance of this message applying the partial message.
43
+ */
44
+ create(partial?: Message<T>): Message<T>;
41
45
  /**
42
46
  * Create a new instance of this message with zero values for fields.
43
47
  */
44
- create(partial?: Message<T>): CompleteMessage<T>;
48
+ createComplete(partial?: Message<T>): CompleteMessage<T>;
45
49
  /**
46
50
  * Create a deep copy.
47
51
  */
@@ -107,8 +111,8 @@ export type MessageTypeParams<T extends Message<T>> = Pick<MessageType<T>, "fiel
107
111
  */
108
112
  export declare function createMessageType<T extends Message<T>, E extends Record<string, Function> = {}>(params: MessageTypeParams<T>, exts?: E): MessageType<T> & E;
109
113
  export declare function compareMessages<T extends Message<T>>(fields: FieldList, a: T | undefined | null, b: T | undefined | null): boolean;
110
- export declare function cloneMessage<T extends Message<T>>(message: T, fields: FieldList): T;
114
+ export declare function cloneMessage<T extends Message<T>>(message: T | null | undefined, fields: FieldList): T | null;
111
115
  /**
112
- * createMessage recursively builds a message filled with zero values based on the given FieldList.
116
+ * createCompleteMessage recursively builds a message filled with zero values based on the given FieldList.
113
117
  */
114
- export declare function createMessage<T extends Message<T>>(fields: FieldList): CompleteMessage<T>;
118
+ export declare function createCompleteMessage<T extends Message<T>>(fields: FieldList): CompleteMessage<T>;
package/dist/message.js CHANGED
@@ -13,9 +13,11 @@
13
13
  // limitations under the License.
14
14
  import { newFieldList, resolveMessageType, } from "./field.js";
15
15
  import { applyPartialMessage } from "./partial.js";
16
- import { ScalarType, scalarEquals } from "./scalar.js";
16
+ import { LongType, ScalarType, scalarEquals, scalarZeroValue, } from "./scalar.js";
17
17
  import { binaryReadMessage, binaryWriteMessage, binaryMakeReadOptions, binaryMakeWriteOptions, } from "./binary.js";
18
18
  import { jsonReadMessage, jsonWriteMessage, jsonMakeReadOptions, jsonMakeWriteOptions, } from "./json.js";
19
+ import { throwSanitizeKey } from "./names.js";
20
+ import { enumZeroValue } from "./enum.js";
19
21
  /**
20
22
  * createMessageType creates a new message type.
21
23
  *
@@ -30,7 +32,12 @@ export function createMessageType(params, exts) {
30
32
  fields,
31
33
  fieldWrapper,
32
34
  create(partial) {
33
- const message = createMessage(fields);
35
+ const message = Object.create(null);
36
+ applyPartialMessage(partial, message, fields);
37
+ return message;
38
+ },
39
+ createComplete(partial) {
40
+ const message = createCompleteMessage(fields);
34
41
  applyPartialMessage(partial, message, fields);
35
42
  return message;
36
43
  },
@@ -47,7 +54,7 @@ export function createMessageType(params, exts) {
47
54
  const message = {};
48
55
  if (bytes && bytes.length) {
49
56
  const opt = binaryMakeReadOptions(options);
50
- binaryReadMessage(message, fields, opt.readerFactory(bytes), bytes.byteLength, opt, delimitedMessageEncoding);
57
+ binaryReadMessage(message, fields, opt.readerFactory(bytes), bytes.byteLength, opt, delimitedMessageEncoding ?? false);
51
58
  }
52
59
  return message;
53
60
  },
@@ -104,9 +111,12 @@ export function compareMessages(fields, a, b) {
104
111
  const va = a[m.localName];
105
112
  const vb = b[m.localName];
106
113
  if (m.repeated) {
107
- if (va.length !== vb.length) {
114
+ if ((va?.length ?? 0) !== (vb?.length ?? 0)) {
108
115
  return false;
109
116
  }
117
+ if (!va?.length) {
118
+ return true;
119
+ }
110
120
  // eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check -- repeated fields are never "map"
111
121
  switch (m.kind) {
112
122
  case "message":
@@ -127,9 +137,12 @@ export function compareMessages(fields, a, b) {
127
137
  case "scalar":
128
138
  return scalarEquals(m.T, va, vb);
129
139
  case "oneof":
130
- if (va.case !== vb.case) {
140
+ if (va?.case !== vb?.case) {
131
141
  return false;
132
142
  }
143
+ if (va == null) {
144
+ return true;
145
+ }
133
146
  const s = m.findField(va.case);
134
147
  if (s === undefined) {
135
148
  return true;
@@ -160,129 +173,55 @@ export function compareMessages(fields, a, b) {
160
173
  }
161
174
  });
162
175
  }
163
- // clone a single field value - i.e. the element type of repeated fields, the value type of maps
164
- function cloneSingularField(value, fieldInfo) {
165
- if (value === undefined) {
166
- return value;
167
- }
168
- if (fieldInfo.kind === "message") {
169
- return cloneMessage(value, resolveMessageType(fieldInfo.T).fields);
170
- }
171
- if (fieldInfo.kind === "oneof") {
172
- if (value.case === undefined) {
173
- return undefined;
174
- }
175
- const selectedField = fieldInfo.findField(value.case);
176
- if (!selectedField) {
177
- throw new Error(`Invalid oneof case "${value.case}" for ${fieldInfo.name}`);
178
- }
179
- return {
180
- case: value.case,
181
- value: cloneSingularField(value.value, selectedField),
182
- };
183
- }
184
- if (value instanceof Uint8Array) {
185
- const c = new Uint8Array(value.byteLength);
186
- c.set(value);
187
- return c;
188
- }
189
- return value;
190
- }
191
- // TODO use isFieldSet() here to support future field presence
192
176
  export function cloneMessage(message, fields) {
193
- const clone = {};
194
- for (const member of fields.byMember()) {
195
- const source = message[member.localName];
196
- let copy;
197
- if (member.repeated) {
198
- copy = source.map((v) => cloneSingularField(v, member));
199
- }
200
- else if (member.kind == "map") {
201
- copy = {};
202
- for (const [key, v] of Object.entries(source)) {
203
- copy[key] = cloneSingularField(v, member);
204
- }
205
- }
206
- else if (member.kind == "oneof") {
207
- const f = member.findField(source.case);
208
- copy =
209
- f ?
210
- { case: source.case, value: cloneSingularField(source.value, member) }
211
- : { case: undefined };
212
- }
213
- else {
214
- copy = cloneSingularField(source, member);
215
- }
216
- clone[member.localName] = copy;
177
+ if (message == null) {
178
+ return null;
217
179
  }
180
+ const clone = Object.create(null);
181
+ applyPartialMessage(message, clone, fields, true);
218
182
  return clone;
219
183
  }
220
184
  /**
221
- * createMessage recursively builds a message filled with zero values based on the given FieldList.
185
+ * createCompleteMessage recursively builds a message filled with zero values based on the given FieldList.
222
186
  */
223
- export function createMessage(fields) {
187
+ export function createCompleteMessage(fields) {
224
188
  const message = {};
225
- for (const field of fields.list()) {
226
- const fieldKind = field.kind;
189
+ for (const field of fields.byMember()) {
190
+ const { localName, kind: fieldKind } = field;
191
+ throwSanitizeKey(localName);
227
192
  switch (fieldKind) {
193
+ case "oneof":
194
+ message[localName] = Object.create(null);
195
+ message[localName].case = undefined;
196
+ break;
228
197
  case "scalar":
229
198
  if (field.repeated) {
230
- message[field.localName] = [];
199
+ message[localName] = [];
231
200
  }
232
201
  else {
233
- switch (field.T) {
234
- case ScalarType.DOUBLE:
235
- case ScalarType.FLOAT:
236
- message[field.localName] = 0;
237
- break;
238
- case ScalarType.INT64:
239
- case ScalarType.UINT64:
240
- case ScalarType.INT32:
241
- case ScalarType.FIXED64:
242
- case ScalarType.FIXED32:
243
- case ScalarType.UINT32:
244
- case ScalarType.SFIXED32:
245
- case ScalarType.SFIXED64:
246
- case ScalarType.SINT32:
247
- case ScalarType.SINT64:
248
- message[field.localName] = 0;
249
- break;
250
- case ScalarType.BOOL:
251
- message[field.localName] = false;
252
- break;
253
- case ScalarType.STRING:
254
- message[field.localName] = "";
255
- break;
256
- case ScalarType.BYTES:
257
- message[field.localName] =
258
- new Uint8Array();
259
- break;
260
- }
202
+ message[localName] = scalarZeroValue(field.T, LongType.BIGINT);
261
203
  }
262
204
  break;
263
205
  case "enum":
264
- if (field.repeated) {
265
- message[field.localName] = [];
266
- }
267
- else {
268
- message[field.localName] = 0;
269
- }
206
+ message[localName] = field.repeated ? [] : enumZeroValue(field.T);
270
207
  break;
271
208
  case "message":
209
+ // oneofs are handled above
272
210
  if (field.oneof) {
273
- message[field.localName] = undefined;
274
- continue;
211
+ break;
275
212
  }
276
- const messageType = resolveMessageType(field.T);
277
213
  if (field.repeated) {
278
- message[field.localName] = [];
279
- }
280
- else {
281
- message[field.localName] = createMessage(messageType.fields);
214
+ message[localName] = [];
215
+ break;
282
216
  }
217
+ const messageType = resolveMessageType(field.T);
218
+ message[localName] =
219
+ !!messageType.fieldWrapper ?
220
+ messageType.fieldWrapper.unwrapField(null)
221
+ : createCompleteMessage(messageType.fields);
283
222
  break;
284
223
  case "map":
285
- message[field.localName] = {};
224
+ message[localName] = Object.create(null);
286
225
  break;
287
226
  default:
288
227
  field;
package/dist/names.d.ts CHANGED
@@ -41,3 +41,5 @@ export declare const safeObjectProperty: (name: string) => string;
41
41
  * Names that can be used for identifiers or class properties
42
42
  */
43
43
  export declare const safeIdentifier: (name: string) => string;
44
+ export declare function checkSanitizeKey(key: string): boolean;
45
+ export declare function throwSanitizeKey(key: string): void;
package/dist/names.js CHANGED
@@ -32,12 +32,7 @@ export function localName(desc) {
32
32
  const pkg = desc.file.proto.package;
33
33
  const offset = pkg === undefined ? 0 : pkg.length + 1;
34
34
  const name = desc.typeName.substring(offset).replace(/\./g, "_");
35
- // For services, we only care about safe identifiers, not safe object properties,
36
- // but we have shipped v1 with a bug that respected object properties, and we
37
- // do not want to introduce a breaking change, so we continue to escape for
38
- // safe object properties.
39
- // See https://github.com/bufbuild/protobuf-es/pull/391
40
- return safeObjectProperty(safeIdentifier(name));
35
+ return safeIdentifier(name);
41
36
  }
42
37
  case "enum_value": {
43
38
  let name = desc.name;
@@ -219,20 +214,7 @@ const reservedObjectProperties = new Set([
219
214
  * Names that cannot be used for object properties because they are reserved
220
215
  * by the runtime.
221
216
  */
222
- const reservedMessageProperties = new Set([
223
- // names reserved by the runtime
224
- "getType",
225
- "clone",
226
- "equals",
227
- "fromBinary",
228
- "fromJson",
229
- "fromJsonString",
230
- "toBinary",
231
- "toJson",
232
- "toJsonString",
233
- // names reserved by the runtime for the future
234
- "toObject",
235
- ]);
217
+ const reservedMessageProperties = new Set(["__proto__"]);
236
218
  const fallback = (name) => `${name}$`;
237
219
  /**
238
220
  * Will wrap names that are Object prototype properties or names reserved
@@ -263,3 +245,14 @@ export const safeIdentifier = (name) => {
263
245
  }
264
246
  return name;
265
247
  };
248
+ export function checkSanitizeKey(key) {
249
+ return typeof key === "string" && key !== "__proto__";
250
+ }
251
+ export function throwSanitizeKey(key) {
252
+ if (typeof key !== "string") {
253
+ throw new Error("illegal non-string object key: " + typeof key);
254
+ }
255
+ if (!checkSanitizeKey(key)) {
256
+ throw new Error("illegal object key: " + key);
257
+ }
258
+ }
package/dist/partial.d.ts CHANGED
@@ -1,3 +1,4 @@
1
- import { FieldList } from "./field.js";
1
+ import { FieldList, MapValueInfo } from "./field.js";
2
2
  import { Message } from "./message.js";
3
- export declare function applyPartialMessage<T extends Message<T>>(source: Message<T> | undefined, target: Message<T>, fields: FieldList): void;
3
+ export declare function applyPartialMessage<T extends Message<T>>(source: Message<T> | undefined, target: Message<T>, fields: FieldList, clone?: boolean): void;
4
+ export declare function applyPartialMap(sourceMap: Record<string, any> | undefined, targetMap: Record<string, any>, value: MapValueInfo, clone: boolean): void;
package/dist/partial.js CHANGED
@@ -1,99 +1,196 @@
1
+ import { normalizeEnumValue } from "./enum.js";
1
2
  import { resolveMessageType } from "./field.js";
2
- import { ScalarType } from "./scalar.js";
3
- // applyPartialMessage applies a partial message to a message.
4
- export function applyPartialMessage(source, target, fields) {
5
- if (source === undefined) {
3
+ import { createCompleteMessage } from "./message.js";
4
+ import { throwSanitizeKey } from "./names.js";
5
+ import { normalizeScalarValue } from "./scalar.js";
6
+ // applyPartialMessage applies a partial source message to a target message.
7
+ //
8
+ // if clone is set: values are deep-copied including Uint8Arrays.
9
+ export function applyPartialMessage(source, target, fields, clone = false) {
10
+ if (source == null || target == null) {
6
11
  return;
7
12
  }
13
+ const t = target, s = source;
8
14
  for (const member of fields.byMember()) {
9
- const localName = member.localName, t = target, s = source;
10
- if (s[localName] === undefined) {
15
+ const localName = member.localName;
16
+ throwSanitizeKey(localName);
17
+ if (!(localName in s) || s[localName] === undefined) {
18
+ continue;
19
+ }
20
+ const sourceValue = s[localName];
21
+ if (sourceValue === null) {
22
+ delete t[localName];
11
23
  continue;
12
24
  }
13
25
  switch (member.kind) {
14
26
  case "oneof":
15
- const sk = s[localName].case;
16
- if (sk === undefined) {
17
- continue;
27
+ if (typeof sourceValue !== "object") {
28
+ throw new Error(`field ${localName}: invalid oneof: must be an object with case and value`);
29
+ }
30
+ // sk, sk are the source case and value
31
+ const { case: sk, value: sv } = sourceValue;
32
+ // sourceField is the field set by the source case, if any.
33
+ const sourceField = sk != null ? member.findField(sk) : null;
34
+ // dv is the destination oneof object
35
+ let dv = localName in t ? t[localName] : undefined;
36
+ if (typeof dv !== "object") {
37
+ dv = Object.create(null);
38
+ }
39
+ // check the case is valid and throw if not
40
+ if (sk != null && sourceField == null) {
41
+ throw new Error(`field ${localName}: invalid oneof case: ${sk}`);
42
+ }
43
+ // update the case
44
+ dv.case = sk;
45
+ // if the case was different or null, clear the value.
46
+ if (dv.case !== sk || sk == null) {
47
+ delete dv.value;
18
48
  }
19
- const sourceField = member.findField(sk);
20
- let val = s[localName].value;
21
- if (sourceField?.kind == "message") {
22
- if (val === undefined) {
23
- val = {};
49
+ t[localName] = dv;
50
+ // stop here if there was no valid case selected
51
+ if (!sourceField) {
52
+ break;
53
+ }
54
+ if (sourceField.kind === "message") {
55
+ // apply the partial to the value
56
+ let dest = dv.value;
57
+ if (typeof dest !== "object") {
58
+ dest = dv.value = Object.create(null);
59
+ }
60
+ // skip zero or null value
61
+ if (sv != null) {
62
+ const sourceFieldMt = resolveMessageType(sourceField.T);
63
+ applyPartialMessage(sv, dest, sourceFieldMt.fields);
24
64
  }
25
65
  }
26
- else if (sourceField &&
27
- sourceField.kind === "scalar" &&
28
- sourceField.T === ScalarType.BYTES) {
29
- val = toU8Arr(val);
66
+ else if (sourceField.kind === "scalar") {
67
+ dv.value = normalizeScalarValue(sourceField.T, sv, clone);
68
+ }
69
+ else {
70
+ dv.value = sv;
30
71
  }
31
- t[localName] = { case: sk, value: val };
32
72
  break;
33
73
  case "scalar":
74
+ if (member.repeated) {
75
+ if (!Array.isArray(sourceValue)) {
76
+ throw new Error(`field ${localName}: invalid value: must be array`);
77
+ }
78
+ let dst = localName in t ? t[localName] : null;
79
+ if (dst == null || !Array.isArray(dst)) {
80
+ dst = t[localName] = [];
81
+ }
82
+ dst.push(...sourceValue.map((v) => normalizeScalarValue(member.T, v, clone)));
83
+ break;
84
+ }
85
+ t[localName] = normalizeScalarValue(member.T, sourceValue, clone);
86
+ break;
34
87
  case "enum":
35
- let copy = s[localName];
36
- if (member.T === ScalarType.BYTES) {
37
- copy =
38
- member.repeated ?
39
- copy.map(toU8Arr)
40
- : toU8Arr(copy);
41
- }
42
- t[localName] = copy;
88
+ t[localName] = normalizeEnumValue(member.T, sourceValue);
43
89
  break;
44
90
  case "map":
45
- switch (member.V.kind) {
46
- case "scalar":
47
- case "enum":
48
- if (member.V.T === ScalarType.BYTES) {
49
- for (const [k, v] of Object.entries(s[localName])) {
50
- t[localName][k] = toU8Arr(v);
51
- }
52
- }
53
- else {
54
- Object.assign(t[localName], s[localName]);
55
- }
56
- break;
57
- case "message":
58
- const messageType = resolveMessageType(member.V.T);
59
- for (const k of Object.keys(s[localName])) {
60
- let val = s[localName][k];
61
- if (!messageType.fieldWrapper) {
62
- if (val === undefined) {
63
- val = {};
64
- }
65
- }
66
- t[localName][k] = val;
67
- }
68
- break;
91
+ if (typeof sourceValue !== "object") {
92
+ throw new Error(`field ${member.localName}: invalid value: must be object`);
93
+ }
94
+ let tMap = t[localName];
95
+ if (typeof tMap !== "object") {
96
+ tMap = t[localName] = Object.create(null);
69
97
  }
98
+ applyPartialMap(sourceValue, tMap, member.V, clone);
70
99
  break;
71
100
  case "message":
72
101
  const mt = resolveMessageType(member.T);
73
102
  if (member.repeated) {
74
- t[localName] = s[localName].map((val) => val ?? {});
103
+ // skip null or undefined values
104
+ if (!Array.isArray(sourceValue)) {
105
+ throw new Error(`field ${localName}: invalid value: must be array`);
106
+ }
107
+ let tArr = t[localName];
108
+ if (!Array.isArray(tArr)) {
109
+ tArr = t[localName] = [];
110
+ }
111
+ for (const v of sourceValue) {
112
+ // skip null or undefined values
113
+ if (v != null) {
114
+ if (mt.fieldWrapper) {
115
+ tArr.push(mt.fieldWrapper.unwrapField(mt.fieldWrapper.wrapField(v)));
116
+ }
117
+ else {
118
+ tArr.push(mt.create(v));
119
+ }
120
+ }
121
+ }
122
+ break;
123
+ }
124
+ if (mt.fieldWrapper) {
125
+ t[localName] = mt.fieldWrapper.unwrapField(mt.fieldWrapper.wrapField(sourceValue));
75
126
  }
76
127
  else {
77
- const val = s[localName];
78
- if (mt.fieldWrapper) {
79
- if (
80
- // We can't use BytesValue.typeName as that will create a circular import
81
- mt.typeName === "google.protobuf.BytesValue") {
82
- t[localName] = toU8Arr(val);
83
- }
84
- else {
85
- t[localName] = val;
86
- }
128
+ if (typeof sourceValue !== "object") {
129
+ throw new Error(`field ${member.localName}: invalid value: must be object`);
87
130
  }
88
- else {
89
- t[localName] = val ?? {};
131
+ let destMsg = t[localName];
132
+ if (typeof destMsg !== "object") {
133
+ destMsg = t[localName] = Object.create(null);
90
134
  }
135
+ applyPartialMessage(sourceValue, destMsg, mt.fields);
91
136
  }
92
137
  break;
93
138
  }
94
139
  }
95
140
  }
96
- // converts any ArrayLike<number> to Uint8Array if necessary.
97
- function toU8Arr(input) {
98
- return input instanceof Uint8Array ? input : new Uint8Array(input);
141
+ // applyPartialMap applies a partial source map to a target map.
142
+ export function applyPartialMap(sourceMap, targetMap, value, clone) {
143
+ if (sourceMap == null) {
144
+ return;
145
+ }
146
+ if (typeof sourceMap !== "object") {
147
+ throw new Error(`invalid map: must be object`);
148
+ }
149
+ switch (value.kind) {
150
+ case "scalar":
151
+ for (const [k, v] of Object.entries(sourceMap)) {
152
+ throwSanitizeKey(k);
153
+ if (v !== undefined) {
154
+ targetMap[k] = normalizeScalarValue(value.T, v, clone);
155
+ }
156
+ else {
157
+ delete targetMap[k];
158
+ }
159
+ }
160
+ break;
161
+ case "enum":
162
+ for (const [k, v] of Object.entries(sourceMap)) {
163
+ throwSanitizeKey(k);
164
+ if (v !== undefined) {
165
+ targetMap[k] = normalizeEnumValue(value.T, v);
166
+ }
167
+ else {
168
+ delete targetMap[k];
169
+ }
170
+ }
171
+ break;
172
+ case "message":
173
+ const messageType = resolveMessageType(value.T);
174
+ for (const [k, v] of Object.entries(sourceMap)) {
175
+ throwSanitizeKey(k);
176
+ if (v === undefined) {
177
+ delete targetMap[k];
178
+ continue;
179
+ }
180
+ if (typeof v !== "object") {
181
+ throw new Error(`invalid value: must be object`);
182
+ }
183
+ let val = targetMap[k];
184
+ if (!!messageType.fieldWrapper) {
185
+ // For wrapper type messages, call createCompleteMessage.
186
+ val = targetMap[k] = createCompleteMessage(messageType.fields);
187
+ }
188
+ else if (typeof val !== "object") {
189
+ // Otherwise apply the partial to the existing value, if any.
190
+ val = targetMap[k] = Object.create(null);
191
+ }
192
+ applyPartialMessage(v, val, messageType.fields);
193
+ }
194
+ break;
195
+ }
99
196
  }
@@ -384,9 +384,17 @@ function generateWktMethods(schema, f, message, ref) {
384
384
  f.print(" }");
385
385
  f.print(` return new Date(ms).toISOString().replace(".000Z", z);`);
386
386
  f.print(" },");
387
- f.print(" toDate(msg: ", message, "): Date {");
387
+ f.print(" toDate(msg: ", message, " | null | undefined): Date | null {");
388
+ f.print(" if (!msg?.", localName(ref.seconds), " && !msg?.", localName(ref.nanos), ") { return null; }");
388
389
  f.print(" return new Date(Number(msg.", localName(ref.seconds), " ?? 0) * 1000 + Math.ceil((msg.", localName(ref.nanos), " ?? 0) / 1000000));");
389
390
  f.print(" },");
391
+ f.print(" fromDate(value: Date | null | undefined): ", message, " {");
392
+ f.print(" if (value == null) { return {}; }");
393
+ f.print(" const ms = value.getTime();");
394
+ f.print(" const seconds = Math.floor(ms / 1000);");
395
+ f.print(" const nanos = (ms % 1000) * 1000000;");
396
+ f.print(" return { ", localName(ref.seconds), ": ", protoInt64, ".parse(seconds), ", localName(ref.nanos), ": nanos };");
397
+ f.print(" },");
390
398
  break;
391
399
  case "google.protobuf.Duration":
392
400
  f.print(" fromJson(json: ", JsonValue, " | null | undefined, _options?: Partial<", JsonReadOptions, ">): ", message, " {");
@@ -552,6 +560,30 @@ function generateWktMethods(schema, f, message, ref) {
552
560
  }
553
561
  function generateWktFieldWrapper(f, message, ref) {
554
562
  switch (ref?.typeName) {
563
+ /* TODO Wrap Timestamp => Date
564
+ 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;
585
+ }
586
+ */
555
587
  case "google.protobuf.DoubleValue":
556
588
  case "google.protobuf.FloatValue":
557
589
  case "google.protobuf.Int64Value":
@@ -564,7 +596,7 @@ function generateWktFieldWrapper(f, message, ref) {
564
596
  const { typing } = getFieldTypeInfo(ref.value);
565
597
  f.print(" fieldWrapper: {");
566
598
  f.print(" wrapField(value: ", typing, " | null | undefined): ", message, " {");
567
- f.print(" return ", message, ".create({ value: value ?? undefined });");
599
+ f.print(" return ", message, ".createComplete({ value: value ?? undefined });");
568
600
  f.print(" },");
569
601
  f.print(" unwrapField(msg: ", message, "): ", typing, " | null | undefined {");
570
602
  f.print(" return msg.", localName(ref.value), ";");
package/dist/scalar.d.ts CHANGED
@@ -67,3 +67,12 @@ export declare function scalarZeroValue<T extends ScalarType, L extends LongType
67
67
  * optional or repeated.
68
68
  */
69
69
  export declare function isScalarZeroValue(type: ScalarType, value: unknown): boolean;
70
+ /**
71
+ * Returns the normalized version of the scalar value.
72
+ * Zero or null is cast to the zero value.
73
+ * Bytes is cast to a Uint8Array.
74
+ * The BigInt long type is used.
75
+ * If clone is set, Uint8Array will always be copied to a new value.
76
+ */
77
+ export declare function normalizeScalarValue<T>(type: ScalarType, value: T | null | undefined, clone: boolean, longType?: LongType): T;
78
+ export declare function toU8Arr(input: ArrayLike<number>, clone: boolean): Uint8Array;